feat(backend): Ajout complet des fonctionnalités Chat, Social, Story et Notifications

Implémentation complète de toutes les fonctionnalités backend :

## Nouvelles Fonctionnalités

### Chat (Messagerie Instantanée)
- Entities : Conversation, Message
- DTOs : ConversationResponseDTO, MessageResponseDTO, SendMessageRequestDTO
- Resources : MessageResource (endpoints REST)
- Services : MessageService (logique métier)
- Repositories : ConversationRepository, MessageRepository
- WebSocket : ChatWebSocket (temps réel)

### Social (Publications Sociales)
- Entities : SocialPost, SocialComment, SocialLike
- DTOs : SocialPostResponseDTO, CreateSocialPostRequestDTO
- Resources : SocialPostResource
- Services : SocialPostService
- Repositories : SocialPostRepository

### Story (Stories temporaires)
- Entities : Story, StoryView
- DTOs : StoryResponseDTO, CreateStoryRequestDTO
- Resources : StoryResource
- Services : StoryService
- Repositories : StoryRepository

### Notifications (Temps Réel)
- Entities : Notification
- DTOs : NotificationResponseDTO
- Resources : NotificationResource
- Services : NotificationService, PresenceService
- Repositories : NotificationRepository
- WebSocket : NotificationWebSocket (temps réel)

## Améliorations

### Users & Friendship
- Mise à jour UserResponseDTO avec nouveaux champs
- Amélioration FriendshipResource avec séparation demandes envoyées/reçues
- FriendSuggestionResponseDTO pour suggestions d'amis
- Optimisations dans UsersService et FriendshipService

### Events
- Améliorations EventsResource et EventService
- Optimisations EventsRepository

### Configuration
- Mise à jour application.properties
- Configuration docker-compose.yml
- Dockerfile pour développement

## Fichiers Modifiés
- .dockerignore, .gitignore
- README.md
- docker-compose.yml
- Configuration Maven wrapper
This commit is contained in:
dahoud
2026-01-10 10:39:58 +00:00
parent fd67140961
commit 093d04c224
60 changed files with 14652 additions and 220 deletions

View File

