clean(CommentaireService): extract soft delete within controller. returning an instance with an error[:base] is not persisted with validation : avoid poluting stuff

This commit is contained in:
Martin 2021-11-16 16:10:08 +01:00
parent 8bbd77f89f
commit f0950b592b
8 changed files with 33 additions and 117 deletions

View file

@ -3,13 +3,19 @@
module Instructeurs
class CommentairesController < ProceduresController
def destroy
result = CommentaireService.soft_delete(current_instructeur, params.permit(:dossier_id, :id))
if result.status
commentaire = Dossier.find(params[:dossier_id]).commentaires.find(params[:id])
if commentaire.sent_by?(current_instructeur)
commentaire.piece_jointe.purge_later if commentaire.piece_jointe.attached?
commentaire.discard!
commentaire.update!(body: '')
flash[:notice] = t('views.shared.commentaires.destroy.notice')
else
flash[:alert] = t('views.shared.commentaires.destroy.alert', reason: result.error_message)
flash[:alert] = I18n.t('views.shared.commentaires.destroy.alert_reasons.acl')
end
redirect_to(messagerie_instructeur_dossier_path(params[:procedure_id], params[:dossier_id]))
rescue Discard::RecordNotDiscarded
flash[:alert] = I18n.t('views.shared.commentaires.destroy.alert_reasons.already_discarded')
redirect_to(messagerie_instructeur_dossier_path(params[:procedure_id], params[:dossier_id]))
end
end
end

View file

@ -22,7 +22,8 @@ class DossierMailer < ApplicationMailer
end
def notify_new_answer
dossier = params[:commentaire].dossier
commentaire = params[:commentaire]
dossier = commentaire.dossier
I18n.with_locale(dossier.user_locale) do
@dossier = dossier
@service = dossier.procedure.service

View file

@ -26,7 +26,7 @@ class Commentaire < ApplicationRecord
has_one_attached :piece_jointe
validates :body, presence: { message: "ne peut être vide" }
validates :body, presence: { message: "ne peut être vide" }, unless: :discarded?
FILE_MAX_SIZE = 20.megabytes
validates :piece_jointe,
@ -105,10 +105,8 @@ class Commentaire < ApplicationRecord
end
end
def notify_user(job_options)
DossierMailer.with(commentaire: self)
.notify_new_answer
.deliver_later(job_options)
def notify_user(job_options = {})
DossierMailer.with(commentaire: self).notify_new_answer.deliver_later(job_options)
end
def messagerie_available?

View file

@ -20,22 +20,5 @@ class CommentaireService
end
Commentaire.new(attributes)
end
def soft_delete(user, params)
commentaire = Dossier.find(params[:dossier_id])
.commentaires
.find(params[:id])
if commentaire.sent_by?(user)
commentaire.piece_jointe.purge_later if commentaire.piece_jointe.attached?
commentaire.body = ''
OpenStruct.new(status: commentaire.discard, error_message: commentaire.errors.full_messages.join(', '))
else
OpenStruct.new(status: false,
error_message: I18n.t('views.shared.commentaires.destroy.alert_reasons.acl'))
end
rescue ActiveRecord::RecordNotFound => e
return OpenStruct.new(status: false,
error_message: I18n.t('views.shared.commentaires.destroy.alert_reasons.ar_not_found', model_name: e.model.humanize))
end
end
end

View file

@ -29,4 +29,4 @@ en:
alert: 'Can not destroy message: #{result.error_message}'
alert_reasons:
acl: "Can not destroy message: it does not belong to you"
ar_not_found: "%{model_name} not found"
already_discarded: "Can not destroy message: it was already destroyed"

View file

@ -26,7 +26,6 @@ fr:
confirm: "Êtes-vous sûr de vouloir supprimer ce message ?"
deleted_body: Message supprimé
notice: 'Votre message a été supprimé'
alert: 'Votre message ne peut être supprimé: #{result.error_message}'
alert_reasons:
acl: "Impossible de supprimer le message, celui ci ne vous appartient pas"
ar_not_found: "%{model_name} introuvable"
already_discarded: "Ce message a déjà été supprimé"

