Skip to content

Commit

Permalink
update affectation #3619
Browse files Browse the repository at this point in the history
  • Loading branch information
sfinx13 committed Feb 4, 2025
1 parent f3923ae commit cb21afe
Show file tree
Hide file tree
Showing 35 changed files with 1,084 additions and 206 deletions.
5 changes: 5 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ services:
tags:
- { name: 'kernel.event_listener', event: 'kernel.exception' }


App\EventListener\SecurityApiExceptionListener:
tags:
- { name: 'kernel.event_listener', event: 'kernel.exception' }

App\EventListener\SeoPageNotFoundRedirectListener:
tags:
- { name: 'kernel.event_listener', event: 'kernel.request' }
Expand Down
27 changes: 27 additions & 0 deletions migrations/Version20250130150909.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20250130150909 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add uuid column to affectation table';
}

public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE affectation ADD uuid VARCHAR(255) NOT NULL AFTER territory_id');
$this->addSql('UPDATE affectation SET uuid = UUID()');
}

public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE affectation DROP uuid');
}
}
194 changes: 194 additions & 0 deletions src/Controller/Api/AffectationUpdateController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?php

namespace App\Controller\Api;

use App\Dto\Api\Request\AffectationRequest;
use App\Dto\Api\Response\AffectationResponse;
use App\Entity\Affectation;
use App\Entity\Enum\AffectationNewStatus;
use App\Entity\Enum\MotifCloture;
use App\Entity\Enum\MotifRefus;
use App\Entity\User;
use App\EventListener\SecurityApiExceptionListener;
use App\Exception\Suivi\UsagerNotificationRequiredException;
use App\Manager\AffectationManager;
use App\Security\Voter\AffectationVoter;
use OpenApi\Attributes as OA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\When;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
use Symfony\Component\Routing\Attribute\Route;

#[When('dev')]
#[When('test')]
#[Route('/api')]
class AffectationUpdateController extends AbstractController
{
public function __construct(private readonly AffectationManager $affectationManager)
{
}

/**
* @throws UsagerNotificationRequiredException
*/
#[Route('/affectations/{uuid:affectation}', name: 'api_affectations_update', methods: 'PATCH')]
#[OA\Patch(
path: '/api/affectations/{uuid}',
description: 'Mise à jour d\'une affectation',
summary: 'Mise à jour d\'une affectation',
security: [['Bearer' => []]],
tags: ['Affectations'],
)]
#[OA\Response(
response: Response::HTTP_OK,
description: 'Une affectation',
content: new OA\JsonContent(ref: '#/components/schemas/Affectation')
)]
#[OA\Response(
response: Response::HTTP_NOT_FOUND,
description: 'Affectation introuvable',
content: new OA\JsonContent(
properties: [
new OA\Property(
property: 'message',
type: 'string',
example: 'Affectation introuvable'
),
new OA\Property(
property: 'statut',
type: 'int',
example: Response::HTTP_NOT_FOUND
),
],
type: 'object'
)
)]
#[OA\Response(
response: Response::HTTP_BAD_REQUEST,
description: 'Mauvaise payload (données invalides).',
content: new OA\JsonContent(
properties: [
new OA\Property(
property: 'message',
type: 'string',
example: 'Valeurs invalides pour les champs suivants :'
),
new OA\Property(
property: 'status',
type: 'integer',
example: 400
),
new OA\Property(
property: 'errors',
type: 'array',
items: new OA\Items(
properties: [
new OA\Property(
property: 'property',
type: 'string',
example: 'statut'
),
new OA\Property(
property: 'message',
type: 'string',
example: 'Cette valeur doit être l\'un des choix suivants : \"NOUVEAU\", \"EN_COURS\", \"FERME\", \"REFUSE\"'
),
new OA\Property(
property: 'invalidValue',
type: 'string',
example: 'NOUVEAddU'
),
],
type: 'object'
)
),
],
type: 'object'
)
)]
#[OA\Response(
response: Response::HTTP_FORBIDDEN,
description: 'Accès à la ressource non autorisée.',
content: new OA\JsonContent(
properties: [
new OA\Property(
property: 'message',
type: 'string',
example: 'Vous n\'avez pas l\'autorisation d\'accéder à cette ressource.'
),
new OA\Property(
property: 'statut',
type: 'int',
example: Response::HTTP_FORBIDDEN
),
],
type: 'object'
)
)]
public function index(
#[MapRequestPayload] AffectationRequest $affectationRequest,
?Affectation $affectation = null,
): JsonResponse {
if (null === $affectation) {
return new JsonResponse(
['message' => 'Affectation introuvable.', 'status' => Response::HTTP_NOT_FOUND],
Response::HTTP_NOT_FOUND
);
}
$affectation->setNextStatut(AffectationNewStatus::mapStatus($affectationRequest->statut));
$this->denyAccessUnlessGranted(AffectationVoter::ANSWER, $affectation, SecurityApiExceptionListener::ACCESS_DENIED);
$this->denyAccessUnlessGranted(AffectationVoter::UPDATE_STATUT, $affectation, SecurityApiExceptionListener::TRANSITION_STATUT_DENIED);
$this->applyUsagerNotification($affectationRequest, $affectation);

$affectation = $this->update($affectationRequest, $affectation);

return new JsonResponse(new AffectationResponse($affectation), Response::HTTP_OK);
}

