diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index dd85cd2..714f374 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -138,6 +138,17 @@ services: - ngrok entrypoint: sh /sync.sh + meilisearch: + image: getmeili/meilisearch:latest + container_name: e_ticket_meilisearch + environment: + MEILI_MASTER_KEY: e_ticket + MEILI_ENV: development + ports: + - "7700:7700" + volumes: + - meilisearch-data:/meili_data + redisinsight: image: redis/redisinsight:latest container_name: e_ticket_redisinsight @@ -153,3 +164,4 @@ volumes: bun-modules: vault-data: minio-data: + meilisearch-data: diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index 1816d79..30358a0 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -106,7 +106,18 @@ services: timeout: 5s retries: 5 + meilisearch: + image: getmeili/meilisearch:latest + restart: unless-stopped + environment: + MEILI_MASTER_KEY: e-ticket + MEILI_ENV: production + MEILI_NO_ANALYTICS: true + volumes: + - meilisearch-data:/meili_data + volumes: db-master-data: db-slave-data: redis-data: + meilisearch-data: diff --git a/key.asc b/key.asc new file mode 100644 index 0000000..25e23f3 --- /dev/null +++ b/key.asc @@ -0,0 +1,51 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=5F8Q +-----END PGP PUBLIC KEY BLOCK----- diff --git a/public/.well-known/dnt-policy.txt b/public/.well-known/dnt-policy.txt new file mode 100644 index 0000000..01d7703 --- /dev/null +++ b/public/.well-known/dnt-policy.txt @@ -0,0 +1 @@ +{"tracking": "N", "qualifiers": "adc", "controller": ["E-Cosplay", "contact@e-cosplay.fr"], "same-party": ["e-cosplay.fr", "ticket.e-cosplay.fr"], "policy": "https://ticket.e-cosplay.fr/rgpd"} diff --git a/public/.well-known/humans.txt b/public/.well-known/humans.txt new file mode 100644 index 0000000..0584028 --- /dev/null +++ b/public/.well-known/humans.txt @@ -0,0 +1,12 @@ +/* TEAM */ +Name: E-Cosplay +Contact: contact@e-cosplay.fr +Site: https://www.e-cosplay.fr +Location: Beautor, France + +/* SITE */ +Project: E-Ticket +Language: French +Standards: HTML5, CSS3, JavaScript +Components: Symfony 8, PHP 8.4, PostgreSQL, Redis, Tailwind CSS +Software: Caddy, Docker, Ansible, Meilisearch diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt new file mode 100644 index 0000000..fd820bf --- /dev/null +++ b/public/.well-known/security.txt @@ -0,0 +1,6 @@ +Contact: mailto:contact@e-cosplay.fr +Expires: 2027-03-18T00:00:00.000Z +Preferred-Languages: fr, en +Canonical: https://ticket.e-cosplay.fr/.well-known/security.txt +Policy: https://ticket.e-cosplay.fr/mentions-legales +Encryption: https://ticket.e-cosplay.fr/key.asc diff --git a/public/key.asc b/public/key.asc new file mode 100644 index 0000000..25e23f3 --- /dev/null +++ b/public/key.asc @@ -0,0 +1,51 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=5F8Q +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index 8250abe..86d376b 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -11,6 +11,10 @@ class HomeController extends AbstractController #[Route('/', name: 'app_home')] public function index(): Response { - return $this->render('home/index.html.twig'); + return $this->render('home/index.html.twig', [ + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ], + ]); } } diff --git a/src/Controller/RedirectController.php b/src/Controller/RedirectController.php index d65d029..63fea16 100644 --- a/src/Controller/RedirectController.php +++ b/src/Controller/RedirectController.php @@ -18,6 +18,12 @@ class RedirectController extends AbstractController return $this->redirectToRoute('app_home'); } - return $this->render('pages/external_redirect.twig'); + return $this->render('pages/external_redirect.twig', [ + 'url' => $url, + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ['name' => 'Redirection externe', 'url' => '/external-redirect'], + ], + ]); } } diff --git a/src/Controller/RobotsController.php b/src/Controller/RobotsController.php new file mode 100644 index 0000000..1ab222f --- /dev/null +++ b/src/Controller/RobotsController.php @@ -0,0 +1,38 @@ +generate('app_sitemap', [], UrlGeneratorInterface::ABSOLUTE_URL); + + $content = << 'text/plain', + ]); + } +} diff --git a/src/Controller/SearchController.php b/src/Controller/SearchController.php new file mode 100644 index 0000000..2da4f71 --- /dev/null +++ b/src/Controller/SearchController.php @@ -0,0 +1,26 @@ +query->get('q', ''); + + return $this->render('search/index.html.twig', [ + 'query' => $query, + 'results' => [], + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ['name' => 'Recherche', 'url' => '/search'], + ], + ]); + } +} diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 40840b7..fdb5ab2 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -22,6 +22,20 @@ class SecurityController extends AbstractController ]); } + #[Route('/mot-de-passe', name: 'app_change_password')] + #[Route('/.well-known/change-password')] + public function changePassword(): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + return $this->render('security/change_password.html.twig', [ + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ['name' => 'Modifier mon mot de passe', 'url' => '/mot-de-passe'], + ], + ]); + } + #[Route('/deconnexion', name: 'app_logout')] public function logout(): void { diff --git a/src/Controller/SitemapController.php b/src/Controller/SitemapController.php new file mode 100644 index 0000000..ddbeaea --- /dev/null +++ b/src/Controller/SitemapController.php @@ -0,0 +1,75 @@ + $this->generateUrl('app_sitemap_main', [], UrlGeneratorInterface::ABSOLUTE_URL)], + ]; + + for ($i = 1; $i <= $eventPages; $i++) { + $sitemaps[] = [ + 'loc' => $this->generateUrl('app_sitemap_events', ['page' => $i], UrlGeneratorInterface::ABSOLUTE_URL), + ]; + } + + return new Response( + $this->renderView('sitemap/index.xml.twig', ['sitemaps' => $sitemaps]), + 200, + ['Content-Type' => 'text/xml'], + ); + } + + #[Route('/sitemap-main.xml', name: 'app_sitemap_main', methods: ['GET'])] + public function main(): Response + { + $urls = [ + [ + 'loc' => $this->generateUrl('app_home', [], UrlGeneratorInterface::ABSOLUTE_URL), + 'changefreq' => 'daily', + 'priority' => '1.0', + ], + [ + 'loc' => $this->generateUrl('app_search', [], UrlGeneratorInterface::ABSOLUTE_URL), + 'changefreq' => 'weekly', + 'priority' => '0.5', + ], + ]; + + return new Response( + $this->renderView('sitemap/urlset.xml.twig', ['urls' => $urls]), + 200, + ['Content-Type' => 'text/xml'], + ); + } + + #[Route('/sitemap-events-{page}.xml', name: 'app_sitemap_events', requirements: ['page' => '\d+'], methods: ['GET'])] + public function events(int $page = 1): Response + { + $offset = ($page - 1) * self::MAX_URLS_PER_SITEMAP; + + // TODO: fetch events from DB with limit/offset + // $events = $eventRepository->findBy([], ['id' => 'ASC'], self::MAX_URLS_PER_SITEMAP, $offset); + $urls = []; + + return new Response( + $this->renderView('sitemap/urlset.xml.twig', ['urls' => $urls]), + 200, + ['Content-Type' => 'text/xml'], + ); + } +} diff --git a/src/Controller/UnsubscribeController.php b/src/Controller/UnsubscribeController.php index 34bf179..47ff83e 100644 --- a/src/Controller/UnsubscribeController.php +++ b/src/Controller/UnsubscribeController.php @@ -23,12 +23,20 @@ class UnsubscribeController extends AbstractController return $this->render('unsubscribe/confirmed.html.twig', [ 'email' => $email, + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ['name' => 'Desinscription', 'url' => '/unsubscribe/' . $token], + ], ]); } return $this->render('unsubscribe/index.html.twig', [ 'email' => $email, 'token' => $token, + 'breadcrumbs' => [ + ['name' => 'Accueil', 'url' => '/'], + ['name' => 'Desinscription', 'url' => '/unsubscribe/' . $token], + ], ]); } } diff --git a/templates/base.html.twig b/templates/base.html.twig index 40c736b..c37c4f3 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -4,6 +4,65 @@ {% block title %}{% endblock %} + {% block meta %} + + {% endblock %} + + + {% if breadcrumbs is defined and breadcrumbs is not empty %} + + {% endif %} {% block stylesheets %}{% endblock %} {% block javascripts %} {{ vite_asset('app.js') }} diff --git a/templates/search/index.html.twig b/templates/search/index.html.twig new file mode 100644 index 0000000..05e3b27 --- /dev/null +++ b/templates/search/index.html.twig @@ -0,0 +1,7 @@ +{% extends 'base.html.twig' %} + +{% block title %}Recherche - E-Ticket{% endblock %} + +{% block body %} + +{% endblock %} diff --git a/templates/sitemap/index.xml.twig b/templates/sitemap/index.xml.twig new file mode 100644 index 0000000..8ae467d --- /dev/null +++ b/templates/sitemap/index.xml.twig @@ -0,0 +1,8 @@ + + + {% for sitemap in sitemaps %} + + {{ sitemap.loc }} + + {% endfor %} + diff --git a/templates/sitemap/urlset.xml.twig b/templates/sitemap/urlset.xml.twig new file mode 100644 index 0000000..057530a --- /dev/null +++ b/templates/sitemap/urlset.xml.twig @@ -0,0 +1,34 @@ + + + {% for url in urls %} + + {{ url.loc }} + {% if url.changefreq is defined %}{{ url.changefreq }}{% endif %} + {% if url.priority is defined %}{{ url.priority }}{% endif %} + {% if url.lastmod is defined %}{{ url.lastmod }}{% endif %} + {% if url.images is defined %} + {% for image in url.images %} + + {{ image.loc }} + {% if image.title is defined %}{{ image.title }}{% endif %} + {% if image.caption is defined %}{{ image.caption }}{% endif %} + + {% endfor %} + {% endif %} + {% if url.videos is defined %} + {% for video in url.videos %} + + {{ video.thumbnail }} + {{ video.title }} + {{ video.description }} + {% if video.content_loc is defined %}{{ video.content_loc }}{% endif %} + {% if video.player_loc is defined %}{{ video.player_loc }}{% endif %} + {% if video.duration is defined %}{{ video.duration }}{% endif %} + + {% endfor %} + {% endif %} + + {% endfor %} +