diff --git a/build.gradle b/build.gradle index 35ebaa2..8c3b14a 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,8 @@ dependencies { implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4' testImplementation 'org.mockito:mockito-core:4.3.+' + implementation 'com.sun.mail:javax.mail:1.6.2' + } test { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/HelloApplication.java b/src/main/java/ch/zhaw/gartenverwaltung/HelloApplication.java index 0b8a0a1..1d8ed5a 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/HelloApplication.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/HelloApplication.java @@ -1,22 +1,23 @@ package ch.zhaw.gartenverwaltung; import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; -import ch.zhaw.gartenverwaltung.notifier.Notifier; +import ch.zhaw.gartenverwaltung.backgroundtasks.BackgroundTasks; import javafx.application.Application; import javafx.stage.Stage; import java.io.IOException; +import java.util.Timer; public class HelloApplication extends Application { + Timer backGroundTaskTimer = new Timer(); + BackgroundTasks backgroundTasks; @Override public void start(Stage stage) throws IOException { AppLoader appLoader = new AppLoader(); - Notifier notifier = new Notifier(appLoader.getGardenSchedule()); - Thread notificationThread = new Thread(notifier); - notificationThread.start(); - notificationThread.interrupt(); + backgroundTasks = new BackgroundTasks(appLoader.getTaskList(), appLoader.getGarden(), appLoader.getPlantList()); + backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 1000); appLoader.loadSceneToStage("MainFXML.fxml", stage); @@ -24,6 +25,11 @@ public class HelloApplication extends Application { stage.show(); } + @Override + public void stop(){ + backGroundTaskTimer.cancel(); + } + public static void main(String[] args) { launch(); } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/Settings.java b/src/main/java/ch/zhaw/gartenverwaltung/Settings.java index c15454c..63cf6e7 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/Settings.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/Settings.java @@ -1,13 +1,23 @@ package ch.zhaw.gartenverwaltung; +import ch.zhaw.gartenverwaltung.backgroundtasks.email.SmtpCredentials; import ch.zhaw.gartenverwaltung.types.HardinessZone; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; +import java.util.List; + public class Settings { + private static final Settings instance; private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A; - private static Settings instance; private final BooleanProperty showTutorial = new SimpleBooleanProperty(false); + private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true); + // Gmail Address: pm3.hs22.it21b.win.team1@gmail.com + // Gmail Passwort: Gartenverwaltung.PM3.2022 + // E-Mail Inbox: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1 + private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com"; + private String mailNotificationSubjectTemplate = "Task %s is due!"; // {0} = Task Name + private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s is due since %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s"; // {0} = Task Name, {1} = nextExecution, {2} = Task description static { instance = new Settings(); @@ -38,4 +48,20 @@ public class Settings { public boolean getShowTutorial() { return this.showTutorial.get(); } + + public SmtpCredentials getSmtpCredentials() { + return smtpCredentials; + } + + public String getMailNotificationReceivers() { + return mailNotificationReceivers; + } + + public String getMailNotificationSubjectTemplate() { + return mailNotificationSubjectTemplate; + } + + public String getMailNotificationTextTemplate() { + return mailNotificationTextTemplate; + } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/BackgroundTasks.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/BackgroundTasks.java new file mode 100644 index 0000000..52e902e --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/BackgroundTasks.java @@ -0,0 +1,42 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks; + +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.Garden; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.TimerTask; + +public class BackgroundTasks extends TimerTask { + private final TaskList taskList; + private final Garden garden; + private final PlantList plantList; + private final Notifier notifier; + //TODO uncomment: privat final WeatherGardenTaskPlaner weatherGardenTaskPlaner; + + public BackgroundTasks(TaskList taskList, Garden garden, PlantList plantList) { + this.taskList = taskList; + this.garden = garden; + this.plantList = plantList; + notifier = new Notifier(taskList, garden, plantList); + //TODO uncomment: weatherGardenTaskPlaner = new WeatherGardenTaskPlaner(taskList); + } + + @Override + public void run() { + // TODO uncomment: weatherGardenTaskPlaner.refreshTasks(); + try { + try { + notifier.sendNotifications(); + } catch (MessagingException e) { + e.printStackTrace(); + // TODO logger + } + } catch (IOException e) { + e.printStackTrace(); + // TODO logger + } + } +} + diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/Notifier.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/Notifier.java new file mode 100644 index 0000000..f36913f --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/Notifier.java @@ -0,0 +1,42 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks; + +import ch.zhaw.gartenverwaltung.Settings; +import ch.zhaw.gartenverwaltung.backgroundtasks.email.EMailSender; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.Garden; +import ch.zhaw.gartenverwaltung.types.Task; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.time.LocalDate; + +public class Notifier { + private final TaskList taskList; + private final Garden garden; + private final PlantList plantList; + private final EMailSender eMailSender = new EMailSender(); + + public Notifier(TaskList taskList, Garden garden, PlantList plantList) { + this.taskList = taskList; + this.garden = garden; + this.plantList = plantList; + } + + private void sendNotification(Task task) throws MessagingException { + String messageSubject = String.format(Settings.getInstance().getMailNotificationSubjectTemplate(), task.getName()); + String messageText = String.format(Settings.getInstance().getMailNotificationTextTemplate(), task.getName(), task.getNextExecution(), task.getDescription()); + //TODO create Exception for email sent fail + eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText); + } + + public void sendNotifications() throws IOException, MessagingException { + System.out.println("sending Notifications"); + for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) { + if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) { + sendNotification(task); + task.setNextNotification(LocalDate.now().plusDays(1)); + } + } + } +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/EMailSender.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/EMailSender.java new file mode 100644 index 0000000..734967c --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/EMailSender.java @@ -0,0 +1,44 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.email; + +import ch.zhaw.gartenverwaltung.Settings; + +import javax.mail.Address; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class EMailSender { + + + public EMailSender(){ + + } + + public void sendMails(String recipients, String subject, String text) throws MessagingException { + // TODO replace printMail with implementation + printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it + MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession()); + message.addHeader("Content-type", "text/HTML; charset=UTF-8"); + message.addHeader("format", "flowed"); + message.addHeader("Content-Transfer-Encoding", "8bit"); + message.setFrom(new InternetAddress(Settings.getInstance().getSmtpCredentials().fromAddress())); + message.setReplyTo(InternetAddress.parse(Settings.getInstance().getSmtpCredentials().fromAddress(), false)); + message.setSubject(subject); + message.setText(text); + message.setSentDate(new Date()); + message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients, false)); + System.out.println("Message is ready: "); + Transport.send(message); + } + + private void printMail(String receiver, String subject, String text){ + System.out.printf("\nSending E-Mail:\nTo: %s\nSubject: %s\nMessage:\n%s\n", receiver, subject, text); + } + +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/SmtpCredentials.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/SmtpCredentials.java new file mode 100644 index 0000000..5e066ec --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/SmtpCredentials.java @@ -0,0 +1,41 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.email; + +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import java.net.Authenticator; +import java.util.Properties; + +public record SmtpCredentials( + String host, + String port, + String fromAddress, + String username, + String password, + boolean startTLS + ) { + + private Properties getProperties() { + Properties properties = new Properties(); + properties.put("mail.smtp.host", host); + properties.put("mail.smtp.port", port); + properties.put("mail.smtp.auth", "true"); + properties.put("mail.smtp.starttls.enable", startTLS ? "true" : "false"); + return properties; + } + + private javax.mail.Authenticator getAuthenticator() { + return new javax.mail.Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }; + } + + public Session getSession() { + return Session.getInstance(getProperties(), getAuthenticator()); + } + + + +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java index 6c660ab..2065278 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java @@ -10,7 +10,6 @@ import ch.zhaw.gartenverwaltung.io.TaskList; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.models.PlantListModel; -import ch.zhaw.gartenverwaltung.notifier.Notifier; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.DialogPane; @@ -157,7 +156,15 @@ public class AppLoader { }; } - public GardenSchedule getGardenSchedule() { - return gardenSchedule; + public PlantList getPlantList() { + return plantList; + } + + public Garden getGarden() { + return garden; + } + + public TaskList getTaskList() { + return taskList; } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/notifier/Notifier.java b/src/main/java/ch/zhaw/gartenverwaltung/notifier/Notifier.java deleted file mode 100644 index 26e22fc..0000000 --- a/src/main/java/ch/zhaw/gartenverwaltung/notifier/Notifier.java +++ /dev/null @@ -1,48 +0,0 @@ -package ch.zhaw.gartenverwaltung.notifier; - -import ch.zhaw.gartenverwaltung.models.GardenSchedule; -import ch.zhaw.gartenverwaltung.types.Task; - -import java.io.IOException; -import java.time.LocalDate; -import java.util.function.Consumer; - -public class Notifier implements Runnable{ - private final GardenSchedule gardenSchedule; - private boolean interrupted = false; - - public Notifier(GardenSchedule gardenSchedule) { - this.gardenSchedule = gardenSchedule; - } - - private void sendNotification(Task task){ - // TODO implement - } - - private void sendNotifications(){ - System.out.println("sending Notifications"); - try { - gardenSchedule.getTaskList().forEach(task -> { - if(task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))){ - sendNotification(task); - task.setNextNotification(task.getNextExecution()); - } - }); - } catch (IOException e) { - // TODO Logger - e.printStackTrace(); - } - } - - @Override - public void run() { - while(!interrupted){ - try { - sendNotifications(); - Thread.sleep(3000); - } catch (InterruptedException e) { - interrupted = true; - } - } - } -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 38607ea..159fd0b 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -5,6 +5,8 @@ module ch.zhaw.gartenverwaltung { requires com.fasterxml.jackson.datatype.jsr310; requires com.fasterxml.jackson.datatype.jdk8; requires java.logging; + requires java.mail; + opens ch.zhaw.gartenverwaltung to javafx.fxml; opens ch.zhaw.gartenverwaltung.types to com.fasterxml.jackson.databind; @@ -13,6 +15,8 @@ module ch.zhaw.gartenverwaltung { exports ch.zhaw.gartenverwaltung.types; exports ch.zhaw.gartenverwaltung.models; exports ch.zhaw.gartenverwaltung.json; - exports ch.zhaw.gartenverwaltung.notifier; - opens ch.zhaw.gartenverwaltung.notifier to javafx.fxml; + exports ch.zhaw.gartenverwaltung.backgroundtasks; + opens ch.zhaw.gartenverwaltung.backgroundtasks to javafx.fxml; + exports ch.zhaw.gartenverwaltung.backgroundtasks.email; + opens ch.zhaw.gartenverwaltung.backgroundtasks.email to javafx.fxml; } \ No newline at end of file