@@ -5,14 +5,19 @@ import org.slf4j.LoggerFactory;
import jakarta.transaction.Transactional;
import com.lions.dev.dto.request.events.EventCreateRequestDTO;
import com.lions.dev.entity.events.Events;
import com.lions.dev.entity.friends.Friendship;
import com.lions.dev.entity.users.Users;
import com.lions.dev.repository.EventsRepository;
import com.lions.dev.exception.EventNotFoundException;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.EventsRepository;
import com.lions.dev.repository.FriendshipRepository;
import com.lions.dev.repository.UsersRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Service de gestion des événements.
@@ -25,6 +30,15 @@ public class EventService {
@Inject
EventsRepository eventsRepository;
@Inject
FriendshipRepository friendshipRepository;
@Inject
UsersRepository usersRepository;
@Inject
NotificationService notificationService;
private static final Logger logger = LoggerFactory.getLogger(EventService.class);
/**
@@ -51,6 +65,33 @@ public class EventService {
// Persiste l'événement dans la base de données
eventsRepository.persist(event);
logger.info("[logger] Événement créé avec succès : {}", event.getTitle());
// Créer des notifications pour tous les amis
try {
List<Friendship> friendships = friendshipRepository.findFriendsByUser(creator, 0, Integer.MAX_VALUE);
String creatorName = creator.getPrenoms() + " " + creator.getNom();
for (Friendship friendship : friendships) {
Users friend = friendship.getUser().equals(creator)
? friendship.getFriend()
: friendship.getUser();
String notificationTitle = "Nouvel événement de " + creatorName;
String notificationMessage = creatorName + " a créé un nouvel événement : " + event.getTitle();
notificationService.createNotification(
notificationTitle,
notificationMessage,
"event",
friend.getId(),
event.getId()
);
}
logger.info("[logger] Notifications créées pour {} ami(s)", friendships.size());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de la création des notifications : {}", e.getMessage());
}
return event;
}
@@ -282,4 +323,42 @@ public class EventService {
logger.info("[logger] Nombre d'événements recommandés pour l'utilisateur : " + events.size());
return events;
}
/**
* Récupère les événements de l'utilisateur et de ses amis (relations d'amitié acceptées).
*
* @param userId L'ID de l'utilisateur
* @param page Le numéro de la page (0-indexé)
* @param size La taille de la page
* @return Liste paginée des événements de l'utilisateur et de ses amis
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<Events> getEventsByFriends(UUID userId, int page, int size) {
logger.info("[logger] Récupération des événements des amis pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
logger.error("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
// Récupérer toutes les relations d'amitié acceptées
List<Friendship> friendships = friendshipRepository.findFriendsByUser(user, 0, Integer.MAX_VALUE);
// Extraire les IDs des amis
List<UUID> friendIds = friendships.stream()
.map(friendship -> {
// L'ami est soit dans 'user' soit dans 'friend', selon qui a initié la relation
return friendship.getUser().equals(user)
? friendship.getFriend().getId()
: friendship.getUser().getId();
})
.distinct()
.collect(Collectors.toList());
logger.info("[logger] " + friendIds.size() + " ami(s) trouvé(s) pour l'utilisateur ID : " + userId);
// Récupérer les événements de l'utilisateur et de ses amis
return eventsRepository.findEventsByFriends(userId, friendIds, page, size);
}
}

View File

@@ -13,11 +13,15 @@ import com.lions.dev.exception.FriendshipNotFoundException;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.FriendshipRepository;
import com.lions.dev.repository.UsersRepository;
import com.lions.dev.websocket.NotificationWebSocket;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.jboss.logging.Logger;
@@ -33,6 +37,8 @@ public class FriendshipService {
FriendshipRepository friendshipRepository; // Injecte le repository des amitiés
@Inject
UsersRepository usersRepository; // Injecte le repository des utilisateurs
@Inject
NotificationService notificationService; // Injecte le service de notifications
private static final Logger logger = Logger.getLogger(FriendshipService.class);
@@ -56,6 +62,12 @@ public class FriendshipService {
throw new UserNotFoundException("Utilisateur avec l'ID " + notFoundId + " introuvable.");
}
// VALIDATION: Empêcher l'utilisateur de s'ajouter lui-même comme ami
if (user.getId().equals(friend.getId())) {
logger.error("[ERROR] Tentative d'ajout de soi-même comme ami bloquée pour l'utilisateur : " + user.getId());
throw new IllegalArgumentException("Vous ne pouvez pas vous ajouter vous-même comme ami.");
}
// Vérifier s'il existe déjà une relation d'amitié
Friendship existingFriendship = friendshipRepository.findByUsers(user, friend).orElse(null);
if (existingFriendship != null) {
@@ -67,6 +79,26 @@ public class FriendshipService {
Friendship friendship = new Friendship(user, friend, FriendshipStatus.PENDING);
friendshipRepository.persist(friendship);
// TEMPS RÉEL: Notifier le destinataire via WebSocket
try {
Map<String, Object> notificationData = new HashMap<>();
notificationData.put("requestId", friendship.getId().toString());
notificationData.put("senderId", user.getId().toString());
notificationData.put("senderName", user.getPrenoms() + " " + user.getNom());
notificationData.put("senderProfileImage", user.getProfileImageUrl() != null ? user.getProfileImageUrl() : "");
NotificationWebSocket.sendNotificationToUser(
friend.getId(),
"friend_request_received",
notificationData
);
logger.info("[LOG] Notification WebSocket envoyée au destinataire : " + friend.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket : " + e.getMessage(), e);
// Ne pas bloquer la demande d'amitié si le WebSocket échoue
}
logger.info("[LOG] Demande d'amitié envoyée avec succès.");
return new FriendshipCreateOneResponseDTO(friendship);
}
@@ -107,6 +139,60 @@ public class FriendshipService {
// Log de succès
logger.info(String.format("[LOG] Demande d'amitié acceptée avec succès pour l'ID: %s", friendshipId)); // Correctement formaté
// TEMPS RÉEL: Notifier l'émetteur de la demande via WebSocket
try {
Users user = friendship.getUser();
Users friend = friendship.getFriend();
String friendName = friend.getPrenoms() + " " + friend.getNom();
Map<String, Object> notificationData = new HashMap<>();
notificationData.put("acceptedBy", friendName);
notificationData.put("friendshipId", friendshipId.toString());
notificationData.put("accepterId", friend.getId().toString());
notificationData.put("accepterProfileImage", friend.getProfileImageUrl() != null ? friend.getProfileImageUrl() : "");
NotificationWebSocket.sendNotificationToUser(
user.getId(),
"friend_request_accepted",
notificationData
);
logger.info("[LOG] Notification WebSocket d'acceptation envoyée à : " + user.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket d'acceptation : " + e.getMessage(), e);
// Ne pas bloquer l'acceptation si le WebSocket échoue
}
// Créer des notifications pour les deux utilisateurs
try {
Users user = friendship.getUser();
Users friend = friendship.getFriend();
String userName = user.getPrenoms() + " " + user.getNom();
String friendName = friend.getPrenoms() + " " + friend.getNom();
// Notification pour l'utilisateur qui a envoyé la demande
notificationService.createNotification(
"Demande d'amitié acceptée",
friendName + " a accepté votre demande d'amitié",
"friend",
user.getId(),
null
);
// Notification pour l'utilisateur qui a accepté la demande
notificationService.createNotification(
"Nouveaux amis",
"Vous êtes maintenant ami(e) avec " + userName,
"friend",
friend.getId(),
null
);
logger.info("[LOG] Notifications d'amitié créées pour les deux utilisateurs");
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de la création des notifications d'amitié : " + e.getMessage());
}
// Retourner la réponse avec les informations de la relation d'amitié
return new FriendshipCreateOneResponseDTO(friendship);
}
@@ -126,6 +212,26 @@ public class FriendshipService {
friendship.setStatus(FriendshipStatus.REJECTED);
friendshipRepository.persist(friendship);
// TEMPS RÉEL: Notifier l'émetteur de la demande via WebSocket (optionnel selon UX)
try {
Users user = friendship.getUser();
Map<String, Object> notificationData = new HashMap<>();
notificationData.put("friendshipId", friendshipId.toString());
notificationData.put("rejectedAt", System.currentTimeMillis());
NotificationWebSocket.sendNotificationToUser(
user.getId(),
"friend_request_rejected",
notificationData
);
logger.info("[LOG] Notification WebSocket de rejet envoyée à : " + user.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket de rejet : " + e.getMessage(), e);
// Ne pas bloquer le rejet si le WebSocket échoue
}
logger.info("[LOG] Demande d'amitié rejetée.");
}
@@ -297,4 +403,126 @@ public class FriendshipService {
return friendships.stream().map(FriendshipReadStatusResponseDTO::new).toList();
}
/**
* Récupérer les suggestions d'amis pour un utilisateur.
*
* L'algorithme suggère des utilisateurs basés sur :
* 1. Amis d'amis (utilisateurs qui ont des amis en commun)
* 2. Utilisateurs récents (qui ne sont ni amis ni ont de demandes en attente)
*
* @param userId ID de l'utilisateur.
* @param limit Nombre maximum de suggestions à retourner.
* @return Liste des suggestions d'amis.
*/
public List<com.lions.dev.dto.response.users.FriendSuggestionResponseDTO> getFriendSuggestions(UUID userId, int limit) {
logger.info("[LOG] Récupération des suggestions d'amis pour l'utilisateur : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
logger.error("[ERROR] Utilisateur non trouvé.");
throw new UserNotFoundException("Utilisateur introuvable.");
}
// Récupérer tous les amis actuels de l'utilisateur (ACCEPTED)
// Utiliser une taille de page élevée pour récupérer tous les résultats
List<Friendship> currentFriendships = friendshipRepository.findByUserAndStatus(user, FriendshipStatus.ACCEPTED, 0, 10000);
Set<UUID> currentFriendIds = new HashSet<>();
for (Friendship friendship : currentFriendships) {
// Ajouter les IDs des amis (que l'utilisateur ait envoyé ou reçu la demande)
if (friendship.getUser().getId().equals(userId)) {
currentFriendIds.add(friendship.getFriend().getId());
} else {
currentFriendIds.add(friendship.getUser().getId());
}
}
// Récupérer toutes les demandes en attente pour exclure ces utilisateurs
List<Friendship> pendingFriendships = friendshipRepository.findByUserAndStatus(user, FriendshipStatus.PENDING, 0, 10000);
Set<UUID> pendingUserIds = new HashSet<>();
for (Friendship friendship : pendingFriendships) {
if (friendship.getUser().getId().equals(userId)) {
pendingUserIds.add(friendship.getFriend().getId());
} else {
pendingUserIds.add(friendship.getUser().getId());
}
}
// Map pour compter les amis en commun
Map<UUID, Integer> mutualFriendsCount = new HashMap<>();
// Pour chaque ami, trouver ses amis (amis d'amis)
for (UUID friendId : currentFriendIds) {
Users friend = usersRepository.findById(friendId);
if (friend == null) continue;
List<Friendship> friendsOfFriend = friendshipRepository.findByUserAndStatus(friend, FriendshipStatus.ACCEPTED, 0, 10000);
for (Friendship fof : friendsOfFriend) {
UUID potentialFriendId;
if (fof.getUser().getId().equals(friendId)) {
potentialFriendId = fof.getFriend().getId();
} else {
potentialFriendId = fof.getUser().getId();
}
// Exclure l'utilisateur lui-même, ses amis actuels et les demandes en attente
if (!potentialFriendId.equals(userId) &&
!currentFriendIds.contains(potentialFriendId) &&
!pendingUserIds.contains(potentialFriendId)) {
mutualFriendsCount.put(potentialFriendId, mutualFriendsCount.getOrDefault(potentialFriendId, 0) + 1);
}
}
}
// Trier par nombre d'amis en commun (décroissant)
List<Map.Entry<UUID, Integer>> sortedSuggestions = mutualFriendsCount.entrySet()
.stream()
.sorted(Map.Entry.<UUID, Integer>comparingByValue().reversed())
.limit(limit)
.toList();
// Créer les DTOs
List<com.lions.dev.dto.response.users.FriendSuggestionResponseDTO> suggestions = new ArrayList<>();
for (Map.Entry<UUID, Integer> entry : sortedSuggestions) {
Users suggestedUser = usersRepository.findById(entry.getKey());
if (suggestedUser != null) {
String reason = entry.getValue() > 1
? entry.getValue() + " amis en commun"
: "1 ami en commun";
suggestions.add(new com.lions.dev.dto.response.users.FriendSuggestionResponseDTO(
suggestedUser,
entry.getValue(),
reason
));
}
}
// Si pas assez de suggestions, ajouter des utilisateurs récents
if (suggestions.size() < limit) {
int remaining = limit - suggestions.size();
Set<UUID> excludedIds = new HashSet<>(currentFriendIds);
excludedIds.addAll(pendingUserIds);
excludedIds.add(userId);
excludedIds.addAll(mutualFriendsCount.keySet());
// Récupérer des utilisateurs récents qui ne sont pas dans les exclusions
List<Users> recentUsers = usersRepository.findAll()
.stream()
.filter(u -> !excludedIds.contains(u.getId()))
.limit(remaining)
.toList();
for (Users recentUser : recentUsers) {
suggestions.add(new com.lions.dev.dto.response.users.FriendSuggestionResponseDTO(
recentUser,
0,
"Nouvel utilisateur"
));
}
}
logger.info("[LOG] " + suggestions.size() + " suggestions d'amis générées.");
return suggestions;
}
}

