package net.gepafin.tendermanagement.dao; import lombok.extern.slf4j.Slf4j; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.ApplicationEntity; import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; import net.gepafin.tendermanagement.entities.NotificationEntity; import net.gepafin.tendermanagement.entities.NotificationTypeEntity; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.entities.UserWithCompanyEntity; import net.gepafin.tendermanagement.enums.NotificationEnum; import net.gepafin.tendermanagement.enums.NotificationTypeEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; import net.gepafin.tendermanagement.model.request.NotificationReq; import net.gepafin.tendermanagement.model.response.NotificationResponse; import net.gepafin.tendermanagement.repositories.NotificationRepository; import net.gepafin.tendermanagement.repositories.NotificationTypeRepository; import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.repositories.UserWithCompanyRepository; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static org.hibernate.internal.util.collections.CollectionHelper.listOf; @Component @Slf4j public class NotificationDao { @Autowired private SimpMessagingTemplate messagingTemplate; @Autowired private NotificationRepository notificationRepository; @Autowired private NotificationTypeRepository notificationTypeRepository; @Autowired private UserWithCompanyRepository userWithCompanyRepository; @Autowired private UserRepository userRepository; @Autowired private CompanyDao companyDao; @Autowired private ApplicationService applicationService; @Autowired private UserDao userDao; public NotificationResponse 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 == null || companyIds.isEmpty()) { sendToUser(userId, notificationEntity); } else { sendToCompanies(userId, companyIds, notificationEntity); } return convertNotificationEntityToNotificationResponse(notificationEntity); } private NotificationEntity saveNotification(NotificationReq notificationReq) { return notificationRepository.save(convertNotificationRequestToNotificationEntity(notificationReq)); } private void sendToUser(Long userId, NotificationEntity notificationEntity) { String userChannel = GepafinConstant.COMMON_SINGLE_CHANNEL_PREFIX + userId; log.info("Channel for User {}", userChannel); NotificationResponse notificationResponse = convertNotificationEntityToNotificationResponse(notificationEntity); messagingTemplate.convertAndSend(userChannel, notificationResponse); } private void sendToCompanies(Long userId, List companyIds, NotificationEntity notificationEntity) { // Send notification to each company provided in the companyIds list companyIds.forEach(companyId -> { UserWithCompanyEntity userWithCompany = userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalseForNotification(userId, companyId); String companyChannel = Utils.createChannelForUserAndCompany(userId, companyId); log.info("Channel for User and Company {}, {}", userId, companyChannel); if (userWithCompany == null) { throw new CustomValidationException(Status.BAD_REQUEST, GepafinConstant.USER_WITH_COMPANY_NOT_FOUND); } notificationEntity.setUserWithCompany(userWithCompany); notificationRepository.save(notificationEntity); NotificationResponse notificationResponse = convertNotificationEntityToNotificationResponse(notificationEntity); messagingTemplate.convertAndSend(companyChannel, notificationResponse); }); } private NotificationResponse convertNotificationEntityToNotificationResponse(NotificationEntity notificationEntity) { NotificationResponse notificationResponse = new NotificationResponse(); notificationResponse.setId(notificationEntity.getId()); notificationResponse.setUserId(notificationEntity.getUserId()); notificationResponse.setStatus(notificationEntity.getStatus()); notificationResponse.setMessage(notificationEntity.getMessage()); notificationResponse.setCreatedDate(notificationEntity.getCreatedDate()); notificationResponse.setUpdatedDate(notificationEntity.getUpdatedDate()); notificationResponse.setRedirectUrl(notificationEntity.getNotificationType()); notificationResponse.setCompanyId(notificationEntity.getUserWithCompany() != null ? notificationEntity.getUserWithCompany().getCompanyId() : null); notificationResponse.setNotificationType(notificationEntity.getNotificationType()); notificationResponse.setTitle(notificationEntity.getTitle()); return notificationResponse; } private NotificationEntity convertNotificationRequestToNotificationEntity(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.setUserWithCompany(notificationReq.getUserWithCompanyEntity() != null ? notificationReq.getUserWithCompanyEntity() : null); notificationEntity.setMessage(message); notificationEntity.setTitle(notificationReq.getTitle()); return notificationEntity; } public NotificationReq createNotificationReq(String notificationType, Map placeholders, Long userId, UserWithCompanyEntity userWithCompanyEntity, List companyIds) { // 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); notificationReq.setCompanyIds(companyIds); String title = Utils.replacePlaceholders(notificationTypeEntity.getTitle(), placeholders); notificationReq.setTitle(title); notificationReq.setUserWithCompanyEntity(userWithCompanyEntity); return notificationReq; } public Map sendNotificationToBeneficiary(ApplicationEntity application, NotificationTypeEnum notificationTypeEnum) { Map placeHolders = new HashMap<>(); placeHolders.put("{{call_name}}", application.getCall().getName()); placeHolders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber())); NotificationReq notificationReq = createNotificationReq(notificationTypeEnum.getValue(), placeHolders, application.getUserId(), application.getUserWithCompany(), listOf(application.getCompanyId())); sendNotification(notificationReq); return placeHolders; } public void sendNotificationToInstructor(Map placeHolders, ApplicationEvaluationEntity applicationEvaluationEntity, NotificationTypeEnum notificationTypeEnum) { Long instructorId = applicationEvaluationEntity.getUserId(); ApplicationEntity application = applicationService.validateApplication(applicationEvaluationEntity.getApplicationId()); if (instructorId != null) { NotificationReq notificationreq = createNotificationReq(notificationTypeEnum.getValue(), placeHolders, instructorId, application.getUserWithCompany(), listOf(application.getCompanyId())); sendNotification(notificationreq); } } public void sendNotificationToSuperUser(ApplicationEntity application, Map placeHolders, NotificationTypeEnum notificationTypeEnum) { List user = userRepository.findByRoleEntity_RoleTypeAndHubId(RoleStatusEnum.ROLE_SUPER_ADMIN.getValue(), application.getHubId()); UserEntity userEntity1 = user.get(0); if (userEntity1 != null) { NotificationReq notificationreq = createNotificationReq(notificationTypeEnum.getValue(), placeHolders, userEntity1.getId(), application.getUserWithCompany(), listOf(application.getCompanyId())); sendNotification(notificationreq); } } public List getAllCompanyIdsForUser(Long userId) { return userWithCompanyRepository.findActiveCompanyIdsByUserId(userId); } public NotificationResponse getNotificationById(Long id) { NotificationEntity notificationEntity = validateNotificationEntity(id); return convertNotificationEntityToNotificationResponse(notificationEntity); } private NotificationEntity validateNotificationEntity(Long id) { NotificationEntity notificationEntity = notificationRepository.findByIdAndIsDeletedFalse(id); if (notificationEntity == null) { throw new CustomValidationException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.NOTIFICATION_NOT_FOUND)); } return notificationEntity; } public List getNotificationByUserId(Long userId, Long companyId, List statuses) { List notificationEntities = notificationRepository.findByUserIdAndIsDeletedFalse(userId); UserWithCompanyEntity userWithCompany = null; List statusStrings = new ArrayList<>(); if (companyId != null) { userWithCompany = companyDao.validateUserWithCompny(userId, companyId); } if (statuses != null) { statusStrings = statuses.stream().map(NotificationEnum::name) // Convert enum to its name as String .toList(); notificationEntities = notificationRepository.findByUserIdAndIsDeletedFalseAndStatusIn(userId, statusStrings); if (userWithCompany != null) { notificationEntities = notificationRepository.findByUserIdAndUserWithCompanyIdAndIsDeletedFalseAndStatusIn(userId, userWithCompany.getId(), statusStrings); } } return notificationEntities.stream().map(this::convertNotificationEntityToNotificationResponse).collect(Collectors.toList()); } public NotificationResponse updateNotificationStatus(Long id, NotificationEnum status) { NotificationEntity notificationEntity = validateNotificationEntity(id); if (notificationEntity.getStatus().equals(status.getValue())) { throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NOTIFICATION_ALREADY_IN_THAT_STATE)); } notificationEntity.setStatus(status.getValue()); notificationEntity.setUpdatedDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); notificationRepository.save(notificationEntity); return convertNotificationEntityToNotificationResponse(notificationEntity); } public void deleteNotification(Long id) { NotificationEntity notificationEntity = validateNotificationEntity(id); notificationEntity.setIsDeleted(true); notificationRepository.save(notificationEntity); } public List getNotificationByCompanyIdAndUserId(Long userId, Long companyId) { companyDao.validateCompany(companyId); userDao.validateUser(userId); UserWithCompanyEntity userWithCompanyData = userWithCompanyRepository.findByUserIdAndCompanyIdAndIsDeletedFalseForNotification(userId, companyId); if (userWithCompanyData == null) { throw new CustomValidationException(Status.BAD_REQUEST, GepafinConstant.USER_MUST_BE_ASSOCIATED_WITH_COMPANY); } List notifications = notificationRepository.findByUserWithCompanyIdAndUserIdAndIsDeletedFalse(userWithCompanyData.getId(), userWithCompanyData.getUserId()); return notifications.stream().map(this::convertNotificationEntityToNotificationResponse).toList(); } }