Améliore les réglages et la documentation

Refs #7 #8 #11 #14 #15 #19
This commit is contained in:
Alexandre NOEL 2026-09-08 00:07:40 +02:00
commit 6bda723f22
14 changed files with 52 additions and 10 deletions

View file

@ -95,3 +95,12 @@ Toutes les modifications importantes du projet sont consignées ici. Le format s
[1.0.0]: https://nnsprod.com/git/oversu/Globinours [1.0.0]: https://nnsprod.com/git/oversu/Globinours
[0.1.0]: https://nnsprod.com/git/oversu/Globinours [0.1.0]: https://nnsprod.com/git/oversu/Globinours
## [1.0.0-rc.9] — 2026-09-08
### Troisième lot de tickets
- ajout de liens publics facultatifs vers WhatsApp, LinkedIn, X et Snapchat, sans ressource chargée depuis un service tiers (`#7`) ;
- clarification de la conservation de l’historique lors de la désactivation d’une salle (`#11`) ;
- distinction explicite entre les frais d’adoption et le catalogue des coûts vétérinaires (`#14`) ;
- rappel du routeur requis par le serveur PHP local pour rendre la recherche universelle disponible (`#19`) ;
- vérification des correctifs déjà livrés pour le lien du pied de page et l’ajout d’espèces aux références biologiques (`#8`, `#15`).

View file

@ -41,3 +41,7 @@ Fiabilisation du géocodage et des formulaires de configuration, amélioration d
## `1.0.0-rc.8` — Deuxième lot de tickets ## `1.0.0-rc.8` — Deuxième lot de tickets
Clarification du diagnostic système et de la santé des sauvegardes, validation des identifiants administratifs et encadrement des longueurs de noms. Clarification du diagnostic système et de la santé des sauvegardes, validation des identifiants administratifs et encadrement des longueurs de noms.
## `1.0.0-rc.9` — Troisième lot de tickets
Extension des liens sociaux du site public, clarification des salles et des tarifs, et documentation du routage nécessaire à la recherche locale.

View file

@ -94,6 +94,8 @@ php -d upload_max_filesize=250M -d post_max_size=260M \
-S 127.0.0.1:8000 -t public public/router.php -S 127.0.0.1:8000 -t public public/router.php
``` ```
Le dernier argument, `public/router.php`, est indispensable : sans lui, les routes telles que la recherche universelle (`/search.json`) renvoient une page introuvable avec le serveur PHP intégré.
Ouvrez ensuite `http://127.0.0.1:8000/setup`. L’assistant vérifie l’environnement, recueille l’identité de l’association et crée le premier compte administrateur. Ouvrez ensuite `http://127.0.0.1:8000/setup`. L’assistant vérifie l’environnement, recueille l’identité de l’association et crée le premier compte administrateur.
Les migrations sont appliquées automatiquement. Elles peuvent aussi être exécutées explicitement : Les migrations sont appliquées automatiquement. Elles peuvent aussi être exécutées explicitement :

View file

@ -1 +1 @@
1.0.0-rc.8 1.0.0-rc.9

View file

