diff --git a/assets/js/contact-form.js b/assets/js/contact-form.js
index 8d2071c..8c8834c 100644
--- a/assets/js/contact-form.js
+++ b/assets/js/contact-form.js
@@ -294,7 +294,38 @@ class ContactFormPersistence {
}
}
+const RecaptchaService = {
+ siteKey: null,
+
+ init() {
+ this.siteKey = window.RECAPTCHA_SITE_KEY || null;
+ },
+
+ isAvailable() {
+ return this.siteKey && typeof grecaptcha !== 'undefined';
+ },
+
+ async getToken(action = 'contact') {
+ if (!this.isAvailable()) {
+ console.warn('reCAPTCHA non disponible, envoi sans protection');
+ return '';
+ }
+
+ return new Promise((resolve) => {
+ grecaptcha.ready(() => {
+ grecaptcha.execute(this.siteKey, { action })
+ .then((token) => resolve(token))
+ .catch((error) => {
+ console.error('Erreur reCAPTCHA:', error);
+ resolve('');
+ });
+ });
+ });
+ }
+};
+
document.addEventListener('DOMContentLoaded', () => {
+ RecaptchaService.init();
window.contactFormValidator = new FormValidator('contact-form');
window.contactFormPersistence = new ContactFormPersistence('contact-form');
});
diff --git a/docs/stories/5.4.integration-recaptcha.md b/docs/stories/5.4.integration-recaptcha.md
index 8b4ac3e..1a5c556 100644
--- a/docs/stories/5.4.integration-recaptcha.md
+++ b/docs/stories/5.4.integration-recaptcha.md
@@ -2,7 +2,7 @@
## Status
-Ready for Dev
+review
## Story
@@ -21,29 +21,29 @@ Ready for Dev
## Tasks / Subtasks
-- [] **Task 1 : Configurer les clés reCAPTCHA** (AC: 5)
- - [] Ajouter RECAPTCHA_SITE_KEY dans .env
- - [] Ajouter RECAPTCHA_SECRET_KEY dans .env
- - [] Créer includes/config.php pour charger .env et définir les constantes
+- [x] **Task 1 : Configurer les clés reCAPTCHA** (AC: 5)
+ - [x] Ajouter RECAPTCHA_SITE_KEY dans .env
+ - [x] Ajouter RECAPTCHA_SECRET_KEY dans .env
+ - [x] Créer includes/config.php pour charger .env et définir les constantes
-- [] **Task 2 : Charger le script Google** (AC: 2)
- - [] Ajouter le script dans templates/footer.php
- - [] Charger de manière asynchrone (async defer)
- - [] Exposer la site key via window.RECAPTCHA_SITE_KEY
+- [x] **Task 2 : Charger le script Google** (AC: 2)
+ - [x] Ajouter le script dans templates/footer.php
+ - [x] Charger de manière asynchrone (async defer)
+ - [x] Exposer la site key via window.RECAPTCHA_SITE_KEY
-- [] **Task 3 : Générer le token** (AC: 3)
- - [] Créer RecaptchaService dans contact-form.js
- - [] Méthode getToken() avec grecaptcha.execute()
- - [] Retourne une Promise avec le token
+- [x] **Task 3 : Générer le token** (AC: 3)
+ - [x] Créer RecaptchaService dans contact-form.js
+ - [x] Méthode getToken() avec grecaptcha.execute()
+ - [x] Retourne une Promise avec le token
-- [] **Task 4 : Envoyer le token au backend** (AC: 4)
- - [] RecaptchaService.getToken() prêt à être utilisé
- - [] Intégration avec AJAX dans Story 5.5/5.6
+- [x] **Task 4 : Envoyer le token au backend** (AC: 4)
+ - [x] RecaptchaService.getToken() prêt à être utilisé
+ - [x] Intégration avec AJAX dans Story 5.5/5.6
-- [] **Task 5 : Dégradation gracieuse** (AC: 6)
- - [] isAvailable() vérifie si grecaptcha est défini
- - [] Retourne chaîne vide si indisponible
- - [] console.warn si non disponible
+- [x] **Task 5 : Dégradation gracieuse** (AC: 6)
+ - [x] isAvailable() vérifie si grecaptcha est défini
+ - [x] Retourne chaîne vide si indisponible
+ - [x] console.warn si non disponible
## Dev Notes
@@ -223,7 +223,11 @@ Si reCAPTCHA échoue :
## Dev Agent Record
### Agent Model Used
-Claude Opus 4.5 (claude-opus-4-5-20251101)
+GPT-5 Codex
+
+### Implementation Plan
+- Implémenter les tâches 1 à 5 dans l’ordre avec tests à chaque étape.
+- Ajouter config .env + chargement côté PHP, puis service JS reCAPTCHA.
### File List
| File | Action | Description |
@@ -233,15 +237,14 @@ Claude Opus 4.5 (claude-opus-4-5-20251101)
| `index.php` | Modified | Ajout require config.php |
| `templates/footer.php` | Modified | Script reCAPTCHA + window.RECAPTCHA_SITE_KEY |
| `assets/js/contact-form.js` | Modified | Ajout RecaptchaService |
+| `tests/recaptcha.test.php` | Added | Tests recaptcha (config + scripts) |
+| `tests/run.ps1` | Modified | Ajout du test recaptcha |
### Completion Notes
-- Système de chargement .env avec loadEnv() dans config.php
-- Constantes PHP : RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY, APP_ENV, etc.
-- Script Google chargé en async/defer dans footer.php
-- RecaptchaService avec méthodes init(), isAvailable(), getToken()
-- Dégradation gracieuse : retourne '' si reCAPTCHA indisponible
-- Clés de test Google utilisées en développement (score toujours 0.9)
-- La vérification côté serveur sera implémentée dans Story 5.5
+- Chargement .env + constantes RECAPTCHA_* via config.php
+- Script Google async/defer + window.RECAPTCHA_SITE_KEY
+- RecaptchaService init/isAvailable/getToken + dégradation gracieuse
+- Tests : `powershell -ExecutionPolicy Bypass -File tests/run.ps1`
### Debug Log References
Aucun problème rencontré.
@@ -252,3 +255,4 @@ Aucun problème rencontré.
|------|---------|-------------|--------|
| 2026-01-22 | 0.1 | Création initiale | Sarah (PO) |
| 2026-01-24 | 1.0 | Implémentation complète | James (Dev) |
+| 2026-02-04 | 1.1 | Intégration reCAPTCHA v3 | Amelia (Dev) |
diff --git a/includes/config.php b/includes/config.php
new file mode 100644
index 0000000..e05b89c
--- /dev/null
+++ b/includes/config.php
@@ -0,0 +1,46 @@
+add('/a-propos', 'pages/about.php')
->add('/contact', 'pages/contact.php');
-$router->dispatch();
\ No newline at end of file
+$router->dispatch();
diff --git a/templates/footer.php b/templates/footer.php
index 29e4b9b..071c0bd 100644
--- a/templates/footer.php
+++ b/templates/footer.php
@@ -15,5 +15,11 @@ $currentYear = date('Y');
+
+
+
+