diff --git a/migrations/Version20260829130000.php b/migrations/Version20260829130000.php new file mode 100644 index 0000000..8890f31 --- /dev/null +++ b/migrations/Version20260829130000.php @@ -0,0 +1,26 @@ +addSql('ALTER TABLE contact_message ADD read_at DATETIME DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE contact_message DROP read_at'); + } +} diff --git a/migrations/Version20260829140000.php b/migrations/Version20260829140000.php new file mode 100644 index 0000000..077ea19 --- /dev/null +++ b/migrations/Version20260829140000.php @@ -0,0 +1,26 @@ +addSql('ALTER TABLE contact_message ADD deleted_at DATETIME DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE contact_message DROP deleted_at'); + } +} diff --git a/src/Game/Controller/GameAdminContactController.php b/src/Game/Controller/GameAdminContactController.php index 69b7252..c7cce47 100644 --- a/src/Game/Controller/GameAdminContactController.php +++ b/src/Game/Controller/GameAdminContactController.php @@ -4,8 +4,11 @@ declare(strict_types=1); namespace App\Game\Controller; +use App\Website\Entity\ContactMessage; use App\Website\Repository\ContactMessageRepository; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; @@ -18,7 +21,38 @@ final class GameAdminContactController extends AbstractController public function index(ContactMessageRepository $contactMessageRepository): Response { return $this->render('game/admin/contact/index.html.twig', [ - 'messages' => $contactMessageRepository->findBy([], ['createdAt' => 'DESC']), + 'messages' => $contactMessageRepository->findActive(), ]); } + + #[Route('/{id}', name: 'game_admin_contact_show', methods: ['GET'])] + public function show(ContactMessage $contactMessage, EntityManagerInterface $entityManager): Response + { + if (!$contactMessage->isRead()) { + $contactMessage->setReadAt(new \DateTimeImmutable()); + $entityManager->flush(); + } + + return $this->render('game/admin/contact/show.html.twig', [ + 'message' => $contactMessage, + ]); + } + + #[Route('/{id}/delete', name: 'game_admin_contact_delete', methods: ['POST'])] + public function delete(ContactMessage $contactMessage, Request $request, EntityManagerInterface $entityManager): Response + { + if (!$this->isCsrfTokenValid('delete_contact_' . $contactMessage->getId(), $request->request->get('_token'))) { + $this->addFlash('danger', 'Invalid CSRF token.'); + return $this->redirectToRoute('game_admin_contact'); + } + + if (!$contactMessage->isDeleted()) { + $contactMessage->setDeletedAt(new \DateTimeImmutable()); + $entityManager->flush(); + } + + $this->addFlash('success', sprintf('Message from "%s" deleted.', $contactMessage->getName())); + + return $this->redirectToRoute('game_admin_contact'); + } } diff --git a/src/Website/Entity/ContactMessage.php b/src/Website/Entity/ContactMessage.php index 1aca114..1292e3f 100644 --- a/src/Website/Entity/ContactMessage.php +++ b/src/Website/Entity/ContactMessage.php @@ -27,6 +27,12 @@ class ContactMessage #[ORM\Column(type: Types::DATETIME_IMMUTABLE)] private ?\DateTimeImmutable $createdAt = null; + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + private ?\DateTimeImmutable $readAt = null; + + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + private ?\DateTimeImmutable $deletedAt = null; + public function __construct() { $this->createdAt = new \DateTimeImmutable(); @@ -84,4 +90,38 @@ class ContactMessage return $this; } + + public function getReadAt(): ?\DateTimeImmutable + { + return $this->readAt; + } + + public function setReadAt(?\DateTimeImmutable $readAt): static + { + $this->readAt = $readAt; + + return $this; + } + + public function isRead(): bool + { + return $this->readAt !== null; + } + + public function getDeletedAt(): ?\DateTimeImmutable + { + return $this->deletedAt; + } + + public function setDeletedAt(?\DateTimeImmutable $deletedAt): static + { + $this->deletedAt = $deletedAt; + + return $this; + } + + public function isDeleted(): bool + { + return $this->deletedAt !== null; + } } diff --git a/src/Website/Repository/ContactMessageRepository.php b/src/Website/Repository/ContactMessageRepository.php index 2634367..f4dbe4e 100644 --- a/src/Website/Repository/ContactMessageRepository.php +++ b/src/Website/Repository/ContactMessageRepository.php @@ -15,4 +15,12 @@ class ContactMessageRepository extends ServiceEntityRepository { parent::__construct($registry, ContactMessage::class); } + + /** + * @return ContactMessage[] + */ + public function findActive(): array + { + return $this->findBy(['deletedAt' => null], ['createdAt' => 'DESC']); + } } diff --git a/templates/game/admin/contact/index.html.twig b/templates/game/admin/contact/index.html.twig index 504dd69..9b694eb 100644 --- a/templates/game/admin/contact/index.html.twig +++ b/templates/game/admin/contact/index.html.twig @@ -15,7 +15,8 @@