unnotified = activityDao.getUnnotifiedActivities();
+ for (Activity activity : unnotified) {
+ //
+ EmailNotifier.handle(activity);
+
+ activity.setNotified(true);
+ activity.setNotifiedAt(LocalDateTime.now());
+ activityDao.update(activity);
+ }
+ }
+}
+
diff --git a/src/main/Mail/Services/SendgridService.java b/src/main/Mail/Services/SendgridService.java
new file mode 100644
index 00000000..d8ea9e78
--- /dev/null
+++ b/src/main/Mail/Services/SendgridService.java
@@ -0,0 +1,112 @@
+package Mail.Services;
+
+import com.sendgrid.*;
+import com.sendgrid.helpers.mail.objects.Content;
+import com.sendgrid.helpers.mail.objects.Email;
+import com.sendgrid.helpers.mail.Mail;
+import io.github.cdimascio.dotenv.Dotenv;
+
+import java.util.Map;
+import java.util.Optional;
+import Mail.Utils.TemplateEngine;
+
+
+import java.io.IOException;
+
+public class SendgridService {
+ private static final String SENDGRID_API_KEY =
+ Optional.ofNullable(System.getenv("SENDGRID_API_KEY"))
+ .orElseGet(() -> Dotenv.configure()
+ .ignoreIfMissing()
+ .load()
+ .get("SENDGRID_API_KEY"));
+
+ //private static final String SENDGRID_API_KEY = System.getenv("SENDGRID_API_KEY");
+
+ private static void sendEmail(String toEmail, String subject, String bodyHtml) {
+ Email from = new Email("vanessachung@keep.id");
+ Email to = new Email(toEmail);
+ Content content = new Content("text/html", bodyHtml);
+ Mail mail = new Mail(from, subject, to, content);
+
+ SendGrid sg = new SendGrid(SENDGRID_API_KEY);
+ Request request = new Request();
+
+ try {
+ request.setMethod(Method.POST);
+ request.setEndpoint("mail/send");
+ request.setBody(mail.build());
+ Response response = sg.api(request);
+
+ if (response.getStatusCode() >= 400) {
+ System.err.println("Email failed: " + response.getBody());
+ }
+ } catch (IOException ex) {
+ System.err.println("SendGrid Exception: " + ex.getMessage());
+ }
+ }
+ // Triggered by CreateClientActivity
+ public static void handleCreateClientActivity(String username, String state) {
+ try {
+ String body = TemplateEngine.renderTemplate("welcome.html", Map.of(
+ "username", username,
+ "state", state
+ ));
+ sendEmail(username, "Welcome to Keep.id!", body);
+ } catch (IOException e) {
+ System.err.println("Failed to load welcome template: " + e.getMessage());
+ }
+ }
+ // Triggered by UploadFileActivity
+ public static void handleUploadFileActivity(String username, String docType) {
+ String subject = "You uploaded a " + docType;
+ String body = "We’ve saved your " + docType + ". Here's what to upload next…
";
+ sendEmail(username, subject, body);
+ }
+
+ // Triggered by MailApplicationActivity
+ public static void handleMailApplicationActivity(String username) {
+ String subject = "Finish your application";
+ String body = "You started an application. Come back and finish it!
";
+ sendEmail(username, subject, body);
+ }
+
+ // Triggered by SubmitApplicationActivity
+ public static void handleSubmitApplicationActivity(String username, String nonprofit) {
+ String subject = "Pick up your ID";
+ String body = "Your documents are ready! Go to " + nonprofit + " to pick them up.
";
+ sendEmail(username, subject, body);
+ }
+
+ // For debugging
+ public static void sendTestEmail() {
+ String subject = "Test from Keep.id";
+ String body = "Hello! This is a test email sent via SendGrid!
";
+ sendEmail("vanessachung@keep.id", subject, body);
+ }
+// public static void sendWelcomeWithQuickStart(String username, String state) {
+// String subject = "Welcome to Keep.id!";
+// String body = "Hi " + username + ", welcome! Here's how to get your ID in " + state + "...
";
+// sendEmail(username, subject, body); // Replace with real email
+// }
+//
+// public static void sendUploadReminder(String username, String docType) {
+// String subject = "You uploaded a " + docType;
+// String body = "We’ve saved your " + docType + ". Here's what to upload next…
";
+// sendEmail(username, subject, body);
+// }
+//
+// public static void sendApplicationReminder(String username) {
+// sendEmail(username , "Finish your application", "You started an application. Come back and finish it!
");
+// }
+//
+// public static void sendPickupInfo(String username, String nonprofit) {
+// sendEmail(username , "Pick up your ID", "Your documents are ready! Go to " + nonprofit + " to pick them up.
");
+// }
+// public static void sendTestEmail() {
+// String subject = "Test from Keep.id";
+// String body = "Hello! This is a test email sent via SendGrid!
";
+// sendEmail("vanessachung@keep.id", subject, body);
+// }
+
+}
diff --git a/src/main/Mail/Utils/TemplateEngine.java b/src/main/Mail/Utils/TemplateEngine.java
new file mode 100644
index 00000000..95e6c717
--- /dev/null
+++ b/src/main/Mail/Utils/TemplateEngine.java
@@ -0,0 +1,20 @@
+package Mail.Utils;
+
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+
+public class TemplateEngine {
+ public static String renderTemplate(String templateName, Map variables) throws IOException {
+ String templatePath = "src/main/Mail/email_templates/" + templateName;
+ String content = Files.readString(Paths.get(templatePath));
+
+ for (Map.Entry entry : variables.entrySet()) {
+ content = content.replace("{{" + entry.getKey() + "}}", entry.getValue());
+ }
+
+ return content;
+ }
+}
diff --git a/src/main/Mail/email_templates/upload_reminder.html b/src/main/Mail/email_templates/upload_reminder.html
new file mode 100644
index 00000000..ebfb3243
--- /dev/null
+++ b/src/main/Mail/email_templates/upload_reminder.html
@@ -0,0 +1 @@
+We’ve saved your {{docType}}. Here's what to upload next…
\ No newline at end of file
diff --git a/src/main/Mail/email_templates/welcome.html b/src/main/Mail/email_templates/welcome.html
new file mode 100644
index 00000000..baae1b48
--- /dev/null
+++ b/src/main/Mail/email_templates/welcome.html
@@ -0,0 +1,62 @@
+
+
+
+
+ Welcome to Keep.id!
+
+
+
+
+
+
+
+
+
+
+
+
+ Welcome, {{username}}!
+
+
We're excited to have you join Keep.id — your secure and simple way to manage your identity
+ online.
+
+
To get started with your ID application in {{state}}, here’s what you can do next:
+
+
+
+ -
+
+ Complete your profile and required documents
+
+ -
+
+ Upload scans or photos of your identification
+
+ -
+
+ Pick a nonprofit location for pickup
+
+
+
+
If you have any questions, feel free to reach out to our support team.
+
+
+
+

