diff --git a/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java index ebb697ec..08d9a518 100644 --- a/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java +++ b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java @@ -21,16 +21,19 @@ public class FirebaseMessagingConfig { private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); - @Value("${firebase.enabled:false}") + @Value("${firebase.enabled}") private boolean firebaseEnabled; - @Value("${firebase.credential-file:}") + @Value("${firebase.credential-file}") private String firebaseCredentialFile; @Bean @ConditionalOnProperty(name = "firebase.enabled", havingValue = "true") public FirebaseMessaging firebaseMessaging() throws IOException { + logger.info("===== Initializing Firebase ====="); + logger.info("firebaseEnabled={}", firebaseEnabled); + logger.info("firebaseCredentialFile={}", firebaseCredentialFile); if (!firebaseEnabled) { logger.error("⚠️ Firebase disabled by config"); return null; @@ -42,9 +45,11 @@ public FirebaseMessaging firebaseMessaging() throws IOException { return null; // don't throw, app will still start } - GoogleCredentials credentials = GoogleCredentials.fromStream( - new ClassPathResource(firebaseCredentialFile).getInputStream() - ); + GoogleCredentials credentials = + GoogleCredentials.fromStream( + new FileInputStream(firebaseCredentialFile) + ); + FirebaseOptions options = FirebaseOptions.builder() .setCredentials(credentials) .build(); diff --git a/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java index 3bb10cfc..1cb2753d 100644 --- a/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java +++ b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java @@ -28,9 +28,12 @@ import com.iemr.common.model.notification.UserToken; import com.iemr.common.service.firebaseNotification.FirebaseNotificationService; import com.iemr.common.utils.exception.IEMRException; +import com.iemr.common.utils.response.ApiResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @@ -41,17 +44,60 @@ public class FirebaseNotificationController { @Autowired FirebaseNotificationService firebaseNotificationService; - @RequestMapping(value = "sendNotification",method = RequestMethod.POST,headers = "Authorization") - public String sendNotificationByToken(@RequestBody NotificationMessage notificationMessage){ - return firebaseNotificationService.sendNotification(notificationMessage); + + @PostMapping("/sendNotification") + public ResponseEntity sendNotificationByToken(@RequestBody NotificationMessage notificationMessage) { + + logger.info("Received notification request. Token={}, Title={}, ReceiverId={}, Type={}", + notificationMessage.getToken(), + notificationMessage.getTitle(), + notificationMessage.getData() != null ? notificationMessage.getData().get("receiver_user_id") : null, + notificationMessage.getData() != null ? notificationMessage.getData().get("notification_type") : null); + + logger.debug("Notification payload: {}", notificationMessage); + + try { + String response = firebaseNotificationService.sendNotification(notificationMessage); + + logger.info("Notification processed successfully. Response={}", response); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + + logger.error("Failed to process notification request. Token={}, ReceiverId={}, Error={}", + notificationMessage.getToken(), + notificationMessage.getData() != null ? notificationMessage.getData().get("receiver_user_id") : null, + e.getMessage(), + e); + + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Failed to send notification"); + } } - @RequestMapping(value = "updateToken",method = RequestMethod.POST,headers = "Authorization") - public String updateToken(@RequestBody UserToken userToken){ - return firebaseNotificationService.updateToken(userToken); + @PostMapping("/updateToken") + public ResponseEntity updateToken(@RequestBody UserToken userToken) { + try { + + Object result = firebaseNotificationService.updateToken(userToken); + + return ResponseEntity.ok(result); + + } catch (IllegalArgumentException e) { + + return ResponseEntity.badRequest().body(e.getMessage()); + + } catch (Exception e) { + + logger.error("Error while updating Firebase token", e); + + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Failed to update Firebase token."); + } } - @RequestMapping(value = "getToken",method = RequestMethod.GET,headers = "Authorization") + @PostMapping(value = "getToken") public String getUserToken() throws IEMRException { return firebaseNotificationService.getUserToken(); diff --git a/src/main/java/com/iemr/common/data/userToken/UserTokenData.java b/src/main/java/com/iemr/common/data/userToken/UserFcmTokenData.java similarity index 77% rename from src/main/java/com/iemr/common/data/userToken/UserTokenData.java rename to src/main/java/com/iemr/common/data/userToken/UserFcmTokenData.java index 0646972e..0a0fefbe 100644 --- a/src/main/java/com/iemr/common/data/userToken/UserTokenData.java +++ b/src/main/java/com/iemr/common/data/userToken/UserFcmTokenData.java @@ -24,23 +24,24 @@ */ package com.iemr.common.data.userToken; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Data; import java.sql.Timestamp; +import static jakarta.persistence.GenerationType.IDENTITY; + @Entity -@Table(name = "user_tokens", schema = "db_iemr") +@Table(name = "user_fcm_tokens", schema = "db_iemr") @Data -public class UserTokenData { +public class UserFcmTokenData { @Id + @GeneratedValue(strategy = IDENTITY) + private int id; @Column(name = "user_id") - Integer userId; + private Integer userId; @Column(name = "token") - String token; + private String token; @Column(name = "updated_at") - Timestamp updatedAt; + private Timestamp updatedAt; } diff --git a/src/main/java/com/iemr/common/model/notification/NotificationMessage.java b/src/main/java/com/iemr/common/model/notification/NotificationMessage.java index 58343034..55cb0e62 100644 --- a/src/main/java/com/iemr/common/model/notification/NotificationMessage.java +++ b/src/main/java/com/iemr/common/model/notification/NotificationMessage.java @@ -35,4 +35,4 @@ public class NotificationMessage { private String title; private String body; private Map data; -} +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java b/src/main/java/com/iemr/common/repo/userToken/UserFcmTokenRepo.java similarity index 78% rename from src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java rename to src/main/java/com/iemr/common/repo/userToken/UserFcmTokenRepo.java index 817f26f0..b2ed14df 100644 --- a/src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java +++ b/src/main/java/com/iemr/common/repo/userToken/UserFcmTokenRepo.java @@ -24,8 +24,15 @@ */ package com.iemr.common.repo.userToken; -import com.iemr.common.data.userToken.UserTokenData; +import com.iemr.common.data.userToken.UserFcmTokenData; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; -public interface UserTokenRepo extends JpaRepository { +import java.util.Optional; + +@Repository + +public interface UserFcmTokenRepo extends JpaRepository { + + Optional findByUserId(Integer userId); } diff --git a/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java b/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java index 7f33c453..66140ccc 100644 --- a/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java +++ b/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java @@ -26,12 +26,15 @@ import com.google.firebase.FirebaseException; import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; import com.google.firebase.messaging.Message; import com.google.firebase.messaging.Notification; -import com.iemr.common.data.userToken.UserTokenData; +import com.google.gson.Gson; +import com.iemr.common.config.firebase.FirebaseMessagingConfig; +import com.iemr.common.data.userToken.UserFcmTokenData; import com.iemr.common.model.notification.NotificationMessage; import com.iemr.common.model.notification.UserToken; -import com.iemr.common.repo.userToken.UserTokenRepo; +import com.iemr.common.repo.userToken.UserFcmTokenRepo; import com.iemr.common.utils.CookieUtil; import com.iemr.common.utils.JwtUtil; import com.iemr.common.utils.exception.IEMRException; @@ -39,11 +42,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.sql.Timestamp; import java.util.Optional; @Service @@ -51,10 +54,10 @@ public class FirebaseNotificationService { final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); @Autowired(required = false) - FirebaseMessaging firebaseMessaging; + private FirebaseMessaging firebaseMessaging; @Autowired - private UserTokenRepo userTokenRepo; + private UserFcmTokenRepo userTokenRepo; @Autowired private CookieUtil cookieUtil; @@ -64,42 +67,77 @@ public class FirebaseNotificationService { private Message message; + @Value("${firebase.enabled}") + private boolean firebaseEnabled; + + @Value("${firebase.credential-file}") + private String firebaseCredentialFile; + + public String sendNotification(NotificationMessage notificationMessage) { + + logger.info("===== Initializing Firebase ====="); + logger.info("firebaseEnabled={}", firebaseEnabled); + logger.info("firebaseCredentialFile={}", firebaseCredentialFile); + + logger.info("========== FCM Notification Request =========="); + logger.info("Request : {}", new Gson().toJson(notificationMessage)); + if (firebaseMessaging == null) { - logger.error("⚠️ Firebase is not configured, skipping notification"); - return null; + logger.error("FirebaseMessaging bean is not initialized."); + return "FirebaseMessaging bean is not initialized."; } - Notification notification = Notification.builder().setTitle(notificationMessage.getTitle()).setBody(notificationMessage.getBody()).build(); + try { - Message message = Message.builder().setTopic(notificationMessage.getToken()).setNotification(notification).putAllData(notificationMessage.getData()).build(); + Notification notification = Notification.builder() + .setTitle(notificationMessage.getTitle()) + .setBody(notificationMessage.getBody()) + .build(); + Message message = Message.builder() + .setToken(notificationMessage.getToken()) + .setNotification(notification) + .putAllData(notificationMessage.getData()) + .build(); - try { - String response = FirebaseMessaging.getInstance().send(message); + logger.info("Sending notification to token: {}", notificationMessage.getToken()); + + String response = firebaseMessaging.send(message); + + logger.info("Notification sent successfully."); + logger.info("Firebase Message Id : {}", response); return response; - } catch (FirebaseException e) { - return "Error sending notification"; + } catch (FirebaseMessagingException e) { + + logger.error("FirebaseMessagingException"); + logger.error("Error Code : {}", e.getMessagingErrorCode()); + logger.error("Error Message : {}", e.getMessage(), e); + + return "FCM Error : " + e.getMessage(); + + } catch (Exception e) { + + logger.error("Unexpected exception while sending notification.", e); + + return "Unexpected Error : " + e.getMessage(); } } - public String updateToken(UserToken userToken) { - Optional existingTokenData = userTokenRepo.findById(userToken.getUserId()); + Optional existingTokenData = userTokenRepo.findByUserId(userToken.getUserId()); - UserTokenData userTokenData; + UserFcmTokenData userTokenData; if (existingTokenData.isPresent()) { userTokenData = existingTokenData.get(); userTokenData.setToken(userToken.getToken()); - userTokenData.setUpdatedAt(new Timestamp(System.currentTimeMillis())); } else { - userTokenData = new UserTokenData(); + userTokenData = new UserFcmTokenData(); userTokenData.setUserId(userToken.getUserId()); userTokenData.setToken(userToken.getToken()); - userTokenData.setUpdatedAt(new Timestamp(System.currentTimeMillis())); } userTokenRepo.save(userTokenData); @@ -111,7 +149,7 @@ public String getUserToken() throws IEMRException { .getRequest(); String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(requestHeader); return userTokenRepo.findById(Integer.parseInt(jwtUtil.getUserIdFromToken(jwtTokenFromCookie))) // because your userId is Long in DB - .map(UserTokenData::getToken) + .map(UserFcmTokenData::getToken) .orElse(null); // }