Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,22 @@
public class FreeMarkerConfiguration {
private final TemplateLoader templateLoader;
private final Template extensionCreatedStudentEmailTemplate;
private final Template extensionApprovedStudentEmailTemplate;
private final Template extensionDeniedStudentEmailTemplate;
private final Template extensionCreatedInstructorEmailTemplate;

public FreeMarkerConfiguration(
@Value("${grading-admin.email.templates.template-directory}")
String templatePath,
@Value("${grading-admin.email.templates.extension-created-student}")
String extensionCreatedStudentTemplateName,
@Value("${grading-admin.email.templates.extension-approved-student}")
String extensionApprovedStudentTemplateName,
@Value("${grading-admin.email.templates.extension-denied-student}")
String extensionDeniedStudentTemplateName,
@Value("${grading-admin.email.templates.extension-created-instructor}")
String extensionCreatedInstructorTemplateName) {
String extensionCreatedInstructorTemplateName
) {
templateLoader = new ClassTemplateLoader(this.getClass(), templatePath);

freemarker.template.Configuration configuration = new freemarker.template.Configuration(
Expand All @@ -34,6 +41,8 @@ public FreeMarkerConfiguration(
configuration.setTemplateLoader(templateLoader);

extensionCreatedStudentEmailTemplate = readTemplates(configuration, extensionCreatedStudentTemplateName);
extensionApprovedStudentEmailTemplate = readTemplates(configuration, extensionApprovedStudentTemplateName);
extensionDeniedStudentEmailTemplate = readTemplates(configuration, extensionDeniedStudentTemplateName);
extensionCreatedInstructorEmailTemplate = readTemplates(configuration, extensionCreatedInstructorTemplateName);

}
Expand Down Expand Up @@ -64,6 +73,16 @@ public Template getExtensionCreatedStudentEmailTemplate() {
return extensionCreatedStudentEmailTemplate;
}

@Bean(name = "extensionApprovedStudentEmailTemplate")
public Template getExtensionApprovedStudentEmailTemplate() {
return extensionApprovedStudentEmailTemplate;
}

@Bean(name = "extensionDeniedStudentEmailTemplate")
public Template extensionDeniedStudentEmailTemplate() {
return extensionDeniedStudentEmailTemplate;
}

@Bean(name = "extensionCreatedInstructorEmailTemplate")
public Template getExtensionCreatedInstructorEmailTemplate() {
return extensionCreatedInstructorEmailTemplate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,12 +321,14 @@ public ResponseEntity<List<CourseMemberDTO>> getInstructorEnrollments(UUID cours
}

@Override
@Transactional
public ResponseEntity<LateRequestDTO> approveExtension(UUID courseId, UUID extensionId, String reason) {
LateRequest lateRequest = extensionService.approveExtension(extensionId, reason);
return ResponseEntity.accepted().body(DTOFactory.toDto(lateRequest));
}

@Override
@Transactional
public ResponseEntity<LateRequestDTO> denyExtension(UUID courseId, UUID extensionId, String reason) {
LateRequest lateRequest = extensionService.denyExtension(extensionId, reason);
return ResponseEntity.accepted().body(DTOFactory.toDto(lateRequest));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package edu.mines.packtrain.data.templates;

import lombok.Data;

@Data
public class ExtensionApprovedStudentEmailDTO {
private String reviewer;
private String student;
private String assignmentName;
private String courseName;
private int extensionDays;
private String reviewerResponse;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package edu.mines.packtrain.data.templates;

import lombok.Data;

@Data
public class ExtensionDeniedStudentEmailDTO {
private String reviewer;
private String student;
private String assignmentName;
private String courseName;
private int extensionDays;
private String reviewerResponse;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ public void sendEmail(String to, List<String> cc, String subject, String html) {
if (!enabled) {
return;
}

EmailPopulatingBuilder builder = EmailBuilder.startingBlank()
.from(fromName, fromEmail)
.to(overrideTo != null ? overrideTo : to)
.to(!overrideTo.isEmpty() ? overrideTo : to)
.withSubject(subject)
.withHTMLText(html);

// (overrideCC != null ? List.of(overrideCC) : cc).forEach(s -> builder.cc(s));
(!overrideCC.isEmpty() ? List.of(overrideCC) : cc).forEach(s -> builder.cc(s));

log.debug("Sending email '{}' to '{}'", subject, to);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,43 @@
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import edu.mines.packtrain.data.templates.ExtensionApprovedStudentEmailDTO;
import edu.mines.packtrain.data.templates.ExtensionCreatedInstructorEmailDTO;
import edu.mines.packtrain.data.templates.ExtensionCreatedStudentEmailDTO;
import edu.mines.packtrain.data.templates.ExtensionDeniedStudentEmailDTO;
import edu.mines.packtrain.models.Course;
import edu.mines.packtrain.models.LateRequest;
import edu.mines.packtrain.models.User;
import edu.mines.packtrain.models.enums.LateRequestType;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ExtensionEmailService {
private final EmailService emailService;
private final Template extensionCreatedStudentEmailTemplate;
private final Template extensionApprovedStudentEmailTemplate;
private final Template extensionDeniedStudentEmailTemplate;
private final Template extensionCreatedInStructorEmailTemplate;
private final ObjectMapper mapper;
private final String frontendUrl;

public ExtensionEmailService(EmailService emailService,
@Qualifier("extensionCreatedStudentEmailTemplate") Template extensionCreatedStudentEmailTemplate,
@Qualifier("extensionApprovedStudentEmailTemplate") Template extensionApprovedStudentEmailTemplate,
@Qualifier("extensionDeniedStudentEmailTemplate") Template extensionDeniedStudentEmailTemplate,
@Qualifier("extensionCreatedInstructorEmailTemplate") Template extensionCreatedInStructorEmailTemplate,
@Value("${grading-admin.frontend-url}") String frontendUrl,

ObjectMapper mapper) {
this.emailService = emailService;
this.extensionCreatedStudentEmailTemplate = extensionCreatedStudentEmailTemplate;
this.extensionApprovedStudentEmailTemplate = extensionApprovedStudentEmailTemplate;
this.extensionDeniedStudentEmailTemplate = extensionDeniedStudentEmailTemplate;
this.extensionCreatedInStructorEmailTemplate = extensionCreatedInStructorEmailTemplate;
this.frontendUrl = frontendUrl;
this.mapper = mapper;
Expand All @@ -58,11 +68,10 @@ public void handleExtensionCreated(LateRequest lateRequest, Course course, User
return;
}


{
ExtensionCreatedInstructorEmailDTO model = new ExtensionCreatedInstructorEmailDTO();
model.setCourseName(lateRequest.getAssignment().getName());
model.setAssignmentName(course.getName());
model.setCourseName(course.getName());
model.setAssignmentName(lateRequest.getAssignment().getName());
model.setStudent(requester.getName());
model.setInstructor(instructor.getName());
model.setExtensionDays(lateRequest.getDaysRequested());
Expand All @@ -73,6 +82,32 @@ public void handleExtensionCreated(LateRequest lateRequest, Course course, User
}
}

@Transactional
public void handleExtensionApproved(LateRequest lateRequest, Course course, User student, User approver) {
ExtensionApprovedStudentEmailDTO model = new ExtensionApprovedStudentEmailDTO();

model.setAssignmentName(lateRequest.getAssignment().getName());
model.setStudent(student.getName());
model.setReviewer(approver.getName());
model.setReviewerResponse(lateRequest.getExtension().getReviewerResponse());
model.setExtensionDays(lateRequest.getDaysRequested());

createExtensionApprovedStudentEmail(student.getEmail(), approver.getEmail(), model);
}

@Transactional
public void handleExtensionDenied(LateRequest lateRequest, Course course, User student, User approver) {
ExtensionDeniedStudentEmailDTO model = new ExtensionDeniedStudentEmailDTO();

model.setAssignmentName(lateRequest.getAssignment().getName());
model.setStudent(student.getName());
model.setReviewer(approver.getName());
model.setReviewerResponse(lateRequest.getExtension().getReviewerResponse());
model.setExtensionDays(lateRequest.getDaysRequested());

createExtensionDeniedStudentEmail(student.getEmail(), approver.getEmail(), model);
}

private void createExtensionCreatedStudentEmail(String emailAddress, ExtensionCreatedStudentEmailDTO model) {

StringWriter writer = new StringWriter();
Expand Down Expand Up @@ -124,4 +159,56 @@ private void createExtensionCreatedInstructorEmail(String emailAddress, Extensio
renderedTemplate);
}

private void createExtensionApprovedStudentEmail(String studentEmail, String instructorEmail,
ExtensionApprovedStudentEmailDTO model) {
StringWriter writer = new StringWriter();

try {
extensionApprovedStudentEmailTemplate
.process(mapper.convertValue(model, new TypeReference<Map<String, Object>>() {
}), writer);
} catch (TemplateException | IOException e) {
log.error("Failed to render email template!", e);
return;
}

String renderedTemplate = writer.toString();

if (renderedTemplate.isEmpty()) {
log.error("Failed to render email template! Template is empty!");
return;
}

emailService.sendEmail(studentEmail, List.of(instructorEmail),
String.format("[Packtrain] [%s] [%s] Extension Request Approved", model.getCourseName(),
model.getAssignmentName()),
renderedTemplate);
}

private void createExtensionDeniedStudentEmail(String studentEmail, String instructorEmail,
ExtensionDeniedStudentEmailDTO model) {
StringWriter writer = new StringWriter();

try {
extensionDeniedStudentEmailTemplate
.process(mapper.convertValue(model, new TypeReference<Map<String, Object>>() {
}), writer);
} catch (TemplateException | IOException e) {
log.error("Failed to render email template!", e);
return;
}

String renderedTemplate = writer.toString();

if (renderedTemplate.isEmpty()) {
log.error("Failed to render email template! Template is empty!");
return;
}

emailService.sendEmail(studentEmail, List.of(instructorEmail),
String.format("[Packtrain] [%s] [%s] Extension Request Denied", model.getCourseName(),
model.getAssignmentName()),
renderedTemplate);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import edu.mines.packtrain.models.enums.LateRequestType;
import edu.mines.packtrain.repositories.ExtensionRepo;
import edu.mines.packtrain.repositories.LateRequestRepo;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand Down Expand Up @@ -62,6 +63,7 @@ public List<LateRequest> getAllLateRequests(UUID courseId, String lateRequestSta
return List.of();
}

@Transactional
public LateRequest approveExtension(UUID extensionId, String reason) {
Optional<LateRequest> lateRequest = getLateRequest(extensionId);
String userId = securityManager.getUser().getCwid();
Expand All @@ -78,9 +80,12 @@ public LateRequest approveExtension(UUID extensionId, String reason) {

extensionRepo.save(lateRequest.get().getExtension());

extensionEmailService.handleExtensionApproved(lateRequest.get(), lateRequest.get().getAssignment().getCourse(), lateRequest.get().getRequestingUser(), securityManager.getUser());

return lateRequestRepo.save(lateRequest.get());
}

@Transactional
public LateRequest denyExtension(UUID extensionId, String reason) {
Optional<LateRequest> lateRequest = getLateRequest(extensionId);
String userId = securityManager.getUser().getCwid();
Expand All @@ -96,6 +101,9 @@ public LateRequest denyExtension(UUID extensionId, String reason) {
lateRequest.get().setStatus(LateRequestStatus.REJECTED);

extensionRepo.save(lateRequest.get().getExtension());

extensionEmailService.handleExtensionDenied(lateRequest.get(), lateRequest.get().getAssignment().getCourse(), lateRequest.get().getRequestingUser(), securityManager.getUser());

return lateRequestRepo.save(lateRequest.get());
}

Expand Down
2 changes: 2 additions & 0 deletions packtrain-service/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ grading-admin:
templates:
template-directory: /templates/emails
extension-created-student: extension-created-student.ftl
extension-approved-student: extension-approved-student.ftl
extension-denied-student: extension-denied-student.ftl
extension-created-instructor: extension-created-instructor.ftl
enabled: true
smtp-server: ${SMTP_SERVER:localhost.dev}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hi ${student},</p>
<p></p>

<p>Your extension request for <strong>${assignmentName}</strong> for ${extensionDays} days has been approved!</p>

<p>Your request was reviewed by Professor ${reviewer}. Below is their response:</p>

<p style="padding-left: 1em; border-left: 2px solid #c7c7c75e;">${reviewerResponse}</p>
<p></p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hi ${student},</p>
<p></p>

<p>Your extension request for <strong>${assignmentName}</strong> for ${extensionDays} days has been denied.</p>

<p>Your request was reviewed by Professor ${reviewer}. Below is their response:</p>

<p style="padding-left: 1em; border-left: 2px solid #c7c7c75e;">${reviewerResponse}</p>
<p></p>

<p>Please contact your instructor directly with any questions or concerns.</p>
</body>
</html>
Loading