View file

@ -8,27 +8,29 @@ describe Instructeurs::CommentairesController, type: :controller do
before { sign_in(instructeur.user) }
describe 'destroy' do
let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) }
subject { delete :destroy, params: { dossier_id: dossier.id, procedure_id: procedure.id, id: commentaire.id } }
it 'redirect to dossier' do
expect(subject).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier))
end
it 'flash success' do
subject
expect(flash[:notice]).to eq(I18n.t('views.shared.commentaires.destroy.notice'))
end
context 'when it works' do
let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) }
subject { delete :destroy, params: { dossier_id: dossier.id, procedure_id: procedure.id, id: commentaire.id } }
context 'when it fails' do
let(:error) { OpenStruct.new(status: false, error_message: "boom") }
before do
expect(CommentaireService).to receive(:soft_delete).and_return(error)
end
it 'redirect to dossier' do
expect(subject).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier))
end
it 'flash success' do
subject
expect(flash[:alert]).to eq(I18n.t('views.shared.commentaires.destroy.alert', reason: error.error_message))
expect(flash[:notice]).to eq(I18n.t('views.shared.commentaires.destroy.notice'))
end
end
context 'when dossier had been discarded' do
let(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier, discarded_at: 2.hours.ago) }
subject { delete :destroy, params: { dossier_id: dossier.id, procedure_id: procedure.id, id: commentaire.id } }
it 'redirect to dossier' do
expect(subject).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier))
end
it 'flash success' do
subject
expect(flash[:alert]).to eq(I18n.t('views.shared.commentaires.destroy.alert_reasons.already_discarded'))
end
end
end

View file

@ -34,77 +34,4 @@ describe CommentaireService do
end
end
end
describe '.soft_delete' do
subject { CommentaireService.soft_delete(user, params) }
context 'when dossier not found' do
let(:user) { create(:instructeur) }
let(:params) { {} }
it 'returns error struct' do
expect(subject.status).to eq(false)
end
it 'returns error message' do
expect(subject.error_message).to eq("Dossier introuvable")
end
end
context 'when commentaire not found' do
let(:user) { create(:instructeur) }
let(:params) { { dossier_id: create(:dossier).id } }
it 'returns error struct' do
expect(subject.status).to eq(false)
end
it 'returns error message' do
expect(subject.error_message).to eq("Commentaire introuvable")
end
end
context 'when commentaire does not belongs to instructeur' do
let(:user) { create(:instructeur) }
let(:dossier) { create(:dossier) }
let(:params) {
{
dossier_id: dossier.id,
id: create(:commentaire, dossier: dossier, instructeur: create(:instructeur)).id
}
}
it 'returns error struct' do
expect(subject.status).to eq(false)
end
it 'returns error message' do
expect(subject.error_message).to eq("Impossible de supprimer le message, celui ci ne vous appartient pas")
end
end
context 'when commentaire belongs to instructeur' do
let(:user) { create(:instructeur) }
let(:dossier) { create(:dossier) }
let(:commentaire) do
create(:commentaire,
dossier: dossier,
instructeur: user,
piece_jointe: fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf'))
end
let(:params) {
{
dossier_id: dossier.id,
id: commentaire.id
}
}
it 'returns error struct' do
expect(subject.status).to eq(true)
end
it 'sets commentaire.body to deleted message' do
expect_any_instance_of(ActiveStorage::Attached::One).to receive(:purge_later)
subject
end
it 'sets commentaire.body to deleted message' do
expect { subject }.to change { commentaire.reload.body }.from(an_instance_of(String)).to("")
end
it 'sets deleted_at' do
expect { subject }.to change { commentaire.reload.discarded? }.from(false).to(true)
end
end
end
end