From d8e51f3a706a93a5e382aa16a6345d9aaa7fbe4b Mon Sep 17 00:00:00 2001 From: piyushkag Date: Fri, 13 Dec 2024 20:57:58 +0530 Subject: [PATCH] Notification Code. --- pom.xml | 14 +++ .../TendermanagementApplication.java | 4 +- .../config/SecurityConfig.java | 1 + .../config/WebSocketConfig.java | 32 ++++++ .../constants/GepafinConstant.java | 4 + .../constants/NotificationConstant.java | 5 + .../gepafin/tendermanagement/dao/CallDao.java | 41 +++++++- .../tendermanagement/dao/NotificationDao.java | 97 +++++++++++++++++++ .../entities/NotificationEntity.java | 31 ++++++ .../entities/NotificationTypeEntity.java | 21 ++++ .../enums/NotificationEnum.java | 27 ++++++ .../enums/NotificationTypeEnum.java | 29 ++++++ .../model/request/NotificationReq.java | 37 +++++++ .../model/response/UserResponseBean.java | 1 + .../repositories/BeneficiaryRepository.java | 5 + .../repositories/NotificationRepository.java | 7 ++ .../NotificationTypeRepository.java | 8 ++ .../service/NotificationService.java | 7 ++ .../service/impl/NotificationServiceImpl.java | 26 +++++ .../gepafin/tendermanagement/util/Utils.java | 4 + .../web/rest/api/NotificationApi.java | 30 ++++++ .../api/impl/NotificationApiController.java | 32 ++++++ .../resources/application-local.properties | 13 ++- .../db/changelog/db.changelog-1.0.0.xml | 45 +++++++++ ...n_template_for_notification_13_12_2024.sql | 5 + 25 files changed, 520 insertions(+), 6 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java create mode 100644 src/main/java/net/gepafin/tendermanagement/constants/NotificationConstant.java create mode 100644 src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/NotificationEntity.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/NotificationTypeEntity.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/NotificationEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/request/NotificationReq.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/NotificationRepository.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/NotificationTypeRepository.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/NotificationService.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/impl/NotificationServiceImpl.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/NotificationApi.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/NotificationApiController.java create mode 100644 src/main/resources/db/dump/insert_json_template_for_notification_13_12_2024.sql diff --git a/pom.xml b/pom.xml index 93a592ed..c463be91 100644 --- a/pom.xml +++ b/pom.xml @@ -231,6 +231,20 @@ spring-test + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.boot + spring-boot-starter-amqp + + + io.projectreactor.netty + reactor-netty + + diff --git a/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java b/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java index 7ec98464..1465ad7e 100644 --- a/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java +++ b/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java @@ -23,7 +23,9 @@ public class TendermanagementApplication { @Override public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**").allowedOrigins("http://localhost:3000") + //remove after testing +//add url for a demo html and js project created on Vs code and ran it from go live on right bottim corner user gepafin_dev_local backup DB for gettng notification on FE. + registry.addMapping("/**").allowedOrigins("http://127.0.0.1:5500", "http://localhost:3000", "http://localhost:5500") .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD").allowCredentials(true); } } diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index 090f3688..8c11eac2 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -109,6 +109,7 @@ public class SecurityConfig { .requestMatchers("/v1/api-docs/**").permitAll() // API docs .requestMatchers("/v1/user/reset-password/initiate").permitAll() .requestMatchers("/v1/user/reset-password").permitAll() + .requestMatchers("/wss/**").permitAll() // if this is not running use this /gs-guide-websocket .anyRequest().authenticated()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) .exceptionHandling(exceptionHandling -> exceptionHandling diff --git a/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java b/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java new file mode 100644 index 00000000..b12207e6 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/config/WebSocketConfig.java @@ -0,0 +1,32 @@ +package net.gepafin.tendermanagement.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + // Enable a simple broker for both /topic (broadcast messages) and /queue (user-specific messages) + config.enableStompBrokerRelay("/topic") + .setRelayHost("localhost") + .setRelayPort(61613) // RabbitMQ is running on port 61613 + .setClientLogin("guest") + .setClientPasscode("guest"); + + // Prefix for application messages (user sends messages to /app endpoints) + config.setApplicationDestinationPrefixes("/app"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + + registry.addEndpoint("/gs-guide-websocket").setAllowedOrigins("http://127.0.0.1:5501/", "http://localhost:5500", "http://localhost:5501", "http://127.0.0.1:5500/") + .withSockJS(); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 14d82b91..f0d9a617 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -341,5 +341,9 @@ public class GepafinConstant { public static final String POLLING_THREAD_NAME = "Ndg-Polling-Thread-"; public static final String DOCUMENT_UPLOADING_IN_PROGRESS = "document.uploading.is.in.progress"; public static final String ASYNC_DOCUMENT_UPLOAD_NAME = "AsyncDocumentUpload-"; + + //Notification + public static final String COMMON_SINGLE_CHANNEL_PREFIX = "/topic/notifications_user_"; + public static final String COMPANY_PREFIX = "_company_"; } diff --git a/src/main/java/net/gepafin/tendermanagement/constants/NotificationConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/NotificationConstant.java new file mode 100644 index 00000000..3f5c1cdc --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/constants/NotificationConstant.java @@ -0,0 +1,5 @@ +package net.gepafin.tendermanagement.constants; + +public class NotificationConstant { + public static final String NOTIFICATION_SENT_SUCCESSFULLY = "Notification Sent Successfully."; +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index 9b3b12a5..772538bb 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -15,7 +15,9 @@ import java.util.zip.ZipOutputStream; import jakarta.servlet.http.HttpServletRequest; import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; +import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.VersionActionTypeEnum; +import net.gepafin.tendermanagement.model.request.NotificationReq; import net.gepafin.tendermanagement.model.request.VersionHistoryRequest; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.repositories.*; @@ -108,6 +110,18 @@ public class CallDao { @Autowired private HttpServletRequest request; + @Autowired + private NotificationDao notificationDao; + + @Autowired + private BeneficiaryRepository beneficiaryRepository; + + @Autowired + private NotificationTypeRepository notificationTypeRepository; + + @Autowired + private UserWithCompanyRepository userWithCompanyRepository; + public CallResponse createCallStep1(CreateCallRequestStep1 createCallRequest, UserEntity userEntity) { createCallRequest.setRegionId(userEntity.getRoleEntity().getRegion().getId()); CallEntity callEntity = convertToCallEntity(createCallRequest, userEntity); @@ -828,13 +842,36 @@ public class CallDao { validateStatusChange(currentStatus, statusReq); callEntity.setStatus(statusReq.getValue()); callEntity = callRepository.save(callEntity); - + + //Creating notification. + List userIds = beneficiaryRepository.findUserIdsByHubIdAndBeneficiaryId(callEntity.getHub().getId()); + Map placeholders = new HashMap<>(); + placeholders.put("{{call_name}}", callEntity.getName()); + userIds.forEach(userId -> { + NotificationReq notificationReq = createNotificationReq(NotificationTypeEnum.CALL_CREATED.getValue(), placeholders, userId); + List companyIds = userWithCompanyRepository.findActiveCompanyIdsByUserId(notificationReq.getUserId()); + notificationReq.setCompanyIds(companyIds); + notificationDao.sendNotification(notificationReq); + }); + /** This code is responsible for adding a version history log for the "update call status" operation **/ loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallEntity).newData(callEntity).build()); - + return convertToCallResponseBean(callEntity); } + public NotificationReq createNotificationReq(String notificationType, Map placeholders, Long userId) { + // Create NotificationReq object + NotificationReq notificationReq = new NotificationReq(); + NotificationTypeEntity notificationTypeEntity = notificationTypeRepository.findByNotificationNameAndIsDeletedFalse(notificationType); + notificationReq.setNotificationType(notificationType); + String message = Utils.replacePlaceholders(notificationTypeEntity.getJsonTemplate(), placeholders); + notificationReq.setMessage(message); + notificationReq.setUserId(userId); + return notificationReq; + } + + private void validateStatusChange(CallStatusEnum currentStatus, CallStatusEnum newStatus) { if (currentStatus == newStatus) { throw new CustomValidationException(Status.VALIDATION_ERROR, diff --git a/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java new file mode 100644 index 00000000..17c5a3c8 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/dao/NotificationDao.java @@ -0,0 +1,97 @@ +package net.gepafin.tendermanagement.dao; + +import lombok.extern.slf4j.Slf4j; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.entities.NotificationEntity; +import net.gepafin.tendermanagement.enums.NotificationEnum; +import net.gepafin.tendermanagement.model.request.NotificationReq; +import net.gepafin.tendermanagement.repositories.NotificationRepository; +import net.gepafin.tendermanagement.repositories.NotificationTypeRepository; +import net.gepafin.tendermanagement.util.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class NotificationDao { + + @Autowired + private SimpMessagingTemplate messagingTemplate; + + @Autowired + private NotificationRepository notificationRepository; + + @Autowired + private NotificationTypeRepository notificationTypeRepository; + + public NotificationReq sendNotification(NotificationReq notificationReq) { + + // Ensure userId is properly set in notificationReq if not already + Long userId = notificationReq.getUserId(); + if (userId == null) { + log.error("User ID is missing in the notification request."); + return null; + } + NotificationEntity notificationEntity = saveNotification(notificationReq); + log.info("Sending notification to user {} with content: {}", userId, notificationReq.getMessage()); + List companyIds = notificationReq.getCompanyIds(); + + if (companyIds.isEmpty()) { + sendToUser(userId, notificationEntity); + } else { + sendToCompanies(userId, companyIds, notificationEntity); + } + + return convertToNotificationReq(notificationEntity); + } + + private NotificationEntity saveNotification(NotificationReq notificationReq) { + + NotificationEntity notificationEntity = convertToNotificationEntity(notificationReq); + return notificationRepository.save(notificationEntity); + } + + private void sendToUser(Long userId, NotificationEntity notificationEntity) { + + String userChannel = GepafinConstant.COMMON_SINGLE_CHANNEL_PREFIX + userId; + log.info("Channel for User {}", userChannel); + messagingTemplate.convertAndSend(userChannel, notificationEntity); + } + + private void sendToCompanies(Long userId, List companyIds, NotificationEntity notificationEntity) { + // Send notification to each company provided in the companyIds list + companyIds.forEach(companyId -> { + String companyChannel = Utils.createChannelForUserAndCompany(userId, companyId); + log.info("Channel for User and Company {}, {}", userId, companyChannel); + messagingTemplate.convertAndSend(companyChannel, notificationEntity); + }); + } + + private NotificationReq convertToNotificationReq(NotificationEntity notificationEntity) { + + NotificationReq notificationReq = new NotificationReq(); + notificationReq.setId(notificationEntity.getId()); + notificationReq.setUserId(notificationEntity.getUserId()); + notificationReq.setStatus(NotificationEnum.UNREAD.getValue()); + notificationReq.setMessage(notificationEntity.getMessage()); + notificationReq.setCreatedDate(notificationEntity.getCreatedDate()); + notificationReq.setUpdatedDate(notificationEntity.getUpdatedDate()); + return notificationReq; + + } + + private NotificationEntity convertToNotificationEntity(NotificationReq notificationReq) { + + NotificationEntity notificationEntity = new NotificationEntity(); + String message = notificationReq.getMessage(); + notificationEntity.setNotificationType(notificationReq.getNotificationType()); + notificationEntity.setUserId(notificationReq.getUserId()); + notificationEntity.setStatus(NotificationEnum.UNREAD.getValue()); + notificationEntity.setIsDeleted(Boolean.FALSE); + notificationEntity.setMessage(message); + return notificationEntity; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/NotificationEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/NotificationEntity.java new file mode 100644 index 00000000..74131d4c --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/NotificationEntity.java @@ -0,0 +1,31 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.Data; + +@Entity +@Table(name = "NOTIFICATION") +@Data +public class NotificationEntity extends BaseEntity { + + @Column(name = "USER_ID") + Long userId; + + @Column(name = "MESSAGE") + String message; + + @Column(name = "STATUS") + String status; + + @Column(name = "IS_DELETED") + Boolean isDeleted; + + @Column(name = "NOTIFICATION_TYPE") + String notificationType; + + @Column(name = "REDIRECT_LINK") + String redirectLink; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/entities/NotificationTypeEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/NotificationTypeEntity.java new file mode 100644 index 00000000..5202c97a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/NotificationTypeEntity.java @@ -0,0 +1,21 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.Data; + +@Entity +@Data +@Table(name = "NOTIFICATION_TYPE") +public class NotificationTypeEntity extends BaseEntity { + + @Column(name = "NOTIFICATION_NAME") + String notificationName; + + @Column(name = "JSON_TEMPLATE") + String jsonTemplate; + + @Column(name="IS_DELETED") + private Boolean isDeleted; +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/NotificationEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/NotificationEnum.java new file mode 100644 index 00000000..5b8bf633 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/NotificationEnum.java @@ -0,0 +1,27 @@ +package net.gepafin.tendermanagement.enums; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum NotificationEnum { + //status + READ("READ"), UNREAD("UNREAD"); + + private final String value; + + NotificationEnum(String value) { + + this.value = value; + } + + @JsonValue + public String getValue() { + + return value; + } + + @Override + public String toString() { + + return String.valueOf(value); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java new file mode 100644 index 00000000..86fd75dc --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/NotificationTypeEnum.java @@ -0,0 +1,29 @@ +package net.gepafin.tendermanagement.enums; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum NotificationTypeEnum { + CALL_CREATED("CALL_CREATED"), + APPLICATION_SUBMISSION("APPLICATION_SUBMISSION"), + AMENDMENT_CREATION("AMENDMENT_CREATION"), + EVALUATION_RESULT("EVALUATION_RESULT"); + + private final String value; + + NotificationTypeEnum(String value) { + + this.value = value; + } + + @JsonValue + public String getValue() { + + return value; + } + + @Override + public String toString() { + + return String.valueOf(value); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/NotificationReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/NotificationReq.java new file mode 100644 index 00000000..8506694a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/NotificationReq.java @@ -0,0 +1,37 @@ +package net.gepafin.tendermanagement.model.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class NotificationReq { + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Long id; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Long userId; + + String message; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + String notificationType; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + String status; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private LocalDateTime createdDate; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private LocalDateTime updatedDate; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + String redirectUrl; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + List companyIds; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java index b0a5ef38..c8724d43 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java @@ -40,6 +40,7 @@ public class UserResponseBean extends BaseBean { private List companies; private Boolean privacy; + private Boolean terms; private Boolean marketing; diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/BeneficiaryRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/BeneficiaryRepository.java index ecb6ed7d..984e477a 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/BeneficiaryRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/BeneficiaryRepository.java @@ -1,11 +1,16 @@ package net.gepafin.tendermanagement.repositories; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import net.gepafin.tendermanagement.entities.BeneficiaryEntity; +import java.util.List; + @Repository public interface BeneficiaryRepository extends JpaRepository { + @Query("SELECT u.id FROM UserEntity u JOIN u.beneficiary b WHERE b.id = u.beneficiary.id AND b.hubId = :hubId") + List findUserIdsByHubIdAndBeneficiaryId(Long hubId); } diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/NotificationRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/NotificationRepository.java new file mode 100644 index 00000000..a52c39de --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/NotificationRepository.java @@ -0,0 +1,7 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.NotificationEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NotificationRepository extends JpaRepository { +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/NotificationTypeRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/NotificationTypeRepository.java new file mode 100644 index 00000000..78cef54d --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/NotificationTypeRepository.java @@ -0,0 +1,8 @@ +package net.gepafin.tendermanagement.repositories; + +import net.gepafin.tendermanagement.entities.NotificationTypeEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NotificationTypeRepository extends JpaRepository { + NotificationTypeEntity findByNotificationNameAndIsDeletedFalse(String value); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/NotificationService.java b/src/main/java/net/gepafin/tendermanagement/service/NotificationService.java new file mode 100644 index 00000000..0b6914c2 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/NotificationService.java @@ -0,0 +1,7 @@ +package net.gepafin.tendermanagement.service; + +import net.gepafin.tendermanagement.model.request.NotificationReq; + +public interface NotificationService { + NotificationReq sendNotification(Long userId, NotificationReq notificationReq); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/NotificationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/NotificationServiceImpl.java new file mode 100644 index 00000000..7928f166 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/NotificationServiceImpl.java @@ -0,0 +1,26 @@ +package net.gepafin.tendermanagement.service.impl; + +import lombok.extern.slf4j.Slf4j; +import net.gepafin.tendermanagement.dao.NotificationDao; +import net.gepafin.tendermanagement.model.request.NotificationReq; +import net.gepafin.tendermanagement.service.NotificationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class NotificationServiceImpl implements NotificationService { + + @Autowired + private NotificationDao notificationDao; + + @Override + public NotificationReq sendNotification(Long userId, NotificationReq notificationReq) { + + log.info("Sending notification to user {} with content: {}", userId, notificationReq.getMessage()); + notificationReq.setUserId(userId); + notificationReq = notificationDao.sendNotification(notificationReq); + return notificationReq; + } + +} \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index e93c8ed9..4290bfff 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -669,4 +669,8 @@ public class Utils { } return null; } + + public static String createChannelForUserAndCompany(Long userId, Long companyId) { + return GepafinConstant.COMMON_SINGLE_CHANNEL_PREFIX + userId + GepafinConstant.COMPANY_PREFIX + companyId; + } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/NotificationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/NotificationApi.java new file mode 100644 index 00000000..85a4ab27 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/NotificationApi.java @@ -0,0 +1,30 @@ +package net.gepafin.tendermanagement.web.rest.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.model.request.NotificationReq; +import net.gepafin.tendermanagement.model.response.LookUpDataResponseBean; +import net.gepafin.tendermanagement.model.util.Response; +import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +public interface NotificationApi { + @Operation(summary = "Api to send notification.", responses = { @ApiResponse(responseCode = "200", description = "OK"), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = + ErrorConstants.NOTFOUND_ERROR_EXAMPLE))), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = + ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE))), + @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = @ExampleObject(value = + ErrorConstants.BADREQUEST_ERROR_EXAMPLE))) }) + @PostMapping(value = "/{userId}", consumes = "application/json", produces = "application/json") + ResponseEntity> sendNotification(HttpServletRequest request, @RequestBody NotificationReq notificationReq, + @Parameter(description = "The user id", required = true) @PathVariable("userId") Long userId); +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/NotificationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/NotificationApiController.java new file mode 100644 index 00000000..054c4c63 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/NotificationApiController.java @@ -0,0 +1,32 @@ +package net.gepafin.tendermanagement.web.rest.api.impl; + +import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.config.Translator; +import net.gepafin.tendermanagement.constants.NotificationConstant; +import net.gepafin.tendermanagement.model.request.NotificationReq; +import net.gepafin.tendermanagement.model.util.Response; +import net.gepafin.tendermanagement.service.NotificationService; +import net.gepafin.tendermanagement.web.rest.api.NotificationApi; +import net.gepafin.tendermanagement.web.rest.api.errors.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("${openapi.gepafin.base-path:/v1/notification}") +public class NotificationApiController implements NotificationApi { + + @Autowired + private NotificationService notificationService; + + public ResponseEntity> sendNotification(HttpServletRequest request, NotificationReq notificationReq, Long userId) { + + NotificationReq notificationData = notificationService.sendNotification(userId, notificationReq); + + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(notificationData, Status.SUCCESS, Translator.toLocale(NotificationConstant.NOTIFICATION_SENT_SUCCESSFULLY))); + } + +} \ No newline at end of file diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 37bcabad..11f3d75e 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -1,6 +1,6 @@ # DataSource Configuration -spring.datasource.url=jdbc:postgresql://localhost:5432/gepafin_local -spring.datasource.username=postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/gepafin_dev_local +spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=org.postgresql.Driver @@ -20,4 +20,11 @@ appointment.portal.user=UtenzaAPIPortal@621 appointment.portal.password=u13nzaAP1P0rtal appointment.portal.source=GEPAFINPORTAL appointment.portal.context=GEPAFINPORTAL -flagDaFirmare=false \ No newline at end of file +flagDaFirmare=false + +# RabbitMQ properties for STOMP broker relay +spring.rabbitmq.host=localhost +spring.rabbitmq.port=5672 +spring.rabbitmq.username=guest +spring.rabbitmq.password=guest +spring.rabbitmq.virtual-host=/ \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index eb77049e..fde4441d 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -1992,4 +1992,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/dump/insert_json_template_for_notification_13_12_2024.sql b/src/main/resources/db/dump/insert_json_template_for_notification_13_12_2024.sql new file mode 100644 index 00000000..50caaefa --- /dev/null +++ b/src/main/resources/db/dump/insert_json_template_for_notification_13_12_2024.sql @@ -0,0 +1,5 @@ +INSERT INTO notification_type (notification_name, json_template) VALUES +('CALL_CREATED', 'Un nuovo bando intitolato {{call_name}} è stato pubblicato. Controllalo e invia le tue candidature prima della scadenza.'), +('APPLICATION_SUBMISSION', 'La tua richiesta per {{call_name}} ai sensi del protocollo n. {{protocol_number}} è stata presentata con successo. È ora in fase di valutazione.'), +('AMENDMENT_CREATION', 'È stato creato un emendamento per la tua domanda in {{call_name}} ai sensi del protocollo n. {{protocol_number}}. Esamina le modifiche e procedi di conseguenza.'), +('EVALUATION_RESULT', 'Il risultato della valutazione per la tua domanda ai sensi del protocollo n. {{protocol_number}} è ora disponibile. Fai clic qui per visualizzare il tuo feedback.');