diff --git a/migrations/Version20250120141313.php b/migrations/Version20250120141313.php
new file mode 100644
index 000000000..df4bc3fc2
--- /dev/null
+++ b/migrations/Version20250120141313.php
@@ -0,0 +1,26 @@
+addSql('ALTER TABLE suivi ADD is_sanitized TINYINT(1) NOT NULL');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE suivi DROP is_sanitized');
+ }
+}
diff --git a/src/Command/SanitizeSuivisCommand.php b/src/Command/SanitizeSuivisCommand.php
new file mode 100644
index 000000000..16a722f09
--- /dev/null
+++ b/src/Command/SanitizeSuivisCommand.php
@@ -0,0 +1,61 @@
+historyEntryManager->removeEntityListeners();
+ $io = new SymfonyStyle($input, $output);
+ $countAll = $this->suiviRepository->count(['isSanitized' => false]);
+ $io->info(sprintf('Found %s suivis to sanitize', $countAll));
+ $suivis = $this->suiviRepository->findBy(['isSanitized' => false], ['createdAt' => 'DESC'], 50000);
+ $i = 0;
+ $progressBar = new ProgressBar($output, \count($suivis));
+ $progressBar->start();
+ foreach ($suivis as $suivi) {
+ $suivi->setDescription($this->htmlSanitizer->sanitize($suivi->getDescription(false, false)));
+ $suivi->setIsSanitized(true);
+ ++$i;
+ $progressBar->advance();
+ if (0 === $i % self::BATCH_SIZE) {
+ $this->entityManager->flush();
+ }
+ }
+ $this->entityManager->flush();
+ $progressBar->finish();
+ $io->newLine();
+ $io->success(sprintf('Sanitized %s/%s suivis', $i, $countAll));
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Entity/Suivi.php b/src/Entity/Suivi.php
index 91fb10977..52f4b6136 100644
--- a/src/Entity/Suivi.php
+++ b/src/Entity/Suivi.php
@@ -73,10 +73,14 @@ class Suivi implements EntityHistoryInterface
#[ORM\Column(nullable: true)]
private ?array $originalData = null;
+ #[ORM\Column]
+ private ?bool $isSanitized = null;
+
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
$this->isPublic = false;
+ $this->isSanitized = true;
}
public function getId(): ?int
@@ -142,8 +146,11 @@ public function getCreatedByLabel(): ?string
return 'OCCUPANT : '.strtoupper($this->getSignalement()->getNomOccupant()).' '.ucfirst($this->getSignalement()->getPrenomOccupant());
}
- public function getDescription($transformHtml = true): ?string
+ public function getDescription($transformHtml = true, $originalData = false): ?string
{
+ if ($originalData) {
+ return $this->description;
+ }
if (null !== $this->deletedAt) {
return self::DESCRIPTION_DELETED.' '.$this->deletedAt->format('d/m/Y');
}
@@ -262,4 +269,16 @@ public function getHistoryRegisteredEvent(): array
{
return [HistoryEntryEvent::CREATE, HistoryEntryEvent::UPDATE, HistoryEntryEvent::DELETE];
}
+
+ public function getIsSanitized(): ?bool
+ {
+ return $this->isSanitized;
+ }
+
+ public function setIsSanitized(bool $isSanitized): static
+ {
+ $this->isSanitized = $isSanitized;
+
+ return $this;
+ }
}
diff --git a/src/Manager/SuiviManager.php b/src/Manager/SuiviManager.php
index b04265c3f..e3c5c4b4a 100644
--- a/src/Manager/SuiviManager.php
+++ b/src/Manager/SuiviManager.php
@@ -14,6 +14,8 @@
use App\Service\Sanitizer;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
+use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class SuiviManager extends Manager
@@ -24,6 +26,8 @@ public function __construct(
private readonly SignalementUpdatedListener $signalementUpdatedListener,
private readonly Security $security,
private readonly DesordreCritereRepository $desordreCritereRepository,
+ #[Autowire(service: 'html_sanitizer.sanitizer.app.message_sanitizer')]
+ private readonly HtmlSanitizerInterface $htmlSanitizer,
string $entityName = Suivi::class,
) {
parent::__construct($managerRegistry, $entityName);
@@ -42,7 +46,7 @@ public function createSuivi(
$suivi = (new Suivi())
->setCreatedBy($user)
->setSignalement($signalement)
- ->setDescription($description)
+ ->setDescription($this->htmlSanitizer->sanitize($description))
->setType($type)
->setIsPublic($isPublic)
->setContext($context)
diff --git a/templates/back/notifications/index.html.twig b/templates/back/notifications/index.html.twig
index f917206e1..e65ca2720 100755
--- a/templates/back/notifications/index.html.twig
+++ b/templates/back/notifications/index.html.twig
@@ -69,10 +69,10 @@
{{ notification.suivi.createdAt|format_datetime(locale='fr', timezone=territory_timezone, pattern='d MMMM yyyy à HH:mm:ss') }} |
{{ notification.suivi.description
- |replace({'&t=___TOKEN___':'/'~notification.signalement.uuid})
- |replace({'?t=___TOKEN___':'/'~notification.signalement.uuid})
- |replace({'?folder=_up':'/'~notification.signalement.uuid~'?variant=resize'})
- |sanitize_html('app.message_sanitizer') }}
+ |replace({'&t=___TOKEN___':'/'~notification.signalement.uuid})
+ |replace({'?t=___TOKEN___':'/'~notification.signalement.uuid})
+ |replace({'?folder=_up':'/'~notification.signalement.uuid~'?variant=resize'})
+ |raw }}
|
{{ notification.suivi.createdBy ? notification.suivi.createdBy.nomComplet : notification.signalement.nomOccupant|upper~' '~notification.signalement.prenomOccupant|capitalize }} |
diff --git a/templates/back/signalement/view/suivis.html.twig b/templates/back/signalement/view/suivis.html.twig
index db3622015..005c880bf 100755
--- a/templates/back/signalement/view/suivis.html.twig
+++ b/templates/back/signalement/view/suivis.html.twig
@@ -61,17 +61,11 @@
{% else %}
{% endif %}
- {#{{ dump(suivi.description
- |replace({'&t=___TOKEN___':'/'~signalement.uuid})
- |replace({'?t=___TOKEN___':'/'~signalement.uuid})
- |replace({'?folder=_up':'/'~signalement.uuid~'?variant=resize'})
- |sanitize_html('app.message_sanitizer'))
- }}#}
{{ suivi.description
- |replace({'&t=___TOKEN___':'/'~signalement.uuid})
- |replace({'?t=___TOKEN___':'/'~signalement.uuid})
- |replace({'?folder=_up':'/'~signalement.uuid~'?variant=resize'})
- |sanitize_html('app.message_sanitizer')
+ |replace({'&t=___TOKEN___':'/'~signalement.uuid})
+ |replace({'?t=___TOKEN___':'/'~signalement.uuid})
+ |replace({'?foldert=_up':'/'~signalement.uuid~'?variant=resize'})
+ |raw
}}
diff --git a/templates/front/_partials/_suivi_signalement_tab_suivi.html.twig b/templates/front/_partials/_suivi_signalement_tab_suivi.html.twig
index 3b660782e..ac9858fc0 100755
--- a/templates/front/_partials/_suivi_signalement_tab_suivi.html.twig
+++ b/templates/front/_partials/_suivi_signalement_tab_suivi.html.twig
@@ -24,7 +24,7 @@
- {{ suivi.description|replace({'___TOKEN___':csrf_token('suivi_signalement_ext_file_view')})|sanitize_html('app.message_sanitizer') }}
+ {{ suivi.description|replace({'___TOKEN___':csrf_token('suivi_signalement_ext_file_view')})|raw }}
{% endfor %}
diff --git a/templates/pdf/signalement.html.twig b/templates/pdf/signalement.html.twig
index c8aefe5c1..8dbdfd1d7 100755
--- a/templates/pdf/signalement.html.twig
+++ b/templates/pdf/signalement.html.twig
@@ -625,7 +625,7 @@
{% endif %}
{{ suivi.createdAt|date('d/m/Y') }}
|
- {{ suivi.description|sanitize_html('app.message_sanitizer') }} |
+ {{ suivi.description|raw }} |
{% endfor %}
diff --git a/tests/Functional/Controller/Back/SignalementActionControllerTest.php b/tests/Functional/Controller/Back/SignalementActionControllerTest.php
index f2cd22400..0bdbb4636 100644
--- a/tests/Functional/Controller/Back/SignalementActionControllerTest.php
+++ b/tests/Functional/Controller/Back/SignalementActionControllerTest.php
@@ -124,7 +124,7 @@ public function testDeleteSuivi(): void
$route = $this->router->generate('back_signalement_delete_suivi', ['uuid' => $signalement->getUuid()]);
$this->client->request('GET', $route);
- $description = 'Un petit message de rappel afin d\'y revenir plus tard';
+ $description = 'Un petit message de rappel afin d'y revenir plus tard';
$suivi = $this->suiviRepository->findOneBy(['description' => $description]);
$this->client->request(
diff --git a/tests/Functional/Manager/SuiviManagerTest.php b/tests/Functional/Manager/SuiviManagerTest.php
index 937d79a8c..8d25ca046 100644
--- a/tests/Functional/Manager/SuiviManagerTest.php
+++ b/tests/Functional/Manager/SuiviManagerTest.php
@@ -13,6 +13,7 @@
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Bundle\SecurityBundle\Security;
+use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\User\UserInterface;
@@ -24,6 +25,7 @@ class SuiviManagerTest extends KernelTestCase
private Security $security;
private UrlGeneratorInterface $urlGenerator;
private DesordreCritereRepository $desordreCritereRepository;
+ private HtmlSanitizerInterface $htmlSanitizerInterface;
protected function setUp(): void
{
@@ -33,6 +35,7 @@ protected function setUp(): void
$this->security = static::getContainer()->get(Security::class);
$this->urlGenerator = static::getContainer()->get(UrlGeneratorInterface::class);
$this->desordreCritereRepository = static::getContainer()->get(DesordreCritereRepository::class);
+ $this->htmlSanitizerInterface = static::getContainer()->get(HtmlSanitizerInterface::class);
}
public function testCreateSuivi(): void
@@ -43,6 +46,7 @@ public function testCreateSuivi(): void
$this->signalementUpdatedListener,
$this->security,
$this->desordreCritereRepository,
+ $this->htmlSanitizerInterface,
Suivi::class,
);
@@ -74,9 +78,10 @@ public function testCreateSuivi(): void
$this->assertEquals(Suivi::TYPE_PARTNER, $suivi->getType());
$this->assertNotEquals($countSuivisBeforeCreate, $countSuivisAfterCreate);
$this->assertInstanceOf(Suivi::class, $suivi);
- $desc = 'Le signalement a été cloturé pour test avec le motif suivant
Non décence
Desc. : Lorem ipsum suivi sit amet, consectetur adipiscing elit.';
+ $desc = 'Le signalement a été cloturé pour test avec le motif suivant
Non décence
Desc. : Lorem ipsum suivi sit amet, consectetur adipiscing elit.';
$this->assertEquals($desc, $suivi->getDescription());
$this->assertTrue($suivi->getIsPublic());
+ $this->assertTrue($suivi->getIsSanitized());
$this->assertInstanceOf(UserInterface::class, $suivi->getCreatedBy());
}
}