diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileDao.java b/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileDao.java index 1737562b61a..09bf55902b6 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileDao.java +++ b/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileDao.java @@ -77,7 +77,9 @@ public interface ProfileDao extends GenericDao { void updateLastModifiedDateAndIndexingStatusWithoutResult(String orcid, Date lastModified, IndexingStatus indexingStatus); public List> findEmailsUnverfiedDays(int daysUnverified, int maxResults); - + + public List> findEmailsUnverifiedDaysByEventType(int daysUnverified, int tooOldNumberOfDays); + String retrieveOrcidType(String orcid); List findInfoForDecryptionAnalysis(); @@ -156,10 +158,10 @@ public interface ProfileDao extends GenericDao { public List getSigninLock(String orcid); public void startSigninLock(String orcid); - + public void resetSigninLock(String orcid); public void updateSigninLock(String orcid, Integer count); - + boolean haveMemberPushedWorksOrAffiliationsToRecord(String orcid, String clientId); } diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileDaoImpl.java b/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileDaoImpl.java index baf0d02de86..d916513f83a 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileDaoImpl.java +++ b/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileDaoImpl.java @@ -21,10 +21,15 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class ProfileDaoImpl extends GenericDaoImpl implements ProfileDao { private static final String PRIVATE_VISIBILITY = "PRIVATE"; + private static final Logger LOGGER = LoggerFactory.getLogger(ProfileDaoImpl.class); + @Value("${org.orcid.postgres.query.timeout:30000}") private Integer queryTimeout; @@ -150,7 +155,31 @@ public List> findEmailsUnverfiedDays(int daysUnver results.add(pair); }); return results; - } + } + + @SuppressWarnings("unchecked") + @Override + public List> findEmailsUnverifiedDaysByEventType(int daysUnverified, int tooOldNumberOfDays) { + StringBuilder queryString = new StringBuilder("SELECT e.email, e.is_primary, ev.email_event_type FROM email e "); + queryString.append("LEFT JOIN email_event ev ON e.email = ev.email "); + queryString.append("JOIN profile p on p.orcid = e.orcid and p.claimed = true "); + queryString.append("AND p.deprecated_date is null AND p.profile_deactivation_date is null AND p.account_expiry is null "); + queryString.append("where e.is_verified = false "); + queryString.append("and e.date_created between (now() - CAST('").append(tooOldNumberOfDays).append("' AS INTERVAL DAY)) and (now() - CAST('") + .append(daysUnverified).append("' AS INTERVAL DAY)) "); + queryString.append("and e.date_created < (now() - CAST('").append(daysUnverified).append("' AS INTERVAL DAY)) "); + queryString.append("and (e.source_id = e.orcid OR e.source_id is null)"); + queryString.append(" ORDER BY e.last_modified"); + + Query query = entityManager.createNativeQuery(queryString.toString()); + List dbInfo = query.getResultList(); + List> results = new ArrayList>(); + dbInfo.stream().forEach(element -> { + Triple pair = Triple.of((String) element[0], (Boolean) element[1], (String) element[2]); + results.add(pair); + }); + return results; + } @SuppressWarnings("unchecked") @Override @@ -785,7 +814,7 @@ public void startSigninLock(String orcid) { query.executeUpdate(); return; } - + @Override @Transactional public void resetSigninLock(String orcid) { @@ -809,7 +838,7 @@ public void updateSigninLock(String orcid, Integer count) { query.executeUpdate(); return; } - + public boolean haveMemberPushedWorksOrAffiliationsToRecord(String orcid, String clientId) { try { String queryString = "select p.orcid from profile p where p.orcid = :orcid and ( exists (select 1 from work w where w.orcid = p.orcid and w.client_source_id = :clientId) or exists (select 1 from org_affiliation_relation o where o.orcid = p.orcid and o.client_source_id = :clientId));"; @@ -817,10 +846,10 @@ public boolean haveMemberPushedWorksOrAffiliationsToRecord(String orcid, String query.setParameter("orcid", orcid); query.setParameter("clientId", clientId); String result = (String) query.getSingleResult(); - if(orcid.equals(result)) { + if (orcid.equals(result)) { return true; - } - } catch(NoResultException nre) { + } + } catch (NoResultException nre) { return false; } return false; diff --git a/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/cli/manager/EmailMessageSenderImpl.java b/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/cli/manager/EmailMessageSenderImpl.java index c4deda62955..d69ee216fa3 100644 --- a/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/cli/manager/EmailMessageSenderImpl.java +++ b/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/cli/manager/EmailMessageSenderImpl.java @@ -70,6 +70,8 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; +import liquibase.repackaged.org.apache.commons.lang3.StringUtils; + /** * * @author Will Simpson @@ -78,17 +80,17 @@ public class EmailMessageSenderImpl implements EmailMessageSender { private static final Logger LOGGER = LoggerFactory.getLogger(EmailMessageSenderImpl.class); - + private final Integer MAX_RETRY_COUNT; - + ExecutorService pool; - + private int verifyReminderAfterTwoDays = 2; - + private int verifyReminderAfterSevenDays = 7; - + private int verifyReminderAfterTwentyEightDays = 28; - + @Resource private NotificationDao notificationDao; @@ -103,7 +105,7 @@ public class EmailMessageSenderImpl implements EmailMessageSender { @Resource private EmailDao emailDao; - + @Resource private TransactionTemplate transactionTemplate; @@ -124,33 +126,33 @@ public class EmailMessageSenderImpl implements EmailMessageSender { @Resource private ProfileEntityCacheManager profileEntityCacheManager; - + @Resource(name = "emailManagerReadOnlyV3") private EmailManagerReadOnly emailManagerReadOnly; - + @Resource private GenericDao emailEventDao; - + @Resource private ProfileDao profileDaoReadOnly; - + @Resource(name = "recordNameManagerV3") private RecordNameManager recordNameManagerV3; - + @Resource private VerifyEmailUtils verifyEmailUtils; - + @Value("${org.notifications.service_announcements.batchSize:60000}") private Integer batchSize; - + @Value("${org.notifications.max_elements_to_show:20}") - private Integer maxNotificationsToShowPerClient; - + private Integer maxNotificationsToShowPerClient; + @Value("${org.orcid.core.email.verify.tooOld:45}") - private int emailTooOld; - - private int emailTooOldLegacy = 15; - + private int emailTooOld; + + private int emailTooOldLegacy = 15; + public EmailMessageSenderImpl(@Value("${org.notifications.service_announcements.maxThreads:8}") Integer maxThreads, @Value("${org.notifications.service_announcements.maxRetry:3}") Integer maxRetry) { if (maxThreads == null || maxThreads > 64 || maxThreads < 1) { @@ -161,7 +163,7 @@ public EmailMessageSenderImpl(@Value("${org.notifications.service_announcements. MAX_RETRY_COUNT = maxRetry; } - + @Override public EmailMessage createDigest(String orcid, Collection notifications) { ProfileEntity record = profileEntityCacheManager.retrieve(orcid); @@ -171,7 +173,7 @@ public EmailMessage createDigest(String orcid, Collection notifica String bodyHtmlDelegate = null; String bodyHtmlDelegateRecipient = null; String bodyHtmlAdminDelegate = null; - + Set memberIds = new HashSet<>(); DigestEmail digestEmail = new DigestEmail(); @@ -227,19 +229,21 @@ public EmailMessage createDigest(String orcid, Collection notifica } } } - + List sortedClientIds = updatesByClient.keySet().stream().sorted().collect(Collectors.toList()); List sortedClientUpdates = new ArrayList(); - sortedClientIds.stream().forEach(s -> {sortedClientUpdates.add(updatesByClient.get(s));}); + sortedClientIds.stream().forEach(s -> { + sortedClientUpdates.add(updatesByClient.get(s)); + }); String emailName = recordNameManagerV3.deriveEmailFriendlyName(record.getId()); String subject = messages.getMessage("email.subject.digest", new String[] { emailName }, locale); Map params = new HashMap<>(); params.put("locale", locale); params.put("messages", messages); - params.put("messageArgs", new Object[0]); + params.put("messageArgs", new Object[0]); params.put("emailName", emailName); - params.put("digestEmail", digestEmail); + params.put("digestEmail", digestEmail); params.put("orcidMessageCount", orcidMessageCount); params.put("baseUri", orcidUrlManager.getBaseUrl()); params.put("subject", subject); @@ -262,17 +266,17 @@ public EmailMessage createDigest(String orcid, Collection notifica emailMessage.setBodyHtml(bodyHtml); return emailMessage; } - + private Locale getUserLocaleFromProfileEntity(ProfileEntity profile) { String locale = profile.getLocale(); if (locale != null) { AvailableLocales loc = AvailableLocales.valueOf(locale); return LocaleUtils.toLocale(loc.value()); } - + return LocaleUtils.toLocale("en"); } - + private String encryptAndEncodePutCode(Long putCode) { String encryptedPutCode = encryptionManager.encryptForExternalUse(String.valueOf(putCode)); try { @@ -285,26 +289,26 @@ private String encryptAndEncodePutCode(Long putCode) { @Override public void sendEmailMessages() { List orcidsWithUnsentNotifications = new ArrayList(); - orcidsWithUnsentNotifications = notificationDaoReadOnly.findRecordsWithUnsentNotifications(); - + orcidsWithUnsentNotifications = notificationDaoReadOnly.findRecordsWithUnsentNotifications(); + for (final Object[] element : orcidsWithUnsentNotifications) { - String orcid = (String) element[0]; + String orcid = (String) element[0]; try { Float emailFrequencyDays = null; Date recordActiveDate = null; recordActiveDate = (Date) element[1]; - + List notifications = notificationManager.findNotificationsToSend(orcid, emailFrequencyDays, recordActiveDate); - + EmailEntity primaryEmail = emailDao.findPrimaryEmail(orcid); if (primaryEmail == null) { LOGGER.info("No primary email for orcid: " + orcid); return; } - - if(!notifications.isEmpty()) { + + if (!notifications.isEmpty()) { LOGGER.info("Found {} messages to send for orcid: {}", notifications.size(), orcid); - EmailMessage digestMessage = createDigest(orcid, notifications); + EmailMessage digestMessage = createDigest(orcid, notifications); digestMessage.setFrom(EmailConstants.DO_NOT_REPLY_NOTIFY_ORCID_ORG); digestMessage.setTo(primaryEmail.getEmail()); boolean successfullySent = mailGunManager.sendEmail(digestMessage.getFrom(), digestMessage.getTo(), digestMessage.getSubject(), @@ -350,11 +354,11 @@ public Boolean call() throws Exception { e.printStackTrace(); } } - + @Override public void sendTips(Integer customBatchSize, String fromAddress) { LOGGER.info("About to send Tips messages"); - + List serviceAnnouncementsOrTips = new ArrayList(); try { long startTime = System.currentTimeMillis(); @@ -381,11 +385,11 @@ public Boolean call() throws Exception { e.printStackTrace(); } } - + private void processServiceAnnouncementOrTipNotification(NotificationEntity n) { processServiceAnnouncementOrTipNotification(n, null); } - + private void processServiceAnnouncementOrTipNotification(NotificationEntity n, String fromAddress) { String orcid = n.getOrcid(); EmailEntity primaryEmail = emailDao.findPrimaryEmail(orcid); @@ -394,7 +398,7 @@ private void processServiceAnnouncementOrTipNotification(NotificationEntity n, S flagAsFailed(orcid, n); return; } - if(!primaryEmail.getVerified()) { + if (!primaryEmail.getVerified()) { LOGGER.info("Primary email not verified for: " + orcid); flagAsFailed(orcid, n); return; @@ -402,23 +406,21 @@ private void processServiceAnnouncementOrTipNotification(NotificationEntity n, S try { boolean successfullySent = false; String fromAddressParam = EmailConstants.DO_NOT_REPLY_NOTIFY_ORCID_ORG; - if(!PojoUtil.isEmpty(fromAddress)) { + if (!PojoUtil.isEmpty(fromAddress)) { fromAddressParam = fromAddress; } if (n instanceof NotificationServiceAnnouncementEntity) { NotificationServiceAnnouncementEntity nc = (NotificationServiceAnnouncementEntity) n; // They might be custom notifications to have the // html/text ready to be sent - successfullySent = mailGunManager.sendMarketingEmail(fromAddressParam, primaryEmail.getEmail(), nc.getSubject(), nc.getBodyText(), - nc.getBodyHtml()); + successfullySent = mailGunManager.sendMarketingEmail(fromAddressParam, primaryEmail.getEmail(), nc.getSubject(), nc.getBodyText(), nc.getBodyHtml()); } else if (n instanceof NotificationTipEntity) { NotificationTipEntity nc = (NotificationTipEntity) n; // They might be custom notifications to have the // html/text ready to be sent - successfullySent = mailGunManager.sendMarketingEmail(fromAddressParam, primaryEmail.getEmail(), nc.getSubject(), nc.getBodyText(), - nc.getBodyHtml()); + successfullySent = mailGunManager.sendMarketingEmail(fromAddressParam, primaryEmail.getEmail(), nc.getSubject(), nc.getBodyText(), nc.getBodyHtml()); } - + if (successfullySent) { flagAsSent(n.getId()); } else { @@ -428,58 +430,58 @@ private void processServiceAnnouncementOrTipNotification(NotificationEntity n, S LOGGER.warn("Problem sending service announcement message to user: " + orcid, e); } } - + private void flagAsSent(Long id) { - transactionTemplate.execute(new TransactionCallbackWithoutResult() { + transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { notificationDao.flagAsSent(Arrays.asList(id)); } - }); + }); } - + private void flagAsFailed(String orcid, NotificationEntity n) { - transactionTemplate.execute(new TransactionCallbackWithoutResult() { + transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { - if(n.getRetryCount() != null && n.getRetryCount() >= MAX_RETRY_COUNT) { + if (n.getRetryCount() != null && n.getRetryCount() >= MAX_RETRY_COUNT) { notificationDao.flagAsNonSendable(orcid, n.getId()); } else { - if(n.getRetryCount() == null) { + if (n.getRetryCount() == null) { notificationDao.updateRetryCount(orcid, n.getId(), 1L); } else { notificationDao.updateRetryCount(orcid, n.getId(), (n.getRetryCount() + 1)); } - } + } } - }); + }); } - + public class ClientUpdates { String clientId; String clientName; String clientDescription; Integer counter = 0; Locale userLocale; - - Map>> updates = new HashMap<>(); - + + Map>> updates = new HashMap<>(); + public void setClientId(String clientId) { this.clientId = clientId; } - + public void setClientName(String clientName) { this.clientName = clientName; } - + public void setClientDescription(String clientDescription) { this.clientDescription = clientDescription; } - + public void setUserLocale(Locale locale) { this.userLocale = locale; } - + public String getClientId() { return clientId; } @@ -495,11 +497,11 @@ public String getClientDescription() { public Locale getUserLocale() { return userLocale; } - + public Map>> getUpdates() { return updates; } - + public Integer getCounter() { return counter; } @@ -507,11 +509,11 @@ public Integer getCounter() { private String renderCreationDate(XMLGregorianCalendar createdDate) { String result = new String(); result += createdDate.getYear(); - result += "-" + (createdDate.getMonth() < 10 ? "0" + createdDate.getMonth() : createdDate.getMonth()); - result += "-" + (createdDate.getDay() < 10 ? "0" + createdDate.getDay() : createdDate.getDay()); + result += "-" + (createdDate.getMonth() < 10 ? "0" + createdDate.getMonth() : createdDate.getMonth()); + result += "-" + (createdDate.getDay() < 10 ? "0" + createdDate.getDay() : createdDate.getDay()); return result; - } - + } + public void addElement(XMLGregorianCalendar createdDate, Item item) { init(item.getItemType().name(), item.getActionType() == null ? null : item.getActionType().name()); String value = null; @@ -548,7 +550,7 @@ public void addElement(XMLGregorianCalendar createdDate, Item item) { counter += 1; } - } + } private void init(String itemType, String actionType) { if (!updates.containsKey(itemType)) { @@ -567,7 +569,7 @@ private String getHtmlBody(NotificationAdministrative notificationAdministrative int bodyTagClose = notificationAdministrative.getBodyHtml().indexOf(""); return notificationAdministrative.getBodyHtml().substring(bodyTag + 6, bodyTagClose); } - + @Override synchronized public void processUnverifiedEmails2Days() { LOGGER.info("About to process unverIfied emails for 2 days reminder"); @@ -576,14 +578,15 @@ synchronized public void processUnverifiedEmails2Days() { elements = profileDaoReadOnly.findEmailsUnverfiedDays(verifyReminderAfterTwoDays, 100); LOGGER.info("Got batch of {} profiles with unverified emails for 2 days reminder", elements.size()); LocalDateTime now = LocalDateTime.now(); - //togglz here + // togglz here Date tooOld = now.minusDays(emailTooOldLegacy).toDate(); - if(Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { + if (Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { tooOld = now.minusDays(emailTooOld).toDate(); } for (Triple element : elements) { - if(element.getRight() == null || element.getRight().after(tooOld)) { - processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_2_DAYS_SENT, EmailEventType.VERIFY_EMAIL_2_DAYS_SENT_SKIPPED); + if (element.getRight() == null || element.getRight().after(tooOld)) { + processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_2_DAYS_SENT, + EmailEventType.VERIFY_EMAIL_2_DAYS_SENT_SKIPPED); } else { // Mark is as too old to send the verification email markUnverifiedEmailAsTooOld(element.getLeft()); @@ -591,51 +594,55 @@ synchronized public void processUnverifiedEmails2Days() { } } while (!elements.isEmpty()); } - - + synchronized public void processUnverifiedEmails7Days() { - if(Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { - LOGGER.info("About to process unverIfied emails for 7 days reminder"); - List> elements = Collections.> emptyList(); - do { - elements = profileDaoReadOnly.findEmailsUnverfiedDays(verifyReminderAfterSevenDays, 100); - LOGGER.info("Got batch of {} profiles with unverified emails for 7 days reminder", elements.size()); - LocalDateTime now = LocalDateTime.now(); - Date tooOld = now.minusDays(emailTooOld).toDate(); - for (Triple element : elements) { - if(element.getRight() == null || element.getRight().after(tooOld)) { - processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_7_DAYS_SENT, EmailEventType.VERIFY_EMAIL_7_DAYS_SENT_SKIPPED); - } else { - // Mark is as too old to send the verification email - markUnverifiedEmailAsTooOld(element.getLeft()); - } + if (Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { + LOGGER.info("About to process unverIfied emails for 7 days reminder"); + List> elements = Collections.> emptyList(); + + elements = profileDaoReadOnly.findEmailsUnverifiedDaysByEventType(verifyReminderAfterSevenDays, emailTooOld); + LOGGER.info("Got {} profiles with email event and unverified emails for 7 days reminder", elements.size()); + + HashMap> hasEventTypesMap = hasEventTypes(elements, + List.of(EmailEventType.VERIFY_EMAIL_7_DAYS_SENT, EmailEventType.VERIFY_EMAIL_7_DAYS_SENT_SKIPPED, EmailEventType.VERIFY_EMAIL_TOO_OLD)); + for (Triple element : elements) { + if (!hasEventTypesMap.containsKey(element.getLeft())) + processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_7_DAYS_SENT, + EmailEventType.VERIFY_EMAIL_7_DAYS_SENT_SKIPPED); + hasEventTypesMap.put(element.getLeft(), element); + } + } + } + + // helper method to get the triple map for an event type list + private HashMap> hasEventTypes(List> elements, List eventTypes) { + HashMap> hasEventTypesMap = new HashMap>(); + for (Triple element : elements) { + if (eventTypes.contains(EmailEventType.valueOf(element.getRight()))) { + hasEventTypesMap.put(element.getLeft(), element); } - } while (!elements.isEmpty()); } + return hasEventTypesMap; } - - + synchronized public void processUnverifiedEmails28Days() { - if(Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { - LOGGER.info("About to process unverIfied emails for 28 days reminder"); - List> elements = Collections.> emptyList(); - do { - elements = profileDaoReadOnly.findEmailsUnverfiedDays(verifyReminderAfterTwentyEightDays, 100); - LOGGER.info("Got batch of {} profiles with unverified emails for 28 days reminder", elements.size()); - LocalDateTime now = LocalDateTime.now(); - Date tooOld = now.minusDays(emailTooOld).toDate(); - for (Triple element : elements) { - if(element.getRight() == null || element.getRight().after(tooOld)) { - processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_28_DAYS_SENT, EmailEventType.VERIFY_EMAIL_28_DAYS_SENT_SKIPPED); - } else { - // Mark is as too old to send the verification email - markUnverifiedEmailAsTooOld(element.getLeft()); - } + if (Features.SEND_ALL_VERIFICATION_EMAILS.isActive()) { + LOGGER.info("About to process unverIfied emails for 28 days reminder"); + List> elements = Collections.> emptyList(); + elements = profileDaoReadOnly.findEmailsUnverifiedDaysByEventType(verifyReminderAfterTwentyEightDays, emailTooOld); + LOGGER.info("Got {} profiles with email event and unverified emails for 28 days reminder", elements.size()); + + HashMap> hasEventTypesMap = hasEventTypes(elements, + List.of(EmailEventType.VERIFY_EMAIL_28_DAYS_SENT, EmailEventType.VERIFY_EMAIL_28_DAYS_SENT_SKIPPED, EmailEventType.VERIFY_EMAIL_TOO_OLD)); + for (Triple element : elements) { + if (!hasEventTypesMap.containsKey(element.getLeft())) + processUnverifiedEmailsInTransaction(element.getLeft(), element.getMiddle(), EmailEventType.VERIFY_EMAIL_28_DAYS_SENT, + EmailEventType.VERIFY_EMAIL_28_DAYS_SENT_SKIPPED); + hasEventTypesMap.put(element.getLeft(), element); } - } while (!elements.isEmpty()); } } - + private void processUnverifiedEmailsInTransaction(final String email, final Boolean isPrimaryEmail, EmailEventType eventSent, EmailEventType eventSkipped) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override @@ -653,19 +660,19 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } } }); - } - + } + private void markUnverifiedEmailAsTooOld(final String email) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override @Transactional - protected void doInTransactionWithoutResult(TransactionStatus status) { + protected void doInTransactionWithoutResult(TransactionStatus status) { emailEventDao.persist(new EmailEventEntity(email, EmailEventType.VERIFY_EMAIL_TOO_OLD)); emailEventDao.flush(); } }); } - + private void sendVerificationReminderEmail(String userOrcid, String email, Boolean isPrimaryEmail) { ProfileEntity profile = profileEntityCacheManager.retrieve(userOrcid); Locale locale = getUserLocaleFromProfileEntity(profile); @@ -678,5 +685,5 @@ private void sendVerificationReminderEmail(String userOrcid, String email, Boole String body = templateManager.processTemplate("verification_email_v2.ftl", templateParams); String htmlBody = templateManager.processTemplate("verification_email_html_v2.ftl", templateParams); mailGunManager.sendEmail(EmailConstants.DO_NOT_REPLY_VERIFY_ORCID_ORG, email, subject, body, htmlBody); - } + } }