View File

@@ -0,0 +1,339 @@
package com.lions.dev.service;
import com.lions.dev.entity.chat.Conversation;
import com.lions.dev.entity.chat.Message;
import com.lions.dev.entity.users.Users;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.ConversationRepository;
import com.lions.dev.repository.MessageRepository;
import com.lions.dev.repository.UsersRepository;
import com.lions.dev.websocket.ChatWebSocket;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Service de gestion des messages et conversations.
*
* Ce service contient la logique métier pour l'envoi de messages,
* la récupération de conversations, et la gestion des messages non lus.
*
* Tous les logs nécessaires pour la traçabilité sont intégrés.
*/
@ApplicationScoped
public class MessageService {
@Inject
MessageRepository messageRepository;
@Inject
ConversationRepository conversationRepository;
@Inject
UsersRepository usersRepository;
@Inject
NotificationService notificationService;
/**
* Envoie un message d'un utilisateur à un autre.
*
* @param senderId L'ID de l'expéditeur
* @param recipientId L'ID du destinataire
* @param content Le contenu du message
* @param messageType Le type de message (text, image, etc.)
* @param mediaUrl L'URL du média (optionnel)
* @return Le message créé
* @throws UserNotFoundException Si l'un des utilisateurs n'existe pas
*/
@Transactional
public Message sendMessage(
UUID senderId,
UUID recipientId,
String content,
String messageType,
String mediaUrl) {
System.out.println("[LOG] Envoi de message de " + senderId + " à " + recipientId);
// Récupérer les utilisateurs
Users sender = usersRepository.findById(senderId);
Users recipient = usersRepository.findById(recipientId);
if (sender == null) {
throw new UserNotFoundException("Expéditeur non trouvé avec l'ID : " + senderId);
}
if (recipient == null) {
throw new UserNotFoundException("Destinataire non trouvé avec l'ID : " + recipientId);
}
// Trouver ou créer la conversation
Conversation conversation = conversationRepository.findOrCreate(sender, recipient);
// Créer le message
Message message = new Message(conversation, sender, content);
message.setMessageType(messageType != null ? messageType : "text");
if (mediaUrl != null && !mediaUrl.isEmpty()) {
message.setMediaUrl(mediaUrl);
}
message.markAsDelivered();
// Persister le message
messageRepository.persist(message);
System.out.println("[LOG] Message créé avec l'ID : " + message.getId());
// Mettre à jour la conversation
conversation.updateLastMessage(message);
conversationRepository.persist(conversation);
// Créer une notification pour le destinataire
try {
String senderName = sender.getPrenoms() + " " + sender.getNom();
String notificationMessage = content.length() > 50
? content.substring(0, 50) + "..."
: content;
notificationService.createNotification(
"Nouveau message de " + senderName,
notificationMessage,
"message",
recipientId,
null
);
System.out.println("[LOG] Notification créée pour le destinataire");
} catch (Exception e) {
System.out.println("[ERROR] Erreur lors de la création de la notification : " + e.getMessage());
}
// TEMPS RÉEL : Envoyer le message via WebSocket au destinataire
try {
Map<String, Object> messageData = new HashMap<>();
messageData.put("id", message.getId().toString());
messageData.put("conversationId", conversation.getId().toString());
messageData.put("senderId", senderId.toString());
messageData.put("senderFirstName", sender.getPrenoms());
messageData.put("senderLastName", sender.getNom());
messageData.put("senderProfileImageUrl", sender.getProfileImageUrl() != null ? sender.getProfileImageUrl() : "");
messageData.put("content", content);
messageData.put("timestamp", message.getCreatedAt().toString());
messageData.put("isRead", message.isRead());
messageData.put("attachmentUrl", mediaUrl != null ? mediaUrl : "");
messageData.put("attachmentType", messageType != null ? messageType : "text");
// Envoyer au destinataire via ChatWebSocket
ChatWebSocket.sendMessageToUser(recipientId, messageData);
System.out.println("[LOG] Message envoyé via WebSocket au destinataire : " + recipientId);
// Envoyer confirmation de délivrance à l'expéditeur
try {
Map<String, Object> deliveryConfirmation = new HashMap<>();
deliveryConfirmation.put("messageId", message.getId().toString());
deliveryConfirmation.put("isDelivered", true);
deliveryConfirmation.put("timestamp", System.currentTimeMillis());
ChatWebSocket.sendDeliveryConfirmation(senderId, deliveryConfirmation);
System.out.println("[LOG] Confirmation de délivrance envoyée à l'expéditeur : " + senderId);
} catch (Exception deliveryEx) {
System.out.println("[ERROR] Erreur envoi confirmation délivrance : " + deliveryEx.getMessage());
// Ne pas bloquer si la confirmation échoue
}
} catch (Exception e) {
System.out.println("[ERROR] Erreur lors de l'envoi du message via WebSocket : " + e.getMessage());
// Ne pas bloquer l'envoi du message si WebSocket échoue
}
return message;
}
/**
* Récupère toutes les conversations d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Liste des conversations
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<Conversation> getUserConversations(UUID userId) {
System.out.println("[LOG] Récupération des conversations pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
return conversationRepository.findByUser(user);
}
/**
* Récupère tous les messages d'une conversation avec pagination.
*
* @param conversationId L'ID de la conversation
* @param page Le numéro de la page
* @param size La taille de la page
* @return Liste paginée des messages
*/
public List<Message> getConversationMessages(UUID conversationId, int page, int size) {
System.out.println("[LOG] Récupération des messages pour la conversation ID : " + conversationId);
return messageRepository.findByConversationId(conversationId, page, size);
}
/**
* Récupère une conversation spécifique.
*
* @param conversationId L'ID de la conversation
* @return La conversation
*/
public Conversation getConversation(UUID conversationId) {
System.out.println("[LOG] Récupération de la conversation ID : " + conversationId);
return conversationRepository.findById(conversationId);
}
/**
* Récupère une conversation entre deux utilisateurs.
*
* @param user1Id L'ID du premier utilisateur
* @param user2Id L'ID du deuxième utilisateur
* @return La conversation ou null si elle n'existe pas
* @throws UserNotFoundException Si l'un des utilisateurs n'existe pas
*/
public Conversation getConversationBetweenUsers(UUID user1Id, UUID user2Id) {
System.out.println("[LOG] Recherche de conversation entre " + user1Id + " et " + user2Id);
Users user1 = usersRepository.findById(user1Id);
Users user2 = usersRepository.findById(user2Id);
if (user1 == null || user2 == null) {
throw new UserNotFoundException("Un ou plusieurs utilisateurs non trouvés");
}
return conversationRepository.findBetweenUsers(user1, user2);
}
/**
* Marque un message comme lu.
*
* @param messageId L'ID du message
* @return Le message mis à jour
*/
@Transactional
public Message markMessageAsRead(UUID messageId) {
System.out.println("[LOG] Marquage du message comme lu : " + messageId);
Message message = messageRepository.findById(messageId);
if (message == null) {
throw new IllegalArgumentException("Message non trouvé avec l'ID : " + messageId);
}
message.markAsRead();
messageRepository.persist(message);
// Envoyer confirmation de lecture à l'expéditeur via WebSocket
try {
// Récupérer le destinataire (l'autre utilisateur de la conversation)
Conversation conversation = message.getConversation();
UUID recipientId = conversation.getUser1().getId().equals(message.getSender().getId())
? conversation.getUser2().getId()
: conversation.getUser1().getId();
Map<String, Object> readConfirmation = new HashMap<>();
readConfirmation.put("messageId", message.getId().toString());
readConfirmation.put("userId", recipientId.toString());
readConfirmation.put("timestamp", java.time.LocalDateTime.now().toString());
// Envoyer via ChatWebSocket avec type "read"
com.lions.dev.websocket.ChatWebSocket.sendReadConfirmation(
message.getSender().getId(),
readConfirmation
);
System.out.println("[LOG] Confirmation de lecture envoyée à l'expéditeur : " + message.getSender().getId());
} catch (Exception e) {
System.out.println("[ERROR] Erreur envoi confirmation lecture : " + e.getMessage());
}
return message;
}
/**
* Marque tous les messages d'une conversation comme lus pour un utilisateur.
*
* @param conversationId L'ID de la conversation
* @param userId L'ID de l'utilisateur
* @return Le nombre de messages marqués comme lus
*/
@Transactional
public int markAllMessagesAsRead(UUID conversationId, UUID userId) {
System.out.println("[LOG] Marquage de tous les messages comme lus pour la conversation " + conversationId);
Conversation conversation = conversationRepository.findById(conversationId);
if (conversation == null) {
throw new IllegalArgumentException("Conversation non trouvée");
}
Users user = usersRepository.findById(userId);
if (user == null) {
throw new UserNotFoundException("Utilisateur non trouvé");
}
// Marquer les messages comme lus
int count = messageRepository.markAllAsRead(conversationId, userId);
// Mettre à jour le compteur de la conversation
conversation.markAllAsReadForUser(user);
conversationRepository.persist(conversation);
return count;
}
/**
* Compte le nombre total de messages non lus pour un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Le nombre de messages non lus
*/
public long getTotalUnreadCount(UUID userId) {
System.out.println("[LOG] Récupération du nombre total de messages non lus pour l'utilisateur " + userId);
return conversationRepository.countTotalUnreadMessages(userId);
}
/**
* Supprime un message.
*
* @param messageId L'ID du message
* @return true si le message a été supprimé
*/
@Transactional
public boolean deleteMessage(UUID messageId) {
System.out.println("[LOG] Suppression du message ID : " + messageId);
Message message = messageRepository.findById(messageId);
if (message == null) {
return false;
}
messageRepository.delete(message);
return true;
}
/**
* Supprime une conversation et tous ses messages.
*
* @param conversationId L'ID de la conversation
* @return true si la conversation a été supprimée
*/
@Transactional
public boolean deleteConversation(UUID conversationId) {
System.out.println("[LOG] Suppression de la conversation ID : " + conversationId);
// Supprimer d'abord tous les messages
messageRepository.deleteByConversationId(conversationId);
// Puis supprimer la conversation
return conversationRepository.deleteConversation(conversationId);
}
}

