Merge pull request #10487 from tchak/feat-graphql-discard-message
feat(graphql): messages can be discarded through api
This commit is contained in:
commit
f55cadc806
8 changed files with 169 additions and 1 deletions
|
@ -819,6 +819,19 @@ class API::V2::StoredQuery
|
|||
}
|
||||
}
|
||||
|
||||
mutation dossierSupprimerMessage($input: DossierSupprimerMessageInput!) {
|
||||
dossierSupprimerMessage(input: $input) {
|
||||
message {
|
||||
id
|
||||
createdAt
|
||||
discardedAt
|
||||
}
|
||||
errors {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation dossierModifierAnnotationText(
|
||||
$input: DossierModifierAnnotationTextInput!
|
||||
) {
|
||||
|
|
|
@ -21,6 +21,9 @@ module Mutations
|
|||
if !dossier.en_construction?
|
||||
return false, { errors: ["Le dossier est déjà #{dossier_display_state(dossier, lower: true)}"] }
|
||||
end
|
||||
if dossier.blocked_with_pending_correction?
|
||||
return false, { errors: ["Le dossier est en attente de correction"] }
|
||||
end
|
||||
dossier_authorized_for?(dossier, instructeur)
|
||||
end
|
||||
end
|
||||
|
|
24
app/graphql/mutations/dossier_supprimer_message.rb
Normal file
24
app/graphql/mutations/dossier_supprimer_message.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Mutations
|
||||
class DossierSupprimerMessage < Mutations::BaseMutation
|
||||
description "Supprimer un message."
|
||||
|
||||
argument :message_id, ID, required: true, loads: Types::MessageType
|
||||
argument :instructeur_id, ID, required: true, loads: Types::ProfileType
|
||||
|
||||
field :message, Types::MessageType, null: true
|
||||
field :errors, [Types::ValidationErrorType], null: true
|
||||
|
||||
def resolve(message:, **args)
|
||||
message.soft_delete!
|
||||
|
||||
{ message: }
|
||||
end
|
||||
|
||||
def authorized?(message:, instructeur:, **args)
|
||||
if !message.soft_deletable?(instructeur)
|
||||
return false, { errors: ["Le message ne peut pas être supprimé"] }
|
||||
end
|
||||
dossier_authorized_for?(message.dossier, instructeur)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2192,6 +2192,30 @@ enum DossierState {
|
|||
sans_suite
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated input type of DossierSupprimerMessage
|
||||
"""
|
||||
input DossierSupprimerMessageInput {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
instructeurId: ID!
|
||||
messageId: ID!
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated return type of DossierSupprimerMessage.
|
||||
"""
|
||||
type DossierSupprimerMessagePayload {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
errors: [ValidationError!]
|
||||
message: Message
|
||||
}
|
||||
|
||||
type DropDownListChampDescriptor implements ChampDescriptor {
|
||||
"""
|
||||
Description des champs d’un bloc répétable.
|
||||
|
@ -3084,6 +3108,7 @@ type Message {
|
|||
body: String!
|
||||
correction: Correction
|
||||
createdAt: ISO8601DateTime!
|
||||
discardedAt: ISO8601DateTime
|
||||
email: String!
|
||||
id: ID!
|
||||
}
|
||||
|
@ -3313,6 +3338,16 @@ type Mutation {
|
|||
input: DossierRepasserEnInstructionInput!
|
||||
): DossierRepasserEnInstructionPayload
|
||||
|
||||
"""
|
||||
Supprimer un message.
|
||||
"""
|
||||
dossierSupprimerMessage(
|
||||
"""
|
||||
Parameters for DossierSupprimerMessage
|
||||
"""
|
||||
input: DossierSupprimerMessageInput!
|
||||
): DossierSupprimerMessagePayload
|
||||
|
||||
"""
|
||||
Ajouter des instructeurs à un groupe instructeur.
|
||||
"""
|
||||
|
|
|
@ -4,6 +4,7 @@ module Types
|
|||
field :email, String, null: false
|
||||
field :body, String, null: false
|
||||
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
|
||||
field :discarded_at, GraphQL::Types::ISO8601DateTime, null: true
|
||||
field :attachment, Types::File, null: true, deprecation_reason: "Utilisez le champ `attachments` à la place.", extensions: [
|
||||
{ Extensions::Attachment => { attachments: :piece_jointe, as: :single } }
|
||||
]
|
||||
|
@ -19,5 +20,9 @@ module Types
|
|||
def correction
|
||||
Loaders::Association.for(object.class, :dossier_correction).load(object)
|
||||
end
|
||||
|
||||
def self.authorized?(object, context)
|
||||
context.authorized_demarche?(object.dossier.revision.procedure)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ module Types
|
|||
field :create_direct_upload, mutation: Mutations::CreateDirectUpload
|
||||
|
||||
field :dossier_envoyer_message, mutation: Mutations::DossierEnvoyerMessage
|
||||
field :dossier_supprimer_message, mutation: Mutations::DossierSupprimerMessage
|
||||
field :dossier_passer_en_instruction, mutation: Mutations::DossierPasserEnInstruction
|
||||
field :dossier_classer_sans_suite, mutation: Mutations::DossierClasserSansSuite
|
||||
field :dossier_refuser, mutation: Mutations::DossierRefuser
|
||||
|
|
|
@ -558,8 +558,12 @@ class Dossier < ApplicationRecord
|
|||
false
|
||||
end
|
||||
|
||||
def blocked_with_pending_correction?
|
||||
procedure.feature_enabled?(:blocking_pending_correction) && pending_correction?
|
||||
end
|
||||
|
||||
def can_passer_en_instruction?
|
||||
return false if procedure.feature_enabled?(:blocking_pending_correction) && pending_correction?
|
||||
return false if blocked_with_pending_correction?
|
||||
|
||||
true
|
||||
end
|
||||
|
|
|
@ -912,6 +912,17 @@ describe API::V2::GraphqlController do
|
|||
expect(ActionMailer::Base.deliveries.size).to eq(0)
|
||||
}
|
||||
end
|
||||
|
||||
context 'with pending corrections' do
|
||||
before { Flipper.enable(:blocking_pending_correction, dossier.procedure) }
|
||||
let!(:dossier_correction) { create(:dossier_correction, dossier:) }
|
||||
|
||||
it {
|
||||
expect(dossier.pending_correction?).to be_truthy
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierPasserEnInstruction][:errors]).to eq([{ message: "Le dossier est en attente de correction" }])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'dossierRepasserEnConstruction' do
|
||||
|
@ -1332,5 +1343,77 @@ describe API::V2::GraphqlController do
|
|||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'dossierEnvoyerMessage' do
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure:) }
|
||||
let(:variables) { { input: { dossierId: dossier.to_typed_id, instructeurId: instructeur.to_typed_id, body: 'Hello World!' } } }
|
||||
let(:operation_name) { 'dossierEnvoyerMessage' }
|
||||
|
||||
it {
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierEnvoyerMessage][:errors]).to be_nil
|
||||
expect(gql_data[:dossierEnvoyerMessage][:message][:id]).to eq(dossier.commentaires.first.to_typed_id)
|
||||
perform_enqueued_jobs
|
||||
expect(ActionMailer::Base.deliveries.size).to eq(1)
|
||||
}
|
||||
end
|
||||
|
||||
context 'dossierSupprimerMessage' do
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure:) }
|
||||
let(:message) { create(:commentaire, dossier:, instructeur:) }
|
||||
let(:dossier_correction) { create(:dossier_correction, dossier:, commentaire: message) }
|
||||
let(:variables) { { input: { messageId: message.to_typed_id, instructeurId: instructeur.to_typed_id } } }
|
||||
let(:operation_name) { 'dossierSupprimerMessage' }
|
||||
|
||||
it {
|
||||
expect(message.discarded?).to be_falsey
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:errors]).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:message][:id]).to eq(message.to_typed_id)
|
||||
expect(gql_data[:dossierSupprimerMessage][:message][:discardedAt]).not_to be_nil
|
||||
expect(message.reload.discarded?).to be_truthy
|
||||
}
|
||||
|
||||
it {
|
||||
expect(dossier_correction.commentaire.discarded?).to be_falsey
|
||||
expect(dossier.pending_correction?).to be_truthy
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:errors]).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:message][:id]).to eq(message.to_typed_id)
|
||||
expect(gql_data[:dossierSupprimerMessage][:message][:discardedAt]).not_to be_nil
|
||||
expect(message.reload.discarded?).to be_truthy
|
||||
expect(dossier.pending_correction?).to be_falsey
|
||||
}
|
||||
|
||||
context 'when unauthorized' do
|
||||
let(:dossier) { create(:dossier, :en_construction, :with_individual) }
|
||||
|
||||
it {
|
||||
expect(message.discarded?).to be_falsey
|
||||
expect(gql_errors.first[:message]).to eq("An object of type Message was hidden due to permissions")
|
||||
}
|
||||
end
|
||||
|
||||
context 'when from not the same instructeur' do
|
||||
let(:other_instructeur) { create(:instructeur, followed_dossiers: dossiers) }
|
||||
let(:variables) { { input: { messageId: message.to_typed_id, instructeurId: other_instructeur.to_typed_id } } }
|
||||
|
||||
it {
|
||||
expect(message.discarded?).to be_falsey
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:errors]).to eq([{ message: "Le message ne peut pas être supprimé" }])
|
||||
}
|
||||
end
|
||||
|
||||
context 'when from usager' do
|
||||
let(:message) { create(:commentaire, dossier:) }
|
||||
|
||||
it {
|
||||
expect(message.discarded?).to be_falsey
|
||||
expect(gql_errors).to be_nil
|
||||
expect(gql_data[:dossierSupprimerMessage][:errors]).to eq([{ message: "Le message ne peut pas être supprimé" }])
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue