Files
afterwork-server-impl-quarkus/src/main/java/com/lions/dev/service/SocialPostService.java
2026-01-31 16:54:46 +00:00

438 lines
15 KiB
Java

package com.lions.dev.service;
import com.lions.dev.entity.friends.Friendship;
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 com.lions.dev.dto.events.ReactionEvent;
import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.jboss.logging.Logger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.
*/
@ApplicationScoped
public class SocialPostService {
private static final Logger logger = Logger.getLogger(SocialPostService.class);
@Inject
SocialPostRepository socialPostRepository;
@Inject
UsersRepository usersRepository;
@Inject
FriendshipRepository friendshipRepository;
@Inject
NotificationService notificationService;
@Inject
@Channel("reactions")
Emitter<ReactionEvent> reactionEmitter; // v2.0 - Publie dans Kafka
/**
* 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) {
logger.info("[SocialPostService] 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) {
logger.info("[SocialPostService] Récupération des posts pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
logger.error("[SocialPostService] 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) {
logger.info("[SocialPostService] Création d'un post par l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
logger.error("[SocialPostService] 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);
logger.info("[SocialPostService] 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);
// v2.0 - Utiliser les nouveaux noms de champs
String userName = user.getFirstName() + " " + user.getLastName();
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
);
}
logger.info("[SocialPostService] Notifications créées pour " + friendships.size() + " ami(s)");
} catch (Exception e) {
logger.error("[SocialPostService] 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) {
logger.info("[SocialPostService] Récupération du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] 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) {
logger.info("[SocialPostService] Mise à jour du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] 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);
logger.info("[SocialPostService] 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) {
logger.info("[SocialPostService] Suppression du post ID : " + postId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] Post non trouvé avec l'ID : " + postId);
return false;
}
socialPostRepository.delete(post);
logger.info("[SocialPostService] 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) {
logger.info("[SocialPostService] 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
* @param userId L'ID de l'utilisateur qui like (v2.0)
* @return Le post mis à jour
*/
@Transactional
public SocialPost likePost(UUID postId, UUID userId) {
logger.info("[SocialPostService] Like du post ID : " + postId + " par utilisateur : " + userId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementLikes();
socialPostRepository.persist(post);
// Notification pour l'auteur du post (sauf auto-like)
try {
Users author = post.getUser();
if (author != null && !author.getId().equals(userId)) {
Users liker = usersRepository.findById(userId);
String likerName = liker != null ? liker.getFirstName() + " " + liker.getLastName() : "Quelqu'un";
notificationService.createNotification(
"Nouveau like",
likerName + " a aimé votre post",
"post",
author.getId(),
null
);
}
} catch (Exception e) {
logger.error("[SocialPostService] Erreur création notification like : " + e.getMessage());
}
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Map<String, Object> reactionData = new HashMap<>();
reactionData.put("ownerId", post.getUser().getId().toString()); // Propriétaire du post
reactionData.put("likesCount", post.getLikesCount());
reactionData.put("postTitle", post.getContent().length() > 50
? post.getContent().substring(0, 50) + "..."
: post.getContent());
ReactionEvent event = new ReactionEvent(
postId.toString(), // targetId
"post", // targetType
userId.toString(), // userId qui réagit
"like", // reactionType
reactionData
);
reactionEmitter.send(event);
logger.info("[SocialPostService] Réaction like publiée dans Kafka pour post: " + postId);
} catch (Exception e) {
logger.error("[SocialPostService] Erreur publication Kafka: " + e.getMessage());
// Ne pas bloquer le like si Kafka échoue
}
return post;
}
/**
* Ajoute un commentaire à un post (incrémente le compteur de commentaires).
*
* @param postId L'ID du post
* @param userId L'ID de l'utilisateur qui commente (v2.0)
* @param commentContent Le contenu du commentaire (v2.0)
* @return Le post mis à jour
*/
@Transactional
public SocialPost addComment(UUID postId, UUID userId, String commentContent) {
logger.info("[SocialPostService] Ajout de commentaire au post ID : " + postId + " par utilisateur : " + userId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementComments();
socialPostRepository.persist(post);
// Notification pour l'auteur du post (sauf auto-commentaire)
try {
Users author = post.getUser();
if (author != null && !author.getId().equals(userId)) {
Users commenter = usersRepository.findById(userId);
String commenterName = commenter != null ? commenter.getFirstName() + " " + commenter.getLastName() : "Quelqu'un";
String preview = commentContent != null && commentContent.length() > 60
? commentContent.substring(0, 60) + "..."
: (commentContent != null ? commentContent : "");
notificationService.createNotification(
"Nouveau commentaire",
commenterName + " a commenté votre post : " + preview,
"post",
author.getId(),
null
);
}
} catch (Exception e) {
logger.error("[SocialPostService] Erreur création notification commentaire : " + e.getMessage());
}
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Users commenter = usersRepository.findById(userId);
Map<String, Object> reactionData = new HashMap<>();
reactionData.put("ownerId", post.getUser().getId().toString()); // Propriétaire du post
reactionData.put("commentsCount", post.getCommentsCount());
reactionData.put("commentContent", commentContent != null && commentContent.length() > 100
? commentContent.substring(0, 100) + "..."
: commentContent);
reactionData.put("commenterName", commenter != null
? commenter.getFirstName() + " " + commenter.getLastName()
: "Utilisateur");
ReactionEvent event = new ReactionEvent(
postId.toString(), // targetId
"post", // targetType
userId.toString(), // userId qui commente
"comment", // reactionType
reactionData
);
reactionEmitter.send(event);
logger.info("[SocialPostService] Réaction comment publiée dans Kafka pour post: " + postId);
} catch (Exception e) {
logger.error("[SocialPostService] Erreur publication Kafka: " + e.getMessage());
// Ne pas bloquer le commentaire si Kafka échoue
}
return post;
}
/**
* Partage un post (incrémente le compteur de partages).
*
* @param postId L'ID du post
* @param userId L'ID de l'utilisateur qui partage (v2.0)
* @return Le post mis à jour
*/
@Transactional
public SocialPost sharePost(UUID postId, UUID userId) {
logger.info("[SocialPostService] Partage du post ID : " + postId + " par utilisateur : " + userId);
SocialPost post = socialPostRepository.findById(postId);
if (post == null) {
logger.error("[SocialPostService] Post non trouvé avec l'ID : " + postId);
throw new IllegalArgumentException("Post non trouvé avec l'ID : " + postId);
}
post.incrementShares();
socialPostRepository.persist(post);
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Map<String, Object> reactionData = new HashMap<>();
reactionData.put("ownerId", post.getUser().getId().toString()); // Propriétaire du post
reactionData.put("sharesCount", post.getSharesCount());
ReactionEvent event = new ReactionEvent(
postId.toString(), // targetId
"post", // targetType
userId.toString(), // userId qui partage
"share", // reactionType
reactionData
);
reactionEmitter.send(event);
logger.info("[SocialPostService] Réaction share publiée dans Kafka pour post: " + postId);
} catch (Exception e) {
logger.error("[SocialPostService] Erreur publication Kafka: " + e.getMessage());
// Ne pas bloquer le partage si Kafka échoue
}
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) {
logger.info("[SocialPostService] Récupération des posts des amis pour l'utilisateur ID : " + userId);
Users user = usersRepository.findById(userId);
if (user == null) {
logger.error("[SocialPostService] 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("[SocialPostService] " + 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);
}
}