DrawController.java
package com.archiweb.api;
import com.archiweb.model.Draw;
import com.archiweb.model.User;
import com.archiweb.model.Win;
import com.archiweb.repository.DrawRepository;
import com.archiweb.repository.UserRepository;
import com.archiweb.repository.WinRepository;
import com.archiweb.service.EmailService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
@RestController
@RequestMapping("/api/draw")
@Tag(
name = "Tirages",
description = """
Module de gestion des **tirages au sort** du jeu concours Thé Tip Top.
Ce contrôleur permet :
- D’effectuer le **tirage final** pour désigner le grand gagnant.
- De **consulter le résultat** du tirage final après son exécution.
Le tirage est unique et ne peut être réalisé qu’une seule fois.
"""
)
public class DrawController {
private final WinRepository winRepository;
private final UserRepository userRepository;
private final DrawRepository drawRepository;
private final EmailService emailService;
public DrawController(WinRepository winRepository,
UserRepository userRepository,
DrawRepository drawRepository,
EmailService emailService) {
this.winRepository = winRepository;
this.userRepository = userRepository;
this.drawRepository = drawRepository;
this.emailService = emailService;
}
// =========================================================
// 1️⃣ Effectuer le tirage final
// =========================================================
@Operation(
summary = "Effectuer le tirage final du jeu concours",
description = """
Sélectionne automatiquement un **gagnant parmi tous les participants** du jeu concours.
Le tirage final ne peut être effectué **qu’une seule fois**.
Si un tirage de type `FINAL` existe déjà, l’appel est rejeté.
""",
responses = {
@ApiResponse(
responseCode = "200",
description = "Tirage final effectué avec succès",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
value = """
{
"status": "success",
"message": "Tirage final effectué avec succès.",
"winner": {
"id": 8,
"username": "lea.dupont",
"email": "lea.dupont@example.com"
},
"drawType": "FINAL",
"createdAt": "2025-10-27T15:30:00"
}
"""
)
)
),
@ApiResponse(
responseCode = "400",
description = "Aucun participant",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
value = "{ \"error\": \"Aucun participant, tirage impossible.\" }"
)
)
),
@ApiResponse(
responseCode = "409",
description = "Tirage déjà effectué",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
value = "{ \"error\": \"Le tirage final a déjà été effectué.\" }"
)
)
)
}
)
@PostMapping("/final")
public ResponseEntity<?> performFinalDraw() {
if (drawRepository.existsByType("FINAL")) {
Map<String, String> error = new HashMap<>();
error.put("error", "Le tirage final a déjà été effectué.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
}
List<Win> allWins = winRepository.findAll();
if (allWins.isEmpty()) {
Map<String, String> error = new HashMap<>();
error.put("error", "Aucun participant, tirage impossible.");
return ResponseEntity.badRequest().body(error);
}
Random random = new Random();
Win selectedWin = allWins.get(random.nextInt(allWins.size()));
User winner = selectedWin.getUser();
Draw draw = new Draw();
draw.setType("FINAL");
draw.setWinner(winner);
draw.setCreatedAt(LocalDateTime.now());
drawRepository.save(draw);
// Envoyer un email au gagnant
try {
String emailContent = generateFinalDrawWinnerEmail(winner);
emailService.sendEmailHtml(
winner.getEmail(),
"🎉 Félicitations ! Vous avez gagné le tirage final !",
emailContent
);
} catch (Exception e) {
// Logger l'erreur mais ne pas faire échouer le tirage
System.err.println("Erreur lors de l'envoi de l'email au gagnant: " + e.getMessage());
}
return ResponseEntity.ok(
String.format(
"{\"status\":\"success\",\"message\":\"Tirage final effectué avec succès.\",\"winner\":{\"id\":%d,\"username\":\"%s\",\"email\":\"%s\"},\"drawType\":\"FINAL\",\"createdAt\":\"%s\"}",
winner.getId(), winner.getUsername(), winner.getEmail(), LocalDateTime.now()
)
);
}
// =========================================================
// 2️⃣ Obtenir le gagnant du tirage final
// =========================================================
@Operation(
summary = "Obtenir le gagnant du tirage final",
description = """
Retourne les informations du **gagnant désigné lors du tirage final**.
Si aucun tirage de type `FINAL` n’a encore été réalisé, un message d’erreur est renvoyé.
""",
responses = {
@ApiResponse(
responseCode = "200",
description = "Gagnant récupéré avec succès",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
value = """
{
"status": "success",
"winner": {
"id": 8,
"username": "lea.dupont",
"email": "lea.dupont@example.com"
},
"drawType": "FINAL",
"drawDate": "2025-10-27T15:30:00"
}
"""
)
)
),
@ApiResponse(
responseCode = "404",
description = "Aucun tirage final encore effectué",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
value = "{ \"error\": \"Aucun tirage final n'a encore été effectué.\" }"
)
)
)
}
)
@GetMapping("/winner")
public ResponseEntity<?> getFinalWinner() {
Optional<Draw> draw = drawRepository.findByType("FINAL");
if (draw.isEmpty()) {
Map<String, String> error = new HashMap<>();
error.put("error", "Aucun tirage final n'a encore été effectué.");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
User winner = draw.get().getWinner();
return ResponseEntity.ok(
String.format(
"{\"status\":\"success\",\"winner\":{\"id\":%d,\"username\":\"%s\",\"email\":\"%s\"},\"drawType\":\"FINAL\",\"drawDate\":\"%s\"}",
winner.getId(), winner.getUsername(), winner.getEmail(), draw.get().getCreatedAt()
)
);
}
// =========================================================
// 3️⃣ Générer l'email HTML pour le gagnant du tirage final
// =========================================================
private String generateFinalDrawWinnerEmail(User winner) {
String drawDate = LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("dd MMMM yyyy 'à' HH:mm", java.util.Locale.FRENCH));
return String.format("""
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🎉 Vous avez gagné le tirage final !</title>
</head>
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f5f5f5;">
<table width="100%%" cellpadding="0" cellspacing="0" style="background-color: #f5f5f5; padding: 40px 20px;">
<tr>
<td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background-color: #ffffff; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 20px rgba(0,0,0,0.1);">
<!-- Header avec gradient doré -->
<tr>
<td style="background: linear-gradient(135deg, #FFD700 0%%, #FFA500 100%%); padding: 50px 30px; text-align: center;">
<div style="font-size: 80px; margin-bottom: 20px;">🏆</div>
<h1 style="color: #ffffff; margin: 0; font-size: 36px; font-weight: 700; text-shadow: 0 2px 4px rgba(0,0,0,0.3);">
🎉 FÉLICITATIONS ! 🎉
</h1>
<p style="color: #ffffff; margin: 15px 0 0 0; font-size: 20px; opacity: 0.95; font-weight: 600;">
Vous avez gagné le TIRAGE FINAL !
</p>
</td>
</tr>
<!-- Contenu principal -->
<tr>
<td style="padding: 40px 30px;">
<div style="text-align: center; margin-bottom: 30px;">
<h2 style="color: #FF6B00; margin: 0 0 20px 0; font-size: 28px; font-weight: 700;">
🎁 Grand Gagnant du Jeu Concours Thé Tip Top
</h2>
<p style="color: #333; font-size: 18px; line-height: 1.6; margin: 0 0 10px 0;">
Félicitations <strong style="color: #FF6B00;">%s</strong> !
</p>
<p style="color: #666; font-size: 16px; line-height: 1.6; margin: 0;">
Vous avez été sélectionné(e) lors du tirage final effectué le <strong>%s</strong>.
</p>
</div>
<!-- Badge de victoire -->
<div style="text-align: center; margin: 30px 0; padding: 25px; background: linear-gradient(135deg, #FFD700 0%%, #FFA500 100%%); border-radius: 12px; box-shadow: 0 4px 15px rgba(255, 215, 0, 0.4);">
<div style="font-size: 50px; margin-bottom: 10px;">✨</div>
<p style="color: #ffffff; font-size: 20px; font-weight: 700; margin: 0; text-shadow: 0 2px 4px rgba(0,0,0,0.2);">
VOUS ÊTES LE GRAND GAGNANT !
</p>
</div>
<!-- Informations importantes -->
<div style="background-color: #FFF3E0; border-left: 4px solid #FF9800; padding: 25px; border-radius: 8px; margin: 30px 0;">
<h3 style="color: #E65100; margin: 0 0 15px 0; font-size: 20px; font-weight: 600;">
📋 Prochaines étapes
</h3>
<ul style="color: #666; font-size: 16px; line-height: 2; margin: 0; padding-left: 25px;">
<li>Vous serez contacté(e) sous <strong>48 heures</strong> par notre équipe</li>
<li>Nous vous expliquerons les modalités de réception de votre lot</li>
<li>Vous devrez confirmer vos coordonnées pour la livraison</li>
<li>Votre lot sera expédié ou disponible en boutique selon votre choix</li>
</ul>
</div>
<!-- Contact -->
<div style="background-color: #E8F5E9; border-left: 4px solid #4CAF50; padding: 20px; border-radius: 8px; margin: 30px 0;">
<h3 style="color: #2E7D32; margin: 0 0 15px 0; font-size: 18px; font-weight: 600;">
📞 Besoin d'aide ?
</h3>
<p style="color: #333; font-size: 16px; margin: 0; line-height: 1.6;">
Pour toute question, n'hésitez pas à nous contacter :<br>
<strong>Email :</strong> service@thetiptop.com<br>
<strong>Téléphone :</strong> 01 23 45 67 89
</p>
</div>
<!-- Message de félicitations -->
<div style="text-align: center; margin: 30px 0; padding: 20px; background-color: #f9f9f9; border-radius: 12px;">
<p style="color: #333; font-size: 18px; font-weight: 600; margin: 0; line-height: 1.6;">
Merci d'avoir participé au jeu concours Thé Tip Top !<br>
<span style="color: #FF6B00; font-size: 24px;">🎊 Félicitations encore une fois ! 🎊</span>
</p>
</div>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="background-color: #2E7D32; padding: 30px; text-align: center;">
<p style="color: #ffffff; margin: 0 0 10px 0; font-size: 16px; font-weight: 600;">
Thé Tip Top - Jeu Concours
</p>
<p style="color: #ffffff; margin: 0; font-size: 14px; opacity: 0.9;">
Merci de votre participation et félicitations pour votre victoire !
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
""", winner.getUsername() != null ? winner.getUsername() : winner.getEmail(), drawDate);
}
}