diff --git a/backend/src/main/java/online/wesal/wesal/repository/UserRepository.java b/backend/src/main/java/online/wesal/wesal/repository/UserRepository.java index d9013c0..308181e 100644 --- a/backend/src/main/java/online/wesal/wesal/repository/UserRepository.java +++ b/backend/src/main/java/online/wesal/wesal/repository/UserRepository.java @@ -2,8 +2,11 @@ package online.wesal.wesal.repository; import online.wesal.wesal.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -12,4 +15,7 @@ public interface UserRepository extends JpaRepository { Optional findByUsername(String username); boolean existsByEmail(String email); boolean existsByUsername(String username); + + @Query("SELECT u FROM User u WHERE u.subscriptions LIKE %:subscription% AND u.fcmToken IS NOT NULL AND u.fcmToken != ''") + List findUsersSubscribedTo(@Param("subscription") String subscription); } \ No newline at end of file diff --git a/backend/src/main/java/online/wesal/wesal/service/InvitationService.java b/backend/src/main/java/online/wesal/wesal/service/InvitationService.java index ac9638c..3617d8b 100644 --- a/backend/src/main/java/online/wesal/wesal/service/InvitationService.java +++ b/backend/src/main/java/online/wesal/wesal/service/InvitationService.java @@ -38,6 +38,9 @@ public class InvitationService { @Autowired private FCMNotificationService fcmNotificationService; + @Autowired + private SubscriptionNotificationService subscriptionNotificationService; + @Transactional public InvitationResponse createInvitation(CreateInvitationRequest request, String userEmail) { User creator = userRepository.findByEmail(userEmail) @@ -58,6 +61,15 @@ public class InvitationService { invitation.setLocation(request.getLocation()); Invitation saved = invitationRepository.save(invitation); + + // Send notification to users subscribed to "newinvites" + String title = "New Invitation! \uD83C\uDF89"; + String body = String.format("%s is looking for people to join them for %s: %s", + creator.getDisplayName(), + tag.getName(), + saved.getTitle()); + subscriptionNotificationService.sendNotificationToSubscription("newinvites", title, body); + return mapToResponse(saved); } diff --git a/backend/src/main/java/online/wesal/wesal/service/SubscriptionNotificationService.java b/backend/src/main/java/online/wesal/wesal/service/SubscriptionNotificationService.java new file mode 100644 index 0000000..5ebcf4f --- /dev/null +++ b/backend/src/main/java/online/wesal/wesal/service/SubscriptionNotificationService.java @@ -0,0 +1,77 @@ +package online.wesal.wesal.service; + +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.MulticastMessage; +import com.google.firebase.messaging.Notification; +import com.google.firebase.messaging.BatchResponse; +import online.wesal.wesal.entity.User; +import online.wesal.wesal.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class SubscriptionNotificationService { + + private static final Logger logger = LoggerFactory.getLogger(SubscriptionNotificationService.class); + + @Autowired + private UserRepository userRepository; + + @Async + public void sendNotificationToSubscription(String subscriptionName, String title, String body) { + try { + // Get all users subscribed to the given subscription + List subscribedUsers = userRepository.findUsersSubscribedTo(subscriptionName); + + if (subscribedUsers.isEmpty()) { + logger.info("No users found subscribed to '{}'", subscriptionName); + return; + } + + // Extract FCM tokens from subscribed users + List tokens = subscribedUsers.stream() + .map(User::getFcmToken) + .filter(token -> token != null && !token.trim().isEmpty()) + .collect(Collectors.toList()); + + if (tokens.isEmpty()) { + logger.warn("No valid FCM tokens found for subscription '{}'", subscriptionName); + return; + } + + // Create multicast message + MulticastMessage message = MulticastMessage.builder() + .setNotification(Notification.builder() + .setTitle(title) + .setBody(body) + .build()) + .addAllTokens(tokens) + .build(); + + // Send the multicast message + BatchResponse response = FirebaseMessaging.getInstance().sendEachForMulticast(message); + + logger.info("Successfully sent notifications for subscription '{}': {} successful, {} failed", + subscriptionName, response.getSuccessCount(), response.getFailureCount()); + + // Log any failures for debugging + if (response.getFailureCount() > 0) { + for (int i = 0; i < response.getResponses().size(); i++) { + if (!response.getResponses().get(i).isSuccessful()) { + logger.error("Failed to send notification to token {}: {}", + tokens.get(i), response.getResponses().get(i).getException().getMessage()); + } + } + } + + } catch (Exception e) { + logger.error("Failed to send notifications for subscription '{}': {}", subscriptionName, e.getMessage(), e); + } + } +} \ No newline at end of file