From 40c919348f1d6772a0b00c087f3cc7ee88c6f5c9 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:53:43 +0800 Subject: [PATCH] feat: improve push notifications --- open-isle-cli/public/notifications-sw.js | 24 +++++++++++++---- .../openisle/service/NotificationService.java | 27 +++++++++++++++++-- .../com/openisle/service/ReactionService.java | 14 +++++++--- .../service/NotificationServiceTest.java | 20 +++++++++----- .../openisle/service/ReactionServiceTest.java | 1 + 5 files changed, 69 insertions(+), 17 deletions(-) diff --git a/open-isle-cli/public/notifications-sw.js b/open-isle-cli/public/notifications-sw.js index bc6378131..1d8aacc13 100644 --- a/open-isle-cli/public/notifications-sw.js +++ b/open-isle-cli/public/notifications-sw.js @@ -1,9 +1,23 @@ self.addEventListener('push', function(event) { - const data = event.data ? event.data.text() : 'New notification'; + let payload = { body: 'New notification', url: '/' } + try { + if (event.data) payload = JSON.parse(event.data.text()) + } catch (e) { + if (event.data) payload.body = event.data.text() + } event.waitUntil( self.registration.showNotification('OpenIsle', { - body: data, - icon: '/favicon.ico' + body: payload.body, + icon: '/favicon.ico', + data: { url: payload.url } }) - ); -}); + ) +}) + +self.addEventListener('notificationclick', function(event) { + const url = event.notification.data && event.notification.data.url + event.notification.close() + if (url) { + event.waitUntil(clients.openWindow(url)) + } +}) diff --git a/src/main/java/com/openisle/service/NotificationService.java b/src/main/java/com/openisle/service/NotificationService.java index a4b805fc9..371879430 100644 --- a/src/main/java/com/openisle/service/NotificationService.java +++ b/src/main/java/com/openisle/service/NotificationService.java @@ -7,6 +7,8 @@ import lombok.RequiredArgsConstructor; import com.openisle.service.EmailSender; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; import java.util.List; @@ -22,6 +24,21 @@ public class NotificationService { @Value("${app.website-url}") private String websiteUrl; + private String buildPayload(String body, String url) { + try { + return new ObjectMapper().writeValueAsString(Map.of( + "body", body, + "url", url + )); + } catch (Exception e) { + return body; + } + } + + public void sendCustomPush(User user, String body, String url) { + pushNotificationService.sendNotification(user, buildPayload(body, url)); + } + public Notification createNotification(User user, NotificationType type, Post post, Comment comment, Boolean approved) { return createNotification(user, type, post, comment, approved, null, null, null); } @@ -38,10 +55,16 @@ public class NotificationService { n.setReactionType(reactionType); n.setContent(content); n = notificationRepository.save(n); - pushNotificationService.sendNotification(user, "You have a new notification"); + + String body = "You have a new notification"; + String url = websiteUrl + "/messages"; + if (type == NotificationType.COMMENT_REPLY && post != null && comment != null) { + body = "有人回复了你"; + url = String.format("%s/posts/%d#comment-%d", websiteUrl, post.getId(), comment.getId()); + } + sendCustomPush(user, body, url); if (type == NotificationType.COMMENT_REPLY && user.getEmail() != null && post != null && comment != null) { - String url = String.format("%s/posts/%d#comment-%d", websiteUrl, post.getId(), comment.getId()); emailSender.sendEmail(user.getEmail(), "【OpenIsle】有人回复了你", url); } diff --git a/src/main/java/com/openisle/service/ReactionService.java b/src/main/java/com/openisle/service/ReactionService.java index b752b828a..deb7cc1b6 100644 --- a/src/main/java/com/openisle/service/ReactionService.java +++ b/src/main/java/com/openisle/service/ReactionService.java @@ -48,9 +48,12 @@ public class ReactionService { if (!user.getId().equals(post.getAuthor().getId())) { notificationService.createNotification(post.getAuthor(), NotificationType.REACTION, post, null, null, user, type, null); long count = reactionRepository.countReceived(post.getAuthor().getUsername()); - if (count % 5 == 0 && post.getAuthor().getEmail() != null) { + if (count % 5 == 0) { String url = websiteUrl + "/messages"; - emailSender.sendEmail(post.getAuthor().getEmail(), "【OpenIsle】你有新的互动", url); + notificationService.sendCustomPush(post.getAuthor(), "你有新的互动", url); + if (post.getAuthor().getEmail() != null) { + emailSender.sendEmail(post.getAuthor().getEmail(), "【OpenIsle】你有新的互动", url); + } } } return reaction; @@ -76,9 +79,12 @@ public class ReactionService { if (!user.getId().equals(comment.getAuthor().getId())) { notificationService.createNotification(comment.getAuthor(), NotificationType.REACTION, comment.getPost(), comment, null, user, type, null); long count = reactionRepository.countReceived(comment.getAuthor().getUsername()); - if (count % 5 == 0 && comment.getAuthor().getEmail() != null) { + if (count % 5 == 0) { String url = websiteUrl + "/messages"; - emailSender.sendEmail(comment.getAuthor().getEmail(), "【OpenIsle】你有新的互动", url); + notificationService.sendCustomPush(comment.getAuthor(), "你有新的互动", url); + if (comment.getAuthor().getEmail() != null) { + emailSender.sendEmail(comment.getAuthor().getEmail(), "【OpenIsle】你有新的互动", url); + } } } return reaction; diff --git a/src/test/java/com/openisle/service/NotificationServiceTest.java b/src/test/java/com/openisle/service/NotificationServiceTest.java index 82bcd12e3..1dca76b33 100644 --- a/src/test/java/com/openisle/service/NotificationServiceTest.java +++ b/src/test/java/com/openisle/service/NotificationServiceTest.java @@ -3,6 +3,7 @@ package com.openisle.service; import com.openisle.model.*; import com.openisle.repository.NotificationRepository; import com.openisle.repository.UserRepository; +import com.openisle.service.PushNotificationService; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -19,7 +20,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User user = new User(); @@ -47,7 +49,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User user = new User(); @@ -69,7 +72,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User user = new User(); @@ -89,7 +93,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User admin = new User(); @@ -110,7 +115,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User admin = new User(); @@ -131,7 +137,8 @@ class NotificationServiceTest { NotificationRepository nRepo = mock(NotificationRepository.class); UserRepository uRepo = mock(UserRepository.class); EmailSender email = mock(EmailSender.class); - NotificationService service = new NotificationService(nRepo, uRepo, email); + PushNotificationService push = mock(PushNotificationService.class); + NotificationService service = new NotificationService(nRepo, uRepo, email, push); org.springframework.test.util.ReflectionTestUtils.setField(service, "websiteUrl", "https://ex.com"); User user = new User(); @@ -145,5 +152,6 @@ class NotificationServiceTest { service.createNotification(user, NotificationType.COMMENT_REPLY, post, comment, null, null, null, null); verify(email).sendEmail("a@a.com", "【OpenIsle】有人回复了你", "https://ex.com/posts/1#comment-2"); + verify(push).sendNotification(eq(user), contains("/posts/1#comment-2")); } } diff --git a/src/test/java/com/openisle/service/ReactionServiceTest.java b/src/test/java/com/openisle/service/ReactionServiceTest.java index fea2e9fd9..9f797fee0 100644 --- a/src/test/java/com/openisle/service/ReactionServiceTest.java +++ b/src/test/java/com/openisle/service/ReactionServiceTest.java @@ -39,5 +39,6 @@ class ReactionServiceTest { service.reactToPost("bob", 3L, ReactionType.LIKE); verify(email).sendEmail("a@a.com", "【OpenIsle】你有新的互动", "https://ex.com/messages"); + verify(notif).sendCustomPush(author, "你有新的互动", "https://ex.com/messages"); } }