From d70635af938bb59e3a15ae72dc8d074d3eadc3f6 Mon Sep 17 00:00:00 2001 From: mekya Date: Mon, 19 Feb 2024 17:13:41 +0300 Subject: [PATCH 1/2] Add APN parameters to the AppSettings --- pom.xml | 5 ++ src/main/java/io/antmedia/AppSettings.java | 58 ++++++++++++++ .../IPushNotificationService.java | 10 ++- .../PushNotificationServiceCommunity.java | 11 +-- .../rest/PushNotificationRestService.java | 78 ++++++++++++------- .../io/antmedia/test/AppSettingsUnitTest.java | 6 +- .../PushNotificationCommunityTest.java | 13 +++- .../rest/PushNotificationRestServiceTest.java | 44 +++++++---- 8 files changed, 169 insertions(+), 56 deletions(-) diff --git a/pom.xml b/pom.xml index 4179cd5ce..d15ac3e4f 100644 --- a/pom.xml +++ b/pom.xml @@ -619,6 +619,11 @@ firebase-admin 9.2.0 + + com.eatthepath + pushy + 0.15.4 + diff --git a/src/main/java/io/antmedia/AppSettings.java b/src/main/java/io/antmedia/AppSettings.java index a192556f1..824f3b939 100644 --- a/src/main/java/io/antmedia/AppSettings.java +++ b/src/main/java/io/antmedia/AppSettings.java @@ -2068,6 +2068,32 @@ public boolean isWriteStatsToDatastore() { */ @Value("${subscriberAuthenticationKey:#{ T(org.apache.commons.lang3.RandomStringUtils).randomAlphanumeric(32)}}") private String subscriberAuthenticationKey = RandomStringUtils.randomAlphanumeric(32); + + + /** + * (Apple Push Notification) Apple Push Notification Server + * Default value is development enviroment(api.sandbox.push.apple.com) and production enviroment is api.push.apple.com + */ + @Value("${apnsServer:api.sandbox.push.apple.com}") + private String apnsServer = "api.sandbox.push.apple.com"; + + /** + * APN(Apple Push Notification) team id + */ + @Value("${apnTeamId:#{null}}") + private String apnTeamId; + + /** + * APN(Apple Push Notification) private key + */ + @Value("${apnPrivateKey:#{null}}") + private String apnPrivateKey; + + /** + * APN(Apple Push Notification) key Id + */ + @Value("${apnKeyId:#{null}}") + private String apnKeyId; public void setWriteStatsToDatastore(boolean writeStatsToDatastore) { this.writeStatsToDatastore = writeStatsToDatastore; @@ -3565,4 +3591,36 @@ public void setSubscriberAuthenticationKey(String subscriberAuthenticationKey) { this.subscriberAuthenticationKey = subscriberAuthenticationKey; } + public String getApnsServer() { + return apnsServer; + } + + public String getApnPrivateKey() { + return apnPrivateKey; + } + + public String getApnKeyId() { + return apnKeyId; + } + + public String getApnTeamId() { + return apnTeamId; + } + + public void setApnTeamId(String apnTeamId) { + this.apnTeamId = apnTeamId; + } + + public void setApnPrivateKey(String apnPrivateKey) { + this.apnPrivateKey = apnPrivateKey; + } + + public void setApnKeyId(String apnKeyId) { + this.apnKeyId = apnKeyId; + } + + public void setApnsServer(String apnsServer) { + this.apnsServer = apnsServer; + } + } diff --git a/src/main/java/io/antmedia/pushnotification/IPushNotificationService.java b/src/main/java/io/antmedia/pushnotification/IPushNotificationService.java index b951fc222..e1f7dd3b8 100644 --- a/src/main/java/io/antmedia/pushnotification/IPushNotificationService.java +++ b/src/main/java/io/antmedia/pushnotification/IPushNotificationService.java @@ -2,6 +2,8 @@ import java.util.List; +import org.json.simple.JSONObject; + import io.antmedia.rest.model.Result; public interface IPushNotificationService { @@ -33,7 +35,7 @@ public String toString() { * @param serviceName: fcm or apn * @return */ - Result sendNotification(String topic, String jsonMessage, String serviceName); + Result sendNotification(String topic, JSONObject jsonMessage, String serviceName); /** * Send notification to both services if they are enabled @@ -42,7 +44,7 @@ public String toString() { * @param jsonMessage * @return */ - Result sendNotification(String topic, String jsonMessage) ; + Result sendNotification(String topic, JSONObject jsonMessage) ; /** @@ -51,7 +53,7 @@ public String toString() { * @param jsonMessage * @return */ - Result sendNotification(List subscriberIds, String jsonMessage); + Result sendNotification(List subscriberIds, JSONObject jsonMessage); /** @@ -60,5 +62,5 @@ public String toString() { * @param jsonMessage * @return */ - Result sendNotification(List subscriberIds, String jsonMessage, String serviceName); + Result sendNotification(List subscriberIds, JSONObject jsonMessage, String serviceName); } diff --git a/src/main/java/io/antmedia/pushnotification/PushNotificationServiceCommunity.java b/src/main/java/io/antmedia/pushnotification/PushNotificationServiceCommunity.java index 39bd279ab..50922022a 100644 --- a/src/main/java/io/antmedia/pushnotification/PushNotificationServiceCommunity.java +++ b/src/main/java/io/antmedia/pushnotification/PushNotificationServiceCommunity.java @@ -2,7 +2,8 @@ import java.util.List; -import io.antmedia.datastore.db.types.PushNotificationToken; +import org.json.simple.JSONObject; + import io.antmedia.rest.model.Result; public class PushNotificationServiceCommunity implements IPushNotificationService { @@ -11,22 +12,22 @@ public class PushNotificationServiceCommunity implements IPushNotificationServic @Override - public Result sendNotification(String topic, String jsonMessage, String serviceName) { + public Result sendNotification(String topic, JSONObject jsonMessage, String serviceName) { return new Result(false, MESSAGE_TO_USE_ENTERPRISE_EDITION); } @Override - public Result sendNotification(String topic, String jsonMessage) { + public Result sendNotification(String topic, JSONObject jsonMessage) { return new Result(false, MESSAGE_TO_USE_ENTERPRISE_EDITION); } @Override - public Result sendNotification(List subscriberIds, String jsonMessage) { + public Result sendNotification(List subscriberIds, JSONObject jsonMessage) { return new Result(false, MESSAGE_TO_USE_ENTERPRISE_EDITION); } @Override - public Result sendNotification(List subscriberIds, String jsonMessage, String serviceName) { + public Result sendNotification(List subscriberIds, JSONObject jsonMessage, String serviceName) { return new Result(false, MESSAGE_TO_USE_ENTERPRISE_EDITION); } diff --git a/src/main/java/io/antmedia/rest/PushNotificationRestService.java b/src/main/java/io/antmedia/rest/PushNotificationRestService.java index 84d3d70d5..7697a88ec 100644 --- a/src/main/java/io/antmedia/rest/PushNotificationRestService.java +++ b/src/main/java/io/antmedia/rest/PushNotificationRestService.java @@ -3,6 +3,9 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; @@ -13,6 +16,7 @@ import io.antmedia.rest.model.PushNotificationToSubscribers; import io.antmedia.rest.model.Result; import io.antmedia.websocket.WebSocketConstants; +import io.grpc.internal.JsonParser; import jakarta.servlet.ServletContext; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.FormParam; @@ -28,18 +32,17 @@ @Component @Path("/v2/push-notification") public class PushNotificationRestService { - + @Context protected ServletContext servletContext; - + protected ApplicationContext appCtx; private IPushNotificationService pushNotificationService; - + private AppSettings appSettings; - - + public ApplicationContext getAppContext() { if (servletContext != null) { appCtx = (ApplicationContext) servletContext @@ -47,8 +50,8 @@ public ApplicationContext getAppContext() { } return appCtx; } - - + + public IPushNotificationService getPushNotificationService() { if (pushNotificationService == null) { ApplicationContext appContext = getAppContext(); @@ -58,7 +61,7 @@ public IPushNotificationService getPushNotificationService() { } return pushNotificationService; } - + public AppSettings getAppSettings() { if (appSettings == null) { ApplicationContext appContext = getAppContext(); @@ -68,8 +71,8 @@ public AppSettings getAppSettings() { } return appSettings; } - - + + @GET @Produces(MediaType.APPLICATION_JSON) @Path("/subscriber-auth-token") @@ -78,35 +81,54 @@ public Result getSubscriberAuthenticationToken(@QueryParam("subscriberId") Strin //one hour default - 3600 seconds timeoutDurationInSeconds = 3600; } - long expireTimeMs = System.currentTimeMillis() + (timeoutDurationInSeconds * 1000); - String jwtToken = JWTFilter.generateJwtToken(getAppSettings().getSubscriberAuthenticationKey(), expireTimeMs, WebSocketConstants.SUBSCRIBER_ID, subscriberId); - - return new Result(true, jwtToken, "Token is available in dataId field"); + if (StringUtils.isNotBlank(subscriberId)) { + long expireTimeMs = System.currentTimeMillis() + (timeoutDurationInSeconds * 1000); + String jwtToken = JWTFilter.generateJwtToken(getAppSettings().getSubscriberAuthenticationKey(), expireTimeMs, WebSocketConstants.SUBSCRIBER_ID, subscriberId); + + return new Result(true, jwtToken, "Token is available in dataId field"); + } + else { + return new Result(false, "subscriberId is blank. Please give subscriberId as query parameter"); + + } } - + @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Path("/subscribers") public Result sendPushNotification(PushNotificationToSubscribers pushNotificationToSubcribers, @QueryParam("serviceName") String serviceName) { - if (StringUtils.isBlank(serviceName)) { - return getPushNotificationService().sendNotification(pushNotificationToSubcribers.getSubscribers() , pushNotificationToSubcribers.getJsonMessage()); - } - else { - return getPushNotificationService().sendNotification(pushNotificationToSubcribers.getSubscribers(), pushNotificationToSubcribers.getJsonMessage(), serviceName); + JSONParser parser = new JSONParser(); + try { + if (StringUtils.isBlank(serviceName)) + { + return getPushNotificationService().sendNotification(pushNotificationToSubcribers.getSubscribers() , (JSONObject)parser.parse(pushNotificationToSubcribers.getJsonMessage())); + } + else + { + return getPushNotificationService().sendNotification(pushNotificationToSubcribers.getSubscribers(), (JSONObject)parser.parse(pushNotificationToSubcribers.getJsonMessage()), serviceName); + } + } catch (ParseException e) { + return new Result(false, "JSON content cannot be parsed. Make sure JSON content is in correct format"); } } - + @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Path("/topics/{topic}") public Result sendPushNotification(@PathParam("topic") String topic, String jsonMessage, @QueryParam("serviceName") String serviceName) { - if (StringUtils.isBlank(serviceName)) { - return getPushNotificationService().sendNotification(topic, jsonMessage); - } - else { - return getPushNotificationService().sendNotification(topic, jsonMessage, serviceName); + JSONParser parser = new JSONParser(); + try { + if (StringUtils.isBlank(serviceName)) { + return getPushNotificationService().sendNotification(topic, (JSONObject)parser.parse(jsonMessage)); + + } + else { + return getPushNotificationService().sendNotification(topic, (JSONObject)parser.parse(jsonMessage), serviceName); + } + } catch (ParseException e) { + return new Result(false, "JSON content cannot be parsed"); } } @@ -114,7 +136,7 @@ public Result sendPushNotification(@PathParam("topic") String topic, String json public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } - - + + } diff --git a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java index 65d2492cb..70b87c6d6 100644 --- a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java +++ b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java @@ -497,12 +497,16 @@ public void testUnsetAppSettings(AppSettings appSettings) { assertNull(appSettings.getTimeTokenSecretForPlay()); assertNotNull(appSettings.getSubscriberAuthenticationKey()); assertNull(appSettings.getFirebaseAccountKeyJSON()); + assertNull(appSettings.getApnKeyId()); + assertNull(appSettings.getApnTeamId()); + assertNull(appSettings.getApnPrivateKey()); + assertEquals("api.sandbox.push.apple.com", appSettings.getApnsServer()); //if we add a new field, we just need to check its default value in this test //When a new field is added or removed please update the number of fields and make this test pass //by also checking its default value. assertEquals("New field is added to settings. PAY ATTENTION: Please CHECK ITS DEFAULT VALUE and fix the number of fields.", - 170, numberOfFields); + 174, numberOfFields); } diff --git a/src/test/java/io/antmedia/test/pushnotification/PushNotificationCommunityTest.java b/src/test/java/io/antmedia/test/pushnotification/PushNotificationCommunityTest.java index 70a3a33f0..6e80581a0 100644 --- a/src/test/java/io/antmedia/test/pushnotification/PushNotificationCommunityTest.java +++ b/src/test/java/io/antmedia/test/pushnotification/PushNotificationCommunityTest.java @@ -5,6 +5,7 @@ import java.util.Arrays; +import org.json.simple.JSONObject; import org.junit.Test; import io.antmedia.pushnotification.PushNotificationServiceCommunity; @@ -17,19 +18,23 @@ public class PushNotificationCommunityTest { public void testPushNotificaitonServiceCommunity() { PushNotificationServiceCommunity pushNotificationServiceCommunity = new PushNotificationServiceCommunity(); - Result sendNotification = pushNotificationServiceCommunity.sendNotification("title", "message", "token"); + JSONObject jsObject = new JSONObject(); + jsObject.put("title", "hello world"); + jsObject.put("apn-topic", "io.antmedia.ios.webrtc.sample"); + + Result sendNotification = pushNotificationServiceCommunity.sendNotification("title", jsObject, "token"); assertFalse(sendNotification.isSuccess()); assertEquals("Push Notification Service is not available community edition. Please use enterprise edition", sendNotification.getMessage()); - sendNotification = pushNotificationServiceCommunity.sendNotification("topic", "message"); + sendNotification = pushNotificationServiceCommunity.sendNotification("topic", jsObject); assertFalse(sendNotification.isSuccess()); assertEquals("Push Notification Service is not available community edition. Please use enterprise edition", sendNotification.getMessage()); - sendNotification = pushNotificationServiceCommunity.sendNotification(Arrays.asList(""), "message"); + sendNotification = pushNotificationServiceCommunity.sendNotification(Arrays.asList(""), jsObject); assertFalse(sendNotification.isSuccess()); assertEquals("Push Notification Service is not available community edition. Please use enterprise edition", sendNotification.getMessage()); - sendNotification = pushNotificationServiceCommunity.sendNotification(Arrays.asList(""), "message", "serviceName"); + sendNotification = pushNotificationServiceCommunity.sendNotification(Arrays.asList(""), jsObject, "serviceName"); assertFalse(sendNotification.isSuccess()); assertEquals("Push Notification Service is not available community edition. Please use enterprise edition", sendNotification.getMessage()); diff --git a/src/test/java/io/antmedia/test/rest/PushNotificationRestServiceTest.java b/src/test/java/io/antmedia/test/rest/PushNotificationRestServiceTest.java index e1515aba5..80abfc8ea 100644 --- a/src/test/java/io/antmedia/test/rest/PushNotificationRestServiceTest.java +++ b/src/test/java/io/antmedia/test/rest/PushNotificationRestServiceTest.java @@ -10,6 +10,7 @@ import java.util.concurrent.TimeUnit; import org.awaitility.Awaitility; +import org.json.simple.JSONObject; import org.junit.Test; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; @@ -39,35 +40,49 @@ public void testSendNotification() { Mockito.when(appContext.getBean(IPushNotificationService.BEAN_NAME)).thenReturn(pushNotificationService); + JSONObject jsObject = new JSONObject(); + jsObject.put("title", "hello world"); + jsObject.put("apn-topic", "io.antmedia.ios.webrtc.sample"); - pushNotificationRestService.sendPushNotification("topic", "jsonMessage","fcm"); - verify(pushNotificationService).sendNotification("topic", "jsonMessage","fcm"); + pushNotificationRestService.sendPushNotification("topic", jsObject.toJSONString(),"fcm"); + verify(pushNotificationService).sendNotification("topic", jsObject,"fcm"); - pushNotificationRestService.sendPushNotification("topic", "jsonMessage","apns"); - verify(pushNotificationService).sendNotification("topic", "jsonMessage","apns"); + pushNotificationRestService.sendPushNotification("topic", jsObject.toJSONString(),"apns"); + verify(pushNotificationService).sendNotification("topic", jsObject,"apns"); - pushNotificationRestService.sendPushNotification("topic", "jsonMessage",""); - verify(pushNotificationService).sendNotification("topic", "jsonMessage"); + pushNotificationRestService.sendPushNotification("topic", jsObject.toJSONString(),""); + verify(pushNotificationService).sendNotification("topic", jsObject); - pushNotificationRestService.sendPushNotification("topic", "jsonMessage", null); - verify(pushNotificationService, times(2)).sendNotification("topic", "jsonMessage"); + pushNotificationRestService.sendPushNotification("topic", jsObject.toJSONString(), null); + verify(pushNotificationService, times(2)).sendNotification("topic", jsObject); + + Result result = pushNotificationRestService.sendPushNotification("topic", "Not json string", null); + assertFalse(result.isSuccess()); + assertTrue(result.getMessage().contains("cannot be parsed")); PushNotificationToSubscribers pushNotificationToSubscribers = new PushNotificationToSubscribers(); - pushNotificationToSubscribers.setJsonMessage("jsonMessage"); + + pushNotificationToSubscribers.setJsonMessage(jsObject.toJSONString()); pushNotificationToSubscribers.setSubscribers(Arrays.asList("subscriber1", "subscriber2")); pushNotificationRestService.sendPushNotification(pushNotificationToSubscribers, "fcm"); - verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), "jsonMessage","fcm"); + verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), jsObject,"fcm"); pushNotificationRestService.sendPushNotification(pushNotificationToSubscribers, "apns"); - verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), "jsonMessage","apns"); + verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), jsObject,"apns"); pushNotificationRestService.sendPushNotification(pushNotificationToSubscribers,""); - verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), "jsonMessage"); + verify(pushNotificationService).sendNotification(Arrays.asList("subscriber1", "subscriber2"), jsObject); pushNotificationRestService.sendPushNotification(pushNotificationToSubscribers, null); - verify(pushNotificationService, times(2)).sendNotification(Arrays.asList("subscriber1", "subscriber2"), "jsonMessage"); + verify(pushNotificationService, times(2)).sendNotification(Arrays.asList("subscriber1", "subscriber2"), jsObject); + + + pushNotificationToSubscribers.setJsonMessage("Not json string"); + result = pushNotificationRestService.sendPushNotification(pushNotificationToSubscribers, null); + assertFalse(result.isSuccess()); + assertTrue(result.getMessage().contains("cannot be parsed")); } @@ -104,7 +119,8 @@ public void testGetToken() { "subscriber1"); }); - } + + } From f020526b0c76a0705b823710b1b7a3218a10d4e0 Mon Sep 17 00:00:00 2001 From: mekya Date: Mon, 19 Feb 2024 18:31:45 +0300 Subject: [PATCH 2/2] Increase code coverage --- .../io/antmedia/test/AppSettingsUnitTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java index 70b87c6d6..82357b772 100644 --- a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java +++ b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java @@ -283,6 +283,22 @@ public void testSettings() { appSettings.setTimeTokenSecretForPublish("secretpublish"); assertEquals("secretpublish", appSettings.getTimeTokenSecretForPublish()); + + String apnKeyId = "apnkeyid"; + appSettings.setApnKeyId(apnKeyId); + assertEquals(apnKeyId, appSettings.getApnKeyId()); + + String teamId = "apnTeamId"; + appSettings.setApnTeamId(teamId); + assertEquals(teamId, appSettings.getApnTeamId()); + + String apnServer = "apnServer"; + appSettings.setApnsServer(apnServer); + assertEquals(apnServer, appSettings.getApnsServer()); + + String privateKey = "privateKey"; + appSettings.setApnPrivateKey(privateKey); + assertEquals(privateKey, appSettings.getApnPrivateKey()); }