@ -825,7 +825,20 @@ final class SettingsController
exit(); exit();
} }
$values['public_site_custom_css'] = $customCss; $values['public_site_custom_css'] = $customCss;
foreach (['public_site_donation_url', 'public_site_facebook_url', 'public_site_instagram_url', 'public_site_youtube_url', 'public_site_tiktok_url'] as $key) { foreach (
[
'public_site_donation_url',
'public_site_facebook_url',
'public_site_instagram_url',
'public_site_youtube_url',
'public_site_tiktok_url',
'public_site_whatsapp_url',
'public_site_linkedin_url',
'public_site_x_url',
'public_site_snapchat_url',
]
as $key
) {
$url = trim((string) ($_POST[$key] ?? '')); $url = trim((string) ($_POST[$key] ?? ''));
$scheme = strtolower((string) parse_url($url, PHP_URL_SCHEME)); $scheme = strtolower((string) parse_url($url, PHP_URL_SCHEME));
if ($url !== '' && (!filter_var($url, FILTER_VALIDATE_URL) || $scheme !== 'https')) { if ($url !== '' && (!filter_var($url, FILTER_VALIDATE_URL) || $scheme !== 'https')) {

View file

@ -39,6 +39,10 @@ final class AppSettings
'public_site_instagram_url' => '', 'public_site_instagram_url' => '',
'public_site_youtube_url' => '', 'public_site_youtube_url' => '',
'public_site_tiktok_url' => '', 'public_site_tiktok_url' => '',
'public_site_whatsapp_url' => '',
'public_site_linkedin_url' => '',
'public_site_x_url' => '',
'public_site_snapchat_url' => '',
'notification_email_enabled' => '0', 'notification_email_enabled' => '0',
'notification_email_frequency' => 'weekly', 'notification_email_frequency' => 'weekly',
'notification_email_recipient' => '', 'notification_email_recipient' => '',

View file

@ -31,10 +31,10 @@
<div class="col-lg-6"> <div class="col-lg-6">
<section class="card h-100"> <section class="card h-100">
<div class="card-body"> <div class="card-body">
<span class="badge bg-blue-lt mb-2">1.0.0-rc.8</span> <span class="badge bg-blue-lt mb-2">1.0.0-rc.9</span>
<h3>Deuxième lot de tickets</h3> <h3>Troisième lot de tickets</h3>
<p class="text-muted">Diagnostic système clarifié, identifiants administratifs contrôlés et <p class="text-muted">Site public enrichi, salles et tarifs clarifiés, et lancement local de la
longueurs des principaux noms encadrées.</p> recherche mieux documenté.</p>
</div> </div>
</section> </section>
</div> </div>

View file

@ -14,7 +14,7 @@ $obfuscate = static fn (string$value): string => implode('', array_reverse(mb_st
class="contact-obfuscated"><?= h($obfuscate($settings['association_email'])) ?></span></div> class="contact-obfuscated"><?= h($obfuscate($settings['association_email'])) ?></span></div>
<?php endif; ?></div> <?php endif; ?></div>
<div class="chips" style="margin-top:25px"> <div class="chips" style="margin-top:25px">
<?php foreach (['facebook' => 'Facebook','instagram' => 'Instagram','youtube' => 'YouTube','tiktok' => 'TikTok'] as $network => $label): <?php foreach (['facebook' => 'Facebook','instagram' => 'Instagram','youtube' => 'YouTube','tiktok' => 'TikTok','whatsapp' => 'WhatsApp','linkedin' => 'LinkedIn','x' => 'X','snapchat' => 'Snapchat'] as $network => $label):
$url = trim((string)($settings['public_site_' . $network . '_url'] ?? '')); $url = trim((string)($settings['public_site_' . $network . '_url'] ?? ''));
if ($url === '') continue; ?> if ($url === '') continue; ?>
<a class="button secondary" href="<?= h($url) ?>" rel="noopener noreferrer"><?= h($label) ?></a> <a class="button secondary" href="<?= h($url) ?>" rel="noopener noreferrer"><?= h($label) ?></a>

View file

@ -10,7 +10,10 @@
<form class="card h-100" method="post" action="/settings/pricing/adoption"> <form class="card h-100" method="post" action="/settings/pricing/adoption">
<div class="card-status-top bg-green"></div> <div class="card-status-top bg-green"></div>
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><?= h(t('pricing.adoption_fees')) ?></h3> <div>
<h3 class="card-title"><?= h(t('pricing.adoption_fees')) ?></h3>
<div class="text-muted small"><?= h(t('pricing.adoption_fees_help')) ?></div>
</div>
</div> </div>
<div class="card-body row g-3"> <div class="card-body row g-3">
<div class="col-6"><label class="form-label"><?= h(t('pricing.sterilized')) ?></label> <div class="col-6"><label class="form-label"><?= h(t('pricing.sterilized')) ?></label>

View file

@ -137,7 +137,7 @@
name="public_site_facebook_url" value="<?= h($settings['public_site_facebook_url']) ?>"></div> name="public_site_facebook_url" value="<?= h($settings['public_site_facebook_url']) ?>"></div>
<div class="col-md-6"><label class="form-label">Instagram</label><input class="form-control" type="url" <div class="col-md-6"><label class="form-label">Instagram</label><input class="form-control" type="url"
name="public_site_instagram_url" value="<?= h($settings['public_site_instagram_url']) ?>"></div> name="public_site_instagram_url" value="<?= h($settings['public_site_instagram_url']) ?>"></div>
<?php foreach (['youtube' => 'YouTube','tiktok' => 'TikTok'] as $network => $label): ?> <?php foreach (['youtube' => 'YouTube','tiktok' => 'TikTok','whatsapp' => 'WhatsApp','linkedin' => 'LinkedIn','x' => 'X','snapchat' => 'Snapchat'] as $network => $label): ?>
<div class="col-md-6"><label class="form-label"><?= h($label) ?></label><input class="form-control" <div class="col-md-6"><label class="form-label"><?= h($label) ?></label><input class="form-control"
type="url" name="public_site_<?= h($network) ?>_url" type="url" name="public_site_<?= h($network) ?>_url"
value="<?= h($settings['public_site_' . $network . '_url']) ?>" placeholder="https://..."></div> value="<?= h($settings['public_site_' . $network . '_url']) ?>" placeholder="https://..."></div>

View file

@ -2,7 +2,7 @@
<?php if ($saved): ?><div class="alert alert-success"><?= h(t('rooms.saved')) ?></div><?php endif; ?> <?php if ($saved): ?><div class="alert alert-success"><?= h(t('rooms.saved')) ?></div><?php endif; ?>
<?php if ($error): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?> <?php if ($error): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
<form method="post" action="/settings/rooms/save"><input type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>"> <form method="post" action="/settings/rooms/save"><input type="hidden" name="csrf" value="<?= h(Auth::csrf()) ?>">
<div class="alert alert-info"><?= h(t('rooms.help')) ?></div> <div class="alert alert-info"><?= h(t('rooms.inactive_help')) ?></div>
<div class="row row-cards"> <div class="row row-cards">
<?php foreach ($rooms as $room):$boxNames = implode("\n", array_column(array_filter($room['boxes'], static fn ($box) => (int)$box['active'] === 1), 'name')); ?> <?php foreach ($rooms as $room):$boxNames = implode("\n", array_column(array_filter($room['boxes'], static fn ($box) => (int)$box['active'] === 1), 'name')); ?>
<div class="col-lg-6"> <div class="col-lg-6">

View file

@ -0,0 +1,5 @@
INSERT OR IGNORE INTO app_settings(setting_key, setting_value) VALUES
('public_site_whatsapp_url', ''),
('public_site_linkedin_url', ''),
('public_site_x_url', ''),
('public_site_snapchat_url', '');

View file

@ -123,4 +123,5 @@ return [
'public_site.image_library'=>'Image library','public_site.image_file'=>'Image to add','public_site.image_upload'=>'Upload image','public_site.image_help'=>'Upload an image, place the cursor in a text field, then choose “Insert”. Accepted formats: JPEG, PNG and WebP.','public_site.image_none'=>'No image uploaded.','public_site.image_insert'=>'Insert','public_site.image_invalid'=>'Choose a valid image.', 'public_site.image_library'=>'Image library','public_site.image_file'=>'Image to add','public_site.image_upload'=>'Upload image','public_site.image_help'=>'Upload an image, place the cursor in a text field, then choose “Insert”. Accepted formats: JPEG, PNG and WebP.','public_site.image_none'=>'No image uploaded.','public_site.image_insert'=>'Insert','public_site.image_invalid'=>'Choose a valid image.',
'rooms.duplicate'=>'A room with this name or code already exists.','settings.species_duplicate'=>'A species with this name or code already exists.', 'rooms.duplicate'=>'A room with this name or code already exists.','settings.species_duplicate'=>'A species with this name or code already exists.',
'settings.invalid_rna'=>'The RNA number must start with W followed by 9 digits.','settings.invalid_siret'=>'The SIRET number must contain 14 digits and be valid.','rooms.name_too_long'=>'A room name cannot exceed 100 characters.','rooms.box_name_too_long'=>'A box name cannot exceed 100 characters.','animal.name_too_long'=>'An animal name cannot exceed 150 characters.', 'settings.invalid_rna'=>'The RNA number must start with W followed by 9 digits.','settings.invalid_siret'=>'The SIRET number must contain 14 digits and be valid.','rooms.name_too_long'=>'A room name cannot exceed 100 characters.','rooms.box_name_too_long'=>'A box name cannot exceed 100 characters.','animal.name_too_long'=>'An animal name cannot exceed 150 characters.',
'pricing.adoption_fees_help'=>'Indicative amounts shared by all animals, according to their sterilisation status.','rooms.inactive_help'=>'An unchecked room becomes inactive, while its previous assignments remain in the history. Its internal code never changes.',
]; ];

View file

@ -123,4 +123,5 @@ return [
'public_site.image_library'=>'Bibliothèque d’images','public_site.image_file'=>'Image à ajouter','public_site.image_upload'=>'Ajouter l’image','public_site.image_help'=>'Ajoutez une image, placez le curseur dans un texte puis choisissez « Insérer ». Formats acceptés : JPEG, PNG et WebP.','public_site.image_none'=>'Aucune image ajoutée.','public_site.image_insert'=>'Insérer','public_site.image_invalid'=>'Choisissez une image valide.', 'public_site.image_library'=>'Bibliothèque d’images','public_site.image_file'=>'Image à ajouter','public_site.image_upload'=>'Ajouter l’image','public_site.image_help'=>'Ajoutez une image, placez le curseur dans un texte puis choisissez « Insérer ». Formats acceptés : JPEG, PNG et WebP.','public_site.image_none'=>'Aucune image ajoutée.','public_site.image_insert'=>'Insérer','public_site.image_invalid'=>'Choisissez une image valide.',
'rooms.duplicate'=>'Une salle portant ce nom ou ce code existe déjà.','settings.species_duplicate'=>'Une espèce portant ce nom ou ce code existe déjà.', 'rooms.duplicate'=>'Une salle portant ce nom ou ce code existe déjà.','settings.species_duplicate'=>'Une espèce portant ce nom ou ce code existe déjà.',
'settings.invalid_rna'=>'Le numéro RNA doit commencer par W et être suivi de 9 chiffres.','settings.invalid_siret'=>'Le numéro SIRET doit contenir 14 chiffres et être valide.','rooms.name_too_long'=>'Le nom d’une salle ne peut pas dépasser 100 caractères.','rooms.box_name_too_long'=>'Le nom d’un box ne peut pas dépasser 100 caractères.','animal.name_too_long'=>'Le nom d’un animal ne peut pas dépasser 150 caractères.', 'settings.invalid_rna'=>'Le numéro RNA doit commencer par W et être suivi de 9 chiffres.','settings.invalid_siret'=>'Le numéro SIRET doit contenir 14 chiffres et être valide.','rooms.name_too_long'=>'Le nom d’une salle ne peut pas dépasser 100 caractères.','rooms.box_name_too_long'=>'Le nom d’un box ne peut pas dépasser 100 caractères.','animal.name_too_long'=>'Le nom d’un animal ne peut pas dépasser 150 caractères.',
'pricing.adoption_fees_help'=>'Montants indicatifs communs à tous les animaux, selon leur état de stérilisation.','rooms.inactive_help'=>'Une salle décochée devient inactive, mais ses anciennes affectations restent dans l’historique. Son code interne ne change jamais.',
]; ];