-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2588 from objectcomputing/feature-2349/bi-weekly-…
…pulse-emails Feature 2349/bi weekly pulse emails
- Loading branch information
Showing
13 changed files
with
536 additions
and
18 deletions.
There are no files selected for viewing
74 changes: 74 additions & 0 deletions
74
server/src/main/java/com/objectcomputing/checkins/services/pulse/PulseEmail.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.objectcomputing.checkins.services.pulse; | ||
|
||
import com.objectcomputing.checkins.configuration.CheckInsConfiguration; | ||
import com.objectcomputing.checkins.notifications.email.EmailSender; | ||
import com.objectcomputing.checkins.notifications.email.MailJetFactory; | ||
import com.objectcomputing.checkins.services.memberprofile.MemberProfileServices; | ||
|
||
import jakarta.inject.Named; | ||
|
||
import java.util.stream.Collectors; | ||
import java.util.List; | ||
|
||
class PulseEmail { | ||
private final EmailSender emailSender; | ||
private final CheckInsConfiguration checkInsConfiguration; | ||
private final MemberProfileServices memberProfileServices; | ||
|
||
private final String SUBJECT = "Check Out the Pulse Survey!"; | ||
|
||
public PulseEmail(@Named(MailJetFactory.HTML_FORMAT) EmailSender emailSender, | ||
CheckInsConfiguration checkInsConfiguration, | ||
MemberProfileServices memberProfileServices) { | ||
this.emailSender = emailSender; | ||
this.checkInsConfiguration = checkInsConfiguration; | ||
this.memberProfileServices = memberProfileServices; | ||
} | ||
|
||
private List<String> getActiveTeamMembers() { | ||
List<String> profiles = memberProfileServices.findAll().stream() | ||
.filter(p -> p.getTerminationDate() == null) | ||
.map(p -> p.getWorkEmail()) | ||
.collect(Collectors.toList()); | ||
return profiles; | ||
} | ||
|
||
private String getEmailContent() { | ||
/* | ||
<mjml> | ||
<mj-body> | ||
<mj-section> | ||
<mj-column> | ||
<mj-divider border-color="#2559a7"></mj-divider> | ||
<mj-text font-size="16px" font-family="'Helvetica Neue', Helvetica, Arial, sans-serif" color="#4d4c4f">Please fill out your Pulse survey, if you haven't already done so. We want to know how you're doing!</mj-text> | ||
<mj-text font-size="16px" font-family="'Helvetica Neue', Helvetica, Arial, sans-serif" color="#4d4c4f">Click <a href="%s/pulse" target="_blank">here</a> to begin.</mj-text> | ||
</mj-column> | ||
</mj-section> | ||
</mj-body> | ||
</mjml> | ||
*/ | ||
return String.format(""" | ||
<html> | ||
<body> | ||
<div style="margin:0px auto;float: left; max-width:600px;"> | ||
<p style="border-top:solid 4px #2559a7;font-size:1px;margin:0px auto;width:100%%;"></p> | ||
<p></p> | ||
<div style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:16px;line-height:1;text-align:left;color:#4d4c4f;"> | ||
Please fill out your Pulse survey, if you haven't already done so. We want to know how you're doing!</div> | ||
<p></p> | ||
<div style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:16px;line-height:1;text-align:left;color:#4d4c4f;"> | ||
Click <a href="%s/pulse" target="_blank">here</a> to begin.</div> | ||
</div> | ||
</div> | ||
</body> | ||
</html> | ||
""", checkInsConfiguration.getWebAddress()); | ||
} | ||
|
||
public void send() { | ||
final List<String> recipients = getActiveTeamMembers(); | ||
final String content = getEmailContent(); | ||
emailSender.sendEmail(null, null, SUBJECT, content, | ||
recipients.toArray(new String[recipients.size()])); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
server/src/main/java/com/objectcomputing/checkins/services/pulse/PulseServices.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.objectcomputing.checkins.services.pulse; | ||
|
||
import java.time.LocalDate; | ||
|
||
public interface PulseServices { | ||
public void sendPendingEmail(LocalDate now); | ||
} |
119 changes: 119 additions & 0 deletions
119
server/src/main/java/com/objectcomputing/checkins/services/pulse/PulseServicesImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package com.objectcomputing.checkins.services.pulse; | ||
|
||
import com.objectcomputing.checkins.configuration.CheckInsConfiguration; | ||
import com.objectcomputing.checkins.notifications.email.EmailSender; | ||
import com.objectcomputing.checkins.notifications.email.MailJetFactory; | ||
import com.objectcomputing.checkins.services.memberprofile.MemberProfileServices; | ||
import com.objectcomputing.checkins.services.settings.SettingsServices; | ||
import com.objectcomputing.checkins.services.settings.Setting; | ||
import com.objectcomputing.checkins.exceptions.NotFoundException; | ||
|
||
import lombok.Getter; | ||
import lombok.AllArgsConstructor; | ||
|
||
import jakarta.inject.Named; | ||
import jakarta.inject.Singleton; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.Map; | ||
import java.util.HashMap; | ||
import java.time.LocalDate; | ||
import java.time.DayOfWeek; | ||
import java.time.temporal.ChronoUnit; | ||
import java.time.temporal.TemporalAdjusters; | ||
|
||
@Singleton | ||
public class PulseServicesImpl implements PulseServices { | ||
@Getter | ||
@AllArgsConstructor | ||
private class Frequency { | ||
private final int count; | ||
private final ChronoUnit units; | ||
} | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(PulseServicesImpl.class); | ||
private final EmailSender emailSender; | ||
private final CheckInsConfiguration checkInsConfiguration; | ||
private final MemberProfileServices memberProfileServices; | ||
private final SettingsServices settingsServices; | ||
private final Map<String, Boolean> sent = new HashMap<String, Boolean>(); | ||
|
||
private final DayOfWeek emailDay = DayOfWeek.MONDAY; | ||
|
||
private String setting = "bi-weekly"; | ||
private final Map<String, Frequency> frequency = Map.of( | ||
"weekly", new Frequency(1, ChronoUnit.WEEKS), | ||
"bi-weekly", new Frequency(2, ChronoUnit.WEEKS), | ||
"monthly", new Frequency(1, ChronoUnit.MONTHS) | ||
); | ||
|
||
public PulseServicesImpl( | ||
@Named(MailJetFactory.HTML_FORMAT) EmailSender emailSender, | ||
CheckInsConfiguration checkInsConfiguration, | ||
MemberProfileServices memberProfileServices, | ||
SettingsServices settingsServices) { | ||
this.emailSender = emailSender; | ||
this.checkInsConfiguration = checkInsConfiguration; | ||
this.memberProfileServices = memberProfileServices; | ||
this.settingsServices = settingsServices; | ||
} | ||
|
||
public void sendPendingEmail(LocalDate check) { | ||
if (check.getDayOfWeek() == emailDay) { | ||
LOG.info("Checking for pending Pulse email"); | ||
// Start from the first of the year and move forward to ensure that we | ||
// are sending email during the correct week. | ||
LocalDate start = check.with(TemporalAdjusters.firstDayOfYear()) | ||
.with(TemporalAdjusters.firstInMonth(emailDay)); | ||
|
||
try { | ||
Setting freq = settingsServices.findByName("PULSE_EMAIL_FREQUENCY"); | ||
if (frequency.containsKey(freq.getValue())) { | ||
setting = freq.getValue(); | ||
} else { | ||
LOG.error("Invalid Pulse Email Frequency Setting: " + freq.getValue()); | ||
} | ||
} catch(NotFoundException ex) { | ||
// Use the default setting. | ||
LOG.error("Pulse Frequency Error: " + ex.toString()); | ||
} | ||
|
||
LOG.info("Using Pulse Frequency: " + setting); | ||
final Frequency freq = frequency.get(setting); | ||
do { | ||
if (start.getDayOfMonth() == check.getDayOfMonth()) { | ||
LOG.info("Check day of month matches frequency day"); | ||
final String key = new StringBuilder(start.getMonth().toString()) | ||
.append("_") | ||
.append(String.valueOf(start.getDayOfMonth())) | ||
.toString(); | ||
if (sent.containsKey(key)) { | ||
LOG.info("The Pulse Email has already been sent today"); | ||
} else { | ||
LOG.info("Sending Pulse Email"); | ||
send(); | ||
sent.put(key, true); | ||
} | ||
break; | ||
} | ||
start = start.plus(freq.getCount(), freq.getUnits()); | ||
|
||
// Apply firstInMonth(emailDay) to support adding one month to the start | ||
// date. When adding weeks, it remains on the original day. But, when | ||
// adding months, it can move away from the first of the month and we | ||
// need the day specified by emailDay. | ||
if (freq.getUnits() == ChronoUnit.MONTHS) { | ||
start = start.with(TemporalAdjusters.firstInMonth(emailDay)); | ||
} | ||
} while(start.isBefore(check) || start.isEqual(check)); | ||
} | ||
} | ||
|
||
private void send() { | ||
PulseEmail email = new PulseEmail(emailSender, checkInsConfiguration, | ||
memberProfileServices); | ||
email.send(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.