From 52b3662b1998b477c013be99e24ca4273650e82f Mon Sep 17 00:00:00 2001 From: Hai Nguyen Date: Wed, 29 Jan 2025 00:04:38 -0800 Subject: [PATCH] Event handlers for new comment (#63) --- .../modules/collab/EmailContext.java | 1 + .../collab/controller/CommentController.java | 6 +- .../collab/service/CommentService.java | 8 +- .../service/TeamRequestHealthEvalService.java | 8 +- ...va => TeamRequestCommentCreatedEvent.java} | 4 +- .../listener/NewTeamCreatedEventListener.java | 16 --- ...ewTeamRequestCreatedMailEventListener.java | 2 +- ...questCreatedNotificationEventListener.java | 17 ++- ...RemoveUserOutOfTeamMailEventListener.java} | 2 +- ...luateConversationHealthEventListener.java} | 8 +- ...equestCommentCreatedMailEventListener.java | 80 ++++++++++++ ...mmentCreatedNotificationEventListener.java | 121 ++++++++++++++++++ .../repository/UserRepository.java | 2 + .../io/flowinquiry/utils/StringUtils.java | 11 ++ .../resources/i18n/messages_en.properties | 17 ++- .../templates/mail/activationEmail.html | 6 +- .../templates/mail/creationEmail.html | 6 +- .../templates/mail/newTicketCommentEmail.html | 56 ++++++++ .../templates/mail/newTicketEmail.html | 11 +- .../templates/mail/passwordResetEmail.html | 6 +- 20 files changed, 330 insertions(+), 58 deletions(-) rename commons/src/main/java/io/flowinquiry/modules/teams/service/event/{TeamRequestNewCommentEvent.java => TeamRequestCommentCreatedEvent.java} (66%) delete mode 100644 commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamCreatedEventListener.java rename commons/src/main/java/io/flowinquiry/modules/teams/service/listener/{RemoveUserOutOfTeamEmailEventListener.java => RemoveUserOutOfTeamMailEventListener.java} (90%) rename commons/src/main/java/io/flowinquiry/modules/teams/service/listener/{TeamRequestNewCommentAiEvaluateConversationHealthEventListener.java => TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener.java} (84%) create mode 100644 commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedMailEventListener.java create mode 100644 commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedNotificationEventListener.java create mode 100644 commons/src/main/java/io/flowinquiry/utils/StringUtils.java create mode 100644 commons/src/main/resources/templates/mail/newTicketCommentEmail.html diff --git a/commons/src/main/java/io/flowinquiry/modules/collab/EmailContext.java b/commons/src/main/java/io/flowinquiry/modules/collab/EmailContext.java index bd931547..e778c552 100644 --- a/commons/src/main/java/io/flowinquiry/modules/collab/EmailContext.java +++ b/commons/src/main/java/io/flowinquiry/modules/collab/EmailContext.java @@ -29,6 +29,7 @@ public EmailContext(Locale locale) { public EmailContext setToUser(UserDTO toUser) { this.toUser = toUser; + thymeleafContext.setVariable("user", toUser); return this; } diff --git a/commons/src/main/java/io/flowinquiry/modules/collab/controller/CommentController.java b/commons/src/main/java/io/flowinquiry/modules/collab/controller/CommentController.java index d3594e03..a9a707df 100644 --- a/commons/src/main/java/io/flowinquiry/modules/collab/controller/CommentController.java +++ b/commons/src/main/java/io/flowinquiry/modules/collab/controller/CommentController.java @@ -1,6 +1,5 @@ package io.flowinquiry.modules.collab.controller; -import io.flowinquiry.modules.collab.domain.Comment; import io.flowinquiry.modules.collab.domain.EntityType; import io.flowinquiry.modules.collab.service.CommentService; import io.flowinquiry.modules.collab.service.dto.CommentDTO; @@ -32,9 +31,8 @@ public ResponseEntity saveComment(@RequestBody CommentDTO comment) { } @GetMapping("/{id}") - public ResponseEntity getCommentById(@PathVariable("id") Long id) { - Comment comment = commentService.getCommentById(id); - return ResponseEntity.ok(comment); + public CommentDTO getCommentById(@PathVariable("id") Long id) { + return commentService.getCommentById(id); } @GetMapping diff --git a/commons/src/main/java/io/flowinquiry/modules/collab/service/CommentService.java b/commons/src/main/java/io/flowinquiry/modules/collab/service/CommentService.java index 5fa71f19..064ab9e4 100644 --- a/commons/src/main/java/io/flowinquiry/modules/collab/service/CommentService.java +++ b/commons/src/main/java/io/flowinquiry/modules/collab/service/CommentService.java @@ -1,11 +1,10 @@ package io.flowinquiry.modules.collab.service; -import io.flowinquiry.modules.collab.domain.Comment; import io.flowinquiry.modules.collab.domain.EntityType; import io.flowinquiry.modules.collab.repository.CommentRepository; import io.flowinquiry.modules.collab.service.dto.CommentDTO; import io.flowinquiry.modules.collab.service.mapper.CommentMapper; -import io.flowinquiry.modules.teams.service.event.TeamRequestNewCommentEvent; +import io.flowinquiry.modules.teams.service.event.TeamRequestCommentCreatedEvent; import java.util.List; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -34,14 +33,15 @@ public CommentDTO saveComment(CommentDTO comment) { CommentDTO savedComment = commentMapper.toDTO(commentRepository.save(commentMapper.toEntity(comment))); if (savedComment.getEntityType() == EntityType.Team_Request) { - eventPublisher.publishEvent(new TeamRequestNewCommentEvent(this, savedComment)); + eventPublisher.publishEvent(new TeamRequestCommentCreatedEvent(this, savedComment)); } return savedComment; } - public Comment getCommentById(Long id) { + public CommentDTO getCommentById(Long id) { return commentRepository .findById(id) + .map(commentMapper::toDTO) .orElseThrow( () -> new IllegalArgumentException("Comment not found with id: " + id)); } diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/TeamRequestHealthEvalService.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/TeamRequestHealthEvalService.java index 7c4f20a2..9ebf9ddf 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/TeamRequestHealthEvalService.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/TeamRequestHealthEvalService.java @@ -1,10 +1,11 @@ package io.flowinquiry.modules.teams.service; +import static io.flowinquiry.utils.StringUtils.polishedHtmlTagsMessage; + import io.flowinquiry.modules.ai.service.ChatModelService; import io.flowinquiry.modules.teams.domain.TeamRequest; import io.flowinquiry.modules.teams.domain.TeamRequestConversationHealth; import io.flowinquiry.modules.teams.repository.TeamRequestConversationHealthRepository; -import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.prompt.Prompt; @@ -177,9 +178,4 @@ private TeamRequestConversationHealth createNewConversationHealth( health.setSummary(generateSummary(firstMessage)); return teamRequestConversationHealthRepository.save(health); } - - private String polishedHtmlTagsMessage(String message) { - String preProcessedHtml = message.replaceAll(">(\\s*)<", "> <"); - return StringEscapeUtils.unescapeHtml4(preProcessedHtml).replaceAll("<[^>]+>", ""); - } } diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestNewCommentEvent.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestCommentCreatedEvent.java similarity index 66% rename from commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestNewCommentEvent.java rename to commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestCommentCreatedEvent.java index 9caf4c5c..4fd5424e 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestNewCommentEvent.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/event/TeamRequestCommentCreatedEvent.java @@ -5,10 +5,10 @@ import org.springframework.context.ApplicationEvent; @Getter -public class TeamRequestNewCommentEvent extends ApplicationEvent { +public class TeamRequestCommentCreatedEvent extends ApplicationEvent { private final CommentDTO commentDTO; - public TeamRequestNewCommentEvent(Object source, CommentDTO commentDTO) { + public TeamRequestCommentCreatedEvent(Object source, CommentDTO commentDTO) { super(source); this.commentDTO = commentDTO; } diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamCreatedEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamCreatedEventListener.java deleted file mode 100644 index 0eb99c87..00000000 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamCreatedEventListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.flowinquiry.modules.teams.service.listener; - -import io.flowinquiry.modules.teams.service.event.NewTeamRequestCreatedEvent; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -@Component -public class NewTeamCreatedEventListener { - - @Async("asyncTaskExecutor") - @Transactional - @EventListener - public void onNewTeamCreated(NewTeamRequestCreatedEvent event) {} -} diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedMailEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedMailEventListener.java index 78223ffc..490690af 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedMailEventListener.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedMailEventListener.java @@ -50,7 +50,7 @@ public void onNewTeamRequestCreated(NewTeamRequestCreatedEvent event) { new EmailContext(Locale.forLanguageTag("en")) .setToUser(watcherMapper.toUserDto(watcher)) .setSubject( - "mail.newticket.title", + "email.new.ticket.subject", teamRequestDTO.getRequestTitle()) .addVariable("ticket", teamRequestDTO) .setTemplate("mail/newTicketEmail"); diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedNotificationEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedNotificationEventListener.java index adb569ac..876f7a1b 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedNotificationEventListener.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/NewTeamRequestCreatedNotificationEventListener.java @@ -4,6 +4,7 @@ import static j2html.TagCreator.p; import static j2html.TagCreator.text; +import io.flowinquiry.exceptions.ResourceNotFoundException; import io.flowinquiry.modules.collab.domain.ActivityLog; import io.flowinquiry.modules.collab.domain.EntityType; import io.flowinquiry.modules.collab.domain.Notification; @@ -13,6 +14,7 @@ import io.flowinquiry.modules.teams.service.dto.TeamRequestDTO; import io.flowinquiry.modules.teams.service.event.NewTeamRequestCreatedEvent; import io.flowinquiry.modules.usermanagement.domain.User; +import io.flowinquiry.modules.usermanagement.repository.UserRepository; import io.flowinquiry.modules.usermanagement.service.dto.UserWithTeamRoleDTO; import io.flowinquiry.utils.Obfuscator; import java.util.List; @@ -26,14 +28,17 @@ public class NewTeamRequestCreatedNotificationEventListener { private final NotificationRepository notificationRepository; private final TeamRepository teamRepository; private final ActivityLogRepository activityLogRepository; + private final UserRepository userRepository; public NewTeamRequestCreatedNotificationEventListener( NotificationRepository notificationRepository, TeamRepository teamRepository, - ActivityLogRepository activityLogRepository) { + ActivityLogRepository activityLogRepository, + UserRepository userRepository) { this.notificationRepository = notificationRepository; this.teamRepository = teamRepository; this.activityLogRepository = activityLogRepository; + this.userRepository = userRepository; } @Async("asyncTaskExecutor") @@ -41,9 +46,17 @@ public NewTeamRequestCreatedNotificationEventListener( @EventListener public void onNewTeamRequestCreated(NewTeamRequestCreatedEvent event) { TeamRequestDTO teamRequestDTO = event.getTeamRequest(); + User requestUser = + userRepository + .findOneById(teamRequestDTO.getRequestUserId()) + .orElseThrow( + () -> + new ResourceNotFoundException( + "User not found: " + + teamRequestDTO.getRequestUserId())); String html = p( - a(teamRequestDTO.getRequestUserName()) + a(requestUser.getFirstName() + " " + requestUser.getLastName()) .withHref( "/portal/users/" + Obfuscator.obfuscate( diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamEmailEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamMailEventListener.java similarity index 90% rename from commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamEmailEventListener.java rename to commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamMailEventListener.java index 30cb9cda..d658d508 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamEmailEventListener.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/RemoveUserOutOfTeamMailEventListener.java @@ -7,7 +7,7 @@ import org.springframework.transaction.annotation.Transactional; @Component -public class RemoveUserOutOfTeamEmailEventListener { +public class RemoveUserOutOfTeamMailEventListener { @Async("asyncTaskExecutor") @EventListener diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestNewCommentAiEvaluateConversationHealthEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener.java similarity index 84% rename from commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestNewCommentAiEvaluateConversationHealthEventListener.java rename to commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener.java index e677bf4b..ec750491 100644 --- a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestNewCommentAiEvaluateConversationHealthEventListener.java +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener.java @@ -4,7 +4,7 @@ import io.flowinquiry.modules.teams.service.TeamRequestHealthEvalService; import io.flowinquiry.modules.teams.service.TeamRequestService; import io.flowinquiry.modules.teams.service.dto.TeamRequestDTO; -import io.flowinquiry.modules.teams.service.event.TeamRequestNewCommentEvent; +import io.flowinquiry.modules.teams.service.event.TeamRequestCommentCreatedEvent; import java.util.Objects; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.event.EventListener; @@ -13,13 +13,13 @@ @Component @ConditionalOnBean(TeamRequestHealthEvalService.class) -public class TeamRequestNewCommentAiEvaluateConversationHealthEventListener { +public class TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener { private final TeamRequestService teamRequestService; private final TeamRequestHealthEvalService teamRequestHealthEvalService; - public TeamRequestNewCommentAiEvaluateConversationHealthEventListener( + public TeamRequestCommentCreatedAiEvaluateConversationHealthEventListener( TeamRequestService teamRequestService, TeamRequestHealthEvalService teamRequestHealthEvalService) { this.teamRequestHealthEvalService = teamRequestHealthEvalService; @@ -29,7 +29,7 @@ public TeamRequestNewCommentAiEvaluateConversationHealthEventListener( @Async("asyncTaskExecutor") @EventListener public void onTeamRequestNewCommentAiEvaluateConversationHealthEvent( - TeamRequestNewCommentEvent event) { + TeamRequestCommentCreatedEvent event) { CommentDTO comment = event.getCommentDTO(); TeamRequestDTO teamRequestDTO = teamRequestService.getTeamRequestById(comment.getEntityId()); diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedMailEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedMailEventListener.java new file mode 100644 index 00000000..6c7cafab --- /dev/null +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedMailEventListener.java @@ -0,0 +1,80 @@ +package io.flowinquiry.modules.teams.service.listener; + +import io.flowinquiry.modules.collab.EmailContext; +import io.flowinquiry.modules.collab.service.CommentService; +import io.flowinquiry.modules.collab.service.MailService; +import io.flowinquiry.modules.collab.service.dto.CommentDTO; +import io.flowinquiry.modules.teams.repository.TeamRequestWatcherRepository; +import io.flowinquiry.modules.teams.service.TeamRequestService; +import io.flowinquiry.modules.teams.service.dto.TeamRequestDTO; +import io.flowinquiry.modules.teams.service.dto.WatcherDTO; +import io.flowinquiry.modules.teams.service.event.TeamRequestCommentCreatedEvent; +import io.flowinquiry.modules.teams.service.mapper.WatcherMapper; +import io.flowinquiry.utils.Obfuscator; +import java.util.List; +import java.util.Locale; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +public class TeamRequestCommentCreatedMailEventListener { + private final CommentService commentService; + private final WatcherMapper watcherMapper; + private final TeamRequestWatcherRepository teamRequestWatcherRepository; + private final TeamRequestService teamRequestService; + private final MailService mailService; + + public TeamRequestCommentCreatedMailEventListener( + CommentService commentService, + WatcherMapper watcherMapper, + TeamRequestWatcherRepository teamRequestWatcherRepository, + TeamRequestService teamRequestService, + MailService mailService) { + this.commentService = commentService; + this.watcherMapper = watcherMapper; + this.teamRequestWatcherRepository = teamRequestWatcherRepository; + this.teamRequestService = teamRequestService; + this.mailService = mailService; + } + + @Async("asyncTaskExecutor") + @Transactional + @EventListener + public void onTeamRequestCommentCreated(TeamRequestCommentCreatedEvent event) { + CommentDTO commentDTO = commentService.getCommentById(event.getCommentDTO().getId()); + List watchers = + teamRequestWatcherRepository.findWatchersByRequestId(commentDTO.getEntityId()); + + TeamRequestDTO teamRequestDTO = + teamRequestService.getTeamRequestById(commentDTO.getEntityId()); + + if (!watchers.isEmpty()) { + for (WatcherDTO watcher : watchers) { + // Skip sending email if the watcher is the comment creator + if (watcher.getId().equals(commentDTO.getCreatedById())) { + continue; + } + + EmailContext emailContext = + new EmailContext(Locale.forLanguageTag("en")) + .setToUser(watcherMapper.toUserDto(watcher)) + .setSubject( + "email.new.ticket.comment.subject", + teamRequestDTO.getRequestTitle()) + .addVariable("ticket", teamRequestDTO) + .addVariable("comment", commentDTO) + .addVariable( + "obfuscatedTeamId", + Obfuscator.obfuscate(teamRequestDTO.getTeamId())) + .addVariable( + "obfuscatedTicketId", + Obfuscator.obfuscate(teamRequestDTO.getId())) + .setTemplate("mail/newTicketCommentEmail"); + + mailService.sendEmail(emailContext); + } + } + } +} diff --git a/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedNotificationEventListener.java b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedNotificationEventListener.java new file mode 100644 index 00000000..c73cf4cb --- /dev/null +++ b/commons/src/main/java/io/flowinquiry/modules/teams/service/listener/TeamRequestCommentCreatedNotificationEventListener.java @@ -0,0 +1,121 @@ +package io.flowinquiry.modules.teams.service.listener; + +import static j2html.TagCreator.a; +import static j2html.TagCreator.p; +import static j2html.TagCreator.text; + +import io.flowinquiry.exceptions.ResourceNotFoundException; +import io.flowinquiry.modules.collab.domain.ActivityLog; +import io.flowinquiry.modules.collab.domain.EntityType; +import io.flowinquiry.modules.collab.domain.Notification; +import io.flowinquiry.modules.collab.repository.ActivityLogRepository; +import io.flowinquiry.modules.collab.repository.NotificationRepository; +import io.flowinquiry.modules.collab.service.dto.CommentDTO; +import io.flowinquiry.modules.teams.domain.TeamRequest; +import io.flowinquiry.modules.teams.repository.TeamRepository; +import io.flowinquiry.modules.teams.repository.TeamRequestRepository; +import io.flowinquiry.modules.teams.service.event.TeamRequestCommentCreatedEvent; +import io.flowinquiry.modules.usermanagement.domain.User; +import io.flowinquiry.modules.usermanagement.repository.UserRepository; +import io.flowinquiry.modules.usermanagement.service.dto.UserWithTeamRoleDTO; +import io.flowinquiry.utils.Obfuscator; +import io.flowinquiry.utils.StringUtils; +import java.util.List; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +public class TeamRequestCommentCreatedNotificationEventListener { + + private final UserRepository userRepository; + private final TeamRequestRepository teamRequestRepository; + private final TeamRepository teamRepository; + private final NotificationRepository notificationRepository; + private final ActivityLogRepository activityLogRepository; + + public TeamRequestCommentCreatedNotificationEventListener( + UserRepository userRepository, + TeamRequestRepository teamRequestRepository, + TeamRepository teamRepository, + NotificationRepository notificationRepository, + ActivityLogRepository activityLogRepository) { + this.userRepository = userRepository; + this.teamRequestRepository = teamRequestRepository; + this.teamRepository = teamRepository; + this.notificationRepository = notificationRepository; + this.activityLogRepository = activityLogRepository; + } + + @Async("asyncTaskExecutor") + @Transactional + @EventListener + public void onTeamRequestCommentCreated(TeamRequestCommentCreatedEvent event) { + CommentDTO commentDTO = event.getCommentDTO(); + + User createdUser = + userRepository + .findById(commentDTO.getCreatedById()) + .orElseThrow( + () -> + new ResourceNotFoundException( + "User not found " + commentDTO.getCreatedById())); + TeamRequest teamRequest = + teamRequestRepository + .findById(commentDTO.getEntityId()) + .orElseThrow( + () -> + new ResourceNotFoundException( + "TeamRequest not found " + + commentDTO.getEntityId())); + + String commentContent = StringUtils.polishedHtmlTagsMessage(commentDTO.getContent()); + String truncatedContent = + commentContent.length() > 50 + ? commentContent.substring(0, 50) + "..." + : commentContent; + + String html = + p( + a(createdUser.getFirstName() + " " + createdUser.getLastName()) + .withHref( + "/portal/users/" + + Obfuscator.obfuscate( + createdUser.getId())), + text(" has created a new comment for the request "), + a(teamRequest.getRequestTitle()) + .withHref( + "/portal/teams/" + + Obfuscator.obfuscate( + teamRequest.getTeam().getId()) + + "/requests/" + + Obfuscator.obfuscate( + teamRequest.getId())), + text(": " + truncatedContent)) + .render(); + + List usersInTeam = + teamRepository.findUsersByTeamId(teamRequest.getTeam().getId()); + List notifications = + usersInTeam.stream() + .filter(user -> !user.getId().equals(commentDTO.getCreatedById())) + .map( + user -> + Notification.builder() + .content(html) + .user(User.builder().id(user.getId()).build()) + .isRead(false) + .build()) + .toList(); + notificationRepository.saveAll(notifications); + + ActivityLog activityLog = + ActivityLog.builder() + .entityId(teamRequest.getTeam().getId()) + .entityType(EntityType.Team) + .content(html) + .build(); + activityLogRepository.save(activityLog); + } +} diff --git a/commons/src/main/java/io/flowinquiry/modules/usermanagement/repository/UserRepository.java b/commons/src/main/java/io/flowinquiry/modules/usermanagement/repository/UserRepository.java index 9fe3035a..52a41b64 100644 --- a/commons/src/main/java/io/flowinquiry/modules/usermanagement/repository/UserRepository.java +++ b/commons/src/main/java/io/flowinquiry/modules/usermanagement/repository/UserRepository.java @@ -24,6 +24,8 @@ public interface UserRepository extends JpaRepository, JpaSpecificat Optional findOneByEmailIgnoreCase(String email); + Optional findOneById(Long id); + @EntityGraph(attributePaths = "authorities") Optional findOneWithAuthoritiesByEmailIgnoreCase(String email); diff --git a/commons/src/main/java/io/flowinquiry/utils/StringUtils.java b/commons/src/main/java/io/flowinquiry/utils/StringUtils.java new file mode 100644 index 00000000..0968ab08 --- /dev/null +++ b/commons/src/main/java/io/flowinquiry/utils/StringUtils.java @@ -0,0 +1,11 @@ +package io.flowinquiry.utils; + +import org.apache.commons.text.StringEscapeUtils; + +public class StringUtils { + + public static String polishedHtmlTagsMessage(String message) { + String preProcessedHtml = message.replaceAll(">(\\s*)<", "> <"); + return StringEscapeUtils.unescapeHtml4(preProcessedHtml).replaceAll("<[^>]+>", ""); + } +} diff --git a/commons/src/main/resources/i18n/messages_en.properties b/commons/src/main/resources/i18n/messages_en.properties index 67815106..effb353a 100644 --- a/commons/src/main/resources/i18n/messages_en.properties +++ b/commons/src/main/resources/i18n/messages_en.properties @@ -9,8 +9,6 @@ email.activation.title=FlowInquiry account activation email.activation.greeting=Dear {0} email.activation.action=Activate account email.activation.text1=Your FlowInquiry account has been created, please click on the URL below to activate it: -email.activation.text2=Regards, -email.signature=FlowInquiry Team. # Creation email email.creation.text1=Your FlowInquiry account has been created, please click on the URL below to access it: @@ -20,11 +18,22 @@ email.reset.title=FlowInquiry password reset email.reset.greeting=Dear {0} email.reset.action=Reset password email.reset.text1=For your FlowInquiry account a password reset was requested, please click on the URL below to reset it: -email.reset.text2=Regards, + # New ticket -mail.newticket.title=New Ticket Created {0} +email.new.ticket.subject=New Ticket Created {0} +## New ticket comment +email.new.ticket.comment.subject=New Comment on Ticket: {0} +email.ticket.comment.title=New Comment Added to Ticket: {0} +email.ticket.comment.text1=has added a new comment to the ticket: +email.ticket.comment.text2=You can view the full ticket and reply by clicking below: +email.ticket.comment.action=View Ticket +email.ticket.comment.text3=If the button above doesn't work, copy and paste the following URL into your browser: +## Common +email.greeting=Dear {0}, +email.signature=FlowInquiry Team. +email.regards=Regards, email.footer.website=https://flowinquiry.io email.footer.copyright=FlowInquiry. All rights reserved. diff --git a/commons/src/main/resources/templates/mail/activationEmail.html b/commons/src/main/resources/templates/mail/activationEmail.html index b8dd24f3..ac6c54ef 100644 --- a/commons/src/main/resources/templates/mail/activationEmail.html +++ b/commons/src/main/resources/templates/mail/activationEmail.html @@ -4,7 +4,7 @@ diff --git a/commons/src/main/resources/templates/mail/creationEmail.html b/commons/src/main/resources/templates/mail/creationEmail.html index f1a1be9f..f9846b3b 100644 --- a/commons/src/main/resources/templates/mail/creationEmail.html +++ b/commons/src/main/resources/templates/mail/creationEmail.html @@ -4,7 +4,7 @@ diff --git a/commons/src/main/resources/templates/mail/newTicketCommentEmail.html b/commons/src/main/resources/templates/mail/newTicketCommentEmail.html new file mode 100644 index 00000000..851ee6f4 --- /dev/null +++ b/commons/src/main/resources/templates/mail/newTicketCommentEmail.html @@ -0,0 +1,56 @@ + + + + + + + diff --git a/commons/src/main/resources/templates/mail/newTicketEmail.html b/commons/src/main/resources/templates/mail/newTicketEmail.html index 9212f6c3..c05f8b7b 100644 --- a/commons/src/main/resources/templates/mail/newTicketEmail.html +++ b/commons/src/main/resources/templates/mail/newTicketEmail.html @@ -3,10 +3,11 @@ \ No newline at end of file diff --git a/commons/src/main/resources/templates/mail/passwordResetEmail.html b/commons/src/main/resources/templates/mail/passwordResetEmail.html index a2c508b3..857c227f 100644 --- a/commons/src/main/resources/templates/mail/passwordResetEmail.html +++ b/commons/src/main/resources/templates/mail/passwordResetEmail.html @@ -4,7 +4,7 @@