From 3bc5f3933eb5ad69dded901589fe69801d880996 Mon Sep 17 00:00:00 2001 From: Rob Sterner Date: Tue, 2 Jan 2024 20:13:03 -0500 Subject: [PATCH 1/4] adds the gem --- Gemfile | 23 ++++------------------- Gemfile.lock | 11 +++++++---- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Gemfile b/Gemfile index 63ab7204..8b2bb232 100644 --- a/Gemfile +++ b/Gemfile @@ -5,42 +5,28 @@ ruby "3.2.0" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" gem "rails", "7.1.2" -# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem "sprockets-rails" -# Use postgresql as the database for Active Record gem "pg", "~> 1.1" -# Use the Puma web server [https://github.com/puma/puma] gem "puma", ">= 5.0" -# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] gem "importmap-rails" - -# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] gem "turbo-rails" - -# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] gem "stimulus-rails" - -# Use Tailwind CSS [https://github.com/rails/tailwindcss-rails] gem "tailwindcss-rails" -# Build JSON APIs with ease [https://github.com/rails/jbuilder] -gem "jbuilder" - # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] # gem "kredis" -# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] -# gem "bcrypt", "~> 3.1.7" - # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ windows jruby ] +gem "passwordless", "~> 1.1" +gem "graphql", "~> 2.2" gem "view_component" # Reduces boot times through caching; required in config/boot.rb @@ -66,6 +52,7 @@ group :development do # gem "rack-mini-profiler" gem "letter_opener" + gem "graphiql-rails" end group :test do @@ -77,6 +64,4 @@ group :test do gem "factory_bot_rails" gem 'shoulda-matchers', '~> 5.0' gem "timecop" -end - -gem "passwordless", "~> 1.1" +end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index ac34571c..ffe24bab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -120,6 +120,11 @@ GEM i18n (>= 1.8.11, < 2) globalid (1.2.1) activesupport (>= 6.1) + graphiql-rails (1.9.0) + railties + sprockets-rails + graphql (2.2.3) + racc (~> 1.4) i18n (1.14.1) concurrent-ruby (~> 1.0) importmap-rails (1.2.3) @@ -130,9 +135,6 @@ GEM irb (1.11.0) rdoc reline (>= 0.3.8) - jbuilder (2.11.5) - actionview (>= 5.0.0) - activesupport (>= 5.0.0) launchy (2.5.2) addressable (~> 2.8) letter_opener (1.8.1) @@ -305,8 +307,9 @@ DEPENDENCIES dotenv-rails factory_bot_rails faker + graphiql-rails + graphql (~> 2.2) importmap-rails - jbuilder letter_opener passwordless (~> 1.1) pg (~> 1.1) From 0a50fb8a90d8ce8a581585fde1938b18fdcfeea2 Mon Sep 17 00:00:00 2001 From: Rob Sterner Date: Tue, 2 Jan 2024 20:13:17 -0500 Subject: [PATCH 2/4] roughing in an overall APi --- app/controllers/graphql_controller.rb | 52 +++++++++++++++++++ app/graphql/mutations/.keep | 0 app/graphql/mutations/base_mutation.rb | 10 ++++ app/graphql/resolvers/base_resolver.rb | 4 ++ app/graphql/staffplan_redux_schema.rb | 42 +++++++++++++++ app/graphql/types/.keep | 0 app/graphql/types/base_argument.rb | 6 +++ app/graphql/types/base_connection.rb | 8 +++ app/graphql/types/base_edge.rb | 8 +++ app/graphql/types/base_enum.rb | 6 +++ app/graphql/types/base_field.rb | 7 +++ app/graphql/types/base_input_object.rb | 7 +++ app/graphql/types/base_interface.rb | 11 ++++ app/graphql/types/base_object.rb | 9 ++++ app/graphql/types/base_scalar.rb | 6 +++ app/graphql/types/base_union.rb | 8 +++ app/graphql/types/mutation_type.rb | 12 +++++ app/graphql/types/node_type.rb | 9 ++++ app/graphql/types/query_type.rb | 36 +++++++++++++ .../types/staff_plan/assignment_type.rb | 20 +++++++ app/graphql/types/staff_plan/client_type.rb | 20 +++++++ app/graphql/types/staff_plan/company_type.rb | 30 +++++++++++ app/graphql/types/staff_plan/project_type.rb | 33 ++++++++++++ app/graphql/types/staff_plan/user_type.rb | 32 ++++++++++++ .../types/staff_plan/work_week_type.rb | 29 +++++++++++ app/graphql/types/staff_plan_query_type.rb | 25 +++++++++ config/routes.rb | 9 ++++ 27 files changed, 439 insertions(+) create mode 100644 app/controllers/graphql_controller.rb create mode 100644 app/graphql/mutations/.keep create mode 100644 app/graphql/mutations/base_mutation.rb create mode 100644 app/graphql/resolvers/base_resolver.rb create mode 100644 app/graphql/staffplan_redux_schema.rb create mode 100644 app/graphql/types/.keep create mode 100644 app/graphql/types/base_argument.rb create mode 100644 app/graphql/types/base_connection.rb create mode 100644 app/graphql/types/base_edge.rb create mode 100644 app/graphql/types/base_enum.rb create mode 100644 app/graphql/types/base_field.rb create mode 100644 app/graphql/types/base_input_object.rb create mode 100644 app/graphql/types/base_interface.rb create mode 100644 app/graphql/types/base_object.rb create mode 100644 app/graphql/types/base_scalar.rb create mode 100644 app/graphql/types/base_union.rb create mode 100644 app/graphql/types/mutation_type.rb create mode 100644 app/graphql/types/node_type.rb create mode 100644 app/graphql/types/query_type.rb create mode 100644 app/graphql/types/staff_plan/assignment_type.rb create mode 100644 app/graphql/types/staff_plan/client_type.rb create mode 100644 app/graphql/types/staff_plan/company_type.rb create mode 100644 app/graphql/types/staff_plan/project_type.rb create mode 100644 app/graphql/types/staff_plan/user_type.rb create mode 100644 app/graphql/types/staff_plan/work_week_type.rb create mode 100644 app/graphql/types/staff_plan_query_type.rb diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb new file mode 100644 index 00000000..a2eef17d --- /dev/null +++ b/app/controllers/graphql_controller.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +class GraphqlController < ApplicationController + # If accessing from outside this domain, nullify the session + # This allows for outside API access while preventing CSRF attacks, + # but you'll have to authenticate your user separately + # protect_from_forgery with: :null_session + + def execute + variables = prepare_variables(params[:variables]) + query = params[:query] + operation_name = params[:operationName] + context = { + # Query context goes here, for example: + current_user: current_user, + } + result = StaffplanReduxSchema.execute(query, variables: variables, context: context, operation_name: operation_name) + render json: result + rescue StandardError => e + raise e unless Rails.env.development? + handle_error_in_development(e) + end + + private + + # Handle variables in form data, JSON body, or a blank value + def prepare_variables(variables_param) + case variables_param + when String + if variables_param.present? + JSON.parse(variables_param) || {} + else + {} + end + when Hash + variables_param + when ActionController::Parameters + variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables. + when nil + {} + else + raise ArgumentError, "Unexpected parameter: #{variables_param}" + end + end + + def handle_error_in_development(e) + logger.error e.message + logger.error e.backtrace.join("\n") + + render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500 + end +end diff --git a/app/graphql/mutations/.keep b/app/graphql/mutations/.keep new file mode 100644 index 00000000..e69de29b diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb new file mode 100644 index 00000000..0ff6c4ee --- /dev/null +++ b/app/graphql/mutations/base_mutation.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Mutations + class BaseMutation < GraphQL::Schema::RelayClassicMutation + argument_class Types::BaseArgument + field_class Types::BaseField + input_object_class Types::BaseInputObject + object_class Types::BaseObject + end +end diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb new file mode 100644 index 00000000..89b7f9da --- /dev/null +++ b/app/graphql/resolvers/base_resolver.rb @@ -0,0 +1,4 @@ +module Resolvers + class BaseResolver < GraphQL::Schema::Resolver + end +end diff --git a/app/graphql/staffplan_redux_schema.rb b/app/graphql/staffplan_redux_schema.rb new file mode 100644 index 00000000..2bd91357 --- /dev/null +++ b/app/graphql/staffplan_redux_schema.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class StaffplanReduxSchema < GraphQL::Schema + mutation(Types::MutationType) + query(Types::QueryType) + + # For batch-loading (see https://graphql-ruby.org/dataloader/overview.html) + use GraphQL::Dataloader + + # GraphQL-Ruby calls this when something goes wrong while running a query: + def self.type_error(err, context) + # if err.is_a?(GraphQL::InvalidNullError) + # # report to your bug tracker here + # return nil + # end + super + end + + # Union and Interface Resolution + def self.resolve_type(abstract_type, obj, ctx) + # TODO: Implement this method + # to return the correct GraphQL object type for `obj` + raise(GraphQL::RequiredImplementationMissingError) + end + + # Stop validating when it encounters this many errors: + validate_max_errors(100) + + # Relay-style Object Identification: + + # Return a string UUID for `object` + def self.id_from_object(object, type_definition, query_ctx) + # For example, use Rails' GlobalID library (https://github.com/rails/globalid): + object.to_gid_param + end + + # Given a string UUID, find the object + def self.object_from_id(global_id, query_ctx) + # For example, use Rails' GlobalID library (https://github.com/rails/globalid): + GlobalID.find(global_id) + end +end diff --git a/app/graphql/types/.keep b/app/graphql/types/.keep new file mode 100644 index 00000000..e69de29b diff --git a/app/graphql/types/base_argument.rb b/app/graphql/types/base_argument.rb new file mode 100644 index 00000000..2e2278c5 --- /dev/null +++ b/app/graphql/types/base_argument.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module Types + class BaseArgument < GraphQL::Schema::Argument + end +end diff --git a/app/graphql/types/base_connection.rb b/app/graphql/types/base_connection.rb new file mode 100644 index 00000000..366c69e8 --- /dev/null +++ b/app/graphql/types/base_connection.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Types + class BaseConnection < Types::BaseObject + # add `nodes` and `pageInfo` fields, as well as `edge_type(...)` and `node_nullable(...)` overrides + include GraphQL::Types::Relay::ConnectionBehaviors + end +end diff --git a/app/graphql/types/base_edge.rb b/app/graphql/types/base_edge.rb new file mode 100644 index 00000000..e0d2f79c --- /dev/null +++ b/app/graphql/types/base_edge.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Types + class BaseEdge < Types::BaseObject + # add `node` and `cursor` fields, as well as `node_type(...)` override + include GraphQL::Types::Relay::EdgeBehaviors + end +end diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb new file mode 100644 index 00000000..cf43fea4 --- /dev/null +++ b/app/graphql/types/base_enum.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module Types + class BaseEnum < GraphQL::Schema::Enum + end +end diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb new file mode 100644 index 00000000..611eb056 --- /dev/null +++ b/app/graphql/types/base_field.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Types + class BaseField < GraphQL::Schema::Field + argument_class Types::BaseArgument + end +end diff --git a/app/graphql/types/base_input_object.rb b/app/graphql/types/base_input_object.rb new file mode 100644 index 00000000..27951132 --- /dev/null +++ b/app/graphql/types/base_input_object.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Types + class BaseInputObject < GraphQL::Schema::InputObject + argument_class Types::BaseArgument + end +end diff --git a/app/graphql/types/base_interface.rb b/app/graphql/types/base_interface.rb new file mode 100644 index 00000000..18899387 --- /dev/null +++ b/app/graphql/types/base_interface.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module BaseInterface + include GraphQL::Schema::Interface + edge_type_class(Types::BaseEdge) + connection_type_class(Types::BaseConnection) + + field_class Types::BaseField + end +end diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb new file mode 100644 index 00000000..487af2f5 --- /dev/null +++ b/app/graphql/types/base_object.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Types + class BaseObject < GraphQL::Schema::Object + edge_type_class(Types::BaseEdge) + connection_type_class(Types::BaseConnection) + field_class Types::BaseField + end +end diff --git a/app/graphql/types/base_scalar.rb b/app/graphql/types/base_scalar.rb new file mode 100644 index 00000000..719bc808 --- /dev/null +++ b/app/graphql/types/base_scalar.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module Types + class BaseScalar < GraphQL::Schema::Scalar + end +end diff --git a/app/graphql/types/base_union.rb b/app/graphql/types/base_union.rb new file mode 100644 index 00000000..95941696 --- /dev/null +++ b/app/graphql/types/base_union.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Types + class BaseUnion < GraphQL::Schema::Union + edge_type_class(Types::BaseEdge) + connection_type_class(Types::BaseConnection) + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb new file mode 100644 index 00000000..5b9c1ade --- /dev/null +++ b/app/graphql/types/mutation_type.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class MutationType < Types::BaseObject + # TODO: remove me + field :test_field, String, null: false, + description: "An example field added by the generator" + def test_field + "Hello World" + end + end +end diff --git a/app/graphql/types/node_type.rb b/app/graphql/types/node_type.rb new file mode 100644 index 00000000..c71ec3ee --- /dev/null +++ b/app/graphql/types/node_type.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Types + module NodeType + include Types::BaseInterface + # Add the `id` field + include GraphQL::Types::Relay::NodeBehaviors + end +end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb new file mode 100644 index 00000000..d3a9e8ec --- /dev/null +++ b/app/graphql/types/query_type.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Types + class QueryType < Types::BaseObject + field :node, Types::NodeType, null: true, description: "Fetches an object given its ID." do + argument :id, ID, required: true, description: "ID of the object." + end + + def node(id:) + context.schema.object_from_id(id, context) + end + + field :nodes, [Types::NodeType, null: true], null: true, description: "Fetches a list of objects given a list of IDs." do + argument :ids, [ID], required: true, description: "IDs of the objects." + end + + def nodes(ids:) + ids.map { |id| context.schema.object_from_id(id, context) } + end + + field :clients, [Types::StaffPlan::ClientType], null: false + def clients + context[:current_user].current_company.clients.all + end + + field :assignments, [Types::StaffPlan::AssignmentType], null: false + def assignments + User.first.assignments.all + end + + field :users, [Types::StaffPlan::UserType], null: false + def users + Company.first.users.all + end + end +end diff --git a/app/graphql/types/staff_plan/assignment_type.rb b/app/graphql/types/staff_plan/assignment_type.rb new file mode 100644 index 00000000..0467a6a7 --- /dev/null +++ b/app/graphql/types/staff_plan/assignment_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class AssignmentType < Types::BaseObject + field :id, ID, null: false + field :user_id, ID, null: false + field :project_id, ID, null: false + field :status, String, null: false + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :work_weeks, [Types::StaffPlan::WorkWeekType], null: false + + def work_weeks + object.work_weeks + end + end + end +end diff --git a/app/graphql/types/staff_plan/client_type.rb b/app/graphql/types/staff_plan/client_type.rb new file mode 100644 index 00000000..a46765c1 --- /dev/null +++ b/app/graphql/types/staff_plan/client_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class ClientType < Types::BaseObject + field :id, ID, null: false + field :name, String, null: false + field :description, String, null: true + field :status, String, null: false + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :projects, [Types::StaffPlan::ProjectType], null: false + + def projects + object.projects + end + end + end +end diff --git a/app/graphql/types/staff_plan/company_type.rb b/app/graphql/types/staff_plan/company_type.rb new file mode 100644 index 00000000..05a4a753 --- /dev/null +++ b/app/graphql/types/staff_plan/company_type.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class CompanyType < Types::BaseObject + field :id, ID, null: false + field :name, String, null: false + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :projects, [Types::StaffPlan::ProjectType], null: false + + def projects + object.projects + end + + field :clients, [Types::StaffPlan::ClientType], null: false + + def clients + object.clients + end + + field :users, [Types::StaffPlan::UserType], null: false + + def users + object.users + end + end + end +end diff --git a/app/graphql/types/staff_plan/project_type.rb b/app/graphql/types/staff_plan/project_type.rb new file mode 100644 index 00000000..0d080664 --- /dev/null +++ b/app/graphql/types/staff_plan/project_type.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class ProjectType < Types::BaseObject + field :id, ID, null: false + field :client_id, ID, null: false + field :name, String, null: false + field :status, String, null: false + field :payment_frequency, String, null: false + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :assignments, [Types::StaffPlan::AssignmentType], null: false + + def assigmnents + object.assignments + end + + field :users, [Types::StaffPlan::UserType], null: false + + def users + object.users + end + + field :work_weeks, [Types::StaffPlan::WorkWeekType], null: false + + def work_weeks + object.work_weeks + end + end + end +end diff --git a/app/graphql/types/staff_plan/user_type.rb b/app/graphql/types/staff_plan/user_type.rb new file mode 100644 index 00000000..c4358968 --- /dev/null +++ b/app/graphql/types/staff_plan/user_type.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class UserType < Types::BaseObject + field :id, ID, null: false + field :name, String, null: false + field :email, String, null: false + field :current_company_id, ID, null: true + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :companies, [Types::StaffPlan::CompanyType], null: false + + def companies + object.companies + end + + field :assignments, [Types::StaffPlan::AssignmentType], null: false + + def assignments + object.assignments + end + + field :projects, [Types::StaffPlan::ProjectType], null: false + + def projects + object.projects + end + end + end +end diff --git a/app/graphql/types/staff_plan/work_week_type.rb b/app/graphql/types/staff_plan/work_week_type.rb new file mode 100644 index 00000000..4a90ac26 --- /dev/null +++ b/app/graphql/types/staff_plan/work_week_type.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Types + module StaffPlan + class WorkWeekType < Types::BaseObject + field :id, ID, null: false + field :assignment_id, Integer, null: false + field :cweek, Integer, null: false + field :year, Integer, null: false + field :beginning_of_week, Integer, null: false + field :estimated_hours, Integer, null: false + field :actual_hours, Integer, null: false + field :created_at, GraphQL::Types::ISO8601DateTime, null: false + field :updated_at, GraphQL::Types::ISO8601DateTime, null: false + + field :user, Types::StaffPlan::UserType, null: false + + def user + object.user + end + + field :project, Types::StaffPlan::ProjectType, null: false + + def project + object.project + end + end + end +end diff --git a/app/graphql/types/staff_plan_query_type.rb b/app/graphql/types/staff_plan_query_type.rb new file mode 100644 index 00000000..5dc3b6d9 --- /dev/null +++ b/app/graphql/types/staff_plan_query_type.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Types + class StaffPlanQueryType < Types::BaseObject + field :node, Types::NodeType, null: true, description: "Fetches an object given its ID." do + argument :id, ID, required: true, description: "ID of the object." + end + + def node(id:) + context.schema.object_from_id(id, context) + end + + field :nodes, [Types::NodeType, null: true], null: true, description: "Fetches a list of objects given a list of IDs." do + argument :ids, [ID], required: true, description: "IDs of the objects." + end + + def nodes(ids:) + ids.map { |id| context.schema.object_from_id(id, context) } + end + + field :user_staff_plan, Types::StaffPlan::UserStaffPlanType, null: true do + argument :user_id + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 3c58fc32..4c7b16ca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,13 @@ Rails.application.routes.draw do + namespace :api do + get 'current_user/create' + end + if Rails.env.development? + mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql" + end + + post "/graphql", to: "graphql#execute" + resources :work_weeks resources :assignments resources :projects From d0b3d77ca9e672a27aa98ab763152853da9800b9 Mon Sep 17 00:00:00 2001 From: Rob Sterner Date: Tue, 2 Jan 2024 21:12:11 -0500 Subject: [PATCH 3/4] some API cleanup --- app/controllers/graphql_controller.rb | 2 ++ app/graphql/types/query_type.rb | 4 ++-- app/graphql/types/staff_plan_query_type.rb | 25 ---------------------- 3 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 app/graphql/types/staff_plan_query_type.rb diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index a2eef17d..b63ba2b3 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -6,6 +6,8 @@ class GraphqlController < ApplicationController # but you'll have to authenticate your user separately # protect_from_forgery with: :null_session + skip_before_action :verify_authenticity_token + def execute variables = prepare_variables(params[:variables]) query = params[:query] diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index d3a9e8ec..4e132232 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -25,12 +25,12 @@ def clients field :assignments, [Types::StaffPlan::AssignmentType], null: false def assignments - User.first.assignments.all + context[:current_user].assignments.all end field :users, [Types::StaffPlan::UserType], null: false def users - Company.first.users.all + context[:current_user].current_company.users.all end end end diff --git a/app/graphql/types/staff_plan_query_type.rb b/app/graphql/types/staff_plan_query_type.rb deleted file mode 100644 index 5dc3b6d9..00000000 --- a/app/graphql/types/staff_plan_query_type.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Types - class StaffPlanQueryType < Types::BaseObject - field :node, Types::NodeType, null: true, description: "Fetches an object given its ID." do - argument :id, ID, required: true, description: "ID of the object." - end - - def node(id:) - context.schema.object_from_id(id, context) - end - - field :nodes, [Types::NodeType, null: true], null: true, description: "Fetches a list of objects given a list of IDs." do - argument :ids, [ID], required: true, description: "IDs of the objects." - end - - def nodes(ids:) - ids.map { |id| context.schema.object_from_id(id, context) } - end - - field :user_staff_plan, Types::StaffPlan::UserStaffPlanType, null: true do - argument :user_id - end - end -end From eb5caa6a617fc6420902b061585e1bd5a7385c9e Mon Sep 17 00:00:00 2001 From: Rob Sterner Date: Thu, 4 Jan 2024 21:09:04 -0500 Subject: [PATCH 4/4] should be good for a first pass --- app/controllers/graphql_controller.rb | 1 + app/graphql/mutations/base_mutation.rb | 7 ++--- app/graphql/mutations/create_work_week.rb | 14 ++++++++++ app/graphql/mutations/set_current_company.rb | 13 +++++++++ app/graphql/mutations/update_work_week.rb | 14 ++++++++++ app/graphql/types/mutation_type.rb | 9 +++---- app/graphql/types/query_type.rb | 27 ++++++++++++++++--- .../types/staff_plan/assignment_type.rb | 4 +-- app/graphql/types/staff_plan/project_type.rb | 2 +- .../types/staff_plan/work_week_type.rb | 3 +-- 10 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 app/graphql/mutations/create_work_week.rb create mode 100644 app/graphql/mutations/set_current_company.rb create mode 100644 app/graphql/mutations/update_work_week.rb diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index b63ba2b3..6ce0ead2 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -15,6 +15,7 @@ def execute context = { # Query context goes here, for example: current_user: current_user, + current_company: current_company } result = StaffplanReduxSchema.execute(query, variables: variables, context: context, operation_name: operation_name) render json: result diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb index 0ff6c4ee..4f318d4e 100644 --- a/app/graphql/mutations/base_mutation.rb +++ b/app/graphql/mutations/base_mutation.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true module Mutations - class BaseMutation < GraphQL::Schema::RelayClassicMutation - argument_class Types::BaseArgument - field_class Types::BaseField - input_object_class Types::BaseInputObject - object_class Types::BaseObject + class BaseMutation < GraphQL::Schema::Mutation + null false end end diff --git a/app/graphql/mutations/create_work_week.rb b/app/graphql/mutations/create_work_week.rb new file mode 100644 index 00000000..138411b1 --- /dev/null +++ b/app/graphql/mutations/create_work_week.rb @@ -0,0 +1,14 @@ +module Mutations + class CreateWorkWeek < BaseMutation + # arguments passed to the `resolve` method + # argument :description, String, required: true + # argument :url, String, required: true + + # return type from the mutation + type Types::StaffPlan::WorkWeekType + + def resolve + # TODO: implement + end + end +end \ No newline at end of file diff --git a/app/graphql/mutations/set_current_company.rb b/app/graphql/mutations/set_current_company.rb new file mode 100644 index 00000000..c5af4796 --- /dev/null +++ b/app/graphql/mutations/set_current_company.rb @@ -0,0 +1,13 @@ +module Mutations + class SetCurrentCompany < BaseMutation + # arguments passed to the `resolve` method + argument :company_id, ID, required: true + + # return type from the mutation + type Types::StaffPlan::CompanyType + + def resolve + # TODO: implement + end + end +end \ No newline at end of file diff --git a/app/graphql/mutations/update_work_week.rb b/app/graphql/mutations/update_work_week.rb new file mode 100644 index 00000000..cf2b2676 --- /dev/null +++ b/app/graphql/mutations/update_work_week.rb @@ -0,0 +1,14 @@ +module Mutations + class UpdateWorkWeek < BaseMutation + # arguments passed to the `resolve` method + # argument :description, String, required: true + # argument :url, String, required: true + + # return type from the mutation + type Types::StaffPlan::WorkWeekType + + def resolve + # TODO: implement + end + end +end \ No newline at end of file diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 5b9c1ade..321b5dee 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -2,11 +2,8 @@ module Types class MutationType < Types::BaseObject - # TODO: remove me - field :test_field, String, null: false, - description: "An example field added by the generator" - def test_field - "Hello World" - end + field :set_current_company, mutation: Mutations::SetCurrentCompany + field :create_work_week, mutation: Mutations::CreateWorkWeek + field :update_work_week, mutation: Mutations::UpdateWorkWeek end end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 4e132232..8a50de20 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -23,9 +23,30 @@ def clients context[:current_user].current_company.clients.all end - field :assignments, [Types::StaffPlan::AssignmentType], null: false - def assignments - context[:current_user].assignments.all + field :project_assignments, [Types::StaffPlan::AssignmentType], null: false do + argument :project_id, ID, required: true, description: "ID of the project to fetch assignments for." + end + + def project_assignments(project_id: nil) + context[:current_company] + .projects + .find(project_id) + .assignments + .all + end + + field :user_assignments, [Types::StaffPlan::AssignmentType], null: false do + argument :user_id, ID, required: false, + description: "ID of the user to fetch assignments for. The current user's assignments will be returned if this argument is not provided." + end + def user_assignments(user_id: nil) + target = if user_id.present? + context[:current_company].users.find(user_id) + else + context[:current_user] + end + + target.assignments.all end field :users, [Types::StaffPlan::UserType], null: false diff --git a/app/graphql/types/staff_plan/assignment_type.rb b/app/graphql/types/staff_plan/assignment_type.rb index 0467a6a7..cdc0ec44 100644 --- a/app/graphql/types/staff_plan/assignment_type.rb +++ b/app/graphql/types/staff_plan/assignment_type.rb @@ -4,8 +4,8 @@ module Types module StaffPlan class AssignmentType < Types::BaseObject field :id, ID, null: false - field :user_id, ID, null: false - field :project_id, ID, null: false + field :user, Types::StaffPlan::UserType, null: false + field :project, Types::StaffPlan::ProjectType, null: false field :status, String, null: false field :created_at, GraphQL::Types::ISO8601DateTime, null: false field :updated_at, GraphQL::Types::ISO8601DateTime, null: false diff --git a/app/graphql/types/staff_plan/project_type.rb b/app/graphql/types/staff_plan/project_type.rb index 0d080664..1a7f7a71 100644 --- a/app/graphql/types/staff_plan/project_type.rb +++ b/app/graphql/types/staff_plan/project_type.rb @@ -4,7 +4,7 @@ module Types module StaffPlan class ProjectType < Types::BaseObject field :id, ID, null: false - field :client_id, ID, null: false + field :client, Types::StaffPlan::ClientType, null: false field :name, String, null: false field :status, String, null: false field :payment_frequency, String, null: false diff --git a/app/graphql/types/staff_plan/work_week_type.rb b/app/graphql/types/staff_plan/work_week_type.rb index 4a90ac26..76fbd2a9 100644 --- a/app/graphql/types/staff_plan/work_week_type.rb +++ b/app/graphql/types/staff_plan/work_week_type.rb @@ -4,6 +4,7 @@ module Types module StaffPlan class WorkWeekType < Types::BaseObject field :id, ID, null: false + field :user, Types::StaffPlan::UserType, null: false field :assignment_id, Integer, null: false field :cweek, Integer, null: false field :year, Integer, null: false @@ -13,8 +14,6 @@ class WorkWeekType < Types::BaseObject field :created_at, GraphQL::Types::ISO8601DateTime, null: false field :updated_at, GraphQL::Types::ISO8601DateTime, null: false - field :user, Types::StaffPlan::UserType, null: false - def user object.user end