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..61652824719 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 @@ -78,6 +78,8 @@ public interface ProfileDao extends GenericDao { public List> findEmailsUnverfiedDays(int daysUnverified, int maxResults); + public List> findEmailsUnverifiedDaysByEventType(int daysUnverified, int tooOldNumberOfDays); + String retrieveOrcidType(String orcid); List findInfoForDecryptionAnalysis(); 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..27e5948d70f 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,9 +21,14 @@ 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,32 @@ 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 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..134285ddb23 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 @@ -596,43 +598,45 @@ synchronized public void processUnverifiedEmails2Days() { 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)) { + 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); - } else { - // Mark is as too old to send the verification email - markUnverifiedEmailAsTooOld(element.getLeft()); - } + hasEventTypesMap.put(element.getLeft(), element); + } } - } while (!elements.isEmpty()); - } } + //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); + } + } + 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()); - } - } - } while (!elements.isEmpty()); + 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); + } } }