+
We’re here to help you every step of the way.
+
+
+
Welcome aboard!
The Keep.id Team
+
+
+
+
+ © {2020} Keep.id – All rights reserved.
+
+
+
diff --git a/src/test/DatabaseTest/Activity/ActivityDaoImplUnitTests.java b/src/test/DatabaseTest/Activity/ActivityDaoImplUnitTests.java
index e6347896..f07b88ea 100644
--- a/src/test/DatabaseTest/Activity/ActivityDaoImplUnitTests.java
+++ b/src/test/DatabaseTest/Activity/ActivityDaoImplUnitTests.java
@@ -7,12 +7,17 @@
import Database.Activity.ActivityDao;
import Database.Activity.ActivityDaoFactory;
import File.FileType;
+import Mail.EmailNotifier;
import TestUtils.EntityFactory;
import TestUtils.TestUtils;
import java.time.LocalDateTime;
+import java.util.Arrays;
import java.util.List;
import org.bson.types.ObjectId;
import org.junit.*;
+import static org.mockito.Mockito.*;
+import org.mockito.MockedStatic;
+
public class ActivityDaoImplUnitTests {
private ActivityDao activityDao;
@@ -247,4 +252,21 @@ static boolean areActivitiesEqual(List activities1, List act
}
return isEqual;
}
+
+// @Test
+// public void testSaveCallsEmailNotifierHandle() {
+// Activity activity = new Activity();
+// activity.setUsername("testuser");
+// activity.setType(Arrays.asList("Activity", "UploadFileActivity"));
+//
+// try (MockedStatic mockedNotifier = mockStatic(EmailNotifier.class)) {
+//
+// activityDao.save(activity);
+//
+//
+// mockedNotifier.verify(() -> EmailNotifier.handle(activity), times(1));
+// }
+// Activity found = activityDao.get(activity.getId()).get();
+// assertEquals("testuser", found.getUsername());
+// }
}
diff --git a/src/test/EmailTest/EmailIntTest.java b/src/test/EmailTest/EmailIntTest.java
new file mode 100644
index 00000000..e031721c
--- /dev/null
+++ b/src/test/EmailTest/EmailIntTest.java
@@ -0,0 +1,37 @@
+package EmailTest;
+
+import Activity.Activity;
+import Mail.EmailNotifier;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class EmailIntTest {
+
+ @Test
+ public void testSendEmailsForAllActivities() {
+
+ // change the email to test
+ String testEmail = "vanessachung@keep.id";
+
+ Activity createClient = new Activity();
+ createClient.setUsername(testEmail);
+ createClient.setType(Arrays.asList("Activity", "CreateClientActivity"));
+ EmailNotifier.handle(createClient);
+
+// Activity uploadFile = new Activity();
+// uploadFile.setUsername(testEmail);
+// uploadFile.setType(Arrays.asList("Activity", "UploadFileActivity"));
+// EmailNotifier.handle(uploadFile);
+//
+// Activity submitApp = new Activity();
+// submitApp.setUsername(testEmail);
+// submitApp.setType(Arrays.asList("Activity", "SubmitApplicationActivity"));
+// EmailNotifier.handle(submitApp);
+//
+// Activity mailApp = new Activity();
+// mailApp.setUsername(testEmail);
+// mailApp.setType(Arrays.asList("Activity", "MailApplicationActivity"));
+// EmailNotifier.handle(mailApp);
+ }
+}
+
diff --git a/src/test/EmailTest/EmailNotifierTest.java b/src/test/EmailTest/EmailNotifierTest.java
new file mode 100644
index 00000000..3a4b7f75
--- /dev/null
+++ b/src/test/EmailTest/EmailNotifierTest.java
@@ -0,0 +1,68 @@
+package EmailTest;
+
+import Mail.EmailNotifier;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import Activity.Activity;
+import Mail.Services.SendgridService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import java.util.Arrays;
+import static org.mockito.Mockito.*;
+
+public class EmailNotifierTest {
+
+ Activity activity;
+
+ @BeforeEach
+ public void setUp() {
+ activity = new Activity();
+ activity.setUsername("testuser");
+ }
+
+ @Test
+ public void testCreateClientActivity() {
+ activity.setType(Arrays.asList("Activity", "CreateClientActivity"));
+ try (MockedStatic mocked = mockStatic(SendgridService.class)) {
+ EmailNotifier.handle(activity);
+ mocked.verify(() -> SendgridService.handleCreateClientActivity("testuser", "PA"));
+ }
+ }
+
+ @Test
+ public void testUploadFileActivity() {
+ activity.setType(Arrays.asList("Activity", "UploadFileActivity"));
+ try (MockedStatic mocked = mockStatic(SendgridService.class)) {
+ EmailNotifier.handle(activity);
+ mocked.verify(() -> SendgridService.handleUploadFileActivity("testuser", "DocumentType"));
+ }
+ }
+
+ @Test
+ public void testMailApplicationActivity() {
+ activity.setType(Arrays.asList("Activity", "MailApplicationActivity"));
+ try (MockedStatic mocked = mockStatic(SendgridService.class)) {
+ EmailNotifier.handle(activity);
+ mocked.verify(() -> SendgridService.handleMailApplicationActivity("testuser"));
+ }
+ }
+
+ @Test
+ public void testSubmitApplicationActivity() {
+ activity.setType(Arrays.asList("Activity", "SubmitApplicationActivity"));
+ try (MockedStatic mocked = mockStatic(SendgridService.class)) {
+ EmailNotifier.handle(activity);
+ mocked.verify(() -> SendgridService.handleSubmitApplicationActivity("testuser", "NonprofitName"));
+ }
+ }
+
+ @Test
+ public void testUnknownActivityType() {
+ activity.setType(Arrays.asList("Activity", "SomethingElse"));
+ try (MockedStatic mocked = mockStatic(SendgridService.class)) {
+ EmailNotifier.handle(activity);
+ mocked.verifyNoInteractions();
+ }
+ }
+}
diff --git a/src/test/EmailTest/SendgridManualTest.java b/src/test/EmailTest/SendgridManualTest.java
new file mode 100644
index 00000000..1229ac8e
--- /dev/null
+++ b/src/test/EmailTest/SendgridManualTest.java
@@ -0,0 +1,44 @@
+package EmailTest;
+
+
+import com.sendgrid.*;
+import com.sendgrid.helpers.mail.Mail;
+import com.sendgrid.helpers.mail.objects.Content;
+import com.sendgrid.helpers.mail.objects.Email;
+import io.github.cdimascio.dotenv.Dotenv;
+
+import java.io.IOException;
+// ensure sendgrid API is connected
+public class SendgridManualTest {
+ public static void main(String[] args) {
+ // manually load .env
+ Dotenv dotenv = Dotenv.load();
+ String SENDGRID_API_KEY = dotenv.get("SENDGRID_API_KEY");
+
+ if (SENDGRID_API_KEY == null) {
+ System.err.println("SENDGRID_API_KEY is missing or .env not loaded.");
+ return;
+ }
+
+ Email from = new Email("vanessachung@keep.id"); // sender
+ Email to = new Email("vanessa137222@gmail.com");
+ String subject = "Manual Test Email from KeepID";
+ Content content = new Content("text/plain", "This is a test email sent directly via SendGrid.");
+ Mail mail = new Mail(from, subject, to, content);
+
+ SendGrid sg = new SendGrid(SENDGRID_API_KEY);
+ Request request = new Request();
+
+ try {
+ request.setMethod(Method.POST);
+ request.setEndpoint("mail/send");
+ request.setBody(mail.build());
+ Response response = sg.api(request);
+
+ System.out.println("Status code: " + response.getStatusCode());
+ System.out.println("Response body: " + response.getBody());
+ } catch (IOException ex) {
+ System.err.println("Failed to send email: " + ex.getMessage());
+ }
+ }
+}