2e8298b3b6
- Created V16 Flyway migration for pre_inscription and token_pre_inscription tables. - Added PreInscription and TokenPreInscription entities with respective repositories. - Updated SecurityConfig to allow public access to /inscription-public/**. - Implemented CaptchaValidationService to interact with Cloudflare Turnstile API. - Created PublicInscriptionController for managing the QR code entry, CAPTCHA validation, ephemeral tokens, and public form submission. - Added public Thymeleaf views (demarrer, formulaire, succes, lien-expire) with TailwindCSS. - Developed AdminPreInscriptionController and PreInscriptionService to handle back-office validation and rejection workflows. - Built the admin pre-inscriptions dashboard list view. - Added a dynamic, polling notification badge in the sidebar using HTMX, auto-updating on validation/rejection events.
102 lines
4.2 KiB
Java
102 lines
4.2 KiB
Java
package com.astalange.web.controller;
|
|
|
|
import com.astalange.core.entity.PreInscription;
|
|
import com.astalange.core.entity.TokenPreInscription;
|
|
import com.astalange.core.entity.Saison;
|
|
import com.astalange.core.repository.PreInscriptionRepository;
|
|
import com.astalange.core.repository.TokenPreInscriptionRepository;
|
|
import com.astalange.core.repository.SaisonRepository;
|
|
import com.astalange.core.service.CaptchaValidationService;
|
|
import org.springframework.stereotype.Controller;
|
|
import org.springframework.ui.Model;
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|
|
|
import java.time.LocalDateTime;
|
|
import java.util.UUID;
|
|
|
|
@Controller
|
|
@RequestMapping("/inscription-public")
|
|
public class PublicInscriptionController {
|
|
|
|
private final CaptchaValidationService captchaValidationService;
|
|
private final TokenPreInscriptionRepository tokenRepository;
|
|
private final PreInscriptionRepository preInscriptionRepository;
|
|
private final SaisonRepository saisonRepository;
|
|
|
|
public PublicInscriptionController(CaptchaValidationService captchaValidationService,
|
|
TokenPreInscriptionRepository tokenRepository,
|
|
PreInscriptionRepository preInscriptionRepository,
|
|
SaisonRepository saisonRepository) {
|
|
this.captchaValidationService = captchaValidationService;
|
|
this.tokenRepository = tokenRepository;
|
|
this.preInscriptionRepository = preInscriptionRepository;
|
|
this.saisonRepository = saisonRepository;
|
|
}
|
|
|
|
@GetMapping("/demarrer")
|
|
public String showDemarrer() {
|
|
return "public/demarrer";
|
|
}
|
|
|
|
@PostMapping("/demarrer")
|
|
public String processDemarrer(@RequestParam("cf-turnstile-response") String captchaResponse, RedirectAttributes redirectAttributes) {
|
|
// En vrai, captchaResponse dépend du fournisseur. Cloudflare Turnstile = cf-turnstile-response
|
|
if (!captchaValidationService.validateCaptcha(captchaResponse)) {
|
|
redirectAttributes.addFlashAttribute("error", "Validation CAPTCHA échouée. Veuillez réessayer.");
|
|
return "redirect:/inscription-public/demarrer";
|
|
}
|
|
|
|
TokenPreInscription token = new TokenPreInscription();
|
|
token.setValeurUuid(UUID.randomUUID().toString());
|
|
token.setDateExpiration(LocalDateTime.now().plusMinutes(10));
|
|
tokenRepository.save(token);
|
|
|
|
return "redirect:/inscription-public/formulaire?token=" + token.getValeurUuid();
|
|
}
|
|
|
|
@GetMapping("/formulaire")
|
|
public String showFormulaire(@RequestParam("token") String tokenUuid, Model model) {
|
|
TokenPreInscription token = tokenRepository.findByValeurUuid(tokenUuid).orElse(null);
|
|
if (token == null || !token.isValide()) {
|
|
return "public/lien-expire";
|
|
}
|
|
|
|
model.addAttribute("preInscription", new PreInscription());
|
|
model.addAttribute("tokenUuid", tokenUuid);
|
|
return "public/formulaire";
|
|
}
|
|
|
|
@PostMapping("/formulaire")
|
|
public String processFormulaire(@RequestParam("token") String tokenUuid,
|
|
@ModelAttribute("preInscription") PreInscription preInscription,
|
|
RedirectAttributes redirectAttributes) {
|
|
TokenPreInscription token = tokenRepository.findByValeurUuid(tokenUuid).orElse(null);
|
|
if (token == null || !token.isValide()) {
|
|
return "public/lien-expire";
|
|
}
|
|
|
|
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
|
if (activeSaison == null) {
|
|
redirectAttributes.addFlashAttribute("error", "Les inscriptions sont actuellement fermées.");
|
|
return "redirect:/inscription-public/demarrer";
|
|
}
|
|
|
|
// Sauvegarde de la pré-inscription
|
|
preInscription.setSaison(activeSaison);
|
|
preInscription.setStatutTraite(false);
|
|
preInscriptionRepository.save(preInscription);
|
|
|
|
// Invalidation du token
|
|
token.setEstUtilise(true);
|
|
tokenRepository.save(token);
|
|
|
|
return "redirect:/inscription-public/succes";
|
|
}
|
|
|
|
@GetMapping("/succes")
|
|
public String showSucces() {
|
|
return "public/succes";
|
|
}
|
|
}
|