Lien d'inscription protégé par jeton, reçus fiscaux mécénat, infobulles et revue de sécurité
- Lien d'inscription protégé par un jeton (FormTemplate.access_token, /inscription/<token>), avec régénération depuis l'écran de configuration. - Reçus fiscaux mécénat (cerfa 11580*05) : un PDF par bénévole ayant payé en mécénat, donateur/montant (chiffres et toutes lettres en français, app/mecenat/number_words.py)/date complétés par-dessus le modèle officiel. - Jeu de démonstration : bénévoles avec cotisation classique ou mécénat payée. - Infobulles (HelpTip et détail de cellule de la grille des besoins) repositionnées en position: fixed via JS, bornées à l'écran. - Revue de sécurité : logo des emails en pièce jointe inline au lieu d'une URL (fuyait le jeton d'inscription), sujet retiré du log de remise des emails (pouvait porter un nom de bénévole), photo du formulaire public revalidée par décodage réel avant stockage, export Excel protégé contre l'injection de formule, sondage du statut de paiement limité en fréquence, pyjwt mis à jour. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a2b748566b
commit
096b7cd26a
@@ -94,7 +94,9 @@ async function checkPublicForm() {
|
||||
await api.forms.setFields(e, {
|
||||
fields: ['EMAIL', 'POSITION_WISHES', 'ARTIST_WISHES', 'COMMENT', 'WILLING_TO_PAY_FEE'],
|
||||
});
|
||||
const config = await api.forms.getPublicConfig(e);
|
||||
const template = await api.forms.getTemplate(e);
|
||||
const formToken = template.access_token;
|
||||
const config = await api.forms.getPublicConfig(e, formToken);
|
||||
if (!config.is_open) throw new Error('formulaire public : devrait être ouvert par défaut');
|
||||
if (config.positions.length !== positions.length) {
|
||||
throw new Error('formulaire public : postes manquants dans la config publique');
|
||||
@@ -107,7 +109,7 @@ async function checkPublicForm() {
|
||||
// qu'exécuté ici) ; seul le texte d'introduction et la config SumUp sont
|
||||
// vérifiables ici.
|
||||
await api.forms.setOpen(e, { description: 'Bienvenue au festival de test !' });
|
||||
const configWithDescription = await api.forms.getPublicConfig(e);
|
||||
const configWithDescription = await api.forms.getPublicConfig(e, formToken);
|
||||
if (configWithDescription.description !== 'Bienvenue au festival de test !') {
|
||||
throw new Error("formulaire public : le texte d'introduction ne revient pas correctement");
|
||||
}
|
||||
@@ -127,7 +129,7 @@ async function checkPublicForm() {
|
||||
amount: 15,
|
||||
});
|
||||
await api.forms.paymentOptions.create(e, { label: 'Mécénat', amount: 50 });
|
||||
const configWithSumup = await api.forms.getPublicConfig(e);
|
||||
const configWithSumup = await api.forms.getPublicConfig(e, formToken);
|
||||
if (!configWithSumup.sumup_enabled || configWithSumup.payment_options.length !== 2) {
|
||||
throw new Error('formulaire public : la configuration SumUp ne revient pas correctement');
|
||||
}
|
||||
@@ -136,7 +138,7 @@ async function checkPublicForm() {
|
||||
let tooManyArtistsRejectedWith = 'non';
|
||||
if (sameDay.length >= 2) {
|
||||
try {
|
||||
await api.forms.submitPublic(e, {
|
||||
await api.forms.submitPublic(e, formToken, {
|
||||
first_name: 'Test',
|
||||
last_name: 'Smoke',
|
||||
hcaptcha_token: 'dev',
|
||||
@@ -151,7 +153,7 @@ async function checkPublicForm() {
|
||||
let tooManyPositionsRejectedWith = 'non';
|
||||
if (positions.length >= 3) {
|
||||
try {
|
||||
await api.forms.submitPublic(e, {
|
||||
await api.forms.submitPublic(e, formToken, {
|
||||
first_name: 'Test',
|
||||
last_name: 'Smoke',
|
||||
hcaptcha_token: 'dev',
|
||||
@@ -165,7 +167,7 @@ async function checkPublicForm() {
|
||||
|
||||
// Paiement en ligne choisi : rien en base tant que la « banque » (mock) ne
|
||||
// confirme pas — voir CLAUDE.md § 2, Paiement de la cotisation.
|
||||
const result = await api.forms.submitPublic(e, {
|
||||
const result = await api.forms.submitPublic(e, formToken, {
|
||||
first_name: 'test',
|
||||
last_name: 'smoke',
|
||||
hcaptcha_token: 'dev',
|
||||
@@ -430,7 +432,9 @@ await checkGridLayout().catch((err) => fail('checkGridLayout', err));
|
||||
|
||||
renderPublic('/connexion');
|
||||
renderPublic('/connexion/coordination');
|
||||
renderPublic('/inscription'); // formulaire public, hors de <RequireAuth/>
|
||||
// formulaire public, hors de <RequireAuth/> — jeton fixe du mock (voir
|
||||
// frontend/src/api/mock/dataset.ts, buildMockState).
|
||||
renderPublic('/inscription/demo-access-token');
|
||||
|
||||
if (coordinator) {
|
||||
setAuthToken(coordinatorToken);
|
||||
|
||||
Reference in New Issue
Block a user