private function update(AffectationRequest $affectationRequest, Affectation $affectation): Affectation
{
/** @var User $user */
$user = $this->getUser();

$statut = AffectationNewStatus::mapStatus($affectationRequest->statut);
if ($statut !== $affectation->getStatut()) {
if (Affectation::STATUS_CLOSED === $statut) {
$motifCloture = MotifCloture::tryFrom($affectationRequest->motifCloture);

return $this->affectationManager->closeAffectation(
$affectation,
$user,
$motifCloture,
$affectationRequest->message,
true
);
}
$motifRefus = $message = null;
if (Affectation::STATUS_REFUSED === $statut) {
$motifRefus = MotifRefus::tryFrom($affectationRequest->motifRefus)->value;
$message = $affectationRequest->message;
}

return $this->affectationManager->updateAffectation($affectation, $user, $statut, $motifRefus, $message);
}

return $affectation;
}

/**
* @throws UsagerNotificationRequiredException
*/
private function applyUsagerNotification(AffectationRequest $affectationRequest, Affectation $affectation): void
{
if (Affectation::STATUS_CLOSED === $affectation->getStatut()
&& Affectation::STATUS_WAIT === $affectation->getNextStatut()) {
if (null === $affectationRequest->notifyUsager) {
throw new UsagerNotificationRequiredException($affectationRequest);
}

$affectation->setHasNotificationUsagerToCreate($affectationRequest->notifyUsager);
}
}
}
63 changes: 8 additions & 55 deletions src/Controller/Back/AffectationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,37 @@

use App\Entity\Affectation;
use App\Entity\Signalement;
use App\Entity\Suivi;
use App\Entity\User;
use App\Event\AffectationAnsweredEvent;
use App\Factory\Interconnection\Idoss\DossierMessageFactory;
use App\Manager\AffectationManager;
use App\Manager\SignalementManager;
use App\Manager\SuiviManager;
use App\Manager\UserManager;
use App\Messenger\InterconnectionBus;
use App\Repository\AffectationRepository;
use App\Repository\PartnerRepository;
use App\Security\Voter\AffectationVoter;
use App\Service\Signalement\SearchFilterOptionDataProvider;
use App\Specification\Signalement\FirstAffectationAcceptedSpecification;
use Psr\Cache\InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Exception\ExceptionInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Cache\TagAwareCacheInterface;

