From ba648de666241784792e6a99bd0d6607f3825613 Mon Sep 17 00:00:00 2001 From: Lars Johansson <lars.johansson@ess.eu> Date: Tue, 16 Nov 2021 16:22:52 +0100 Subject: [PATCH] NT-330: Send notification email once per batch request --- .../names/nameviews/TransactionBean.java | 297 ++++++++++++++---- .../names/util/NotificationService.java | 45 +++ 2 files changed, 289 insertions(+), 53 deletions(-) diff --git a/NamingConventionTool/src/main/java/org/openepics/names/nameviews/TransactionBean.java b/NamingConventionTool/src/main/java/org/openepics/names/nameviews/TransactionBean.java index 172894a9..ec21f818 100644 --- a/NamingConventionTool/src/main/java/org/openepics/names/nameviews/TransactionBean.java +++ b/NamingConventionTool/src/main/java/org/openepics/names/nameviews/TransactionBean.java @@ -92,7 +92,9 @@ public class TransactionBean { private static final String PENDING = "pending"; private static final String STATUS = "status"; - private static final String DEFAULT_MAIL_SUBJECT = "There are new changes in Naming"; + private static final String CHANGES_NEEDS_TO_BE_APPROVED = "[Changes - Needs to be approved]"; + private static final String CHANGES_NOTIFICATION = "[Changes - Notification]"; + private static final String DEFAULT_MAIL_SUBJECT = "There are new changes in Naming"; private static final String MNEMONIC_IS_NOT_UNIQUE_ACCORDING_TO_NAMING_RULES = "Mnemonic is not unique according to naming rules."; @@ -124,10 +126,51 @@ public class TransactionBean { @Inject private NamingHelper namingHelper; + // mail notification lists + // keep track of MailNotificationDTO + // keep track of cc per MailNotificationDTO + // comparator for MailNotificationDTO to sort + private List<MailNotificationDTO> modificationSystemStructureApproval; + private List<MailNotificationDTO> modificationDeviceStructureApproval; + private List<MailNotificationDTO> modificationSystemStructureNonApproval; + private List<MailNotificationDTO> modificationDeviceStructureNonApproval; + private List<MailNotificationDTO> EMPTY_MODIFICATIONS = Collections.emptyList(); + private HashMap<String, List<MailNotificationDTO>> ccModificationSystemStructure; + private HashMap<String, List<MailNotificationDTO>> ccModificationDeviceStructure; + private Comparator<MailNotificationDTO> comparatorMailNotificationDTO = new Comparator<MailNotificationDTO>() { + @Override + public int compare(MailNotificationDTO first, MailNotificationDTO second) { + List<String> list1 = first.getNodeList(); + List<String> list2 = second.getNodeList(); + if (list1.size() < list2.size()) { + return -1; + } else if (list2.size() < list1.size()) { + return 1; + } else { + for (int i=0; i<list1.size(); i++) { + int val = list1.get(i).compareTo(list2.get(i)); + if (val != 0) { + return val; + } else { + continue; + } + } + return 0; + } + } + }; + private String nameViewStructure; @PostConstruct private void init() { + // mail notification lists + modificationSystemStructureApproval = new ArrayList<>(); + modificationDeviceStructureApproval = new ArrayList<>(); + modificationSystemStructureNonApproval = new ArrayList<>(); + modificationDeviceStructureNonApproval = new ArrayList<>(); + ccModificationSystemStructure = new HashMap<>(); + ccModificationDeviceStructure = new HashMap<>(); } /** @@ -154,6 +197,9 @@ public class TransactionBean { em = emf.createEntityManager(); Action action = new Action(); + // clear mail notifications + clearNotifications(); + for (NameOperation operation : operations) { if (operation instanceof Delete) { action.execute((Delete) operation); @@ -174,6 +220,12 @@ public class TransactionBean { } } + // send mail notifications + sendNotifications(); + + // clear mail notifications + clearNotifications(); + transaction.commit(); nameViewProvider.update(action.getRevisions()); @@ -859,19 +911,17 @@ public class TransactionBean { String message = "Added - Needs to be approved"; - notificationService.notifyUserFromChange( - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode(newRevision, NamePartType.SECTION), - message, - operation.getMessage())), - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode(newRevision, NamePartType.DEVICE_TYPE), - message, - operation.getMessage())), - Collections.singletonList( - sessionService.user().getUsername()), "[Added - Needs to be approved]"); + // notify users + addNotificationSystemStructureApproval( + new MailNotificationDTO( + namingHelper.parentListForNode(newRevision, NamePartType.SECTION), + message, + operation.getMessage())); + addNotificationDeviceStructureApproval( + new MailNotificationDTO( + namingHelper.parentListForNode(newRevision, NamePartType.DEVICE_TYPE), + message, + operation.getMessage())); } } @@ -925,19 +975,16 @@ public class TransactionBean { } // notify users - notificationService.notifyUserFromChange( - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode(namePartRevision, NamePartType.SECTION), - message, - operation.getMessage())), - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode(namePartRevision, NamePartType.DEVICE_TYPE), - message, - operation.getMessage())), - Collections.singletonList( - sessionService.user().getUsername()), "[Modification - Needs to be approved]"); + addNotificationSystemStructureApproval( + new MailNotificationDTO( + namingHelper.parentListForNode(namePartRevision, NamePartType.SECTION), + message, + operation.getMessage())); + addNotificationDeviceStructureApproval( + new MailNotificationDTO( + namingHelper.parentListForNode(namePartRevision, NamePartType.DEVICE_TYPE), + message, + operation.getMessage())); } } @@ -1204,9 +1251,7 @@ public class TransactionBean { * @param subject the subject of the email */ private void notifyAdminsFromChange(NameArtifact artifact, String operator, String subject, String commitMessage) { - List<MailNotificationDTO> modificationSystemStructure = null; - List<MailNotificationDTO> modificationDeviceStructure = null; - String requesterMail = null; + String requester = null; // get info for sending mail notification if (NameType.DEVICE_REGISTRY.equals(artifact.getNameType())) { @@ -1232,34 +1277,180 @@ public class TransactionBean { .setParameter(NAME_PART, artifact.asNamePart()) .getSingleResult(); - requesterMail = namePartRevision.getRequestedBy().getUsername(); - - modificationSystemStructure = - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode( - namePartRevision, NamePartType.SECTION), operator, commitMessage)); - modificationDeviceStructure = - Collections.singletonList( - new MailNotificationDTO( - namingHelper.parentListForNode( - namePartRevision, NamePartType.DEVICE_TYPE), operator, commitMessage)); + requester = namePartRevision.getRequestedBy().getUsername(); + + MailNotificationDTO mailNotificationSystemStructure = + NameType.SYSTEM_STRUCTURE.equals(artifact.getNameType()) + ? new MailNotificationDTO( + namingHelper.parentListForNode(namePartRevision, NamePartType.SECTION), + operator, + commitMessage) + : null; + MailNotificationDTO mailNotificationDeviceStructure = + NameType.DEVICE_STRUCTURE.equals(artifact.getNameType()) + ? new MailNotificationDTO( + namingHelper.parentListForNode(namePartRevision, NamePartType.DEVICE_TYPE), + operator, + commitMessage) + : null; + + if (mailNotificationSystemStructure != null) { + addNotificationSystemStructureNonApproval(mailNotificationSystemStructure); + addCCNotificationSystemStructure(requester, mailNotificationSystemStructure); + } + if (mailNotificationDeviceStructure != null) { + addNotificationDeviceStructureNonApproval(mailNotificationDeviceStructure); + addCCNotificationDeviceStructure(requester, mailNotificationDeviceStructure); + } + } + } + + /** + * Clear (mail) notifications. + */ + private void clearNotifications() { + // clear mail notifications + // admin approval + // admin non approval + // cc + + modificationSystemStructureApproval.clear(); + modificationDeviceStructureApproval.clear(); + modificationSystemStructureNonApproval.clear(); + modificationDeviceStructureNonApproval.clear(); + ccModificationSystemStructure.clear(); + ccModificationDeviceStructure.clear(); + } + + /** + * Add (mail) notification for system structure (approval notification, admin). + * + * @param e notification + */ + private void addNotificationSystemStructureApproval(MailNotificationDTO e) { + modificationSystemStructureApproval.add(e); + } + + /** + * Add (mail) notification for device structure (approval notification, admin). + * + * @param e notification + */ + private void addNotificationDeviceStructureApproval(MailNotificationDTO e) { + modificationDeviceStructureApproval.add(e); + } + + /** + * Add (mail) notification for system structure (non-approval notification, admin). + * + * @param e notification + */ + private void addNotificationSystemStructureNonApproval(MailNotificationDTO e) { + modificationSystemStructureNonApproval.add(e); + } + + /** + * Add (mail) notification for device structure (non-approval notification, admin). + * + * @param e notification + */ + private void addNotificationDeviceStructureNonApproval(MailNotificationDTO e) { + modificationDeviceStructureNonApproval.add(e); + } + + /** + * Add (mail) notification for system structure (notification, non-admin). + * + * @param user user for cc + * @param e notification + */ + private void addCCNotificationSystemStructure(String user, MailNotificationDTO e) { + List<MailNotificationDTO> ccList = ccModificationSystemStructure.get(user); + if (ccList == null) { + ccList = new ArrayList<>(); + } + + ccList.add(e); + ccModificationSystemStructure.put(user, ccList); + } + + /** + * Add (mail) notification for device structure (notification, non-admin). + * + * @param user user for cc + * @param e notification + */ + private void addCCNotificationDeviceStructure(String user, MailNotificationDTO e) { + List<MailNotificationDTO> ccList = ccModificationDeviceStructure.get(user); + if (ccList == null) { + ccList = new ArrayList<>(); + } + + ccList.add(e); + ccModificationDeviceStructure.put(user, ccList); + } + + /** + * Send (mail) notifications. + */ + private void sendNotifications() { + // send mail notificationss + // sort and send + // sort according to nodelist in MailNotificationDTO + // cc + // sessionService.user.getUsername (requester if approve, cancel, reject, delete + // subject + // [Changes - Needs to be approved] + // [Changes - Notification] + // send if conditions apply - content to send, non-admin cc + + // sort + Collections.sort(modificationSystemStructureApproval, comparatorMailNotificationDTO); + Collections.sort(modificationDeviceStructureApproval, comparatorMailNotificationDTO); + Collections.sort(modificationSystemStructureNonApproval, comparatorMailNotificationDTO); + Collections.sort(modificationDeviceStructureNonApproval, comparatorMailNotificationDTO); + + // send mail notification admin + if (!modificationSystemStructureApproval.isEmpty() || !modificationDeviceStructureApproval.isEmpty()) { + notificationService.notifyUserFromChange( + modificationSystemStructureApproval, + modificationDeviceStructureApproval, + null, + CHANGES_NEEDS_TO_BE_APPROVED); } - List<String> ccUsers = new ArrayList<>(Arrays.asList(sessionService.user().getUsername())); + // send mail notification cc admin + if (!modificationSystemStructureNonApproval.isEmpty() || !modificationDeviceStructureNonApproval.isEmpty()) { + notificationService.notifyUserFromChange( + modificationSystemStructureNonApproval, + modificationDeviceStructureNonApproval, + null, + CHANGES_NOTIFICATION); + } - //notify the requester user admin about decision - if(StringUtils.isNotEmpty(requesterMail)) { - ccUsers.add(requesterMail); + // send mail notification cc system structure if single non-admin cc + for (Map.Entry<String, List<MailNotificationDTO>> entry : ccModificationSystemStructure.entrySet()) { + Collections.sort(entry.getValue(), comparatorMailNotificationDTO); + if (!entry.getValue().isEmpty()) { + notificationService.notifyCCFromChange( + entry.getValue(), + EMPTY_MODIFICATIONS, + Arrays.asList(entry.getKey()), + CHANGES_NOTIFICATION); + } } - // notify users - // sending notification when "deleting" and entity - notificationService.notifyUserFromChange( - modificationSystemStructure, - modificationDeviceStructure, - ccUsers, - subject); + // send mail notification cc device structure if single non-admin cc + for (Map.Entry<String, List<MailNotificationDTO>> entry : ccModificationDeviceStructure.entrySet()) { + Collections.sort(entry.getValue(), comparatorMailNotificationDTO); + if (!entry.getValue().isEmpty()) { + notificationService.notifyCCFromChange( + EMPTY_MODIFICATIONS, + entry.getValue(), + Arrays.asList(entry.getKey()), + CHANGES_NOTIFICATION); + } + } } } diff --git a/NamingConventionTool/src/main/java/org/openepics/names/util/NotificationService.java b/NamingConventionTool/src/main/java/org/openepics/names/util/NotificationService.java index 8942e875..48b32f4b 100644 --- a/NamingConventionTool/src/main/java/org/openepics/names/util/NotificationService.java +++ b/NamingConventionTool/src/main/java/org/openepics/names/util/NotificationService.java @@ -110,6 +110,51 @@ public class NotificationService { return true; } + /** + * Sends email notification to cc if someone has made an operation + * on a node (system structure or device structure) or a leaf (device registry). + * + * @param modificationSystemStructure the system structure list that has been modified with an operator + * @param modificationDeviceStructure the device structure list that has been modified with an operator + * @param ccList the user that has applied the operator on a node/nodes + * @param subject subject for email notification + * @return was the mail sending successful, or not + */ + public boolean notifyCCFromChange(List<MailNotificationDTO> modificationSystemStructure, + List<MailNotificationDTO> modificationDeviceStructure, + List<String> ccList, + String subject) { + // send email notifications as cc + // no need to consider + // getCCLoginListForNotification(SYSTEM_STRUCTURE_CHANGE) + // getCCLoginListForNotification(DEVICE_STRUCTURE_CHANGE) + // handled in notifyUserFromChange + + LOGGER.log(Level.INFO, "Changes in Naming, trying to send email to cc if single non-admin cc"); + if (ccList == null + || ccList.size() != 1 + || userDirectoryService.getAllAdministratorEmails().contains( + userDirectoryService.getEmail(ccList.get(0)))) { + LOGGER.log(Level.INFO, "Changes in Naming, not send email as not single non-admin cc"); + return false; + } + + try { + subject = subject + " - " + appBaseUrl; + + mailService.sendMail(emailsForNames(ccList), emailsForNames(ccList), subject, + generateChangeNotificationBody( + modificationSystemStructure, + modificationDeviceStructure, + true), + null, null, false); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error while trying to send changes-notification to cc", e); + return false; + } + return true; + } + /** * Send batch-notification to all admins about devices that have been deleted * -- GitLab