Skip to content

Commit

Permalink
adds upsertProject
Browse files Browse the repository at this point in the history
  • Loading branch information
fermion committed Mar 6, 2024
1 parent a323b1d commit de36d3b
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 0 deletions.
57 changes: 57 additions & 0 deletions app/graphql/mutations/upsert_project.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Mutations
class UpsertProject < BaseMutation
description "Create or update a project."

# arguments passed to the `resolve` method
argument :id, ID, required: false, description: "The ID of the project to update."
argument :client_id, ID, required: false, description: "The ID of the client for this project."
argument :name, String, required: false, description: "The name of the project."
argument :status, String, required: false, description: "The status of the assignment."
argument :cost, Float, required: false, description: "The cost of the project."
argument :payment_frequency, String, required: false, description: "The frequency of payment for the project."
argument :starts_on, GraphQL::Types::ISO8601Date, required: false, description: "The date this assignment starts."
argument :ends_on, GraphQL::Types::ISO8601Date, required: false, description: "The date this assignment ends."

# return type from the mutation
type Types::StaffPlan::ProjectType

def resolve(id: nil, client_id: nil, name: nil, status: nil, cost: nil, payment_frequency: nil, starts_on: nil, ends_on: nil)
current_company = context[:current_company]

# try and find the assignment
project = if id.present?
current_company.projects.find(id)
end

if project.blank?
project = current_company.projects.new(client_id:, name:, status:)
end

project.assign_attributes(name:) if name.present?
project.assign_attributes(status:) if status.present?
project.assign_attributes(cost:) if cost.present?
project.assign_attributes(payment_frequency:) if payment_frequency.present?
project.assign_attributes(starts_on:) if starts_on.present?
project.assign_attributes(ends_on:) if ends_on.present?

if project.valid?
project.save!
else
project.errors.group_by_attribute.each do |attribute, errors|
errors.each do |error|
context.add_error(
GraphQL::ExecutionError.new(
error.full_message,
extensions: {
attribute: attribute.to_s,
}
)
)
end
end
end

project
end
end
end
45 changes: 45 additions & 0 deletions app/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,51 @@ type Mutation {
userId: ID!
): Assignment!

"""
Create or update a project.
"""
upsertProject(
"""
The ID of the client for this project.
"""
clientId: ID!

"""
The cost of the project.
"""
cost: Float

"""
The date this assignment ends.
"""
endsOn: ISO8601Date

"""
The ID of the project to update.
"""
id: ID

"""
The name of the project.
"""
name: String!

"""
The frequency of payment for the project.
"""
paymentFrequency: String

"""
The date this assignment starts.
"""
startsOn: ISO8601Date

"""
The status of the assignment.
"""
status: String!
): Project!

"""
Create or update a work week record for a StaffPlan user.
"""
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/mutation_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ class MutationType < Types::BaseObject
field :set_current_company, mutation: Mutations::SetCurrentCompany
field :upsert_work_week, mutation: Mutations::UpsertWorkWeek
field :upsert_assignment, mutation: Mutations::UpsertAssignment
field :upsert_project, mutation: Mutations::UpsertProject
end
end
198 changes: 198 additions & 0 deletions spec/graphql/mutations/upsert_project_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Mutations::UpsertAssignment do

context "resolve" do
it "creates a new assignment with valid params" do
query_string = <<-GRAPHQL
mutation($clientId: ID, $name: String, $status: String) {
upsertProject(clientId: $clientId, name: $name, status: $status) {
id
client {
id
}
name
status
startsOn
endsOn
}
}
GRAPHQL

user = create(:user)
client = create(:client, company: user.current_company)

result = StaffplanReduxSchema.execute(
query_string,
context: {
current_user: user,
current_company: user.current_company
},
variables: {
clientId: client.id,
name: project_name = Faker::Company.buzzword,
status: Project::PROPOSED
}
)

