1010import com .objectcomputing .checkins .services .feedback_request .FeedbackRequest ;
1111import com .objectcomputing .checkins .services .memberprofile .MemberProfileRepository ;
1212import com .objectcomputing .checkins .services .memberprofile .MemberProfile ;
13+ import io .micronaut .context .annotation .Value ;
1314import io .micronaut .context .env .Environment ;
15+ import io .micronaut .core .io .Readable ;
16+ import io .micronaut .core .io .IOUtils ;
1417import jakarta .inject .Named ;
1518import jakarta .inject .Singleton ;
1619import jakarta .validation .constraints .NotNull ;
2528import java .util .Set ;
2629import java .util .UUID ;
2730import java .util .stream .Collectors ;
31+ import java .io .BufferedReader ;
2832
2933@ Singleton
3034class ReviewPeriodServicesImpl implements ReviewPeriodServices {
@@ -40,12 +44,17 @@ class ReviewPeriodServicesImpl implements ReviewPeriodServices {
4044 private final Environment environment ;
4145 private final String webAddress ;
4246
47+ @ Value ("classpath:mjml/supervisor_review_assignment.mjml" )
48+ private Readable supervisorReviewAssignmentTemplate ;
49+ @ Value ("classpath:mjml/review_period_announcement.mjml" )
50+ private Readable reviewPeriodAnnouncementTemplate ;
51+
4352 ReviewPeriodServicesImpl (ReviewPeriodRepository reviewPeriodRepository ,
4453 ReviewAssignmentRepository reviewAssignmentRepository ,
4554 MemberProfileRepository memberProfileRepository ,
4655 FeedbackRequestServices feedbackRequestServices ,
4756 ReviewStatusTransitionValidator reviewStatusTransitionValidator ,
48- @ Named (MailJetFactory .HTML_FORMAT ) EmailSender emailSender ,
57+ @ Named (MailJetFactory .MJML_FORMAT ) EmailSender emailSender ,
4958 Environment environment ,
5059 CheckInsConfiguration checkInsConfiguration ) {
5160 this .reviewPeriodRepository = reviewPeriodRepository ;
@@ -173,8 +182,20 @@ public ReviewPeriod update(@NotNull ReviewPeriod reviewPeriod) {
173182 " does not have a self-review template." );
174183 }
175184
185+ Set <String > allInvolved = new HashSet <>();
176186 Set <UUID > selfRevieweeIds = new HashSet <>();
177187 for (ReviewAssignment assignment : assignments ) {
188+ Optional <MemberProfile > reviewerProfile =
189+ memberProfileRepository .findById (assignment .getReviewerId ());
190+ if (!reviewerProfile .isEmpty ()) {
191+ allInvolved .add (reviewerProfile .get ().getWorkEmail ());
192+ }
193+ Optional <MemberProfile > revieweeProfile =
194+ memberProfileRepository .findById (assignment .getRevieweeId ());
195+ if (!revieweeProfile .isEmpty ()) {
196+ allInvolved .add (revieweeProfile .get ().getWorkEmail ());
197+ }
198+
178199 // This person is being reviewed and will need a self-review
179200 // request.
180201 selfRevieweeIds .add (assignment .getRevieweeId ());
@@ -197,11 +218,46 @@ period, findCreatorId(assignment.getReviewerId()),
197218 selfReviewCloseDate );
198219 }
199220 }
221+
222+ String emailContent = constructReviewPeriodAnnouncementEmail (
223+ period .getName (), period .getPeriodStartDate (),
224+ period .getPeriodEndDate (), period .getLaunchDate (),
225+ period .getSelfReviewCloseDate (), period .getCloseDate ()
226+ );
227+ emailSender .sendEmail (null , null , "It's time for performance reviews!" , emailContent , allInvolved .toArray (new String [0 ]));
200228 }
201229
202230 return period ;
203231 }
204232
233+ private String dateAsString (LocalDateTime dateTime ) {
234+ String str = String .format ("%s %d, %d" ,
235+ dateTime .getMonth (),
236+ dateTime .getDayOfMonth (),
237+ dateTime .getYear ());
238+ return str .substring (0 , 1 ) + str .substring (1 ).toLowerCase ();
239+ }
240+
241+ private String constructReviewPeriodAnnouncementEmail (
242+ String reviewPeriodName , LocalDateTime startDate ,
243+ LocalDateTime endDate , LocalDateTime launchDate ,
244+ LocalDateTime selfReviewDate , LocalDateTime closeDate
245+ ) {
246+ try {
247+ return String .format (IOUtils .readText (
248+ new BufferedReader (
249+ reviewPeriodAnnouncementTemplate .asReader ())),
250+ reviewPeriodName , reviewPeriodName ,
251+ dateAsString (startDate ), dateAsString (endDate ),
252+ dateAsString (launchDate ),
253+ dateAsString (selfReviewDate ),
254+ dateAsString (closeDate ));
255+ } catch (Exception ex ) {
256+ LOG .error (ex .toString ());
257+ return "" ;
258+ }
259+ }
260+
205261 private void notifyRevieweeSupervisorsByReviewPeriod (UUID reviewPeriodId , String reviewPeriodName ) {
206262 if (environment .getActiveNames ().contains (Environments .LOCAL )) return ;
207263 Set <ReviewAssignment > reviewAssignments = reviewAssignmentRepository .findByReviewPeriodId (reviewPeriodId );
@@ -217,14 +273,20 @@ private void notifyRevieweeSupervisorsByReviewPeriod(UUID reviewPeriodId, String
217273 List <String > supervisorEmails = memberProfileRepository .findWorkEmailByIdIn (supervisorIdsToString );
218274
219275 // send notification to supervisors
220- String emailContent = constructEmailContent (reviewPeriodId , reviewPeriodName );
276+ String emailContent = constructSupervisorEmail (reviewPeriodId , reviewPeriodName );
221277 emailSender .sendEmail (null , null , "Review Assignments Awaiting Approval" , emailContent , supervisorEmails .toArray (new String [0 ]));
222278 }
223279
224- private String constructEmailContent (UUID reviewPeriodId , String reviewPeriodName ){
225- return """
226- <h3>Review Assignments for Review Period '%s' are ready for your approval.</h3>\
227- <a href="%s/feedback/reviews?period=%s">Click here</a> to review and approve reviewer assignments in the Check-Ins app.""" .formatted (reviewPeriodName , webAddress , reviewPeriodId );
280+ private String constructSupervisorEmail (UUID reviewPeriodId , String reviewPeriodName ){
281+ try {
282+ return String .format (IOUtils .readText (
283+ new BufferedReader (
284+ supervisorReviewAssignmentTemplate .asReader ())),
285+ reviewPeriodName , webAddress , reviewPeriodId );
286+ } catch (Exception ex ) {
287+ LOG .error (ex .toString ());
288+ return "" ;
289+ }
228290 }
229291
230292 private void validateDates (ReviewPeriod period ) {
0 commit comments