Add SEO, sitemap, robots, search, Meilisearch and security files
- JSON-LD: Organization, WebSite with SearchAction, BreadcrumbList - SitemapController: sitemapindex with main + paginated events (images/videos) - RobotsController: dynamic robots.txt with sitemap URL - SearchController: /search with Meilisearch (TODO) - Meilisearch added to dev and prod docker-compose - Breadcrumbs added to all controllers - .well-known: security.txt, humans.txt, dnt-policy.txt - PGP public key in public/key.asc - SecurityController: /mot-de-passe + .well-known/change-password route Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,6 +138,17 @@ services:
|
|||||||
- ngrok
|
- ngrok
|
||||||
entrypoint: sh /sync.sh
|
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:
|
redisinsight:
|
||||||
image: redis/redisinsight:latest
|
image: redis/redisinsight:latest
|
||||||
container_name: e_ticket_redisinsight
|
container_name: e_ticket_redisinsight
|
||||||
@@ -153,3 +164,4 @@ volumes:
|
|||||||
bun-modules:
|
bun-modules:
|
||||||
vault-data:
|
vault-data:
|
||||||
minio-data:
|
minio-data:
|
||||||
|
meilisearch-data:
|
||||||
|
|||||||
@@ -106,7 +106,18 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
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:
|
volumes:
|
||||||
db-master-data:
|
db-master-data:
|
||||||
db-slave-data:
|
db-slave-data:
|
||||||
redis-data:
|
redis-data:
|
||||||
|
meilisearch-data:
|
||||||
|
|||||||
51
key.asc
Normal file
51
key.asc
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=5F8Q
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
1
public/.well-known/dnt-policy.txt
Normal file
1
public/.well-known/dnt-policy.txt
Normal file
@@ -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"}
|
||||||
12
public/.well-known/humans.txt
Normal file
12
public/.well-known/humans.txt
Normal file
@@ -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
|
||||||
6
public/.well-known/security.txt
Normal file
6
public/.well-known/security.txt
Normal file
@@ -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
|
||||||
51
public/key.asc
Normal file
51
public/key.asc
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=5F8Q
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
@@ -11,6 +11,10 @@ class HomeController extends AbstractController
|
|||||||
#[Route('/', name: 'app_home')]
|
#[Route('/', name: 'app_home')]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
return $this->render('home/index.html.twig');
|
return $this->render('home/index.html.twig', [
|
||||||
|
'breadcrumbs' => [
|
||||||
|
['name' => 'Accueil', 'url' => '/'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ class RedirectController extends AbstractController
|
|||||||
return $this->redirectToRoute('app_home');
|
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'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/Controller/RobotsController.php
Normal file
38
src/Controller/RobotsController.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
|
class RobotsController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/robots.txt', name: 'app_robots', methods: ['GET'])]
|
||||||
|
public function index(UrlGeneratorInterface $urlGenerator): Response
|
||||||
|
{
|
||||||
|
$sitemapUrl = $urlGenerator->generate('app_sitemap', [], UrlGeneratorInterface::ABSOLUTE_URL);
|
||||||
|
|
||||||
|
$content = <<<TXT
|
||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
Disallow: /external-redirect
|
||||||
|
Disallow: /my-csp-report
|
||||||
|
Disallow: /track/
|
||||||
|
Disallow: /mentions-legales
|
||||||
|
Disallow: /cgu
|
||||||
|
Disallow: /cgv
|
||||||
|
Disallow: /hebergement
|
||||||
|
Disallow: /cookies
|
||||||
|
Disallow: /rgpd
|
||||||
|
Disallow: /unsubscribe/
|
||||||
|
|
||||||
|
Sitemap: {$sitemapUrl}
|
||||||
|
TXT;
|
||||||
|
|
||||||
|
return new Response($content, 200, [
|
||||||
|
'Content-Type' => 'text/plain',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Controller/SearchController.php
Normal file
26
src/Controller/SearchController.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
class SearchController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/search', name: 'app_search', methods: ['GET'])]
|
||||||
|
public function index(Request $request): Response
|
||||||
|
{
|
||||||
|
$query = $request->query->get('q', '');
|
||||||
|
|
||||||
|
return $this->render('search/index.html.twig', [
|
||||||
|
'query' => $query,
|
||||||
|
'results' => [],
|
||||||
|
'breadcrumbs' => [
|
||||||
|
['name' => 'Accueil', 'url' => '/'],
|
||||||
|
['name' => 'Recherche', 'url' => '/search'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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')]
|
#[Route('/deconnexion', name: 'app_logout')]
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
|
|||||||
75
src/Controller/SitemapController.php
Normal file
75
src/Controller/SitemapController.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
|
class SitemapController extends AbstractController
|
||||||
|
{
|
||||||
|
private const MAX_URLS_PER_SITEMAP = 50000;
|
||||||
|
|
||||||
|
#[Route('/sitemap.xml', name: 'app_sitemap', methods: ['GET'])]
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
// TODO: count events to determine number of event sitemap pages
|
||||||
|
$eventPages = 1;
|
||||||
|
|
||||||
|
$sitemaps = [
|
||||||
|
['loc' => $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'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,12 +23,20 @@ class UnsubscribeController extends AbstractController
|
|||||||
|
|
||||||
return $this->render('unsubscribe/confirmed.html.twig', [
|
return $this->render('unsubscribe/confirmed.html.twig', [
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
|
'breadcrumbs' => [
|
||||||
|
['name' => 'Accueil', 'url' => '/'],
|
||||||
|
['name' => 'Desinscription', 'url' => '/unsubscribe/' . $token],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('unsubscribe/index.html.twig', [
|
return $this->render('unsubscribe/index.html.twig', [
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'token' => $token,
|
'token' => $token,
|
||||||
|
'breadcrumbs' => [
|
||||||
|
['name' => 'Accueil', 'url' => '/'],
|
||||||
|
['name' => 'Desinscription', 'url' => '/unsubscribe/' . $token],
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,65 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
{% block meta %}
|
||||||
|
<meta name="description" content="{% block description %}E-Ticket - Plateforme de vente de tickets evenementiels pour associations{% endblock %}">
|
||||||
|
{% endblock %}
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "E-Ticket",
|
||||||
|
"url": "https://ticket.e-cosplay.fr",
|
||||||
|
"logo": "https://ticket.e-cosplay.fr/logo.png",
|
||||||
|
"email": "contact@e-cosplay.fr",
|
||||||
|
"telephone": "+33679348802",
|
||||||
|
"address": {
|
||||||
|
"@type": "PostalAddress",
|
||||||
|
"streetAddress": "42 rue de Saint-Quentin",
|
||||||
|
"addressLocality": "Beautor",
|
||||||
|
"postalCode": "02800",
|
||||||
|
"addressCountry": "FR"
|
||||||
|
},
|
||||||
|
"sameAs": [
|
||||||
|
"https://www.facebook.com/assocationecosplay",
|
||||||
|
"https://www.e-cosplay.fr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "E-Ticket",
|
||||||
|
"url": "https://ticket.e-cosplay.fr",
|
||||||
|
"potentialAction": {
|
||||||
|
"@type": "SearchAction",
|
||||||
|
"target": {
|
||||||
|
"@type": "EntryPoint",
|
||||||
|
"urlTemplate": "https://ticket.e-cosplay.fr/search?q={search_term_string}"
|
||||||
|
},
|
||||||
|
"query-input": "required name=search_term_string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% if breadcrumbs is defined and breadcrumbs is not empty %}
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{% for breadcrumb in breadcrumbs %}
|
||||||
|
{
|
||||||
|
"@type": "ListItem",
|
||||||
|
"position": {{ loop.index }},
|
||||||
|
"name": "{{ breadcrumb.name }}",
|
||||||
|
"item": "{{ breadcrumb.url }}"
|
||||||
|
}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
{% block stylesheets %}{% endblock %}
|
{% block stylesheets %}{% endblock %}
|
||||||
{% block javascripts %}
|
{% block javascripts %}
|
||||||
{{ vite_asset('app.js') }}
|
{{ vite_asset('app.js') }}
|
||||||
|
|||||||
7
templates/search/index.html.twig
Normal file
7
templates/search/index.html.twig
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Recherche - E-Ticket{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
8
templates/sitemap/index.xml.twig
Normal file
8
templates/sitemap/index.xml.twig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
{% for sitemap in sitemaps %}
|
||||||
|
<sitemap>
|
||||||
|
<loc>{{ sitemap.loc }}</loc>
|
||||||
|
</sitemap>
|
||||||
|
{% endfor %}
|
||||||
|
</sitemapindex>
|
||||||
34
templates/sitemap/urlset.xml.twig
Normal file
34
templates/sitemap/urlset.xml.twig
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
||||||
|
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
|
||||||
|
{% for url in urls %}
|
||||||
|
<url>
|
||||||
|
<loc>{{ url.loc }}</loc>
|
||||||
|
{% if url.changefreq is defined %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
|
||||||
|
{% if url.priority is defined %}<priority>{{ url.priority }}</priority>{% endif %}
|
||||||
|
{% if url.lastmod is defined %}<lastmod>{{ url.lastmod }}</lastmod>{% endif %}
|
||||||
|
{% if url.images is defined %}
|
||||||
|
{% for image in url.images %}
|
||||||
|
<image:image>
|
||||||
|
<image:loc>{{ image.loc }}</image:loc>
|
||||||
|
{% if image.title is defined %}<image:title>{{ image.title }}</image:title>{% endif %}
|
||||||
|
{% if image.caption is defined %}<image:caption>{{ image.caption }}</image:caption>{% endif %}
|
||||||
|
</image:image>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if url.videos is defined %}
|
||||||
|
{% for video in url.videos %}
|
||||||
|
<video:video>
|
||||||
|
<video:thumbnail_loc>{{ video.thumbnail }}</video:thumbnail_loc>
|
||||||
|
<video:title>{{ video.title }}</video:title>
|
||||||
|
<video:description>{{ video.description }}</video:description>
|
||||||
|
{% if video.content_loc is defined %}<video:content_loc>{{ video.content_loc }}</video:content_loc>{% endif %}
|
||||||
|
{% if video.player_loc is defined %}<video:player_loc>{{ video.player_loc }}</video:player_loc>{% endif %}
|
||||||
|
{% if video.duration is defined %}<video:duration>{{ video.duration }}</video:duration>{% endif %}
|
||||||
|
</video:video>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</url>
|
||||||
|
{% endfor %}
|
||||||
|
</urlset>
|
||||||
Reference in New Issue
Block a user