View File

@@ -0,0 +1,218 @@
package com.lions.dev.service;
import com.lions.dev.entity.events.Events;
import com.lions.dev.entity.notification.Notification;
import com.lions.dev.entity.users.Users;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.EventsRepository;
import com.lions.dev.repository.NotificationRepository;
import com.lions.dev.repository.UsersRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.UUID;
/**
* Service de gestion des notifications.
*
* Ce service contient la logique métier pour la création, récupération,
* mise à jour et suppression des notifications.
*
* Tous les logs nécessaires pour la traçabilité sont intégrés.
*/
@ApplicationScoped
public class NotificationService {
@Inject
NotificationRepository notificationRepository;
@Inject
UsersRepository usersRepository;
@Inject
EventsRepository eventsRepository;
/**
* Récupère toutes les notifications d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Liste des notifications de l'utilisateur
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<Notification> getNotificationsByUserId(UUID userId) {
System.out.println("[LOG] Récupération des notifications pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
List<Notification> notifications = notificationRepository.findByUserId(userId);
System.out.println("[LOG] " + notifications.size() + " notification(s) récupérée(s) pour l'utilisateur ID : " + userId);
return notifications;
}
/**
* Récupère les notifications d'un utilisateur avec pagination.
*
* @param userId L'ID de l'utilisateur
* @param page Le numéro de la page (0-indexé)
* @param size La taille de la page
* @return Liste paginée des notifications
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<Notification> getNotificationsByUserIdWithPagination(UUID userId, int page, int size) {
System.out.println("[LOG] Récupération paginée des notifications pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
return notificationRepository.findByUserIdWithPagination(userId, page, size);
}
/**
* Crée une nouvelle notification.
*
* @param title Le titre de la notification
* @param message Le message de la notification
* @param type Le type de notification (event, friend, reminder, other)
* @param userId L'ID de l'utilisateur destinataire
* @param eventId L'ID de l'événement associé (optionnel)
* @return La notification créée
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
@Transactional
public Notification createNotification(
String title,
String message,
String type,
UUID userId,
UUID eventId) {
System.out.println("[LOG] Création d'une notification : " + title + " pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
Notification notification = new Notification(title, message, type, user);
if (eventId != null) {
Events event = eventsRepository.findById(eventId);
if (event != null) {
notification.setEvent(event);
System.out.println("[LOG] Notification associée à l'événement ID : " + eventId);
}
}
notificationRepository.persist(notification);
System.out.println("[LOG] Notification créée avec succès : " + notification.getId());
return notification;
}
/**
* Marque une notification comme lue.
*
* @param notificationId L'ID de la notification
* @return La notification mise à jour
*/
@Transactional
public Notification markAsRead(UUID notificationId) {
System.out.println("[LOG] Marquage de la notification ID : " + notificationId + " comme lue");
Notification notification = notificationRepository.findById(notificationId);
if (notification == null) {
System.out.println("[ERROR] Notification non trouvée avec l'ID : " + notificationId);
throw new IllegalArgumentException("Notification non trouvée avec l'ID : " + notificationId);
}
notification.markAsRead();
notificationRepository.persist(notification);
System.out.println("[LOG] Notification marquée comme lue avec succès");
return notification;
}
/**
* Marque toutes les notifications d'un utilisateur comme lues.
*
* @param userId L'ID de l'utilisateur
* @return Le nombre de notifications mises à jour
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
@Transactional
public int markAllAsRead(UUID userId) {
System.out.println("[LOG] Marquage de toutes les notifications comme lues pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
int updated = notificationRepository.markAllAsReadByUserId(userId);
System.out.println("[LOG] " + updated + " notification(s) marquée(s) comme lue(s)");
return updated;
}
/**
* Supprime une notification.
*
* @param notificationId L'ID de la notification
* @return true si la notification a été supprimée, false sinon
*/
@Transactional
public boolean deleteNotification(UUID notificationId) {
System.out.println("[LOG] Suppression de la notification ID : " + notificationId);
Notification notification = notificationRepository.findById(notificationId);
if (notification == null) {
System.out.println("[ERROR] Notification non trouvée avec l'ID : " + notificationId);
return false;
}
notificationRepository.delete(notification);
System.out.println("[LOG] Notification supprimée avec succès");
return true;
}
/**
* Récupère une notification par son ID.
*
* @param notificationId L'ID de la notification
* @return La notification trouvée
*/
public Notification getNotificationById(UUID notificationId) {
System.out.println("[LOG] Récupération de la notification ID : " + notificationId);
Notification notification = notificationRepository.findById(notificationId);
if (notification == null) {
System.out.println("[ERROR] Notification non trouvée avec l'ID : " + notificationId);
throw new IllegalArgumentException("Notification non trouvée avec l'ID : " + notificationId);
}
return notification;
}
/**
* Compte le nombre de notifications non lues d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Le nombre de notifications non lues
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public long countUnreadNotifications(UUID userId) {
Users user = usersRepository.findById(userId);
if (user == null) {
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
return notificationRepository.countUnreadByUserId(userId);
}
}

View File

@@ -0,0 +1,122 @@
package com.lions.dev.service;
import com.lions.dev.entity.users.Users;
import com.lions.dev.repository.UsersRepository;
import com.lions.dev.websocket.NotificationWebSocket;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.*;
/**
* Service pour gérer la présence des utilisateurs (online/offline).
*
* Ce service gère:
* - Le marquage des utilisateurs comme en ligne/hors ligne
* - Le heartbeat pour maintenir le statut online
* - La diffusion de la présence aux amis via WebSocket
*/
@ApplicationScoped
public class PresenceService {
@Inject
UsersRepository usersRepository;
/**
* Marque un utilisateur comme en ligne et broadcast sa présence.
*
* @param userId L'ID de l'utilisateur
*/
@Transactional
public void setUserOnline(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.updatePresence();
usersRepository.persist(user);
// Broadcast présence aux autres utilisateurs
broadcastPresenceToAll(userId, true, user.getLastSeen());
System.out.println("[PRESENCE] Utilisateur " + userId + " marqué online");
}
}
/**
* Marque un utilisateur comme hors ligne.
*
* @param userId L'ID de l'utilisateur
*/
@Transactional
public void setUserOffline(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.setOffline();
usersRepository.persist(user);
// Broadcast présence aux autres utilisateurs
broadcastPresenceToAll(userId, false, user.getLastSeen());
System.out.println("[PRESENCE] Utilisateur " + userId + " marqué offline");
}
}
/**
* Met à jour le heartbeat d'un utilisateur (keep-alive).
*
* @param userId L'ID de l'utilisateur
*/
@Transactional
public void heartbeat(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.updatePresence();
usersRepository.persist(user);
System.out.println("[PRESENCE] Heartbeat reçu pour utilisateur " + userId);
}
}
/**
* Broadcast la présence d'un utilisateur à tous les utilisateurs connectés via WebSocket.
*
* @param userId L'ID de l'utilisateur
* @param isOnline Le statut online
* @param lastSeen La dernière fois que l'utilisateur était en ligne
*/
private void broadcastPresenceToAll(UUID userId, boolean isOnline, LocalDateTime lastSeen) {
try {
Map<String, Object> presenceData = new HashMap<>();
presenceData.put("userId", userId.toString());
presenceData.put("isOnline", isOnline);
presenceData.put("lastSeen", lastSeen != null ? lastSeen.toString() : null);
presenceData.put("timestamp", System.currentTimeMillis());
// Envoyer via NotificationWebSocket
NotificationWebSocket.broadcastPresenceUpdate(presenceData);
System.out.println("[PRESENCE] Broadcast de la présence de " + userId + " : " + isOnline);
} catch (Exception e) {
System.out.println("[ERROR] Erreur lors du broadcast de présence : " + e.getMessage());
}
}
/**
* Récupère le statut de présence d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Map contenant isOnline et lastSeen
*/
public Map<String, Object> getUserPresence(UUID userId) {
Users user = usersRepository.findById(userId);
Map<String, Object> presence = new HashMap<>();
if (user != null) {
presence.put("userId", userId.toString());
presence.put("isOnline", user.isOnline());
presence.put("lastSeen", user.getLastSeen() != null ? user.getLastSeen().toString() : null);
}
return presence;
}
}

