Merge pull request #7503 from tchak/graphql-edit-blocks

fix(graphql): annotation edit mutation inside blocks
This commit is contained in:
Paul Chavard 2022-07-21 14:59:49 +02:00 committed by GitHub
commit 07acc0db94
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 303 additions and 39 deletions

View file

@ -7,8 +7,12 @@ module Mutations
field :annotation, Types::ChampType, null: true field :annotation, Types::ChampType, null: true
field :errors, [Types::ValidationErrorType], null: true field :errors, [Types::ValidationErrorType], null: true
def resolve_with_type(type, dossier, annotation_id, instructeur, value) def resolve_with_type(dossier:, annotation_id:, instructeur:, value:)
annotation = find_annotation(dossier, type, annotation_id) annotation = find_annotation(dossier, annotation_id)
if annotation.nil?
return { errors: ["Lannotation \"#{annotation_id}\" nexiste pas"] }
end
if block_given? if block_given?
annotation.value = yield annotation.type_champ, value annotation.value = yield annotation.type_champ, value
@ -31,18 +35,22 @@ module Mutations
private private
def find_annotation(dossier, type, annotation_id) def input_type
_, stable_id = GraphQL::Schema::UniqueWithinType.decode(annotation_id) :text
dossier.champs_private
.joins(:type_de_champ)
.find_by!(types_de_champ: {
type_champ: annotation_type_champ(type),
stable_id: stable_id
})
end end
def annotation_type_champ(type) def find_annotation(dossier, annotation_id)
case type stable_id, row = Champ.decode_typed_id(annotation_id)
Champ.joins(:type_de_champ).find_by(type_de_champ: {
type_champ: annotation_type_champ,
stable_id: stable_id,
private: true
}, private: true, row: row, dossier: dossier)
end
def annotation_type_champ
case input_type
when :text when :text
[ [
TypeDeChamp.type_champs.fetch(:text), TypeDeChamp.type_champs.fetch(:text),

View file

@ -0,0 +1,38 @@
module Mutations
class DossierModifierAnnotationAjouterLigne < Mutations::BaseMutation
argument :dossier_id, ID, "Dossier ID", required: true, loads: Types::DossierType
argument :instructeur_id, ID, "Instructeur qui demande la modification.", required: true, loads: Types::ProfileType
argument :annotation_id, ID, "Annotation ID", required: true
field :annotation, Types::Champs::RepetitionChampType, null: true
field :errors, [Types::ValidationErrorType], null: true
def resolve(dossier:, annotation_id:, instructeur:)
annotation = find_annotation(dossier, annotation_id)
if annotation.nil?
return { errors: ["Lannotation \"#{annotation_id}\" nexiste pas"] }
end
annotation.add_row(dossier.revision)
{ annotation: annotation, errors: nil }
end
def authorized?(dossier:, instructeur:, **args)
dossier_authorized_for?(dossier, instructeur)
end
private
def find_annotation(dossier, annotation_id)
stable_id, row = Champ.decode_typed_id(annotation_id)
Champ.joins(:type_de_champ).find_by(type_de_champ: {
type_champ: TypeDeChamp.type_champs.fetch(:repetition),
stable_id: stable_id,
private: true
}, private: true, row: row, dossier: dossier)
end
end
end

View file

@ -6,11 +6,10 @@ module Mutations
def resolve(dossier:, annotation_id:, instructeur:, value:) def resolve(dossier:, annotation_id:, instructeur:, value:)
resolve_with_type( resolve_with_type(
:checkbox, dossier: dossier,
dossier, annotation_id: annotation_id,
annotation_id, instructeur: instructeur,
instructeur, value: value
value
) do |type_champ, value| ) do |type_champ, value|
if type_champ == TypeDeChamp.type_champs.fetch(:yes_no) if type_champ == TypeDeChamp.type_champs.fetch(:yes_no)
value ? 'true' : 'false' value ? 'true' : 'false'
@ -19,5 +18,11 @@ module Mutations
end end
end end
end end
private
def input_type
:checkbox
end
end end
end end

View file

@ -6,12 +6,17 @@ module Mutations
def resolve(dossier:, annotation_id:, instructeur:, value:) def resolve(dossier:, annotation_id:, instructeur:, value:)
resolve_with_type( resolve_with_type(
:date, dossier: dossier,
dossier, annotation_id: annotation_id,
annotation_id, instructeur: instructeur,
instructeur, value: value
value
) )
end end
private
def input_type
:date
end
end end
end end

View file

@ -6,12 +6,17 @@ module Mutations
def resolve(dossier:, annotation_id:, instructeur:, value:) def resolve(dossier:, annotation_id:, instructeur:, value:)
resolve_with_type( resolve_with_type(
:datetime, dossier: dossier,
dossier, annotation_id: annotation_id,
annotation_id, instructeur: instructeur,
instructeur, value: value
value
) )
end end
private
def input_type
:datetime
end
end end
end end

View file

@ -6,12 +6,17 @@ module Mutations
def resolve(dossier:, annotation_id:, instructeur:, value:) def resolve(dossier:, annotation_id:, instructeur:, value:)
resolve_with_type( resolve_with_type(
:integer_number, dossier: dossier,
dossier, annotation_id: annotation_id,
annotation_id, instructeur: instructeur,
instructeur, value: value
value
) )
end end
private
def input_type
:integer_number
end
end end
end end

View file

@ -6,12 +6,17 @@ module Mutations
def resolve(dossier:, annotation_id:, instructeur:, value:) def resolve(dossier:, annotation_id:, instructeur:, value:)
resolve_with_type( resolve_with_type(
:text, dossier: dossier,
dossier, annotation_id: annotation_id,
annotation_id, instructeur: instructeur,
instructeur, value: value
value
) )
end end
private
def input_type
:text
end
end end
end end

View file

@ -1026,6 +1026,44 @@ type DossierLinkChamp implements Champ {
stringValue: String stringValue: String
} }
"""
Autogenerated input type of DossierModifierAnnotationAjouterLigne
"""
input DossierModifierAnnotationAjouterLigneInput {
"""
Annotation ID
"""
annotationId: ID!
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Dossier ID
"""
dossierId: ID!
"""
Instructeur qui demande la modification.
"""
instructeurId: ID!
}
"""
Autogenerated return type of DossierModifierAnnotationAjouterLigne
"""
type DossierModifierAnnotationAjouterLignePayload {
annotation: RepetitionChamp
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
errors: [ValidationError!]
}
""" """
Autogenerated input type of DossierModifierAnnotationCheckbox Autogenerated input type of DossierModifierAnnotationCheckbox
""" """
@ -1664,6 +1702,12 @@ type Mutation {
""" """
input: DossierEnvoyerMessageInput! input: DossierEnvoyerMessageInput!
): DossierEnvoyerMessagePayload ): DossierEnvoyerMessagePayload
dossierModifierAnnotationAjouterLigne(
"""
Parameters for DossierModifierAnnotationAjouterLigne
"""
input: DossierModifierAnnotationAjouterLigneInput!
): DossierModifierAnnotationAjouterLignePayload
""" """
Modifier lannotation au format oui/non. Modifier lannotation au format oui/non.

View file

@ -17,5 +17,6 @@ module Types
field :dossier_modifier_annotation_date, mutation: Mutations::DossierModifierAnnotationDate field :dossier_modifier_annotation_date, mutation: Mutations::DossierModifierAnnotationDate
field :dossier_modifier_annotation_datetime, mutation: Mutations::DossierModifierAnnotationDatetime field :dossier_modifier_annotation_datetime, mutation: Mutations::DossierModifierAnnotationDatetime
field :dossier_modifier_annotation_integer_number, mutation: Mutations::DossierModifierAnnotationIntegerNumber field :dossier_modifier_annotation_integer_number, mutation: Mutations::DossierModifierAnnotationIntegerNumber
field :dossier_modifier_annotation_ajouter_ligne, mutation: Mutations::DossierModifierAnnotationAjouterLigne
end end
end end

View file

@ -126,8 +126,17 @@ class Champ < ApplicationRecord
end end
def to_typed_id def to_typed_id
if row.present?
GraphQL::Schema::UniqueWithinType.encode('Champ', "#{stable_id}|#{row}")
else
type_de_champ.to_typed_id type_de_champ.to_typed_id
end end
end
def self.decode_typed_id(typed_id)
_, stable_id_with_maybe_row = GraphQL::Schema::UniqueWithinType.decode(typed_id)
stable_id_with_maybe_row.split('|')
end
def html_label? def html_label?
true true

View file

@ -224,6 +224,7 @@ FactoryBot.define do
type_de_champ_text = build(:type_de_champ_text, type_de_champ_text = build(:type_de_champ_text,
procedure: champ_repetition.type_de_champ.procedure, procedure: champ_repetition.type_de_champ.procedure,
position: 0, position: 0,
private: champ_repetition.private?,
parent: parent, parent: parent,
libelle: 'Nom') libelle: 'Nom')
types_de_champ.push(type_de_champ_text) types_de_champ.push(type_de_champ_text)
@ -234,6 +235,7 @@ FactoryBot.define do
type_de_champ_number = build(:type_de_champ_number, type_de_champ_number = build(:type_de_champ_number,
procedure: champ_repetition.type_de_champ.procedure, procedure: champ_repetition.type_de_champ.procedure,
position: 1, position: 1,
private: champ_repetition.private?,
parent: parent, parent: parent,
libelle: 'Age') libelle: 'Age')
types_de_champ.push(type_de_champ_number) types_de_champ.push(type_de_champ_number)
@ -241,7 +243,7 @@ FactoryBot.define do
evaluator.rows.times do |row| evaluator.rows.times do |row|
champ_repetition.champs << types_de_champ.map do |type_de_champ| champ_repetition.champs << types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", dossier: champ_repetition.dossier, row: row, type_de_champ: type_de_champ, parent: champ_repetition) build(:"champ_#{type_de_champ.type_champ}", dossier: champ_repetition.dossier, row: row, type_de_champ: type_de_champ, parent: champ_repetition, private: champ_repetition.private?)
end end
end end
end end

View file

@ -190,6 +190,12 @@ FactoryBot.define do
end end
end end
trait :with_private_repetition do
after(:build) do |procedure, _evaluator|
build(:type_de_champ_repetition, :private, procedure: procedure)
end
end
trait :with_number do trait :with_number do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
build(:type_de_champ_number, procedure: procedure) build(:type_de_champ_number, procedure: procedure)

View file

@ -0,0 +1,131 @@
RSpec.describe Mutations::DossierModifierAnnotation, type: :graphql do
let(:admin) { create(:administrateur) }
let(:procedure) { create(:procedure, :published, :for_individual, :with_private_repetition, :with_type_de_champ_private, administrateurs: [admin]) }
let(:dossiers) { [] }
let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) }
let(:query) { '' }
let(:context) { { administrateur_id: admin.id } }
let(:variables) { {} }
subject { API::V2::Schema.execute(query, variables: variables, context: context) }
let(:data) { subject['data'].deep_symbolize_keys }
let(:errors) { subject['errors'].deep_symbolize_keys }
before do
instructeur.assign_to_procedure(procedure)
end
describe 'dossierModifierAnnotationAjouterLigne' do
let(:dossier) { create(:dossier, :en_construction, :with_populated_annotations, procedure: procedure) }
let(:dossiers) { [dossier] }
let(:annotation) { dossier.champs_private.find(&:repetition?) }
let(:query) { DOSSIER_MODIFIER_ANNOTATION_AJOUTER_LIGNE_MUTATION }
let(:variables) do
{
input: {
dossierId: dossier.to_typed_id,
annotationId: annotation.to_typed_id,
instructeurId: instructeur.to_typed_id
}
}
end
context 'with invalid champ' do
let(:annotation) { dossier.champs_private.last }
it 'return error' do
expect(data).to eq(dossierModifierAnnotationAjouterLigne: {
annotation: nil,
errors: [{ message: "Lannotation \"#{annotation.to_typed_id}\" nexiste pas" }]
})
end
end
it 'add row' do
expect(annotation.champs.size).to eq(4)
expect(data).to eq(dossierModifierAnnotationAjouterLigne: {
annotation: {
id: annotation.to_typed_id
},
errors: nil
})
expect(annotation.reload.champs.size).to eq(6)
end
end
describe 'dossierModifierAnnotationText' do
let(:dossier) { create(:dossier, :en_construction, :with_populated_annotations, procedure: procedure) }
let(:dossiers) { [dossier] }
let(:annotation) { dossier.champs_private.last }
let(:query) { DOSSIER_MODIFIER_ANNOTATION_TEXT_MUTATION }
let(:variables) do
{
input: {
dossierId: dossier.to_typed_id,
annotationId: annotation.to_typed_id,
instructeurId: instructeur.to_typed_id,
value: 'Hello world'
}
}
end
it 'update champ' do
expect(data).to eq(dossierModifierAnnotationText: {
annotation: {
id: annotation.to_typed_id
},
errors: nil
})
expect(annotation.reload.value).to eq('Hello world')
end
context 'with invalid champ' do
let(:annotation) { dossier.champs_private.find(&:repetition?) }
it 'return error' do
expect(data).to eq(dossierModifierAnnotationText: {
annotation: nil,
errors: [{ message: "Lannotation \"#{annotation.to_typed_id}\" nexiste pas" }]
})
end
end
context 'with rows' do
let(:annotation) { dossier.champs_private.find(&:repetition?).rows.first.first }
let(:other_annotation) { dossier.champs_private.find(&:repetition?).rows.second.first }
it 'update champ' do
expect(data).to eq(dossierModifierAnnotationText: {
annotation: {
id: annotation.to_typed_id
},
errors: nil
})
expect(annotation.reload.value).to eq('Hello world')
expect(other_annotation.reload.value).not_to eq('Hello world')
end
end
end
DOSSIER_MODIFIER_ANNOTATION_AJOUTER_LIGNE_MUTATION = <<-GRAPHQL
mutation($input: DossierModifierAnnotationAjouterLigneInput!) {
dossierModifierAnnotationAjouterLigne(input: $input) {
annotation { id }
errors { message }
}
}
GRAPHQL
DOSSIER_MODIFIER_ANNOTATION_TEXT_MUTATION = <<-GRAPHQL
mutation($input: DossierModifierAnnotationTextInput!) {
dossierModifierAnnotationText(input: $input) {
annotation { id }
errors { message }
}
}
GRAPHQL
end