post_result = result["data"]["upsertProject"]
expect(result["errors"]).to be_nil
expect(post_result["client"]["id"]).to eq(client.id.to_s)
expect(post_result["name"]).to eq(project_name)
expect(post_result["status"]).to eq(Project::PROPOSED)
expect(post_result["startsOn"]).to be_nil
expect(post_result["endsOn"]).to be_nil
end

it "updates a project with valid params" do
query_string = <<-GRAPHQL
mutation($id: ID, $clientId: ID, $name: String, $status: String, $cost: Float, $paymentFrequency: String, $startsOn: ISO8601Date, $endsOn: ISO8601Date) {
upsertProject(id: $id, clientId: $clientId, name: $name, status: $status, cost: $cost, paymentFrequency: $paymentFrequency, startsOn: $startsOn, endsOn: $endsOn) {
id
client {
id
}
name
cost
paymentFrequency
status
startsOn
endsOn
}
}
GRAPHQL

project = create(:project)
user = User.find_by(current_company_id: project.company.id)

result = StaffplanReduxSchema.execute(
query_string,
context: {
current_user: user,
current_company: user.current_company
},
variables: {
id: project.id,
clientId: project.client.id,
name: project.name + " updated",
status: Project::COMPLETED,
cost: 1000.00,
paymentFrequency: Project::ANNUALLY,
startsOn: starts_on = 2.weeks.from_now.to_date.iso8601,
endsOn: ends_on = 10.weeks.from_now.to_date.iso8601
}
)

post_result = result["data"]["upsertProject"]
expect(result["errors"]).to be_nil
expect(post_result["client"]["id"]).to eq(project.client.id.to_s)
expect(post_result["name"]).to eq(project.name + " updated")
expect(post_result["status"]).to eq(Project::COMPLETED)
expect(post_result["cost"]).to eq(1000.00)
expect(post_result["paymentFrequency"]).to eq(Project::ANNUALLY)
expect(post_result["startsOn"]).to eq(starts_on.to_s)
expect(post_result["endsOn"]).to eq(ends_on.to_s)
end

it "does not allow client_id to be overridden" do
query_string = <<-GRAPHQL
mutation($id: ID, $clientId: ID) {
upsertProject(id: $id, clientId: $clientId) {
id
client {
id
}
}
}
GRAPHQL

project = create(:project)
user = project.company.users.first
other_client = create(:client)

expect(project.client.company).to_not eq(other_client.company)

result = StaffplanReduxSchema.execute(
query_string,
context: {
current_user: user,
current_company: user.current_company
},
variables: {
id: project.id,
clientId: other_client.id,
}
)

post_result = result["data"]["upsertProject"]
expect(post_result["client"]["id"]).to eq(project.client.id.to_s)
end

it "renders validation errors" do
query_string = <<-GRAPHQL
mutation($id: ID, $status: String) {
upsertProject(id: $id, status: $status) {
id
client {
id
}
status
}
}
GRAPHQL

project = create(:project)
user = project.company.users.first

result = StaffplanReduxSchema.execute(
query_string,
context: {
current_user: user,
current_company: user.current_company
},
variables: {
id: project.id,
status: "invalid-status",
}
)

post_result = result["errors"]
expect(post_result.length).to eq(1)
expect(post_result.first["message"]).to eq("Status is not included in the list")
end

it "raises a 404 if given an assignment id that doesn't exist on the company" do
query_string = <<-GRAPHQL
mutation($id: ID, $name: String) {
upsertProject(id: $id, name: $name) {
id
name
}
}
GRAPHQL

project = create(:project)
user = project.company.users.first
second_project = create(:project)

expect(project.company).to_not eq(second_project.company)

result = StaffplanReduxSchema.execute(
query_string,
context: {
current_user: user,
current_company: user.current_company
},
variables: {
id: second_project.id,
name: "new name"
}
)

post_result = result["errors"]
expect(post_result.first["message"]).to eq("Project not found")
end
end
end

0 comments on commit de36d3b

Please sign in to comment.