View File

@@ -0,0 +1,308 @@
package com.lions.dev.service;
import com.lions.dev.entity.friends.Friendship;
import com.lions.dev.entity.friends.FriendshipStatus;
import com.lions.dev.entity.social.SocialPost;
import com.lions.dev.entity.users.Users;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.FriendshipRepository;
import com.lions.dev.repository.SocialPostRepository;
import com.lions.dev.repository.UsersRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Service de gestion des posts sociaux.
*
* Ce service contient la logique métier pour la création, récupération,
* mise à jour et suppression des posts sociaux.
*
* Tous les logs nécessaires pour la traçabilité sont intégrés.
*/
@ApplicationScoped
public class SocialPostService {
@Inject
SocialPostRepository socialPostRepository;
@Inject
UsersRepository usersRepository;
@Inject
FriendshipRepository friendshipRepository;
@Inject
NotificationService notificationService;
/**
* Récupère tous les posts avec pagination.
*
* @param page Le numéro de la page (0-indexé)
* @param size La taille de la page
* @return Liste paginée des posts
*/
public List<SocialPost> getAllPosts(int page, int size) {
System.out.println("[LOG] Récupération de tous les posts (page: " + page + ", size: " + size + ")");
return socialPostRepository.findAllWithPagination(page, size);
}
/**
* Récupère tous les posts d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Liste des posts de l'utilisateur
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<SocialPost> getPostsByUserId(UUID userId) {
System.out.println("[LOG] Récupération des posts pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
return socialPostRepository.findByUserId(userId);
}
/**
* Crée un nouveau post social.
*
* @param content Le contenu du post
* @param userId L'ID de l'utilisateur créateur
* @param imageUrl L'URL de l'image (optionnel)
* @return Le post créé
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
@Transactional
public SocialPost createPost(String content, UUID userId, String imageUrl) {
System.out.println("[LOG] Création d'un post par l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
SocialPost post = new SocialPost(content, user);
if (imageUrl != null && !imageUrl.isEmpty()) {
post.setImageUrl(imageUrl);
}
socialPostRepository.persist(post);
System.out.println("[LOG] Post créé avec succès : " + post.getId());
// Créer des notifications pour tous les amis
try {
List<Friendship> friendships = friendshipRepository.findFriendsByUser(user, 0, Integer.MAX_VALUE);
String userName = user.getPrenoms() + " " + user.getNom();
for (Friendship friendship : friendships) {
Users friend = friendship.getUser().equals(user)
? friendship.getFriend()
: friendship.getUser();
String notificationTitle = "Nouveau post de " + userName;
String notificationMessage = userName + " a publié un nouveau post : " +
(content.length() > 50 ? content.substring(0, 50) + "..." : content);
notificationService.createNotification(
notificationTitle,
notificationMessage,
"post",
friend.getId(),
null
);
}
System.out.println("[LOG] Notifications créées pour " + friendships.size() + " ami(s)");
} catch (Exception e) {
System.out.println("[ERROR] Erreur lors de la création des notifications : " + e.getMessage());
}
return post;
}
/**
* Récupère un post par son ID.
*
* @param postId L'ID du post
* @return Le post trouvé
*/
public SocialPost getPostById(UUID postId) {
System.out.println("[LOG] Récupération du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
return post;
}
/**
* Met à jour un post.
*
* @param postId L'ID du post
* @param content Le nouveau contenu
* @param imageUrl La nouvelle URL d'image (optionnel)
* @return Le post mis à jour
*/
@Transactional
public SocialPost updatePost(UUID postId, String content, String imageUrl) {
System.out.println("[LOG] Mise à jour du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.setContent(content);
if (imageUrl != null) {
post.setImageUrl(imageUrl);
}
socialPostRepository.persist(post);
System.out.println("[LOG] Post mis à jour avec succès");
return post;
}
/**
* Supprime un post.
*
* @param postId L'ID du post
* @return true si le post a été supprimé, false sinon
*/
@Transactional
public boolean deletePost(UUID postId) {
System.out.println("[LOG] Suppression du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
return false;
}
socialPostRepository.delete(post);
System.out.println("[LOG] Post supprimé avec succès");
return true;
}
/**
* Recherche des posts par contenu.
*
* @param query Le terme de recherche
* @return Liste des posts correspondant à la recherche
*/
public List<SocialPost> searchPosts(String query) {
System.out.println("[LOG] Recherche de posts avec la requête : " + query);
return socialPostRepository.searchByContent(query);
}
/**
* Like un post (incrémente le compteur de likes).
*
* @param postId L'ID du post
* @return Le post mis à jour
*/
@Transactional
public SocialPost likePost(UUID postId) {
System.out.println("[LOG] Like du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementLikes();
socialPostRepository.persist(post);
return post;
}
/**
* Ajoute un commentaire à un post (incrémente le compteur de commentaires).
*
* @param postId L'ID du post
* @return Le post mis à jour
*/
@Transactional
public SocialPost addComment(UUID postId) {
System.out.println("[LOG] Ajout de commentaire au post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementComments();
socialPostRepository.persist(post);
return post;
}
/**
* Partage un post (incrémente le compteur de partages).
*
* @param postId L'ID du post
* @return Le post mis à jour
*/
@Transactional
public SocialPost sharePost(UUID postId) {
System.out.println("[LOG] Partage du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
System.out.println("[ERROR] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementShares();
socialPostRepository.persist(post);
return post;
}
/**
* Récupère les posts de l'utilisateur et de ses amis (relations d'amitié acceptées).
*
* @param userId L'ID de l'utilisateur
* @param page Le numéro de la page (0-indexé)
* @param size La taille de la page
* @return Liste paginée des posts de l'utilisateur et de ses amis
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<SocialPost> getPostsByFriends(UUID userId, int page, int size) {
System.out.println("[LOG] Récupération des posts des amis pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
// Récupérer toutes les relations d'amitié acceptées
List<Friendship> friendships = friendshipRepository.findFriendsByUser(user, 0, Integer.MAX_VALUE);
// Extraire les IDs des amis
List<UUID> friendIds = friendships.stream()
.map(friendship -> {
// L'ami est soit dans 'user' soit dans 'friend', selon qui a initié la relation
return friendship.getUser().equals(user)
? friendship.getFriend().getId()
: friendship.getUser().getId();
})
.distinct()
.collect(Collectors.toList());
System.out.println("[LOG] " + friendIds.size() + " ami(s) trouvé(s) pour l'utilisateur ID : " + userId);
// Récupérer les posts de l'utilisateur et de ses amis
return socialPostRepository.findPostsByFriends(userId, friendIds, page, size);
}
}

View File

@@ -0,0 +1,212 @@
package com.lions.dev.service;
import com.lions.dev.entity.story.MediaType;
import com.lions.dev.entity.story.Story;
import com.lions.dev.entity.users.Users;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.StoryRepository;
import com.lions.dev.repository.UsersRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.UUID;
/**
* Service de gestion des stories.
*
* Ce service contient la logique métier pour la création, récupération,
* mise à jour et suppression des stories.
*
* Tous les logs nécessaires pour la traçabilité sont intégrés.
*/
@ApplicationScoped
public class StoryService {
@Inject
StoryRepository storyRepository;
@Inject
UsersRepository usersRepository;
/**
* Récupère toutes les stories actives (non expirées).
*
* @return Liste des stories actives
*/
public List<Story> getAllActiveStories() {
System.out.println("[LOG] Récupération de toutes les stories actives");
return storyRepository.findAllActive();
}
/**
* Récupère toutes les stories actives d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Liste des stories actives de l'utilisateur
* @throws UserNotFoundException Si l'utilisateur n'existe pas
*/
public List<Story> getActiveStoriesByUserId(UUID userId) {
System.out.println("[LOG] Récupération des stories actives pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
return storyRepository.findActiveByUserId(userId);
}
/**
* Crée une nouvelle story.
*
* @param userId L'ID de l'utilisateur créateur
* @param mediaType Le type de média (IMAGE ou VIDEO)
* @param mediaUrl L'URL du média
* @param thumbnailUrl L'URL du thumbnail (optionnel, pour les vidéos)
* @param durationSeconds La durée en secondes (optionnel, pour les vidéos)
* @return La story créée
* @throws UserNotFoundException Si l'utilisateur n'existe pas
* @throws IllegalArgumentException Si les paramètres sont invalides
*/
@Transactional
public Story createStory(UUID userId, MediaType mediaType, String mediaUrl, String thumbnailUrl, Integer durationSeconds) {
System.out.println("[LOG] Création d'une story par l'utilisateur ID : " + userId);
// Validation de l'utilisateur
Users user = usersRepository.findById(userId);
if (user == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + userId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId);
}
// Validation des paramètres
if (mediaUrl == null || mediaUrl.trim().isEmpty()) {
System.out.println("[ERROR] L'URL du média est obligatoire");
throw new IllegalArgumentException("L'URL du média est obligatoire");
}
if (mediaType == null) {
System.out.println("[ERROR] Le type de média est obligatoire");
throw new IllegalArgumentException("Le type de média est obligatoire");
}
// Création de la story
Story story = new Story(user, mediaType, mediaUrl);
if (thumbnailUrl != null && !thumbnailUrl.trim().isEmpty()) {
story.setThumbnailUrl(thumbnailUrl);
}
if (durationSeconds != null && durationSeconds > 0) {
story.setDurationSeconds(durationSeconds);
}
storyRepository.persist(story);
System.out.println("[LOG] Story créée avec succès : " + story.getId());
return story;
}
/**
* Récupère une story par son ID.
*
* @param storyId L'ID de la story
* @return La story trouvée
* @throws IllegalArgumentException Si la story n'existe pas
*/
public Story getStoryById(UUID storyId) {
System.out.println("[LOG] Récupération de la story ID : " + storyId);
Story story = storyRepository.findById(storyId);
if (story == null) {
System.out.println("[ERROR] Story non trouvée avec l'ID : " + storyId);
throw new IllegalArgumentException("Story non trouvée avec l'ID : " + storyId);
}
return story;
}
/**
* Marque une story comme vue par un utilisateur.
*
* @param storyId L'ID de la story
* @param viewerId L'ID de l'utilisateur qui voit la story
* @return La story mise à jour
* @throws UserNotFoundException Si l'utilisateur n'existe pas
* @throws IllegalArgumentException Si la story n'existe pas
*/
@Transactional
public Story markStoryAsViewed(UUID storyId, UUID viewerId) {
System.out.println("[LOG] Marquage de la story ID : " + storyId + " comme vue par l'utilisateur ID : " + viewerId);
// Validation de l'utilisateur
Users viewer = usersRepository.findById(viewerId);
if (viewer == null) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'ID : " + viewerId);
throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + viewerId);
}
// Validation de la story
Story story = storyRepository.findById(storyId);
if (story == null) {
System.out.println("[ERROR] Story non trouvée avec l'ID : " + storyId);
throw new IllegalArgumentException("Story non trouvée avec l'ID : " + storyId);
}
// Marquer comme vue
boolean isNewView = story.markAsViewed(viewerId);
if (isNewView) {
storyRepository.persist(story);
System.out.println("[LOG] Story marquée comme vue (nouvelle vue)");
} else {
System.out.println("[LOG] Story déjà vue par cet utilisateur");
}
return story;
}
/**
* Supprime une story.
*
* @param storyId L'ID de la story
* @return true si la story a été supprimée, false sinon
*/
@Transactional
public boolean deleteStory(UUID storyId) {
System.out.println("[LOG] Suppression de la story ID : " + storyId);
Story story = storyRepository.findById(storyId);
if (story == null) {
System.out.println("[ERROR] Story non trouvée avec l'ID : " + storyId);
return false;
}
storyRepository.delete(story);
System.out.println("[LOG] Story supprimée avec succès");
return true;
}
/**
* Désactive toutes les stories expirées.
* Cette méthode doit être appelée périodiquement par un job schedulé.
*
* @return Le nombre de stories désactivées
*/
@Transactional
public int deactivateExpiredStories() {
System.out.println("[LOG] Désactivation des stories expirées");
return storyRepository.deactivateExpiredStories();
}
/**
* Récupère les stories les plus vues.
*
* @param limit Le nombre maximum de stories à retourner
* @return Liste des stories les plus vues
*/
public List<Story> getMostViewedStories(int limit) {
System.out.println("[LOG] Récupération des " + limit + " stories les plus vues");
return storyRepository.findMostViewedStories(limit);
}
}

View File

@@ -191,4 +191,21 @@ public class UsersService {
}
return deleted;
}
/**
* Recherche un utilisateur par son email.
*
* @param email L'email de l'utilisateur à rechercher.
* @return L'utilisateur trouvé.
* @throws UserNotFoundException Si l'utilisateur n'est pas trouvé.
*/
public Users getUserByEmail(String email) {
Optional<Users> userOptional = usersRepository.findByEmail(email);
if (userOptional.isEmpty()) {
System.out.println("[ERROR] Utilisateur non trouvé avec l'email : " + email);
throw new UserNotFoundException("Utilisateur non trouvé avec l'email : " + email);
}
System.out.println("[LOG] Utilisateur trouvé avec l'email : " + email);
return userOptional.get();
}
}