NewsletterController.java
package com.archiweb.api;
import com.archiweb.model.NewsletterEmail;
import com.archiweb.model.NewsletterSubscriber;
import com.archiweb.model.User;
import com.archiweb.repository.NewsletterEmailRepository;
import com.archiweb.repository.NewsletterSubscriberRepository;
import com.archiweb.repository.UserRepository;
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.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/newsletter")
@RequiredArgsConstructor
@Tag(
name = "Newsletter",
description = """
Gestion de l'abonnement à la newsletter et envoi d'emails groupés.
"""
)
public class NewsletterController {
private final NewsletterSubscriberRepository newsletterSubscriberRepository;
private final NewsletterEmailRepository newsletterEmailRepository;
private final UserRepository userRepository;
private final EmailService emailService;
@Operation(
summary = "S'abonner à la newsletter",
description = """
Permet à un utilisateur de s'abonner à la newsletter en fournissant son adresse email.
""",
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Adresse email de l'utilisateur",
required = true,
content = @Content(
schema = @Schema(implementation = NewsletterSubscribeRequest.class),
examples = @ExampleObject(
value = """
{
"email": "user@example.com"
}
"""
)
)
),
responses = {
@ApiResponse(
responseCode = "200",
description = "Abonnement réussi"
),
@ApiResponse(
responseCode = "400",
description = "Email invalide ou manquant"
)
}
)
@PostMapping("/subscribe")
public ResponseEntity<?> subscribe(@RequestBody NewsletterSubscribeRequest request) {
if (request.getEmail() == null || request.getEmail().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "L'adresse email est requise"));
}
String email = request.getEmail().trim().toLowerCase();
// Vérifier si l'utilisateur existe
java.util.Optional<User> userOptional = userRepository.findByEmail(email);
if (userOptional.isPresent()) {
// Si l'utilisateur existe, mettre à jour son consentement
User user = userOptional.get();
user.setConsentGiven(true);
userRepository.save(user);
// Enregistrer aussi dans la table newsletter_subscribers si pas déjà présent
if (!newsletterSubscriberRepository.existsByEmail(email)) {
NewsletterSubscriber subscriber = NewsletterSubscriber.builder()
.email(email)
.consentGiven(true)
.active(true)
.build();
newsletterSubscriberRepository.save(subscriber);
} else {
// Mettre à jour le consentement dans newsletter_subscribers
java.util.Optional<NewsletterSubscriber> subscriberOpt = newsletterSubscriberRepository.findByEmail(email);
if (subscriberOpt.isPresent()) {
NewsletterSubscriber subscriber = subscriberOpt.get();
subscriber.setConsentGiven(true);
subscriber.setActive(true);
newsletterSubscriberRepository.save(subscriber);
}
}
return ResponseEntity.ok(Map.of("message", "Vous êtes maintenant abonné à notre newsletter !"));
} else {
// Si l'utilisateur n'existe pas, enregistrer dans newsletter_subscribers
java.util.Optional<NewsletterSubscriber> existingSubscriber = newsletterSubscriberRepository.findByEmail(email);
if (existingSubscriber.isPresent()) {
// Mettre à jour l'abonné existant
NewsletterSubscriber subscriber = existingSubscriber.get();
subscriber.setConsentGiven(true);
subscriber.setActive(true);
newsletterSubscriberRepository.save(subscriber);
} else {
// Créer un nouvel abonné
NewsletterSubscriber subscriber = NewsletterSubscriber.builder()
.email(email)
.consentGiven(true)
.active(true)
.build();
newsletterSubscriberRepository.save(subscriber);
}
return ResponseEntity.ok(Map.of("message", "Vous êtes maintenant abonné à notre newsletter !"));
}
}
@Operation(
summary = "Compter les abonnés actifs",
description = """
Retourne le nombre total d'abonnés actifs à la newsletter.
Accessible uniquement aux administrateurs et employés.
""",
responses = {
@ApiResponse(
responseCode = "200",
description = "Nombre d'abonnés récupéré avec succès"
),
@ApiResponse(
responseCode = "403",
description = "Accès refusé - Réservé aux administrateurs et employés"
)
}
)
@GetMapping("/subscribers/count")
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_EMPLOYEE')")
public ResponseEntity<Map<String, Long>> getSubscriberCount() {
long count = newsletterSubscriberRepository.count();
return ResponseEntity.ok(Map.of("count", count));
}
@Operation(
summary = "Envoyer un email à tous les abonnés",
description = """
Envoie un email newsletter à tous les abonnés actifs.
L'email est enregistré dans l'historique.
Accessible uniquement aux administrateurs et employés.
""",
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Contenu de l'email",
required = true,
content = @Content(
schema = @Schema(implementation = SendNewsletterRequest.class),
examples = @ExampleObject(
value = """
{
"subject": "Nouvelle offre spéciale !",
"content": "Découvrez nos nouveaux thés..."
}
"""
)
)
),
responses = {
@ApiResponse(
responseCode = "200",
description = "Email envoyé avec succès"
),
@ApiResponse(
responseCode = "400",
description = "Données invalides"
),
@ApiResponse(
responseCode = "403",
description = "Accès refusé - Réservé aux administrateurs et employés"
)
}
)
@PostMapping("/send")
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_EMPLOYEE')")
public ResponseEntity<?> sendNewsletter(
@RequestBody SendNewsletterRequest request,
Authentication authentication) {
// Validation
if (request.getSubject() == null || request.getSubject().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Le sujet est requis"));
}
if (request.getContent() == null || request.getContent().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Le contenu est requis"));
}
try {
// Récupérer tous les abonnés actifs
List<NewsletterSubscriber> subscribers = newsletterSubscriberRepository.findAll()
.stream()
.filter(NewsletterSubscriber::isActive)
.filter(NewsletterSubscriber::isConsentGiven)
.toList();
if (subscribers.isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Aucun abonné actif trouvé"));
}
// Envoyer les emails
int sentCount = 0;
String senderEmail = authentication.getName(); // Email de l'employé/admin
for (NewsletterSubscriber subscriber : subscribers) {
try {
emailService.sendNewsletterEmail(
subscriber.getEmail(),
request.getSubject().trim(),
request.getContent().trim()
);
sentCount++;
} catch (Exception e) {
// Continuer même si un email échoue
System.err.println("Erreur envoi à " + subscriber.getEmail() + ": " + e.getMessage());
}
}
// Enregistrer dans l'historique
NewsletterEmail newsletterEmail = NewsletterEmail.builder()
.subject(request.getSubject().trim())
.content(request.getContent().trim())
.recipientCount(sentCount)
.sentBy(senderEmail)
.build();
newsletterEmailRepository.save(newsletterEmail);
return ResponseEntity.ok(Map.of(
"message", "Email envoyé avec succès",
"sentCount", sentCount,
"totalSubscribers", subscribers.size()
));
} catch (Exception e) {
return ResponseEntity.status(500).body(Map.of(
"error", "Erreur lors de l'envoi de l'email : " + e.getMessage()
));
}
}
@Operation(
summary = "Récupérer l'historique des emails envoyés",
description = """
Récupère la liste paginée des emails newsletter envoyés.
Accessible uniquement aux administrateurs et employés.
""",
responses = {
@ApiResponse(
responseCode = "200",
description = "Historique récupéré avec succès"
),
@ApiResponse(
responseCode = "403",
description = "Accès refusé - Réservé aux administrateurs et employés"
)
}
)
@GetMapping("/emails")
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_EMPLOYEE')")
public ResponseEntity<?> getEmailHistory(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "sentAt"));
Page<NewsletterEmail> emails = newsletterEmailRepository.findAllByOrderBySentAtDesc(pageable);
return ResponseEntity.ok(Map.of(
"content", emails.getContent(),
"totalElements", emails.getTotalElements(),
"totalPages", emails.getTotalPages(),
"size", emails.getSize(),
"number", emails.getNumber(),
"first", emails.isFirst(),
"last", emails.isLast()
));
}
@Operation(
summary = "Prévisualiser l'email",
description = """
Génère le HTML de prévisualisation de l'email sans l'envoyer.
Accessible uniquement aux administrateurs et employés.
""",
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Contenu de l'email",
required = true,
content = @Content(
schema = @Schema(implementation = SendNewsletterRequest.class)
)
),
responses = {
@ApiResponse(
responseCode = "200",
description = "Prévisualisation générée avec succès"
),
@ApiResponse(
responseCode = "403",
description = "Accès refusé - Réservé aux administrateurs et employés"
)
}
)
@PostMapping("/preview")
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'ROLE_EMPLOYEE')")
public ResponseEntity<?> previewEmail(@RequestBody SendNewsletterRequest request) {
if (request.getSubject() == null || request.getSubject().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Le sujet est requis"));
}
if (request.getContent() == null || request.getContent().trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("error", "Le contenu est requis"));
}
// Utiliser le service EmailService pour générer le template
// On va créer une méthode publique pour ça
String htmlContent = emailService.buildNewsletterTemplate(
request.getSubject().trim(),
request.getContent().trim()
);
return ResponseEntity.ok(Map.of("html", htmlContent));
}
@Data
public static class NewsletterSubscribeRequest {
@Schema(description = "Adresse email", example = "user@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
private String email;
}
@Data
public static class SendNewsletterRequest {
@Schema(description = "Sujet de l'email", example = "Nouvelle offre spéciale !", requiredMode = Schema.RequiredMode.REQUIRED)
private String subject;
@Schema(description = "Contenu de l'email (texte simple)", example = "Découvrez nos nouveaux thés...", requiredMode = Schema.RequiredMode.REQUIRED)
private String content;
}
}