8.4 KiB
Recherche technique — faits vérifiés (2026-06-29)
Document de référence pour l'implémentation. Toutes les valeurs ci-dessous sont vérifiées sur le HTML/ICS réel, pas supposées. Re-vérifier si > 6 mois.
1. Source : calendrier Nextcloud (CalDAV)
- URL :
https://atelier-huit.frama.space/remote.php/dav/calendars/Pierre/latelier-du-huit-sbastien_shared_by_admin/?export - Auth : session navigateur (cookies). Depuis l'extension →
fetch(url, { credentials: 'include' })+host_permissionssurhttps://atelier-huit.frama.space/*. Aucun mot de passe stocké. - Réponse : flux iCalendar brut (VCALENDAR/VEVENT).
- Si non connecté → la requête échoue : prévoir un message "connecte-toi à Nextcloud dans un onglet".
Cas limites du flux réel (échantillon 2026-06-29, 473 VEVENT)
| Réalité | Chiffre | Conséquence parsing |
|---|---|---|
| VEVENT total | 473 | |
| UID uniques | 381 | Dédoublonner par UID (récurrences = même UID répété) |
| Récurrents (RRULE) | 54 | Gérer/ignorer les occurrences passées |
Journée entière (DTSTART;VALUE=DATE) |
7 | Pas d'heure → le formulaire mairie attend une heure : cas à traiter |
| Avec LOCATION | 51 / 473 | La majorité n'a pas de lieu → défaut = adresse du café |
| Avec DESCRIPTION | 142 / 473 | La majorité n'a pas de description → champ souvent vide |
| Fuseaux | Europe/Paris mais aussi Africa/Lagos |
Ne PAS supposer Europe/Paris : lire le vrai TZID |
Recommandation parsing :
ical.js(Mozilla) plutôt que regex maison — gère RRULE, TZID, VALUE=DATE.
T1 — parseur :
ical.jsv2.2.1 vendoré (build ESMdist/ical.js) dansextension/vendor/ical.js. ⚠️ LesVTIMEZONEembarqués dans le flux doivent être enregistrés (ICAL.TimezoneService.register) avanttoJSDate(), sinon l'offset est faux pour les TZID non standards (ex.Africa/Lagos).
Écriture CalDAV — mesuré le 2026-08-13 (spike navigateur, T2)
Mesures faites depuis la console de la page d'extension, session Nextcloud
ouverte. La séquence complète a été jouée, PUT no-op compris (contenu
reposé à l'identique : rien modifié).
| Étape | Résultat mesuré |
|---|---|
GET /csrftoken |
200, corps {"token":"…=:…="} (le repli data-requesttoken n'a pas servi) |
REPORT sur la collection (calendar-query filtrée sur UID) |
207, en-têtes Depth: 1 + Content-Type: application/xml; charset=utf-8 |
PUT avec If-Match |
204 → le partage est en écriture |
REPORT avec un requesttoken invalide |
207 quand même : l'endpoint DAV n'exige pas le jeton CSRF |
- Collection = URL du calendrier sans
?export(d'oùURL_COLLECTIONdérivée dansnextcloud.js). - Préfixes réels du
multistatus:d:→DAV:,cal:→urn:ietf:params:xml:ns:caldav(pluss:,cs:,oc:,nc:). Ce sont des préfixes, pas un contrat : sélectionner par namespace (getElementsByTagNameNS), jamais par préfixe. - ⚠️ Le nom de la ressource n'est PAS l'UID : l'événement d'UID
db2d146b-8e18-…vit dans…/00D03211-DA2E-4D06-AAAE-6E8C2355BA2B.ics. Déduire l'URL en<uid>.icsaurait échoué — d'où leREPORTpréalable. hrefdumultistatus= chemin absolu depuis la racine (/remote.php/dav/…) → à résoudre contre la collection.getetagest rendu avec ses guillemets ("8ee26a8f…") :If-Matchle reprend verbatim.
2. Cible : formulaire mairie (Gravity Forms, form id = 6)
URL : https://www.ville-cugnaux.fr/mes-loisirs/associations/proposer-un-evenement-dans-lagenda/
Stratégie de soumission
Content script qui remplit le DOM par id, puis l'utilisateur soumet à la main.
- Pas de params URL : Gravity Forms n'accepte
?input_X=que si "population dynamique" est activé par champ côté mairie (non). - Les tokens CSRF (
gform_currency,state_6,version_hash) sont dans la page et gérés par le formulaire lui-même : on n'y touche pas. ⚠️ Les tokens du curl capturé sont par session, non réutilisables.
Mapping des champs (ids confirmés présents dans le HTML)
⚠️ La colonne « balise réelle » a été payée par un bug (2026-07-17). Le corps de la tâche T1 affirmait « Heures = 2 selects » : c'est faux, ce sont des
<input type="number">. Le code l'a suivi et les 4 champs d'heures ont échoué (champ.optionsundefined → TypeError). Ne pas déduire le type d'un champ de son intitulé : le HTML est la seule source de vérité. Types ci-dessous vérifiés sur la page réelle le 2026-07-17.
| id DOM | name | Balise réelle | Contenu | Source |
|---|---|---|---|---|
#input_6_42 |
input_42 |
input[type=text] |
Organisateur | config (« L'Atelier du Huit ») |
#input_6_41 |
input_41 |
input[type=email] |
config | |
#input_6_1 |
input_1 |
input[type=text] |
Titre | SUMMARY |
#input_6_3 |
input_3 |
textarea |
Description | DESCRIPTION |
#input_6_20 |
input_20 |
select |
Thème | mapping (voir §3) |
#input_6_31 |
input_31 |
input[type=text] (datepicker) |
Date début jj/mm/aaaa |
DTSTART |
#input_6_32 |
input_32 |
input[type=text] (datepicker) |
Date fin jj/mm/aaaa |
DTEND |
#input_6_38_1 / #input_6_38_2 |
input_38[] |
input[type=number] (min/max, placeholder HH/MM) |
Heure début [HH, MM] | DTSTART |
#input_6_39_1 / #input_6_39_2 |
input_39[] |
input[type=number] |
Heure fin [HH, MM] | DTEND |
#input_6_35 (_1) |
input_35.1 |
input[type=checkbox] |
Accessibilité | ⚠️ laissé intact : la machine ne sait pas si le lieu est accessible |
#input_6_36 |
input_36 |
Public ciblé | optionnel | |
#input_6_40 |
input_40 |
textarea |
Tarifs | défaut « Gratuit » |
#nova_address |
nova_address |
input[type=text] |
Adresse texte | défaut café |
#input_6_18 |
input_18 |
input[type=hidden] |
lat|lng|adresse |
défaut café |
#input_6_34 |
input_34 |
input[type=file] |
Image | ⚠️ non remplissable par script (sécurité) → manuel |
#input_6_23, #input_6_43 |
Honeypot | laisser vide |
Les 4 champs d'heures acceptent le zéro-padding ("09", "00") : une suite
de chiffres est un valid floating-point number au sens HTML.
Défaut café : 8 Rue du Pré Vicinal 31270 Cugnaux
input_18 = 43.53753132806989|1.342981890597508|8 Rue du Pré Vicinal 31270 Cugnaux
3. Valeurs exactes du dropdown Thème (#input_6_20)
Chaînes value à utiliser telles quelles :
Culture
Atelier - Stage
Economie - Emploi
Exposition
Photographie
Rencontre
Spectacle
Enfance - Jeunesse
Jeunesse
Parentalité
Petite enfance
Scolarité
Loisirs
Mobilité
Nature - Environnement
Numérique
Participation citoyenne
Cérémonies officielles
Réunion publique
Santé
Seniors
Solidarité
Sport
Le calendrier Nextcloud n'a pas de thème → prévoir un choix par l'utilisateur dans l'UI, défaut « Culture ».
4. Vérification publication (agenda public mairie)
URL filtrée par mois :
https://www.ville-cugnaux.fr/mes-loisirs/agenda/?f=1&theme=&date=periode&date_debut=MM%2FYYYY&date_fin=MM%2FYYYY&public=
Structure HTML d'un résultat (confirmée)
Chaque événement publié = <article class="card card-thumbnail card-event ...">
contenant (balise <article>, PAS <div> : vérifié sur l'agenda réel le
2026-07-17 — matcher sur la classe .card-event, agnostique de balise) :
- Date :
<time datetime="YYYY-MM-DD">(ancre de match la plus fiable) - Lien direct :
<a href="/agenda/<slug>/">— parfois relatif, à résoudre contre l'agenda avant affichage ; c'est le lien à afficher dans l'extension - Titre :
.card-title > a - Thème : classe
event_theme-<slug>
Exemples de liens réels observés : /agenda/spectacle-jhabite-ici/, /agenda/atelier-bebe-gym/, /agenda/fete-du-14-juillet-inscription-au-repas-republicain/.
Matching Nextcloud ↔ mairie
Comparer date (<time datetime> vs DTSTART) + titre (normalisé : sans accents/emojis, ou via le slug). Tolérer les écarts mineurs.
5. Modèle de statut (rappel)
- ignoré / soumis:AAAA-MM-JJ → tag
CATEGORIESécrit en CalDAV (partagé, durable) - publié → dérivé de l'agenda mairie (§4), donne le lien direct
- à faire → futur, ni ignoré, ni soumis, ni publié