diff --git a/app/graphql/api/v2/stored_query.rb b/app/graphql/api/v2/stored_query.rb index 5b5a5b6be..80177c1d3 100644 --- a/app/graphql/api/v2/stored_query.rb +++ b/app/graphql/api/v2/stored_query.rb @@ -801,5 +801,17 @@ class API::V2::StoredQuery } } } + + mutation demarcheCloner($input: DemarcheClonerInput!) { + demarcheCloner(input: $input) { + demarche { + id + number + } + errors { + message + } + } + } GRAPHQL end diff --git a/app/graphql/mutations/demarche_cloner.rb b/app/graphql/mutations/demarche_cloner.rb new file mode 100644 index 000000000..86bd03ff2 --- /dev/null +++ b/app/graphql/mutations/demarche_cloner.rb @@ -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 diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 748e15141..41fce971b 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -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 n’expose 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. """ diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index f01bca909..ce2f8ac56 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -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 diff --git a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb index eec532f1b..9dfcf0330 100644 --- a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb @@ -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