Merge pull request #8108 from tchak/graphql-clone-demarche

feat(graphql): add demarcheCloner mutation
This commit is contained in:
Paul Chavard 2023-01-11 23:50:02 +01:00 committed by GitHub
commit 8958ba0725
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 132 additions and 6 deletions

View file

@ -12,23 +12,29 @@ class API::V2::Schema < GraphQL::Schema
context_class API::V2::Context
def self.id_from_object(object, type_definition, ctx)
if object.is_a?(Hash)
if type_definition == Types::DemarcheDescriptorType
(object.is_a?(Procedure) ? object : object.procedure).to_typed_id
elsif object.is_a?(Hash)
object[:id]
else
object.to_typed_id
end
end
def self.object_from_id(id, query_ctx)
def self.object_from_id(id, ctx)
ApplicationRecord.record_from_typed_id(id)
rescue => e
raise GraphQL::ExecutionError.new(e.message, extensions: { code: :not_found })
end
def self.resolve_type(type, obj, ctx)
case obj
def self.resolve_type(type_definition, object, ctx)
case object
when Procedure
if type_definition == Types::DemarcheDescriptorType
type_definition
else
Types::DemarcheType
end
when Dossier
Types::DossierType
when Commentaire
@ -42,7 +48,7 @@ class API::V2::Schema < GraphQL::Schema
when GroupeInstructeur
Types::GroupeInstructeurType
else
raise GraphQL::ExecutionError.new("Unexpected object: #{obj}")
raise GraphQL::ExecutionError.new("Unexpected object: #{object}")
end
end

View file

@ -801,5 +801,17 @@ class API::V2::StoredQuery
}
}
}
mutation demarcheCloner($input: DemarcheClonerInput!) {
demarcheCloner(input: $input) {
demarche {
id
number
}
errors {
message
}
}
}
GRAPHQL
end

View file

@ -0,0 +1,25 @@
module Mutations
class DemarcheCloner < Mutations::BaseMutation
description "Cloner une démarche."
argument :demarche, Types::DemarcheDescriptorType::FindDemarcheInput, "La démarche", required: true
argument :title, String, "Le titre de la nouvelle démarche.", required: false
field :demarche, Types::DemarcheDescriptorType, null: true
field :errors, [Types::ValidationErrorType], null: true
def resolve(demarche:, title: nil)
demarche_number = demarche.number.presence || ApplicationRecord.id_from_typed_id(demarche.id)
demarche = Procedure.find_by(id: demarche_number)
if demarche.present? && (demarche.opendata? || context.authorized_demarche?(demarche))
cloned_demarche = demarche.clone(context.current_administrateur, false)
cloned_demarche.update!(libelle: title) if title.present?
{ demarche: cloned_demarche.draft_revision }
else
{ errors: ["La démarche \"#{demarche_number}\" ne peut pas être clonée."] }
end
end
end
end

View file

@ -595,6 +595,38 @@ type Demarche {
title: String!
}
"""
Autogenerated input type of DemarcheCloner
"""
input DemarcheClonerInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
La démarche
"""
demarche: FindDemarcheInput!
"""
Le titre de la nouvelle démarche.
"""
title: String
}
"""
Autogenerated return type of DemarcheCloner.
"""
type DemarcheClonerPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
demarche: DemarcheDescriptor
errors: [ValidationError!]
}
"""
Une démarche (métadonnées)
Ceci est une version abrégée du type `Demarche`, qui nexpose que les métadonnées.
@ -1922,6 +1954,16 @@ type Mutation {
input: CreateDirectUploadInput!
): CreateDirectUploadPayload
"""
Cloner une démarche.
"""
demarcheCloner(
"""
Parameters for DemarcheCloner
"""
input: DemarcheClonerInput!
): DemarcheClonerPayload
"""
Accepter le dossier.
"""

View file

@ -23,5 +23,6 @@ module Types
field :groupe_instructeur_creer, mutation: Mutations::GroupeInstructeurCreer
field :groupe_instructeur_ajouter_instructeurs, mutation: Mutations::GroupeInstructeurAjouterInstructeurs
field :groupe_instructeur_supprimer_instructeurs, mutation: Mutations::GroupeInstructeurSupprimerInstructeurs
field :demarche_cloner, mutation: Mutations::DemarcheCloner
end
end

View file

@ -367,5 +367,45 @@ describe API::V2::GraphqlController do
expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }])
}
end
context 'demarcheCloner' do
let(:operation_name) { 'demarcheCloner' }
context 'find by number' do
let(:variables) { { input: { demarche: { number: procedure.id } } } }
it {
expect(gql_errors).to be_nil
expect(gql_data[:demarcheCloner][:errors]).to be_nil
expect(gql_data[:demarcheCloner][:demarche][:id]).not_to be_nil
expect(gql_data[:demarcheCloner][:demarche][:id]).not_to eq(procedure.to_typed_id)
expect(gql_data[:demarcheCloner][:demarche][:id]).to eq(Procedure.last.to_typed_id)
}
end
context 'find by id' do
let(:variables) { { input: { demarche: { id: procedure.to_typed_id } } } }
it {
expect(gql_errors).to be_nil
expect(gql_data[:demarcheCloner][:errors]).to be_nil
expect(gql_data[:demarcheCloner][:demarche][:id]).not_to be_nil
expect(gql_data[:demarcheCloner][:demarche][:id]).not_to eq(procedure.to_typed_id)
expect(gql_data[:demarcheCloner][:demarche][:id]).to eq(Procedure.last.to_typed_id)
}
end
context 'with title' do
let(:variables) { { input: { demarche: { id: procedure.to_typed_id }, title: new_title } } }
let(:new_title) { "#{procedure.libelle} TEST 1" }
it {
expect(gql_errors).to be_nil
expect(gql_data[:demarcheCloner][:errors]).to be_nil
expect(gql_data[:demarcheCloner][:demarche][:id]).to eq(Procedure.last.to_typed_id)
expect(Procedure.last.libelle).to eq(new_title)
}
end
end
end
end