#[Route('/bo/signalements')]
class AffectationController extends AbstractController
{
public function __construct(
private SignalementManager $signalementManager,
private AffectationManager $affectationManager,
private PartnerRepository $partnerRepository,
private InterconnectionBus $interconnectionBus,
private EventDispatcherInterface $eventDispatcher,
private readonly SignalementManager $signalementManager,
private readonly AffectationManager $affectationManager,
private readonly PartnerRepository $partnerRepository,
private readonly InterconnectionBus $interconnectionBus,
) {
}

/**
* @throws ExceptionInterface
* @throws InvalidArgumentException
*/
#[Route('/{uuid:signalement}/affectation/toggle', name: 'back_signalement_toggle_affectation')]
Expand Down Expand Up @@ -122,63 +114,24 @@ public function removePartnerAffectation(
methods: 'POST'
)]
public function affectationResponseSignalement(
SuiviManager $suiviManager,
UserManager $userManager,
ParameterBagInterface $parameterBag,
Signalement $signalement,
Affectation $affectation,
User $user,
Request $request,
FirstAffectationAcceptedSpecification $firstAcceptedAffectationSpecification,
DossierMessageFactory $dossierMessageFactory,
MessageBusInterface $bus,
): Response {
$this->denyAccessUnlessGranted(AffectationVoter::ANSWER, $affectation);
if ($this->isCsrfTokenValid('signalement_affectation_response_'.$signalement->getId(), $request->get('_token'))
&& $response = $request->get('signalement-affectation-response')
) {
$status = isset($response['accept']) ? Affectation::STATUS_ACCEPTED : Affectation::STATUS_REFUSED;
$motifRefus = (Affectation::STATUS_REFUSED === $status) ? $response['motifRefus'] : null;
$affectation = $this->affectationManager->updateAffectation($affectation, $user, $status, $motifRefus);

if ($firstAcceptedAffectationSpecification->isSatisfiedBy($signalement, $affectation)) {
$adminEmail = $parameterBag->get('user_system_email');
$adminUser = $userManager->findOneBy(['email' => $adminEmail]);
$suiviManager->createSuivi(
user: $adminUser,
signalement: $signalement,
description: $parameterBag->get('suivi_message')['first_accepted_affectation'],
type: Suivi::TYPE_AUTO,
isPublic: true,
context: Suivi::CONTEXT_NOTIFY_USAGER_ONLY,
);
}

if (Affectation::STATUS_REFUSED == $status) {
$this->dispatchAffectationAnsweredEvent($affectation, $response);
}
if ($dossierMessageFactory->supports($affectation)) {
$bus->dispatch($dossierMessageFactory->createInstance($affectation));
}
$message = $response['suivi'] ?? null;
$this->affectationManager->updateAffectation($affectation, $user, $status, $motifRefus, $message);
$this->addFlash('success', 'Affectation mise à jour avec succès !');
} else {
$this->addFlash('error', "Une erreur est survenu lors de l'affectation");
}

return $this->redirectToRoute('back_signalement_view', ['uuid' => $signalement->getUuid()]);
}

private function dispatchAffectationAnsweredEvent(
Affectation $affectation,
array $response,
): void {
/** @var User $user */
$user = $this->getUser();
if (isset($response['suivi'])) {
$this->eventDispatcher->dispatch(
new AffectationAnsweredEvent($affectation, $user, $response),
AffectationAnsweredEvent::NAME
);
}
}
}
2 changes: 1 addition & 1 deletion src/Controller/Back/SignalementActionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ public function reopenSignalement(
}
$signalement->setStatut(Signalement::STATUS_ACTIVE);
$suiviManager->createSuivi(
user: $user,
signalement: $signalement,
description: 'Signalement rouvert pour '.$reopenFor,
type: Suivi::TYPE_AUTO,
isPublic: '1' === $request->get('publicSuivi'),
user: $user,
);
$this->addFlash('success', 'Signalement rouvert avec succès !');
} else {
Expand Down
10 changes: 7 additions & 3 deletions src/Controller/Back/SignalementController.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,19 @@ public function viewSignalement(
$eventParams['motif_cloture']
);
$reference = $signalement->getReference();

$eventDispatcher->dispatch(new SignalementClosedEvent($entity, $eventParams), SignalementClosedEvent::NAME);
/* @var Affectation $affectation */
} elseif ($affectation) {
$entity = $affectationManager->closeAffectation($affectation, $user, $eventParams['motif_cloture'], true);
$entity = $affectationManager->closeAffectation(
$affectation,
$user,
$eventParams['motif_cloture'],
$eventParams['motif_suivi'],
true);
$reference = $entity->getSignalement()->getReference();
}

if (!empty($entity)) {
$eventDispatcher->dispatch(new SignalementClosedEvent($entity, $eventParams), SignalementClosedEvent::NAME);
$this->addFlash('success', sprintf('Signalement #%s cloturé avec succès !', $reference));
}
$signalementSearchQuery = $request->getSession()->get('signalementSearchQuery');
Expand Down
Loading

0 comments on commit cb21afe

Please sign in to comment.