-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
526 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<?php | ||
|
||
namespace App\Controller\Api; | ||
|
||
use App\Dto\Api\Request\SuiviRequest; | ||
use App\Dto\Api\Response\SuiviResponse; | ||
use App\Entity\File; | ||
use App\Entity\Signalement; | ||
use App\Entity\Suivi; | ||
use App\Entity\User; | ||
use App\EventListener\SecurityApiExceptionListener; | ||
use App\Manager\SuiviManager; | ||
use App\Service\Sanitizer; | ||
use Nelmio\ApiDocBundle\Attribute\Model; | ||
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; | ||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | ||
|
||
#[When('dev')] | ||
#[When('test')] | ||
#[Route('/api')] | ||
class SuiviCreateController extends AbstractController | ||
{ | ||
public function __construct( | ||
readonly private SuiviManager $suiviManager, | ||
readonly private UrlGeneratorInterface $urlGenerator, | ||
) { | ||
} | ||
|
||
#[Route('/signalements/{uuid:signalement}/suivis', name: 'api_signalements_suivis_post', methods: ['POST'])] | ||
#[OA\Post( | ||
path: '/api/signalements/{uuid}/suivis', | ||
description: 'Création d\'un suivi', | ||
summary: 'Création d\'un suivi', | ||
security: [['Bearer' => []]], | ||
tags: ['Suivis'] | ||
)] | ||
#[OA\Response( | ||
response: Response::HTTP_CREATED, | ||
description: 'Suivi crée avec succès', | ||
content: new OA\JsonContent(ref: new Model(type: SuiviResponse::class)) | ||
)] | ||
#[OA\Response( | ||
response: Response::HTTP_NOT_FOUND, | ||
description: 'Signalement introuvable', | ||
content: new OA\JsonContent( | ||
properties: [ | ||
new OA\Property( | ||
property: 'message', | ||
type: 'string', | ||
example: 'Signalement 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: 'description' | ||
), | ||
new OA\Property( | ||
property: 'message', | ||
type: 'string', | ||
example: 'Le contenu du suivi doit faire au moins 10 caractères !' | ||
), | ||
], | ||
type: 'object' | ||
) | ||
), | ||
], | ||
type: 'object' | ||
) | ||
)] | ||
#[OA\Response( | ||
response: Response::HTTP_FORBIDDEN, | ||
description: 'Accès à la ressource non autorisé.', | ||
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 __invoke( | ||
#[MapRequestPayload] | ||
SuiviRequest $suiviRequest, | ||
?Signalement $signalement = null, | ||
): JsonResponse { | ||
if (null === $signalement) { | ||
return $this->json( | ||
['message' => 'Signalement introuvable', 'status' => Response::HTTP_NOT_FOUND], | ||
Response::HTTP_NOT_FOUND | ||
); | ||
} | ||
$this->denyAccessUnlessGranted('COMMENT_CREATE', | ||
$signalement, | ||
SecurityApiExceptionListener::ACCESS_DENIED | ||
); | ||
|
||
/** @var User $user */ | ||
$user = $this->getUser(); | ||
$suivi = $this->suiviManager->createSuivi( | ||
signalement: $signalement, | ||
description: $this->buildDescription($signalement, $suiviRequest), | ||
type: Suivi::TYPE_PARTNER, | ||
isPublic: $suiviRequest->notifyUsager, | ||
user: $user, | ||
); | ||
|
||
return $this->json(new SuiviResponse($suivi), Response::HTTP_CREATED); | ||
} | ||
|
||
private function buildDescription(Signalement $signalement, SuiviRequest $suiviRequest): string | ||
{ | ||
$fileListAsHtml = ''; | ||
$description = Sanitizer::sanitize($suiviRequest->description); | ||
$filesFiltered = $signalement->getFiles()->filter(function (File $file) use ($suiviRequest) { | ||
return in_array($file->getUuid(), $suiviRequest->files, true); | ||
}); | ||
|
||
if ($filesFiltered->count() > 0) { | ||
$fileListAsHtml = '<ul>'; | ||
/** @var File $file */ | ||
foreach ($filesFiltered as $file) { | ||
$fileUrl = $this->urlGenerator->generate( | ||
'show_file', | ||
['uuid' => $file->getUuid()], | ||
UrlGeneratorInterface::ABSOLUTE_URL | ||
); | ||
$fileListAsHtml .= sprintf("<li><a class='fr-link' target='_blank' rel='noopener' href='%s'>%s</a>", | ||
$fileUrl, | ||
$file->getTitle() | ||
); | ||
} | ||
$fileListAsHtml .= '</ul>'; | ||
} | ||
|
||
return $description.$fileListAsHtml; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
namespace App\Dto\Api\Request; | ||
|
||
use App\Validator\SanitizedLength; | ||
use App\Validator\ValidFiles; | ||
use OpenApi\Attributes as OA; | ||
|
||
#[OA\Schema( | ||
description: 'Payload pour créer un suivi.', | ||
required: ['description'], | ||
)] | ||
class SuiviRequest implements RequestInterface | ||
{ | ||
#[OA\Property( | ||
description: 'Un message de 10 caractère minimum est obligatoire.', | ||
example: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', | ||
)] | ||
#[SanitizedLength(min: 10)] | ||
public ?string $description = null; | ||
|
||
#[OA\Property( | ||
description: 'Permet d\'indiquer si l\'usager doit être notifié.', | ||
default: false, | ||
example: true, | ||
)] | ||
public bool $notifyUsager = false; | ||
|
||
#[OA\Property( | ||
description: 'Tableau contenant une liste d\'UUID des fichiers associés au signalement.', | ||
type: 'array', | ||
items: new OA\Items(type: 'string', format: 'uuid'), | ||
example: ['f47ac10b-58cc-4372-a567-0e02b2c3d479', '8d3c7db7-fc90-43f4-8066-7522f0e9b163'] | ||
)] | ||
#[ValidFiles] | ||
public array $files = []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
|
||
namespace App\Dto\Api\Response; | ||
|
||
use App\Entity\Suivi; | ||
use OpenApi\Attributes as OA; | ||
|
||
class SuiviResponse | ||
{ | ||
#[OA\Property( | ||
description: 'Date de création du suivi.<br>Exemple : `2024-11-01T10:00:00+00:00`', | ||
type: 'string', | ||
format: 'date-time', | ||
example: '2024-11-01T10:00:00+00:00' | ||
)] | ||
public string $dateCreation; | ||
|
||
#[OA\Property( | ||
description: 'Description détaillée du suivi, peut contenir des balises HTML.', | ||
type: 'string', | ||
example: '<ul><li>lorem</li><li>ipsum</li></ul>' | ||
)] | ||
public string $description; | ||
|
||
#[OA\Property( | ||
description: 'Indique si le suivi est visible pour les usagers.', | ||
type: 'boolean', | ||
example: true | ||
)] | ||
public bool $public; | ||
|
||
public function __construct(Suivi $suivi) | ||
{ | ||
$this->dateCreation = $suivi->getCreatedAt()->format(\DATE_ATOM); | ||
$this->description = $suivi->getDescription(); | ||
$this->public = $suivi->getIsPublic(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace App\Validator; | ||
|
||
use Symfony\Component\Validator\Constraint; | ||
|
||
#[\Attribute] | ||
class SanitizedLength extends Constraint | ||
{ | ||
public string $message = 'Le texte doit contenir au moins {{ limit }} caractères après sanitation.'; | ||
public int $min; | ||
|
||
public function __construct(int $min, ?string $message = null) | ||
{ | ||
parent::__construct([]); | ||
$this->min = $min; | ||
if ($message) { | ||
$this->message = $message; | ||
} | ||
} | ||
} |
Oops, something went wrong.