package de.oaa.xxx.social; import de.oaa.xxx.mail.Email; import de.oaa.xxx.mail.MailService; import de.oaa.xxx.mail.MailTemplateService; import org.springframework.beans.factory.annotation.Value; import de.oaa.xxx.social.entity.MessageCause; import de.oaa.xxx.social.entity.MessageEntity; import de.oaa.xxx.social.entity.NotificationPreferenceEntity; import de.oaa.xxx.social.repository.MessageRepository; import de.oaa.xxx.social.repository.NotificationPreferenceRepository; import de.oaa.xxx.user.UserRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.Map; import java.util.UUID; @Service public class SystemMessageService { private static final Logger LOGGER = LoggerFactory.getLogger(SystemMessageService.class); private final MessageRepository messageRepository; private final NotificationPreferenceRepository preferenceRepository; private final UserRepository userRepository; private final SseService sseService; private final MailService mailService; private final MailTemplateService mailTemplateService; @Value("${app.base-url:http://localhost:8080}") private String baseUrl; public SystemMessageService(MessageRepository messageRepository, NotificationPreferenceRepository preferenceRepository, UserRepository userRepository, SseService sseService, MailService mailService, MailTemplateService mailTemplateService) { this.messageRepository = messageRepository; this.preferenceRepository = preferenceRepository; this.userRepository = userRepository; this.sseService = sseService; this.mailService = mailService; this.mailTemplateService = mailTemplateService; } /** * Sendet eine Systemnachricht unter Berücksichtigung der Benachrichtigungseinstellungen des Empfängers. */ public void send(UUID senderId, UUID receiverId, String text, String targetUrl, MessageCause cause) { if (senderId == null || receiverId == null) return; NotificationPreferenceEntity pref = preferenceRepository .findByUserIdAndCause(receiverId, cause) .orElseGet(() -> NotificationPreferenceEntity.defaultFor(receiverId, cause)); // Diese Causes sind immer nur in-app, kein E-Mail boolean sendInApp = cause == MessageCause.FRIENDREQUEST || cause == MessageCause.INVITATION || cause == MessageCause.DATE_INTEREST || cause == MessageCause.LOCATION_MESSAGE || pref.isInApp(); if (sendInApp) { MessageEntity msg = new MessageEntity(); msg.setMessageId(UUID.randomUUID()); msg.setSenderId(senderId); msg.setReceiverId(receiverId); msg.setText(text); msg.setSentAt(LocalDateTime.now()); msg.setSystemMessage(true); msg.setMessageCause(cause); if (targetUrl != null) msg.setTargetUrl(targetUrl); messageRepository.save(msg); long unread = messageRepository.countByReceiverIdAndSystemMessageAndReadAtIsNull(receiverId, true); sseService.push(receiverId, "NOTIFICATION", Map.of("unreadCount", unread, "text", text)); } if (pref.isEmail() && cause != MessageCause.INVITATION && cause != MessageCause.DATE_INTEREST) { userRepository.findById(receiverId).ifPresent(user -> { try { Email email = new Email(); email.setEmailAdresse(user.getEmail()); email.setTitel(causeTitel(cause)); email.setText(mailTemplateService.buildNotificationMail(user.getName(), text, targetUrl, baseUrl)); mailService.send(email); } catch (Exception e) { LOGGER.error("E-Mail-Benachrichtigung fehlgeschlagen für userId={}: {}", receiverId, e.getMessage()); } }); } } /** * Benachrichtigt den Empfänger per SSE, dass sich seine Einladungsliste geändert hat, * ohne eine In-App-Nachricht oder E-Mail zu erstellen. */ public void pushInvitationUpdate(UUID receiverId) { if (receiverId == null) return; sseService.push(receiverId, "INVITATION", java.util.Map.of()); } private String causeTitel(MessageCause cause) { return switch (cause) { case INVITATION -> "XXX The Game – Neue Einladung"; case GAME_STATE -> "XXX The Game – Spielstatus-Änderung"; case EMERGENCY -> "XXX The Game – ⚠️ Notfall"; case FRIENDREQUEST -> "XXX The Game – Neue Freundschaftsanfrage"; case SUPPORT -> "xXx Sphere – Nachricht vom Support"; case DATE_INTEREST -> "xXx Sphere – Interesse an deinem Date"; case EVENT_CANCELLED -> "xXx Sphere – Veranstaltung abgesagt"; case LOCATION_MESSAGE -> "xXx Sphere – Neue Nachricht an deine Location"; }; } }