RED-3584 / RED-3581 - notification issues
This commit is contained in:
parent
e4b8dfffe3
commit
356b15c837
@ -0,0 +1,11 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.model.notification;
|
||||
|
||||
public enum NotificationType {
|
||||
|
||||
ASSIGN_REVIEWER, ASSIGN_APPROVER, UNASSIGNED_FROM_FILE,
|
||||
DOCUMENT_APPROVED, DOSSIER_OWNER_SET, DOSSIER_OWNER_REMOVED,
|
||||
USER_BECOMES_DOSSIER_MEMBER, USER_REMOVED_AS_DOSSIER_MEMBER,
|
||||
USER_PROMOTED_TO_APPROVER, USER_DEGRADED_TO_REVIEWER,
|
||||
DOSSIER_OWNER_DELETED, DOWNLOAD_READY, DOSSIER_DELETED
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.notification.NotificationEntity;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.EmailNotificationType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NotificationEmailService {
|
||||
|
||||
public void sendNotificationEmail(String userId, EmailNotificationType emailNotificationType, List<NotificationEntity> notifications) {
|
||||
|
||||
switch (emailNotificationType) {
|
||||
case DAILY:
|
||||
sendDailyEmail(userId, notifications);
|
||||
case DAILY_SUMMARY:
|
||||
sendDailySummaryEmail(userId, notifications);
|
||||
case WEEKLY_SUMMARY:
|
||||
sendWeeklySummaryEmail(userId, notifications);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendWeeklySummaryEmail(String userId, List<NotificationEntity> notifications) {
|
||||
log.info("Should send weekly notification summary email for {}", userId);
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void sendDailySummaryEmail(String userId, List<NotificationEntity> notifications) {
|
||||
log.info("Should send daily notification summary email for {}", userId);
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void sendDailyEmail(String userId, List<NotificationEntity> notifications) {
|
||||
log.info("Should send daily notification email for {}", userId);
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -4,6 +4,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.notifica
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.audit.AddNotificationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.EmailNotificationType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@ -20,7 +21,12 @@ public class NotificationPersistenceService {
|
||||
|
||||
private final NotificationRepository notificationRepository;
|
||||
|
||||
private final NotificationPreferencesPersistenceService notificationPreferencesPersistenceService;
|
||||
|
||||
private final NotificationEmailService notificationEmailService;
|
||||
|
||||
public boolean hasNewNotificationsSince(String userId, OffsetDateTime since) {
|
||||
notificationPreferencesPersistenceService.initializePreferencesIfNotExists(userId);
|
||||
return notificationRepository.hasInAppNotificationForUser(userId, since.truncatedTo(ChronoUnit.MILLIS)) > 0;
|
||||
}
|
||||
|
||||
@ -30,6 +36,16 @@ public class NotificationPersistenceService {
|
||||
BeanUtils.copyProperties(addNotificationRequest, notification);
|
||||
notification.setCreationDate(OffsetDateTime.now());
|
||||
|
||||
var notificationPreferences = notificationPreferencesPersistenceService.getOrCreateNotificationPreferences(addNotificationRequest.getUserId());
|
||||
if (!notificationPreferences.isInAppNotificationsEnabled() || notificationPreferences.getInAppNotifications().contains(notification.getNotificationType())) {
|
||||
notification.setSoftDeleted(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
|
||||
}
|
||||
|
||||
if (notificationPreferences.isEmailNotificationsEnabled() && notificationPreferences.getEmailNotifications().contains(notification.getNotificationType())
|
||||
&& notificationPreferences.getEmailNotificationType() == EmailNotificationType.DAILY) {
|
||||
notificationEmailService.sendNotificationEmail(notification.getUserId(), EmailNotificationType.DAILY, List.of(notification));
|
||||
}
|
||||
|
||||
notificationRepository.save(notification);
|
||||
}
|
||||
|
||||
@ -66,12 +82,17 @@ public class NotificationPersistenceService {
|
||||
}
|
||||
|
||||
|
||||
public List<NotificationEntity> getNotifications(String userId, boolean includeSeen) {
|
||||
public List<NotificationEntity> getNotificationsForEmailSummary(String userId, OffsetDateTime from, OffsetDateTime to) {
|
||||
return notificationRepository.findEmailNotificationsForUserId(userId, from, to);
|
||||
}
|
||||
|
||||
|
||||
public List<NotificationEntity> getNotifications(String userId, boolean includeSeen) {
|
||||
notificationPreferencesPersistenceService.initializePreferencesIfNotExists(userId);
|
||||
if (includeSeen) {
|
||||
return notificationRepository.findAppNotificationsForUser(userId);
|
||||
} else {
|
||||
return notificationRepository.findNotNotificationsSeenForUser(userId);
|
||||
return notificationRepository.findUnseenNotificationsForUser(userId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.notification.NotificationPreferencesEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationPreferencesRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.NotificationPreferences;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.NotificationType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ -16,12 +23,27 @@ public class NotificationPreferencesPersistenceService {
|
||||
|
||||
private final NotificationPreferencesRepository notificationPreferencesRepository;
|
||||
|
||||
private final NotificationRepository notificationRepository;
|
||||
|
||||
@Transactional
|
||||
public void setNotificationPreference(String userId, NotificationPreferences notification) {
|
||||
public void setNotificationPreference(String userId, NotificationPreferences newNotificationPreferences) {
|
||||
notificationPreferencesRepository.findById(userId)
|
||||
.ifPresentOrElse(n -> BeanUtils.copyProperties(notification, n), () -> {
|
||||
.ifPresentOrElse(oldNotificationPreferences -> {
|
||||
BeanUtils.copyProperties(newNotificationPreferences, oldNotificationPreferences);
|
||||
|
||||
// if we disabled the notification preferences just now
|
||||
if (oldNotificationPreferences.isInAppNotificationsEnabled() && !newNotificationPreferences.isInAppNotificationsEnabled()) {
|
||||
notificationRepository.deleteAllByUserId(userId, OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
|
||||
}
|
||||
|
||||
var removedNotificationTypes = new ArrayList<>(oldNotificationPreferences.getInAppNotifications());
|
||||
removedNotificationTypes.removeAll(newNotificationPreferences.getInAppNotifications());
|
||||
|
||||
notificationRepository.deleteAllByUserIdAndNotificationTypeIn(userId, removedNotificationTypes, OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
|
||||
|
||||
}, () -> {
|
||||
NotificationPreferencesEntity notificationPreferencesEntity = new NotificationPreferencesEntity();
|
||||
BeanUtils.copyProperties(notification, notificationPreferencesEntity);
|
||||
BeanUtils.copyProperties(newNotificationPreferences, notificationPreferencesEntity);
|
||||
notificationPreferencesEntity.setUserId(userId);
|
||||
notificationPreferencesRepository.save(notificationPreferencesEntity);
|
||||
});
|
||||
@ -33,9 +55,26 @@ public class NotificationPreferencesPersistenceService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public NotificationPreferencesEntity getNotificationPreferences(String userId) {
|
||||
return notificationPreferencesRepository.findById(userId).orElseThrow(() -> {
|
||||
throw new NotFoundException("Notification preferences not found for userId: " + userId);
|
||||
public NotificationPreferencesEntity getOrCreateNotificationPreferences(String userId) {
|
||||
return notificationPreferencesRepository.findById(userId).orElseGet(() -> {
|
||||
|
||||
var notificationPreference = new NotificationPreferencesEntity();
|
||||
notificationPreference.setUserId(userId);
|
||||
notificationPreference.setEmailNotificationsEnabled(false);
|
||||
notificationPreference.setInAppNotificationsEnabled(true);
|
||||
notificationPreference.setInAppNotifications(Arrays.stream(NotificationType.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
return notificationPreferencesRepository.save(notificationPreference);
|
||||
});
|
||||
}
|
||||
|
||||
public void initializePreferencesIfNotExists(String userId) {
|
||||
|
||||
if (!notificationPreferencesRepository.existsByUserId(userId)) {
|
||||
getOrCreateNotificationPreferences(userId);
|
||||
}
|
||||
}
|
||||
|
||||
public List<NotificationPreferencesEntity> findAll() {
|
||||
return notificationPreferencesRepository.findAll();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,4 +4,5 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.notifica
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface NotificationPreferencesRepository extends JpaRepository<NotificationPreferencesEntity, String> {
|
||||
boolean existsByUserId(String userId);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface NotificationRepository extends JpaRepository<NotificationEntity, Long> {
|
||||
@ -13,30 +14,24 @@ public interface NotificationRepository extends JpaRepository<NotificationEntity
|
||||
|
||||
@Query("select count(n) from NotificationEntity n where " +
|
||||
" ( " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId )) " +
|
||||
" or" +
|
||||
" not exists (select e from NotificationPreferencesEntity e where e.userId = :userId) " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId and p.inAppNotificationsEnabled = true )) " +
|
||||
" ) " +
|
||||
" and n.softDeleted is null and n.userId = :userId and n.creationDate > :since")
|
||||
int hasInAppNotificationForUser(String userId, OffsetDateTime since);
|
||||
|
||||
@Query("Select n from NotificationEntity n where " +
|
||||
@Query("select n from NotificationEntity n where " +
|
||||
" ( " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId )) " +
|
||||
" or" +
|
||||
" not exists (select e from NotificationPreferencesEntity e where e.userId = :userId) " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId and p.inAppNotificationsEnabled = true )) " +
|
||||
" ) " +
|
||||
" and n.softDeleted is null and n.userId = :userId order by n.creationDate desc")
|
||||
List<NotificationEntity> findAppNotificationsForUser(String userId);
|
||||
|
||||
@Query("Select n from NotificationEntity n where " +
|
||||
@Query("select n from NotificationEntity n where " +
|
||||
" ( " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId )) " +
|
||||
" or" +
|
||||
" not exists (select e from NotificationPreferencesEntity e where e.userId = :userId) " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.inAppNotifications apn where p.userId = :userId and p.inAppNotificationsEnabled = true )) " +
|
||||
" ) " +
|
||||
" and n.seenDate is null and n.softDeleted is null and n.userId = :userId order by n.creationDate desc")
|
||||
List<NotificationEntity> findNotNotificationsSeenForUser(String userId);
|
||||
" and n.seenDate is null and n.softDeleted is null and n.userId = :userId order by n.creationDate desc ")
|
||||
List<NotificationEntity> findUnseenNotificationsForUser(String userId);
|
||||
|
||||
@Modifying
|
||||
@Query("update NotificationEntity n set n.seenDate = :seenDate where n.id = :notificationId and n.userId = :userId")
|
||||
@ -49,4 +44,21 @@ public interface NotificationRepository extends JpaRepository<NotificationEntity
|
||||
@Modifying
|
||||
@Query("update NotificationEntity n set n.softDeleted = :softDeleted where n.id = :notificationId and n.userId = :userId")
|
||||
int softDelete(String userId, long notificationId, OffsetDateTime softDeleted);
|
||||
|
||||
@Modifying
|
||||
@Query("update NotificationEntity n set n.softDeleted = :softDeleted where n.userId = :userId")
|
||||
void deleteAllByUserId(String userId, OffsetDateTime softDeleted);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("update NotificationEntity n set n.softDeleted = :softDeleted where n.userId = :userId and n.notificationType in :removedNotificationTypes")
|
||||
void deleteAllByUserIdAndNotificationTypeIn(String userId, List<String> removedNotificationTypes, OffsetDateTime softDeleted);
|
||||
|
||||
|
||||
@Query("select n from NotificationEntity n where " +
|
||||
" ( " +
|
||||
" (exists (select e from NotificationPreferencesEntity e where e.userId = :userId) and n.notificationType in ( select apn from NotificationPreferencesEntity p join p.emailNotifications apn where p.userId = :userId and p.emailNotificationsEnabled = true )) " +
|
||||
" ) " +
|
||||
" and n.userId = :userId and n.creationDate :from and n.creationDate <= :to order by n.creationDate desc")
|
||||
List<NotificationEntity> findEmailNotificationsForUserId(String userId, OffsetDateTime from, OffsetDateTime to);
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ public class NotificationPreferencesController implements NotificationPreference
|
||||
|
||||
@Override
|
||||
public NotificationPreferences getNotificationPreferences(String userId) {
|
||||
return convert(notificationPreferencesPersistenceService.getNotificationPreferences(userId), NotificationPreferences.class);
|
||||
return convert(notificationPreferencesPersistenceService.getOrCreateNotificationPreferences(userId), NotificationPreferences.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -3,6 +3,7 @@ package com.iqser.red.service.peristence.v1.server.jobs;
|
||||
import com.iqser.red.service.peristence.v1.server.service.job.AutomaticAnalysisJob;
|
||||
import com.iqser.red.service.peristence.v1.server.service.job.DeletedFilesCleanupJob;
|
||||
import com.iqser.red.service.peristence.v1.server.service.job.DownloadCleanupJob;
|
||||
import com.iqser.red.service.peristence.v1.server.service.job.SendNotificationEmailJob;
|
||||
import org.quartz.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -12,6 +13,26 @@ import java.text.ParseException;
|
||||
@Configuration
|
||||
public class CreateJobsConfiguration {
|
||||
|
||||
@Bean
|
||||
public JobDetail notificationEmailSummaryJob() {
|
||||
return JobBuilder.newJob().ofType(SendNotificationEmailJob.class)
|
||||
.storeDurably()
|
||||
.withIdentity("SendNotificationEmailJob")
|
||||
.withDescription("Send summary email with daily/weekly notifications")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Trigger notificationEmailSummaryJobTrigger() throws ParseException {
|
||||
return TriggerBuilder.newTrigger().forJob(notificationEmailSummaryJob())
|
||||
.withIdentity("SendNotificationEmailJobTrigger")
|
||||
.withDescription("Triggers SendNotificationEmailJob every night at 3 AM")
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(new CronExpression("0 0 3 * * ?")))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Bean
|
||||
public JobDetail automaticAnalysisJobDetail() {
|
||||
return JobBuilder.newJob().ofType(AutomaticAnalysisJob.class)
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package com.iqser.red.service.peristence.v1.server.service.job;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationEmailService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPreferencesPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.model.notification.EmailNotificationType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SendNotificationEmailJob implements Job {
|
||||
|
||||
private final NotificationEmailService notificationEmailService;
|
||||
private final NotificationPersistenceService notificationPersistenceService;
|
||||
private final NotificationPreferencesPersistenceService notificationPreferencesPersistenceService;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
|
||||
|
||||
var allConfiguredPreferences = notificationPreferencesPersistenceService.findAll();
|
||||
allConfiguredPreferences.forEach(preference -> {
|
||||
if (preference.isEmailNotificationsEnabled()) {
|
||||
|
||||
// summary emails only
|
||||
if (preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY || preference.getEmailNotificationType() == EmailNotificationType.DAILY_SUMMARY) {
|
||||
|
||||
var now = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS);
|
||||
|
||||
// Weekly summary is sent monday night
|
||||
if (now.getDayOfWeek() == DayOfWeek.MONDAY && preference.getEmailNotificationType() == EmailNotificationType.WEEKLY_SUMMARY) {
|
||||
var from = OffsetDateTime.now().minusDays(7).truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var to = OffsetDateTime.now().truncatedTo(ChronoUnit.HOURS).withHour(0);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.WEEKLY_SUMMARY, notifications);
|
||||
} else {
|
||||
var from = OffsetDateTime.now().minusDays(1).withHour(0).truncatedTo(ChronoUnit.HOURS);
|
||||
var to = OffsetDateTime.now().minusDays(1).withHour(23).truncatedTo(ChronoUnit.HOURS);
|
||||
var notifications = notificationPersistenceService.getNotificationsForEmailSummary(preference.getUserId(), from, to);
|
||||
|
||||
notificationEmailService.sendNotificationEmail(preference.getUserId(), EmailNotificationType.DAILY_SUMMARY, notifications);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user