From 085f3c89d45aa92ba07da604523adcaed01bdcea Mon Sep 17 00:00:00 2001 From: Daniel Palafox Date: Tue, 12 Dec 2023 23:39:28 -0500 Subject: [PATCH 1/2] feature: Add encourage user to add works to email events log --- .../persistence/jpa/entities/EmailEventType.java | 5 +++-- .../cli/manager/EmailMessageSenderImpl.java | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java index a0ba1c35861..6d6095e2899 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java +++ b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java @@ -12,6 +12,7 @@ public enum EmailEventType { VERIFY_EMAIL_7_DAYS_SENT_SKIPPED, /* we are going to skip notifying email address that where already in the system before launching this */ VERIFY_EMAIL_2_DAYS_SENT, VERIFY_EMAIL_2_DAYS_SENT_SKIPPED, - VERIFY_EMAIL_TOO_OLD - ; + VERIFY_EMAIL_TOO_OLD, + ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT, + ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT_SKIPPED; } 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 7be2c7e1417..fd9e6ee1149 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 @@ -597,10 +597,20 @@ private void processUnverifiedEmails(boolean forceSending, int unverifiedDays, E synchronized public void addWorksToRecord() { if (Features.SEND_ADD_WORKS_EMAILS.isActive()) { - LOGGER.info("About to process send emails to encourage user to add works"); - List> elements = profileDaoReadOnly.findEmailsToSendAddWorksEmail(); + List> elements = profileDaoReadOnly.findEmailsToSendAddWorksEmail(); for (Pair element: elements) { - sendAddWorksToRecordEmail(element.getLeft(), element.getRight()); + String email = element.getLeft(); + String userOrcid = element.getRight(); + try { + LOGGER.debug("Sending email to encourage user to add works to email address {}, orcid {}", email, userOrcid); + sendAddWorksToRecordEmail(email, userOrcid); + emailEventDao.persist(new EmailEventEntity(email, EmailEventType.ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT)); + emailEventDao.flush(); + } catch (Exception e) { + LOGGER.error("Unable to send email to encourage user to add works to email: " + email, e); + emailEventDao.persist(new EmailEventEntity(email, EmailEventType.ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT_SKIPPED)); + emailEventDao.flush(); + } } } } From 2d1d09ee0a584029a8c96546d7d6892438630b04 Mon Sep 17 00:00:00 2001 From: Daniel Palafox Date: Fri, 15 Dec 2023 13:04:38 -0500 Subject: [PATCH 2/2] feature: Add log for sending `add works reminder` to `profile_event` table --- .../manager/impl/NotificationManagerImpl.java | 5 +- .../TwoFactorAuthenticationManagerImpl.java | 4 +- .../v3/impl/NotificationManagerImpl.java | 5 +- ...EmailFrequencyServiceAnnouncement2018.java | 7 +- .../profileEvent/ProfileEventManager.java | 8 +-- .../QuarterlyNotificationsManager.java | 5 +- .../core/manager/NotificationManagerTest.java | 3 +- .../TwoFactorAuthenticationManagerTest.java | 3 +- .../manager/v3/NotificationManagerTest.java | 3 +- .../org/orcid/persistence/dao/ProfileDao.java | 2 +- .../persistence/dao/ProfileEventDao.java | 15 ++++ .../persistence/dao/impl/ProfileDaoImpl.java | 19 ++---- .../dao/impl/ProfileEventDaoImpl.java | 28 ++++++++ .../jpa/entities/EmailEventType.java | 4 +- .../jpa/entities/ProfileEventType.java | 10 ++- .../resources/orcid-persistence-context.xml | 4 +- .../orcid/persistence/dao/ProfileDaoTest.java | 6 +- .../cli/manager/EmailMessageSenderImpl.java | 68 ++++++++++++++++--- .../manager/impl/TrickleManagerImpl.java | 3 +- .../resources/orcid-scheduler-context.xml | 4 +- .../manager/impl/TrickleManagerImplTest.java | 4 +- .../frontend/email/RecordEmailSender.java | 3 +- .../frontend/email/RecordEmailSenderTest.java | 3 +- 23 files changed, 158 insertions(+), 58 deletions(-) create mode 100644 orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileEventDao.java create mode 100644 orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileEventDaoImpl.java diff --git a/orcid-core/src/main/java/org/orcid/core/manager/impl/NotificationManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/impl/NotificationManagerImpl.java index fcf4142b081..a6a304ac932 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/impl/NotificationManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/impl/NotificationManagerImpl.java @@ -49,6 +49,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ActionableNotificationEntity; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.ClientRedirectUriEntity; @@ -83,7 +84,7 @@ public class NotificationManagerImpl extends ManagerReadOnlyBaseImpl implements private EncryptionManager encryptionManager; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource private ProfileDao profileDao; @@ -128,7 +129,7 @@ public void setEncryptionManager(EncryptionManager encryptionManager) { this.encryptionManager = encryptionManager; } - public void setProfileEventDao(GenericDao profileEventDao) { + public void setProfileEventDao(ProfileEventDao profileEventDao) { this.profileEventDao = profileEventDao; } diff --git a/orcid-core/src/main/java/org/orcid/core/manager/impl/TwoFactorAuthenticationManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/impl/TwoFactorAuthenticationManagerImpl.java index 207b9d7a7ed..afdd6248659 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/impl/TwoFactorAuthenticationManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/impl/TwoFactorAuthenticationManagerImpl.java @@ -13,8 +13,8 @@ import org.orcid.core.manager.TwoFactorAuthenticationManager; import org.orcid.core.manager.read_only.EmailManagerReadOnly; import org.orcid.jaxb.model.record_v2.Email; -import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; import org.orcid.persistence.jpa.entities.ProfileEventType; @@ -40,7 +40,7 @@ public class TwoFactorAuthenticationManagerImpl implements TwoFactorAuthenticati private BackupCodeManager backupCodeManager; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource private ProfileDao profileDao; diff --git a/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/NotificationManagerImpl.java b/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/NotificationManagerImpl.java index 61c90514f0c..83a26159bd6 100644 --- a/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/NotificationManagerImpl.java +++ b/orcid-core/src/main/java/org/orcid/core/manager/v3/impl/NotificationManagerImpl.java @@ -55,6 +55,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ActionableNotificationEntity; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.ClientRedirectUriEntity; @@ -101,7 +102,7 @@ public class NotificationManagerImpl extends ManagerReadOnlyBaseImpl implements private EncryptionManager encryptionManager; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource private ProfileDao profileDao; @@ -175,7 +176,7 @@ public void setEncryptionManager(EncryptionManager encryptionManager) { this.encryptionManager = encryptionManager; } - public void setProfileEventDao(GenericDao profileEventDao) { + public void setProfileEventDao(ProfileEventDao profileEventDao) { this.profileEventDao = profileEventDao; } diff --git a/orcid-core/src/main/java/org/orcid/core/profileEvent/EmailFrequencyServiceAnnouncement2018.java b/orcid-core/src/main/java/org/orcid/core/profileEvent/EmailFrequencyServiceAnnouncement2018.java index e0f28b4b835..d1263108fe3 100644 --- a/orcid-core/src/main/java/org/orcid/core/profileEvent/EmailFrequencyServiceAnnouncement2018.java +++ b/orcid-core/src/main/java/org/orcid/core/profileEvent/EmailFrequencyServiceAnnouncement2018.java @@ -19,7 +19,6 @@ import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; -import org.orcid.core.manager.NotificationManager; import org.orcid.core.manager.TemplateManager; import org.orcid.core.manager.impl.OrcidUrlManager; import org.orcid.core.manager.v3.RecordNameManager; @@ -27,6 +26,8 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; +import org.orcid.persistence.dao.impl.ProfileEventDaoImpl; import org.orcid.persistence.jpa.entities.NotificationServiceAnnouncementEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; @@ -54,7 +55,7 @@ public class EmailFrequencyServiceAnnouncement2018 { private TemplateManager templateManager; - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; private NotificationDao notificationDao; @@ -100,7 +101,7 @@ private void init() { profileDaoReadOnly = (ProfileDao) context.getBean("profileDaoReadOnly"); messages = (MessageSource) context.getBean("messageSource"); templateManager = (TemplateManager) context.getBean("templateManager"); - profileEventDao = (GenericDao) context.getBean("profileEventDao"); + profileEventDao = (ProfileEventDao) context.getBean("profileEventDao"); notificationDao = (NotificationDao) context.getBean("notificationDao"); orcidUrlManager = (OrcidUrlManager) context.getBean("orcidUrlManager"); recordNameManager = (RecordNameManager) context.getBean("recordNameManagerV3"); diff --git a/orcid-core/src/main/java/org/orcid/core/profileEvent/ProfileEventManager.java b/orcid-core/src/main/java/org/orcid/core/profileEvent/ProfileEventManager.java index 96e2ea64da3..3ca894d6562 100644 --- a/orcid-core/src/main/java/org/orcid/core/profileEvent/ProfileEventManager.java +++ b/orcid-core/src/main/java/org/orcid/core/profileEvent/ProfileEventManager.java @@ -15,8 +15,8 @@ import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; -import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ProfileEventEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +37,7 @@ public class ProfileEventManager { private ProfileDao profileDao; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource private TransactionTemplate transactionTemplate; @@ -136,11 +136,11 @@ public void setProfileDao(ProfileDao profileDao) { this.profileDao = profileDao; } - public GenericDao getProfileEventDao() { + public ProfileEventDao getProfileEventDao() { return profileEventDao; } - public void setProfileEventDao(GenericDao profileEventDao) { + public void setProfileEventDao(ProfileEventDao profileEventDao) { this.profileEventDao = profileEventDao; } diff --git a/orcid-core/src/main/java/org/orcid/core/profileEvent/quarterlyNotifications/QuarterlyNotificationsManager.java b/orcid-core/src/main/java/org/orcid/core/profileEvent/quarterlyNotifications/QuarterlyNotificationsManager.java index 4ff52610b33..9bfb176fb72 100644 --- a/orcid-core/src/main/java/org/orcid/core/profileEvent/quarterlyNotifications/QuarterlyNotificationsManager.java +++ b/orcid-core/src/main/java/org/orcid/core/profileEvent/quarterlyNotifications/QuarterlyNotificationsManager.java @@ -22,6 +22,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.EmailFrequencyEntity; import org.orcid.persistence.jpa.entities.NotificationTipEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; @@ -41,7 +42,7 @@ public abstract class QuarterlyNotificationsManager { private static Logger LOG = LoggerFactory.getLogger(QuarterlyNotificationsManager.class); - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; private ProfileDao profileDaoReadOnly; @@ -89,7 +90,7 @@ public QuarterlyNotificationsManager(ProfileEventType created, ProfileEventType notificationDao = (NotificationDao) context.getBean("notificationDao"); orcidUrlManager = (OrcidUrlManager) context.getBean("orcidUrlManager"); emailFrequencyDao = (EmailFrequencyDao) context.getBean("emailFrequencyDao"); - profileEventDao = (GenericDao) context.getBean("profileEventDao"); + profileEventDao = (ProfileEventDao) context.getBean("profileEventDao"); encryptionManager = (EncryptionManager) context.getBean("encryptionManager"); messages = (MessageSource) context.getBean("messageSource"); transactionTemplate = (TransactionTemplate) context.getBean("transactionTemplate"); diff --git a/orcid-core/src/test/java/org/orcid/core/manager/NotificationManagerTest.java b/orcid-core/src/test/java/org/orcid/core/manager/NotificationManagerTest.java index 5c08f29bd02..0271780d64d 100644 --- a/orcid-core/src/test/java/org/orcid/core/manager/NotificationManagerTest.java +++ b/orcid-core/src/test/java/org/orcid/core/manager/NotificationManagerTest.java @@ -55,6 +55,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.dao.impl.NotificationDaoImpl; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.NotificationEntity; @@ -80,7 +81,7 @@ public class NotificationManagerTest extends DBUnitTest { @Mock - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Mock private SourceManager sourceManager; diff --git a/orcid-core/src/test/java/org/orcid/core/manager/TwoFactorAuthenticationManagerTest.java b/orcid-core/src/test/java/org/orcid/core/manager/TwoFactorAuthenticationManagerTest.java index 3ae364b1fea..a5f4fc10eda 100644 --- a/orcid-core/src/test/java/org/orcid/core/manager/TwoFactorAuthenticationManagerTest.java +++ b/orcid-core/src/test/java/org/orcid/core/manager/TwoFactorAuthenticationManagerTest.java @@ -28,6 +28,7 @@ import org.orcid.jaxb.model.record_v2.Email; import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; @@ -49,7 +50,7 @@ public class TwoFactorAuthenticationManagerTest { private ProfileDao profileDao; @Mock - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @InjectMocks private TwoFactorAuthenticationManagerImpl twoFactorAuthenticationManager; diff --git a/orcid-core/src/test/java/org/orcid/core/manager/v3/NotificationManagerTest.java b/orcid-core/src/test/java/org/orcid/core/manager/v3/NotificationManagerTest.java index fa8f78c8f14..14ee54c0c6e 100644 --- a/orcid-core/src/test/java/org/orcid/core/manager/v3/NotificationManagerTest.java +++ b/orcid-core/src/test/java/org/orcid/core/manager/v3/NotificationManagerTest.java @@ -64,6 +64,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.dao.impl.NotificationDaoImpl; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.EmailEventEntity; @@ -90,7 +91,7 @@ public class NotificationManagerTest extends DBUnitTest { "/data/BiographyEntityData.xml"); @Mock - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Mock private SourceManager mockSourceManager; 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 35f0f8fbe51..8a39bc99c50 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 @@ -164,5 +164,5 @@ public interface ProfileDao extends GenericDao { boolean haveMemberPushedWorksOrAffiliationsToRecord(String orcid, String clientId); - public List> findEmailsToSendAddWorksEmail(); + public List> findEmailsToSendAddWorksEmail(int profileCreatedNumberOfDaysAgo); } diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileEventDao.java b/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileEventDao.java new file mode 100644 index 00000000000..27cc3150e8d --- /dev/null +++ b/orcid-persistence/src/main/java/org/orcid/persistence/dao/ProfileEventDao.java @@ -0,0 +1,15 @@ +package org.orcid.persistence.dao; + +import org.orcid.persistence.jpa.entities.ProfileEventEntity; +import org.orcid.persistence.jpa.entities.ProfileEventType; + +/** + * + * @author Daniel Palafox + * + */ +public interface ProfileEventDao extends GenericDao { + + boolean isAttemptSend(String orcid, ProfileEventType eventType); + +} 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 5ceee7facfd..02f77da8778 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 @@ -842,18 +842,19 @@ public boolean haveMemberPushedWorksOrAffiliationsToRecord(String orcid, String } @Override - public List> findEmailsToSendAddWorksEmail() { + public List> findEmailsToSendAddWorksEmail(int profileCreatedNumberOfDaysAgo) { StringBuilder qs = new StringBuilder("SELECT e.email, p.orcid FROM email e "); qs.append("LEFT JOIN email_frequency ef ON e.orcid = ef.orcid "); qs.append("LEFT OUTER JOIN work w ON e.orcid = w.orcid "); qs.append("JOIN profile p on p.orcid = e.orcid and p.claimed = true AND p.deprecated_date is null AND "); qs.append("p.profile_deactivation_date is null AND p.account_expiry is null "); qs.append("WHERE "); - qs.append(getWorkCreatedNumberOfDaysAgo("7")); - qs.append("OR "); - qs.append(getWorkCreatedNumberOfDaysAgo("28")); - qs.append("OR "); - qs.append(getWorkCreatedNumberOfDaysAgo("90")); + qs.append("e.is_verified = true and e.is_primary = true and "); + qs.append("ef.send_quarterly_tips = true and "); + qs.append("w.orcid is null and "); + qs.append("CAST(p.date_created as date) = CAST(CURRENT_DATE - INTERVAL '"); + qs.append(profileCreatedNumberOfDaysAgo); + qs.append("' day as date) "); qs.append("GROUP BY e.email, p.orcid"); Query query = entityManager.createNativeQuery(qs.toString()); @@ -866,10 +867,4 @@ public List> findEmailsToSendAddWorksEmail() { return results; } - private String getWorkCreatedNumberOfDaysAgo(String days) { - return "e.is_verified = true and e.is_primary = true and\n" + - " ef.send_quarterly_tips = true and\n" + - " w.orcid is null and\n" + - " CAST(p.date_created as date) = CAST(CURRENT_DATE - INTERVAL '"+ days +"' day as date) "; - } } diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileEventDaoImpl.java b/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileEventDaoImpl.java new file mode 100644 index 00000000000..549ea03aac3 --- /dev/null +++ b/orcid-persistence/src/main/java/org/orcid/persistence/dao/impl/ProfileEventDaoImpl.java @@ -0,0 +1,28 @@ +package org.orcid.persistence.dao.impl; + +import org.orcid.persistence.dao.ProfileEventDao; +import org.orcid.persistence.jpa.entities.ProfileEventEntity; +import org.orcid.persistence.jpa.entities.ProfileEventType; + +import javax.persistence.Query; +import java.math.BigInteger; +import java.util.List; + +/** + * + * @author Daniel Palafox + * + */ +public class ProfileEventDaoImpl extends GenericDaoImpl implements ProfileEventDao { + + public ProfileEventDaoImpl() { super(ProfileEventEntity.class); } + + @Override + public boolean isAttemptSend(String orcid, ProfileEventType eventType) { + Query query = entityManager.createNativeQuery("select count(*) from profile_event where orcid=:orcid and profile_event_type=:eventType"); + query.setParameter("orcid", orcid); + query.setParameter("eventType", eventType.toString()); + Long result = ((BigInteger)query.getSingleResult()).longValue(); + return (result != null && result > 0); + } +} diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java index 6d6095e2899..da76c1b0eda 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java +++ b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/EmailEventType.java @@ -12,7 +12,5 @@ public enum EmailEventType { VERIFY_EMAIL_7_DAYS_SENT_SKIPPED, /* we are going to skip notifying email address that where already in the system before launching this */ VERIFY_EMAIL_2_DAYS_SENT, VERIFY_EMAIL_2_DAYS_SENT_SKIPPED, - VERIFY_EMAIL_TOO_OLD, - ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT, - ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT_SKIPPED; + VERIFY_EMAIL_TOO_OLD; } diff --git a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/ProfileEventType.java b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/ProfileEventType.java index 1fd4a6d82fa..0251efbca88 100644 --- a/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/ProfileEventType.java +++ b/orcid-persistence/src/main/java/org/orcid/persistence/jpa/entities/ProfileEventType.java @@ -36,5 +36,13 @@ public enum ProfileEventType { EMAIL_VIS_2019_SENT, EMAIL_VIS_2019_SKIPPED, EMAIL_VIS_2019_FAILED, // 2FA enable/disable events - PROFILE_2FA_ENABLED, PROFILE_2FA_DISABLED, PROFILE_2FA_DISABLED_BY_ADMIN; + PROFILE_2FA_ENABLED, PROFILE_2FA_DISABLED, PROFILE_2FA_DISABLED_BY_ADMIN, + + //Send email to encourage users to add works to their record + ADD_WORKS_FIRST_REMINDER_SENT, + ADD_WORKS_FIRST_REMINDER_SENT_SKIPPED, + ADD_WORKS_SECOND_REMINDER_SENT, + ADD_WORKS_SECOND_REMINDER_SENT_SKIPPED, + ADD_WORKS_THIRD_REMINDER_SENT, + ADD_WORKS_THIRD_REMINDER_SENT_SKIPPED; } diff --git a/orcid-persistence/src/main/resources/orcid-persistence-context.xml b/orcid-persistence/src/main/resources/orcid-persistence-context.xml index 3973873ef34..2d6752cb261 100644 --- a/orcid-persistence/src/main/resources/orcid-persistence-context.xml +++ b/orcid-persistence/src/main/resources/orcid-persistence-context.xml @@ -207,9 +207,7 @@ - - - + diff --git a/orcid-persistence/src/test/java/org/orcid/persistence/dao/ProfileDaoTest.java b/orcid-persistence/src/test/java/org/orcid/persistence/dao/ProfileDaoTest.java index d589d34d42d..61c1fe3d99d 100644 --- a/orcid-persistence/src/test/java/org/orcid/persistence/dao/ProfileDaoTest.java +++ b/orcid-persistence/src/test/java/org/orcid/persistence/dao/ProfileDaoTest.java @@ -61,7 +61,7 @@ public class ProfileDaoTest extends DBUnitTest { private ClientDetailsDao clientDetailsDao; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource(name="entityManager") protected EntityManager entityManager; @@ -381,12 +381,12 @@ public void testDisable2FA() { @Test @Transactional - public void findEmailsToSendAddWorksEmail() { + public void findEmailsToSendAddWorksFirstAttemptEmail() { String orcid = "4444-4444-4444-4441"; updateProfileWithDateCreated(orcid, LocalDateTime.now().minusDays(7).toDate()); - List> results = profileDao.findEmailsToSendAddWorksEmail(); + List> results = profileDao.findEmailsToSendAddWorksEmail(7); assertNotNull(results); assertEquals(1, results.size()); } 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 fd9e6ee1149..b36033c2e4f 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 @@ -51,6 +51,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.EmailEntity; import org.orcid.persistence.jpa.entities.EmailEventEntity; import org.orcid.persistence.jpa.entities.EmailEventType; @@ -58,6 +59,8 @@ import org.orcid.persistence.jpa.entities.NotificationServiceAnnouncementEntity; import org.orcid.persistence.jpa.entities.NotificationTipEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; +import org.orcid.persistence.jpa.entities.ProfileEventEntity; +import org.orcid.persistence.jpa.entities.ProfileEventType; import org.orcid.pojo.DigestEmail; import org.orcid.pojo.ajaxForm.PojoUtil; import org.orcid.utils.email.MailGunManager; @@ -140,6 +143,9 @@ public class EmailMessageSenderImpl implements EmailMessageSender { @Resource private VerifyEmailUtils verifyEmailUtils; + @Resource + private ProfileEventDao profileEventDao; + @Value("${org.notifications.service_announcements.batchSize:60000}") private Integer batchSize; @@ -151,6 +157,15 @@ public class EmailMessageSenderImpl implements EmailMessageSender { private int emailTooOldLegacy = 15; + @Value("${org.orcid.core.email.addWorks.firstAttempt:7}") + private int addWorksFirstAttemptEmail; + + @Value("${org.orcid.core.email.addWorks.secondAttempt:28}") + private int addWorksSecondAttemptEmail; + + @Value("${org.orcid.core.email.addWorks.thirdAttempt:90}") + private int addWorksThirdAttemptEmail; + 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) { @@ -595,21 +610,52 @@ private void processUnverifiedEmails(boolean forceSending, int unverifiedDays, E } } - synchronized public void addWorksToRecord() { + synchronized public void addWorksToRecordFirstReminder() { + sendAddWorksToRecordEmailAttempt(addWorksFirstAttemptEmail, ProfileEventType.ADD_WORKS_FIRST_REMINDER_SENT); + } + + synchronized public void addWorksToRecordSecondReminder() { + sendAddWorksToRecordEmailAttempt(addWorksSecondAttemptEmail, ProfileEventType.ADD_WORKS_SECOND_REMINDER_SENT); + } + + synchronized public void addWorksToRecordThirdReminder() { + sendAddWorksToRecordEmailAttempt(addWorksThirdAttemptEmail, ProfileEventType.ADD_WORKS_THIRD_REMINDER_SENT); + } + + private void sendAddWorksToRecordEmailAttempt(int addWorksAttemptEmail, ProfileEventType profileEventType){ if (Features.SEND_ADD_WORKS_EMAILS.isActive()) { - List> elements = profileDaoReadOnly.findEmailsToSendAddWorksEmail(); + List> elements = profileDaoReadOnly.findEmailsToSendAddWorksEmail(addWorksAttemptEmail); for (Pair element: elements) { String email = element.getLeft(); String userOrcid = element.getRight(); - try { - LOGGER.debug("Sending email to encourage user to add works to email address {}, orcid {}", email, userOrcid); - sendAddWorksToRecordEmail(email, userOrcid); - emailEventDao.persist(new EmailEventEntity(email, EmailEventType.ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT)); - emailEventDao.flush(); - } catch (Exception e) { - LOGGER.error("Unable to send email to encourage user to add works to email: " + email, e); - emailEventDao.persist(new EmailEventEntity(email, EmailEventType.ENCOURAGE_USER_TO_ADD_WORKS_EMAIL_SENT_SKIPPED)); - emailEventDao.flush(); + String numberAttempt = null; + ProfileEventType skipped = null; + + switch (profileEventType) { + case ADD_WORKS_FIRST_REMINDER_SENT: + numberAttempt = "first"; + skipped = ProfileEventType.ADD_WORKS_FIRST_REMINDER_SENT_SKIPPED; + break; + case ADD_WORKS_SECOND_REMINDER_SENT: + numberAttempt = "second"; + skipped = ProfileEventType.ADD_WORKS_SECOND_REMINDER_SENT_SKIPPED; + break; + case ADD_WORKS_THIRD_REMINDER_SENT: + numberAttempt = "third"; + skipped = ProfileEventType.ADD_WORKS_THIRD_REMINDER_SENT_SKIPPED; + break; + } + if (!profileEventDao.isAttemptSend(userOrcid, profileEventType)) { + try { + LOGGER.debug("Sending "+ numberAttempt +" attempt email to encourage user to add works to email address {}, orcid {}", email, userOrcid); + sendAddWorksToRecordEmail(email, userOrcid); + profileEventDao.persist(new ProfileEventEntity(userOrcid, profileEventType, email)); + profileEventDao.flush(); + } catch (Exception e) { + LOGGER.error("Unable to send "+ numberAttempt +" attempt email to encourage user to add works to email: " + email, e); + profileEventDao.persist(new ProfileEventEntity(userOrcid, skipped, email)); + profileEventDao.flush(); + } } } } diff --git a/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImpl.java b/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImpl.java index dfb3f101f33..ac645f66eec 100644 --- a/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImpl.java +++ b/orcid-scheduler-web/src/main/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImpl.java @@ -13,6 +13,7 @@ import org.orcid.persistence.dao.EmailScheduleDao; import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; import org.orcid.persistence.jpa.entities.ProfileEventType; @@ -41,7 +42,7 @@ public class TrickleManagerImpl implements TrickleManager { private ProfileDao profileDaoReadOnly; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource(name = "emailManagerReadOnlyV3") private EmailManagerReadOnly emailManagerReadOnly; diff --git a/orcid-scheduler-web/src/main/resources/orcid-scheduler-context.xml b/orcid-scheduler-web/src/main/resources/orcid-scheduler-context.xml index 565133c8c26..5da8c3ca224 100644 --- a/orcid-scheduler-web/src/main/resources/orcid-scheduler-context.xml +++ b/orcid-scheduler-web/src/main/resources/orcid-scheduler-context.xml @@ -38,7 +38,9 @@ - + + + diff --git a/orcid-scheduler-web/src/test/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImplTest.java b/orcid-scheduler-web/src/test/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImplTest.java index c197b7bcc07..5f47a26582b 100644 --- a/orcid-scheduler-web/src/test/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImplTest.java +++ b/orcid-scheduler-web/src/test/java/org/orcid/scheduler/email/trickle/manager/impl/TrickleManagerImplTest.java @@ -18,8 +18,8 @@ import org.orcid.core.manager.v3.read_only.EmailManagerReadOnly; import org.orcid.persistence.dao.EmailFrequencyDao; import org.orcid.persistence.dao.EmailScheduleDao; -import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.EmailFrequencyEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; @@ -48,7 +48,7 @@ public class TrickleManagerImplTest { private EmailManagerReadOnly emailManagerReadOnly; @Mock - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @InjectMocks private TrickleManagerImpl trickleManager; diff --git a/orcid-web/src/main/java/org/orcid/frontend/email/RecordEmailSender.java b/orcid-web/src/main/java/org/orcid/frontend/email/RecordEmailSender.java index 564c8fb71bb..fc2527e0f95 100644 --- a/orcid-web/src/main/java/org/orcid/frontend/email/RecordEmailSender.java +++ b/orcid-web/src/main/java/org/orcid/frontend/email/RecordEmailSender.java @@ -22,6 +22,7 @@ import org.orcid.jaxb.model.v3.release.record.Email; import org.orcid.jaxb.model.v3.release.record.Emails; import org.orcid.persistence.dao.GenericDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; import org.orcid.persistence.jpa.entities.ProfileEventType; @@ -44,7 +45,7 @@ public class RecordEmailSender { private boolean apiRecordCreationEmailEnabled; @Resource - private GenericDao profileEventDao; + private ProfileEventDao profileEventDao; @Resource(name = "messageSource") private MessageSource messages; diff --git a/orcid-web/src/test/java/org/orcid/frontend/email/RecordEmailSenderTest.java b/orcid-web/src/test/java/org/orcid/frontend/email/RecordEmailSenderTest.java index 68f1396f151..8809913601f 100644 --- a/orcid-web/src/test/java/org/orcid/frontend/email/RecordEmailSenderTest.java +++ b/orcid-web/src/test/java/org/orcid/frontend/email/RecordEmailSenderTest.java @@ -36,6 +36,7 @@ import org.orcid.persistence.dao.GenericDao; import org.orcid.persistence.dao.NotificationDao; import org.orcid.persistence.dao.ProfileDao; +import org.orcid.persistence.dao.ProfileEventDao; import org.orcid.persistence.jpa.entities.EmailEventEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.persistence.jpa.entities.ProfileEventEntity; @@ -51,7 +52,7 @@ public class RecordEmailSenderTest { @Mock - private GenericDao mockProfileEventDao; + private ProfileEventDao mockProfileEventDao; @Mock private SourceManager sourceManager;