Étape 21 : formulaire public d'inscription des bénévoles

Retire « constructeur de formulaire » des exclusions du CLAUDE.md (§ 5) —
décision explicite prise en conversation.

Un formulaire par édition (COORDINATION choisit les champs actifs parmi
neuf : email, téléphone, vœux de poste — max 2, vœux d'artiste — un par
soir de festival, vœu de compagnon en texte libre, disponibilité/
cotisation déclaratives, photo, commentaire ; nom/prénom toujours
collectés) ouvert/fermé à volonté, avec un lien à partager
(/inscription, aucun compte requis).

Backend : FormTemplate/FormField (migration 0013), quatre nouveaux champs
sur Volunteer (photo, companion_wish_note, self_declared_available,
willing_to_pay_fee), app/api/forms.py — les deux seuls endpoints publics
de toute l'API (GET .../form/public, POST .../form/public/submit),
protégés par hCaptcha (app/forms/captcha.py, désactivé sans
HCAPTCHA_SECRET_KEY) et un filet de sécurité global par édition
(form_submission_limiter). resolve_owned_ids/set_artists/
set_wished_positions déplacés vers app/api/_common.py, partagés avec
volunteers.py.

Frontend : écran de configuration (/inscriptions) avec lien copiable et
bascule ouvert/fermé, formulaire public (/inscription, hors RequireAuth)
avec widget hCaptcha chargé dynamiquement, capture photo native
(<input capture>), vœux de poste/artiste avec les mêmes règles que le
back-end. Réponses du formulaire visibles et éditables depuis la fiche
bénévole existante (ConfigVolunteers.tsx).

Vérifié : pytest (273 passés), ruff, alembic check, tsc --noEmit, eslint,
vite build, smoke (rendu SSR de chaque écran + flux de bout en bout du
formulaire en mode démonstration) — tous verts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
AdamThomas
2026-09-21 20:24:32 +02:00
co-authored by Claude Sonnet 5
parent 55c5d539a8
commit 82088f3b0c
41 changed files with 2197 additions and 81 deletions
+47 -1
View File
@@ -300,6 +300,8 @@
"config.vol.noCompanions": "Aucun bénévole choisi",
"config.vol.pickCompanion": "Ajouter un bénévole…",
"config.vol.searchCompanion": "Rechercher un bénévole…",
"config.vol.publicForm.title": "Formulaire public",
"config.vol.publicForm.hint": "Réponses saisies par le bénévole lui-même via le formulaire public d'inscription.",
"config.vol.colWishes": "VŒUX",
"config.vol.wishesCount": "{count} vœu(x)",
"config.vol.addAvailabilityHint": "Les disponibilités se renseignent sur la fiche du bénévole, une fois celui-ci créé.",
@@ -360,5 +362,49 @@
"badge.duplicate_field_type": "Ce champ ne peut apparaître qu'une fois.",
"badge.invalid_size": "La taille du badge doit être strictement positive.",
"badge.no_fields": "Activez au moins un champ sur le recto avant de générer.",
"badge.no_volunteers": "Aucun bénévole ne correspond à cette sélection."
"badge.no_volunteers": "Aucun bénévole ne correspond à cette sélection.",
"tab.forms": "Inscriptions",
"form.field.email": "Email",
"form.field.phone": "Téléphone",
"form.field.positionWishes": "Vœux de poste",
"form.field.positionWishes.help": "Deux vœux au maximum, pour forcer une vraie priorisation.",
"form.field.artistWishes": "Concert(s) à voir",
"form.field.artistWishes.help": "Un seul artiste souhaité par soir de festival.",
"form.field.companionWish": "Collègue apprécié",
"form.field.companionWish.help": "Texte libre : la personne visée n'est pas forcément déjà inscrite. À résoudre ensuite depuis sa fiche.",
"form.field.available": "Case « je suis disponible »",
"form.field.available.help": "Purement informatif — n'a aucun lien avec les disponibilités détaillées de la fiche bénévole.",
"form.field.willingToPayFee": "Case « je veux bien payer une cotisation »",
"form.field.photo": "Photo",
"form.field.comment": "Commentaire",
"form.link.title": "Lien du formulaire",
"form.link.hint": "À partager aux bénévoles potentiels — n'importe qui muni du lien peut s'inscrire.",
"form.link.copy": "Copier",
"form.link.copied": "Copié ✓",
"form.status.title": "Inscriptions",
"form.status.open": "OUVERTES",
"form.status.closed": "FERMÉES",
"form.fields.title": "Champs du formulaire",
"form.save": "Enregistrer",
"form.saving": "Enregistrement…",
"form.saved": "Enregistré ✓",
"publicForm.title": "Inscription bénévole",
"publicForm.positionWishes.count": "{count} / {max}",
"publicForm.artistWishes.none": "— Aucun —",
"publicForm.captcha.disabled": "(Vérification anti-robot non configurée sur cette instance.)",
"publicForm.submitting": "Envoi…",
"publicForm.submit": "Envoyer mon inscription",
"publicForm.success.title": "Inscription reçue",
"publicForm.success.body": "Merci ! Ton inscription a bien été enregistrée. La coordination du festival prendra contact avec toi.",
"publicForm.closed.title": "Inscriptions fermées",
"publicForm.closed.body": "Les inscriptions bénévoles ne sont pas ouvertes pour le moment. Reviens un peu plus tard !",
"form.closed": "Les inscriptions sont actuellement fermées.",
"form.captcha_failed": "Vérification anti-robot invalide, réessaie.",
"form.invalid_payload": "Données du formulaire invalides.",
"form.photo_type_not_supported": "La photo doit être au format PNG ou JPEG.",
"form.photo_too_large": "La photo est trop volumineuse.",
"form.too_many_position_wishes": "Deux vœux de poste au maximum.",
"form.too_many_artists_same_day": "Un seul artiste souhaité par soir de festival."
}