diff --git a/build.gradle b/build.gradle index 35ebaa2..e789fc4 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ tasks.withType(JavaCompile) { application { mainModule = 'ch.zhaw.gartenverwaltung' - mainClass = 'ch.zhaw.gartenverwaltung.HelloApplication' + mainClass = 'ch.zhaw.gartenverwaltung.Main' } javafx { @@ -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 deleted file mode 100644 index 9018a31..0000000 --- a/src/main/java/ch/zhaw/gartenverwaltung/HelloApplication.java +++ /dev/null @@ -1,23 +0,0 @@ -package ch.zhaw.gartenverwaltung; - -import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; -import javafx.application.Application; -import javafx.stage.Stage; - -import java.io.IOException; - -public class HelloApplication extends Application { - @Override - public void start(Stage stage) throws IOException { - AppLoader appLoader = new AppLoader(); - - appLoader.loadSceneToStage("MainFXML.fxml", stage); - - stage.setTitle("Gartenverwaltung"); - stage.show(); - } - - public static void main(String[] args) { - launch(); - } -} \ No newline at end of file diff --git a/src/main/java/ch/zhaw/gartenverwaltung/Main.java b/src/main/java/ch/zhaw/gartenverwaltung/Main.java new file mode 100644 index 0000000..d31860d --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/Main.java @@ -0,0 +1,42 @@ +package ch.zhaw.gartenverwaltung; + +import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; +import ch.zhaw.gartenverwaltung.backgroundtasks.BackgroundTasks; +import ch.zhaw.gartenverwaltung.io.CropList; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.Garden; +import ch.zhaw.gartenverwaltung.types.Crop; +import javafx.application.Application; +import javafx.stage.Stage; + +import java.io.IOException; +import java.util.Timer; + +public class Main extends Application { + Timer backGroundTaskTimer = new Timer(); + BackgroundTasks backgroundTasks; + + @Override + public void start(Stage stage) throws IOException { + AppLoader appLoader = new AppLoader(); + + backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class)); + // TODO reduce period + backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 1000); + + appLoader.loadSceneToStage("MainFXML.fxml", stage); + + stage.setTitle("Gartenverwaltung"); + stage.show(); + } + + @Override + public void stop(){ + backGroundTaskTimer.cancel(); + } + + public static void main(String[] args) { + launch(); + } +} \ No newline at end of file diff --git a/src/main/java/ch/zhaw/gartenverwaltung/Settings.java b/src/main/java/ch/zhaw/gartenverwaltung/Settings.java index 14a1e42..8433dce 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 for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s"; // {0} = Task Name, {1} = plantname, {2} = nextExecution, {3} = Task description private String location = ""; @@ -48,4 +58,20 @@ public class Settings { public String getLocation() { return this.location; } + + 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..96eed67 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/BackgroundTasks.java @@ -0,0 +1,63 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks; + +import ch.zhaw.gartenverwaltung.CropDetailController; +import ch.zhaw.gartenverwaltung.backgroundtasks.weather.WeatherGradenTaskPlanner; +import ch.zhaw.gartenverwaltung.io.CropList; +import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; +import ch.zhaw.gartenverwaltung.types.Task; + +import javax.mail.MessagingException; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class BackgroundTasks extends TimerTask { + private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName()); + private final TaskList taskList; + private final Notifier notifier; + private final WeatherGradenTaskPlanner weatherGardenTaskPlaner; + + private void movePastTasks() throws IOException { + List taskList = this.taskList.getTaskList(LocalDate.MIN, LocalDate.now().minusDays(1)); + taskList.forEach(task -> { + if (!task.isDone()) { + task.setNextExecution(LocalDate.now()); + } + }); + } + + public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) { + this.taskList = taskList; + notifier = new Notifier(taskList, plantList, cropList); + weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList); + } + + @Override + public void run() { + try { + movePastTasks(); + } catch (IOException e) { + e.printStackTrace(); + LOG.log(Level.SEVERE, "Could not execute Background Task: move past Tasks ", e.getCause()); + } + try { + weatherGardenTaskPlaner.refreshTasks(); + } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { + e.printStackTrace(); + LOG.log(Level.SEVERE, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause()); + } + try { + notifier.sendNotifications(); + } catch (IOException | MessagingException | HardinessZoneNotSetException e) { + e.printStackTrace(); + LOG.log(Level.SEVERE, "Could not execute Background Task: send Notification for due Tasks", e.getCause()); + } + } +} + 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..072cd25 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/Notifier.java @@ -0,0 +1,50 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks; + +import ch.zhaw.gartenverwaltung.Settings; +import ch.zhaw.gartenverwaltung.backgroundtasks.email.EMailSender; +import ch.zhaw.gartenverwaltung.io.CropList; +import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.types.Crop; +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 CropList cropList; + private final PlantList plantList; + private final EMailSender eMailSender = new EMailSender(); + + public Notifier(TaskList taskList, PlantList plantList, CropList cropList) { + this.taskList = taskList; + this.cropList = cropList; + this.plantList = plantList; + } + + private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException { + String plantName = "unkown plant"; + if(cropList.getCropById((task.getCropId())).isPresent()){ + Crop crop = cropList.getCropById(task.getCropId()).get(); + if(plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).isPresent()) { + plantName = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get().name(); + } + } + String messageSubject = String.format(Settings.getInstance().getMailNotificationSubjectTemplate(), task.getName()); + String messageText = String.format(Settings.getInstance().getMailNotificationTextTemplate(), task.getName(), plantName, task.getNextExecution(), task.getDescription()); + eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText); + } + + public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException { + 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)); + taskList.saveTask(task); + } + } + } +} 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..1fa470c --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/email/EMailSender.java @@ -0,0 +1,40 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.email; + +import ch.zhaw.gartenverwaltung.Settings; + +import javax.mail.*; +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)); + 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/backgroundtasks/weather/SevereWeather.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/SevereWeather.java new file mode 100644 index 0000000..fa075e7 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/SevereWeather.java @@ -0,0 +1,5 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.weather; + +public enum SevereWeather { + FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherGradenTaskPlanner.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherGradenTaskPlanner.java new file mode 100644 index 0000000..ea9acfc --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherGradenTaskPlanner.java @@ -0,0 +1,127 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.weather; + +import ch.zhaw.gartenverwaltung.io.CropList; +import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; +import ch.zhaw.gartenverwaltung.types.*; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; + +/** + * The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days + * + */ +public class WeatherGradenTaskPlanner { + private final TaskList taskList; + private final PlantList plantList; + private final CropList cropList; + WeatherService weatherService; + private final LocalDate dateSevereWeather = LocalDate.of(2022,12,15); + + public WeatherGradenTaskPlanner(TaskList taskList, PlantList plantList, CropList cropList) { + this.taskList = taskList; + this.plantList = plantList; + this.cropList = cropList; + weatherService = new WeatherService(); + } + + /** + * Method to refresh watering tasks and severe weather tasks + * @throws IOException If the database cannot be accessed + * @throws HardinessZoneNotSetException If the hardiness zone is not available + * @throws PlantNotFoundException if the plant is not available for the watering task + */ + public void refreshTasks() throws IOException, HardinessZoneNotSetException, PlantNotFoundException { + getSevereWeatherEvents(); + getRainAmount(); + } + + private void getSevereWeatherEvents() throws IOException { + SevereWeather actualWeather = weatherService.causeSevereWeather(1); + if (SevereWeather.HAIL.equals(actualWeather)) { + createPreHailTask(); + } else if (SevereWeather.FROST.equals(actualWeather)) { + createPreFrostTask(); + } else if (SevereWeather.SNOW.equals(actualWeather)) { + createPreSnowTask(); + } + } + + private void getRainAmount() throws IOException, HardinessZoneNotSetException, PlantNotFoundException { + int rainAmount = weatherService.causeRainAmount(3); + adjustWateringTask(rainAmount); + } + + /** + * Method to create a PreHailTask + * @throws IOException If the database cannot be accessed + */ + private void createPreHailTask() throws IOException { + + Task preHailTask = new Task("Hail", + "During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin", + dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L)); + taskList.saveTask(preHailTask); + + } + + /** + * Method to create a PreFrosttask + * @throws IOException If the database cannot be accessed + */ + private void createPreFrostTask() throws IOException { + Task preFrostTask = new Task("Frost", + "The temperatur falls below zero degrees, cover especially the root with wool", + dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L)); + taskList.saveTask(preFrostTask); + } + + /** + * Method to create a PreSnowTask + * @throws IOException If the database cannot be accessed + */ + private void createPreSnowTask() throws IOException { + Task preSnowTask = new Task("Snow", + "The weather brings little snowfall. Cover your crops", + dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L)); + taskList.saveTask(preSnowTask); + } + + /** + * Method to adjust the water plant tasks + * @param rainAmount Amount of rain from the last 7 days + * @throws IOException If the database cannot be accessed + * @throws HardinessZoneNotSetException If the hardiness zone is not available + * @throws PlantNotFoundException if the plant is not available for the watering task + */ + private void adjustWateringTask(int rainAmount) throws HardinessZoneNotSetException, IOException, PlantNotFoundException { + + for (Crop crop : cropList.getCrops()) { + Plant plant = plantList.getPlantById(HardinessZone.ZONE_8A,crop.getPlantId()).orElseThrow(PlantNotFoundException::new); + + if(plant.wateringCycle().litersPerSqM() < rainAmount){ + adjustNextExecutionOfWateringTasks(taskList.getTaskList(LocalDate.now(), LocalDate.now().plusDays(7))); + } + } + + } + + /** + * Method to set next execution date of the water plant tasks + * @param cropTaskList List with tasks from crops + * @throws IOException If the database cannot be accessed + * @throws HardinessZoneNotSetException If the hardiness zone is not available + * @throws PlantNotFoundException if the plant is not available for the watering task + */ + private void adjustNextExecutionOfWateringTasks(List cropTaskList){ + for(Task task : cropTaskList){ + if(task.getName().equals("water plant")){ + task.setNextExecution(task.getNextExecution().plusDays(task.getInterval().orElse(1))); + } + } + } +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherService.java b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherService.java new file mode 100644 index 0000000..d189f11 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/backgroundtasks/weather/WeatherService.java @@ -0,0 +1,32 @@ +package ch.zhaw.gartenverwaltung.backgroundtasks.weather; +/** + * The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner + * + */ +public class WeatherService { + private static final int NO_RAIN = 0; + private static final int LITTLE_RAIN = 15; + private static final int RAIN = 25; + private static final int HEAVY_RAIN = 50; + + public SevereWeather causeSevereWeather(int randomWeather) { + return switch (randomWeather) { + case 1 -> SevereWeather.HAIL; + case 2 -> SevereWeather.SNOW; + case 3 -> SevereWeather.FROST; + default -> null; + }; + + } + + public int causeRainAmount(int randomRainAmount) { + return switch (randomRainAmount) { + case 1 -> NO_RAIN; + case 2 -> LITTLE_RAIN; + case 3 -> RAIN; + case 4 -> HEAVY_RAIN; + default -> -1; + }; + + } +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java index 9610471..2499d8b 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java @@ -1,12 +1,7 @@ package ch.zhaw.gartenverwaltung.bootstrap; -import ch.zhaw.gartenverwaltung.HelloApplication; -import ch.zhaw.gartenverwaltung.io.CropList; -import ch.zhaw.gartenverwaltung.io.JsonCropList; -import ch.zhaw.gartenverwaltung.io.JsonPlantList; -import ch.zhaw.gartenverwaltung.io.JsonTaskList; -import ch.zhaw.gartenverwaltung.io.PlantList; -import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.Main; +import ch.zhaw.gartenverwaltung.io.*; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.models.PlantListModel; @@ -82,7 +77,7 @@ public class AppLoader { * @throws IOException if the file could not be loaded */ public Object loadSceneToStage(String fxmlFile, Stage appendee) throws IOException { - FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile))); Pane root = loader.load(); Scene scene = new Scene(root); String css = Objects.requireNonNull(this.getClass().getResource("styles.css")).toExternalForm(); @@ -104,7 +99,7 @@ public class AppLoader { * @throws IOException if the file could not be loaded */ public Object loadPaneToDialog(String fxmlFile, DialogPane appendee) throws IOException { - FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile))); appendee.setContent(loader.load()); Object controller = loader.getController(); annotationInject(controller); @@ -119,7 +114,7 @@ public class AppLoader { * @throws IOException if the file could not be loaded */ public void loadAndCacheFxml(String fxmlFile) throws IOException { - FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(Main.class.getResource(fxmlFile))); Pane pane = loader.load(); panes.put(fxmlFile, pane); annotationInject(loader.getController()); @@ -157,7 +152,7 @@ public class AppLoader { }); } - private Object getAppDependency(Class type) { + public Object getAppDependency(Class type) { return dependencies.get(type.getSimpleName()); } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java b/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java index 29e055a..f0b818b 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java @@ -21,13 +21,9 @@ public class PlantImageDeserializer extends JsonDeserializer { @Override public Image deserialize(JsonParser parser, DeserializationContext context) throws IOException { Image result = null; - URL imageUrl = PlantList.class.getResource(String.format("images/%s", parser.getText())); - if (imageUrl != null) { - try (InputStream is = new FileInputStream(new File(imageUrl.toURI()))) { - result = new Image(is); - } catch (IllegalArgumentException | URISyntaxException e) { - throw new IOException(String.format("Cannot find Image \"%s\"\n", imageUrl.getFile())); - } + InputStream is = PlantList.class.getResourceAsStream(String.format("images/%s", parser.getText())); + if (is != null) { + result = new Image(is); } return result; } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java index 34c7237..f0868be 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java @@ -9,7 +9,6 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.function.Consumer; import java.util.stream.Collectors; public class GardenSchedule { @@ -49,6 +48,10 @@ public class GardenSchedule { public void planTasksForCrop(Crop crop) throws PlantNotFoundException, HardinessZoneNotSetException, IOException { Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).orElseThrow(PlantNotFoundException::new); int growPhaseGroup = plant.getGrowphaseGroupForDate(crop.getStartDate()); + addTask(new Task("watering Task", "pour water over the plant circa : "+ plant.wateringCycle().litersPerSqM() +" per square meter", + crop.getStartDate(), crop.getStartDate().plusDays(plant.timeToHarvest(0)), + plant.wateringCycle().interval(), crop.getCropId().orElse(0L))); + for (GrowthPhase growthPhase : plant.lifecycleForGroup(growPhaseGroup)) { for (TaskTemplate taskTemplate : growthPhase.taskTemplates()) { addTask(taskTemplate.generateTask(crop.getStartDate(), crop.getCropId().orElse(0L))); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Crop.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Crop.java index e8f539f..58cd453 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Crop.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Crop.java @@ -1,5 +1,8 @@ package ch.zhaw.gartenverwaltung.types; +import ch.zhaw.gartenverwaltung.io.JsonPlantList; +import ch.zhaw.gartenverwaltung.io.PlantList; + import java.time.LocalDate; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/GrowthPhase.java b/src/main/java/ch/zhaw/gartenverwaltung/types/GrowthPhase.java index 9348f2b..6efcc44 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/GrowthPhase.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/GrowthPhase.java @@ -12,7 +12,6 @@ public record GrowthPhase( MonthDay startDate, MonthDay endDate, int group, - WateringCycle wateringCycle, @JsonDeserialize(using = GrowthPhaseTypeDeserializer.class) GrowthPhaseType type, @JsonDeserialize(using = HardinessZoneDeserializer.class) HardinessZone zone, List taskTemplates) { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java index 30773df..d602f51 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java @@ -18,6 +18,7 @@ public record Plant( int light, String soil, List pests, + WateringCycle wateringCycle, List lifecycle) { /** diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java index 4158057..ef97003 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java @@ -41,6 +41,16 @@ public class Task { this.cropId = cropId; } + /** + * Constructor for weather events + */ + public Task(String name, String description, LocalDate startDate, LocalDate endDate) { + this.name = name; + this.description = description; + this.startDate = startDate; + this.endDate = endDate; + } + public Task(String name, String description, LocalDate startDate, LocalDate endDate, int interval, long cropId) { this.name = name; this.description = description; @@ -72,8 +82,10 @@ public class Task { public void done(){ if(interval != null && interval != 0 && !nextExecution.plusDays(interval).isAfter(endDate)){ nextExecution = nextExecution.plusDays(interval); + nextNotification = nextExecution; } else { nextExecution = null; + nextNotification = null; } } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 44103dd..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,4 +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.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 diff --git a/src/main/resources/META-INF/javamail.default.address.map b/src/main/resources/META-INF/javamail.default.address.map new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/io/plantdb.json b/src/main/resources/ch/zhaw/gartenverwaltung/io/plantdb.json index d54dd19..867e6a2 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/io/plantdb.json +++ b/src/main/resources/ch/zhaw/gartenverwaltung/io/plantdb.json @@ -14,6 +14,11 @@ "measures": "Less water." } ], + "wateringCycle": { + "litersPerSqM": 25, + "interval": null, + "notes": [] + }, "lifecycle": [ { "startDate": "03-10", @@ -21,11 +26,6 @@ "type": "SOW", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Germinate", @@ -42,11 +42,6 @@ "type": "PLANT", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 7, - "notes": [] - }, "taskTemplates": [ { "name": "hilling", @@ -63,11 +58,6 @@ "type": "HARVEST", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Harvest", @@ -85,6 +75,11 @@ "name": "Early Carrot", "description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.", "image": "carrot.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 3, + "notes": [] + }, "lifecycle": [ { "startDate": "02-20", @@ -92,11 +87,7 @@ "zone": "ZONE_8A", "type": "SOW", "group": 0, - "wateringCycle": { - "litersPerSqM": 15, - "interval": 3, - "notes": [] - }, + "taskTemplates": [ { "name": "hilling", @@ -113,13 +104,6 @@ "zone": "ZONE_8A", "type": "PLANT", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 3, - "notes": [ - "Be careful not to pour water over the leaves, as this will lead to sunburn." - ] - }, "taskTemplates": [ { "name": "hilling", @@ -136,11 +120,6 @@ "zone": "ZONE_8A", "type": "HARVEST", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Harvesting", @@ -167,6 +146,12 @@ "name": "Summertime Onion", "description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.", "image": "onion.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 4, + "notes": [ + ] + }, "lifecycle": [ { "startDate": "03-15", @@ -174,12 +159,6 @@ "type": "SOW", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 15, - "interval": 4, - "notes": [ - ] - }, "taskTemplates": [ { "name": "Plant Sets", @@ -196,13 +175,6 @@ "type": "PLANT", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 3, - "notes": [ - "" - ] - }, "taskTemplates": [ { "name": "hilling", @@ -219,12 +191,6 @@ "type": "HARVEST", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [ - ] - }, "taskTemplates": [ { "name": "Harvesting", @@ -261,6 +227,11 @@ "measures": "Less water." } ], + "wateringCycle": { + "litersPerSqM": 0, + "interval": null, + "notes": [] + }, "lifecycle": [ { "startDate": "12-01", @@ -268,11 +239,7 @@ "type": "SOW", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, + "taskTemplates": [ { "name": "Germinate", @@ -289,11 +256,6 @@ "type": "PLANT", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 7, - "notes": [] - }, "taskTemplates": [ { "name": "hilling", @@ -310,11 +272,6 @@ "type": "HARVEST", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Harvest", diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/io/taskdb.json b/src/main/resources/ch/zhaw/gartenverwaltung/io/taskdb.json index 7b86231..889451a 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/io/taskdb.json +++ b/src/main/resources/ch/zhaw/gartenverwaltung/io/taskdb.json @@ -14,10 +14,10 @@ "id": 2, "name": "water plant", "description": "water the plant, so that the soil is wet around the plant.", - "startDate": "2022-05-01", - "nextExecution": "2022-05-01", + "startDate": "2022-10-29", + "nextExecution": "2022-11-30", "nextNotification": "2022-05-01", - "endDate": "2022-09-01", + "endDate": "2022-12-31", "interval": 2, "cropId": 0 }, diff --git a/src/test/java/ch/zhaw/gartenverwaltung/models/GardenPlanModelTest.java b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenPlanModelTest.java index e39a525..c87f916 100644 --- a/src/test/java/ch/zhaw/gartenverwaltung/models/GardenPlanModelTest.java +++ b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenPlanModelTest.java @@ -49,11 +49,12 @@ public class GardenPlanModelTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), - List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))); + new WateringCycle(15, 0, null), + List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))); exampleCropOnion = new Crop(examplePlantOnion.id(), LocalDate.of(2023, 3, 1)) .withId(3); @@ -66,7 +67,8 @@ public class GardenPlanModelTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), - List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))); + new WateringCycle(25, 0, null), + List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))); exampleCropCarrot = new Crop(examplePlantCarrot.id(), LocalDate.now()) .withId(5); diff --git a/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java index 0c05e36..8bce1be 100644 --- a/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java +++ b/src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java @@ -7,8 +7,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.time.LocalDate; import java.time.MonthDay; +import java.time.format.DateTimeFormatter; import java.util.*; import static org.junit.jupiter.api.Assertions.*; @@ -88,14 +94,19 @@ class GardenScheduleTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), + new WateringCycle(15, 0, null), List.of( - new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, List.of( + + new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, List.of( exampleTaskTemplateList.get(0), exampleTaskTemplateList.get(1) )), - new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, List.of( + new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, List.of( exampleTaskTemplateList.get(2), exampleTaskTemplateList.get(3) + )), + new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, List.of( + )) ))); } @@ -187,8 +198,7 @@ class GardenScheduleTest { } @Test - void planTasksForCrop() throws HardinessZoneNotSetException, PlantNotFoundException, IOException { - assertThrows(PlantNotFoundException.class,()-> model.planTasksForCrop(new Crop())); + void planTasksForCrop() throws HardinessZoneNotSetException, PlantNotFoundException, IOException, URISyntaxException { model.planTasksForCrop(new Crop(20, exampleStartDate).withId(30)); verify(exampleTaskTemplateList.get(0), times(1)).generateTask(exampleStartDate, 30); verify(exampleTaskTemplateList.get(1), times(1)).generateTask(exampleStartDate, 30); @@ -198,5 +208,18 @@ class GardenScheduleTest { verify(taskList, times(1)).saveTask(exampleTaskList.get(1)); verify(taskList, times(1)).saveTask(exampleTaskList.get(2)); verify(taskList, times(1)).saveTask(exampleTaskList.get(3)); + + final URL dbDataSource = this.getClass().getResource("test-taskdb.json"); + final URL testFile = this.getClass().getResource("template-taskdb.json"); + + Files.copy(Path.of(testFile.toURI()), Path.of(dbDataSource.toURI()), StandardCopyOption.REPLACE_EXISTING); + JsonTaskList testTaskList = new JsonTaskList(dbDataSource); + + model = spy(new GardenSchedule(testTaskList,plantList)); + model.planTasksForCrop(new Crop(20, exampleStartDate).withId(30)); + assertEquals(5,testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).size()); + testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).get(0); } + + } \ No newline at end of file diff --git a/src/test/java/ch/zhaw/gartenverwaltung/models/PlantListModelTest.java b/src/test/java/ch/zhaw/gartenverwaltung/models/PlantListModelTest.java index 0033299..5f71e1f 100644 --- a/src/test/java/ch/zhaw/gartenverwaltung/models/PlantListModelTest.java +++ b/src/test/java/ch/zhaw/gartenverwaltung/models/PlantListModelTest.java @@ -49,11 +49,12 @@ class PlantListModelTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), - List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) + new WateringCycle(25, 0, null), + List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) ); examplePlantList.add(new Plant( 0, @@ -64,8 +65,9 @@ class PlantListModelTest { 6, "sandy", new ArrayList<>(), - List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), - new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) + new WateringCycle(0, 0, null), + List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()), + new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) ); examplePlantList.add(new Plant( 1, @@ -76,7 +78,8 @@ class PlantListModelTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), - List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) + new WateringCycle(25, 0, null), + List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()))) ); } diff --git a/src/test/java/ch/zhaw/gartenverwaltung/types/PlantTest.java b/src/test/java/ch/zhaw/gartenverwaltung/types/PlantTest.java index 88cdf54..903d036 100644 --- a/src/test/java/ch/zhaw/gartenverwaltung/types/PlantTest.java +++ b/src/test/java/ch/zhaw/gartenverwaltung/types/PlantTest.java @@ -20,16 +20,16 @@ class PlantTest { @BeforeEach void setUp() { List growthPhases = new ArrayList<>(); - growthPhases.add(new GrowthPhase(MonthDay.of(2, 1), MonthDay.of(4, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(4, 2), MonthDay.of(6, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(6, 3), MonthDay.of(8, 6), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(3, 1), MonthDay.of(5, 4), 1, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(5, 2), MonthDay.of(7, 5), 1, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(7, 3), MonthDay.of(9, 6), 1, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(4, 1), MonthDay.of(6, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.SOW, HardinessZone.ZONE_1A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(6, 2), MonthDay.of(8, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(7, 2), MonthDay.of(9, 5), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>())); - growthPhases.add(new GrowthPhase(MonthDay.of(8, 3), MonthDay.of(10, 6), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_1A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(2, 1), MonthDay.of(4, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(4, 2), MonthDay.of(6, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(6, 3), MonthDay.of(8, 6), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(3, 1), MonthDay.of(5, 4), 1, GrowthPhaseType.SOW, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(5, 2), MonthDay.of(7, 5), 1, GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(7, 3), MonthDay.of(9, 6), 1, GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(4, 1), MonthDay.of(6, 4), 0, GrowthPhaseType.SOW, HardinessZone.ZONE_1A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(6, 2), MonthDay.of(8, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(7, 2), MonthDay.of(9, 5), 0, GrowthPhaseType.PLANT, HardinessZone.ZONE_1A, new ArrayList<>())); + growthPhases.add(new GrowthPhase(MonthDay.of(8, 3), MonthDay.of(10, 6), 0, GrowthPhaseType.HARVEST, HardinessZone.ZONE_1A, new ArrayList<>())); testPlant = new Plant( 20, @@ -40,6 +40,7 @@ class PlantTest { 0, "sandy to loamy, loose soil, free of stones", new ArrayList<>(), + new WateringCycle(25, 0, null), growthPhases); } diff --git a/src/test/resources/ch/zhaw/gartenverwaltung/io/plantdb.json b/src/test/resources/ch/zhaw/gartenverwaltung/io/plantdb.json new file mode 100644 index 0000000..abd61ef --- /dev/null +++ b/src/test/resources/ch/zhaw/gartenverwaltung/io/plantdb.json @@ -0,0 +1,215 @@ +[ + { + "id": 0, + "name": "Potato", + "description": "The potato is a tuber, round or oval, with small white roots called 'eyes', that are growth buds. The size varies depending on the variety; the colour of the skin can be white, yellow or even purple.", + "light": 6, + "spacing": "35", + "soil": "sandy", + "image": "potato.jpg", + "pests": [ + { + "name": "Rot", + "description": "Rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.", + "measures": "Less water." + } + ], + "wateringCycle": { + "litersPerSqM": 25, + "interval": null, + "notes": [] + }, + "lifecycle": [ + { + "startDate": "03-10", + "endDate": "04-10", + "type": "SOW", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "Germinate", + "relativeStartDate": -14, + "relativeEndDate": null, + "description": "Take an egg carton and fill it with soil. Put the seedling deep enough so its half covered with soil. Keep it in 10-15 * Celsius with lots of light.", + "interval": null + } + ] + }, + { + "startDate": "04-10", + "endDate": "07-10", + "type": "PLANT", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "hilling", + "relativeStartDate": 0, + "relativeEndDate": null, + "description": "When the plants are 20 cm tall, begin hilling the potatoes by gently mounding the soil from the center of your rows around the stems of the plant. Mound up the soil around the plant until just the top few leaves show above the soil. Two weeks later, hill up the soil again when the plants grow another 20 cm.", + "interval": 21 + } + ] + }, + { + "startDate": "06-10", + "endDate": "08-10", + "type": "HARVEST", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "Harvest", + "relativeStartDate": 0, + "relativeEndDate": null, + "description": "Once the foliage has wilted and dried completely, harvest on a dry day. Store in a dark and cool location.", + "interval": null + } + ] + } + ] + }, + { + "id": 1, + "name": "Early Carrot", + "description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.", + "image": "carrot.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 3, + "notes": [] + }, + "lifecycle": [ + { + "startDate": "02-20", + "endDate": "03-10", + "zone": "ZONE_8A", + "type": "SOW", + "group": 0, + + "taskTemplates": [ + { + "name": "hilling", + "relativeStartDate": 0, + "relativeEndDate": 0, + "description": "Mound up the soil around the plant until just the top few leaves show above the soil. ", + "interval": null + } + ] + }, + { + "startDate": "03-10", + "endDate": "05-10", + "zone": "ZONE_8A", + "type": "PLANT", + "group": 0, + "taskTemplates": [ + { + "name": "hilling", + "relativeStartDate": 0, + "relativeEndDate": null, + "description": "Mound up the soil around the plant until just the top few leaves show above the soil. ", + "interval": 15 + } + ] + }, + { + "startDate": "05-10", + "endDate": "05-20", + "zone": "ZONE_8A", + "type": "HARVEST", + "group": 0, + "taskTemplates": [ + { + "name": "Harvesting", + "relativeStartDate": 0, + "relativeEndDate": 14, + "description": "When the leaves turn to a yellowish brown. Do not harvest earlier. The plant will show when it's ready.", + "interval": null + } + ] + } + ], + "soil": "sandy to loamy, loose soil, free of stones", + "spacing": "5,35,2.5", + "pests": [ + { + "name": "Rot", + "description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.", + "measures": "less water" + } + ] + }, + { + "id": 2, + "name": "Summertime Onion", + "description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.", + "image": "onion.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 4, + "notes": [ + ] + }, + "lifecycle": [ + { + "startDate": "03-15", + "endDate": "04-10", + "type": "SOW", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "Plant Sets", + "relativeStartDate": 0, + "relativeEndDate": 0, + "description": "Plant the sets about 5cm deep into the soil.", + "interval": null + } + ] + }, + { + "startDate": "04-10", + "endDate": "07-10", + "type": "PLANT", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "hilling", + "relativeStartDate": 0, + "relativeEndDate": null, + "description": "Mound up the soil around the plant until just the top few leaves show above the soil. ", + "interval": 15 + } + ] + }, + { + "startDate": "07-10", + "endDate": "09-20", + "type": "HARVEST", + "zone": "ZONE_8A", + "group": 0, + "taskTemplates": [ + { + "name": "Harvesting", + "relativeStartDate": 0, + "relativeEndDate": 14, + "description": "When ready for harvest, the leaves on your onion plants will start to flop over. This happens at the \"neck\" of the onion and it signals that the plant has stopped growing and is ready for storage. Onions should be harvested soon thereafter", + "interval": null + } + ] + } + ], + "soil": "sandy to loamy, loose soil, free of stones", + "spacing": "15,30,2", + "pests": [ + { + "name": "Rot", + "description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.", + "measures": "less water" + } + ] + } +] diff --git a/src/test/resources/ch/zhaw/gartenverwaltung/io/template-taskdb.json b/src/test/resources/ch/zhaw/gartenverwaltung/io/template-taskdb.json index 7728bb0..b10124d 100644 --- a/src/test/resources/ch/zhaw/gartenverwaltung/io/template-taskdb.json +++ b/src/test/resources/ch/zhaw/gartenverwaltung/io/template-taskdb.json @@ -4,6 +4,8 @@ "name" : "sow plant", "description": "Plant the seeds, crops in de bed.", "startDate" : "2022-05-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-05-01", "interval" : 0, "cropId" : 0 @@ -13,6 +15,8 @@ "name" : "water plant", "description": "water the plant, so that the soil is wet around the plant.", "startDate" : "2022-05-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-09-01", "interval" : 2, "cropId" : 0 @@ -22,6 +26,8 @@ "name" : "fertilize plant", "description": "The fertilizer has to be mixed with water. Then fertilize the plants soil with the mixture", "startDate" : "2022-06-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-08-01", "interval" : 28, "cropId" : 0 @@ -31,6 +37,8 @@ "name" : "covering plant", "description": "Take a big enough coverage for the plants. Cover the whole plant with a bit space between the plant and the coverage", "startDate" : "2022-07-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-07-01", "interval" : 0, "cropId" : 0 @@ -40,6 +48,8 @@ "name" : "look after plant", "description": "Look for pest or illness at the leaves of the plant. Check the soil around the plant, if the roots are enough covered with soil", "startDate" : "2022-05-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-09-01", "interval" : 5, "cropId" : 0 @@ -49,6 +59,8 @@ "name" : "harvest plant", "description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ", "startDate" : "2022-09-01", + "nextExecution": "2022-05-01", + "nextNotification": "2022-05-01", "endDate" : "2022-09-01", "interval" : 0, "cropId" : 0 diff --git a/src/test/resources/ch/zhaw/gartenverwaltung/io/test-plantdb.json b/src/test/resources/ch/zhaw/gartenverwaltung/io/test-plantdb.json index 4268df1..abd61ef 100644 --- a/src/test/resources/ch/zhaw/gartenverwaltung/io/test-plantdb.json +++ b/src/test/resources/ch/zhaw/gartenverwaltung/io/test-plantdb.json @@ -14,6 +14,11 @@ "measures": "Less water." } ], + "wateringCycle": { + "litersPerSqM": 25, + "interval": null, + "notes": [] + }, "lifecycle": [ { "startDate": "03-10", @@ -21,11 +26,6 @@ "type": "SOW", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Germinate", @@ -42,11 +42,6 @@ "type": "PLANT", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 7, - "notes": [] - }, "taskTemplates": [ { "name": "hilling", @@ -63,11 +58,6 @@ "type": "HARVEST", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Harvest", @@ -85,6 +75,11 @@ "name": "Early Carrot", "description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.", "image": "carrot.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 3, + "notes": [] + }, "lifecycle": [ { "startDate": "02-20", @@ -92,11 +87,7 @@ "zone": "ZONE_8A", "type": "SOW", "group": 0, - "wateringCycle": { - "litersPerSqM": 15, - "interval": 3, - "notes": [] - }, + "taskTemplates": [ { "name": "hilling", @@ -113,13 +104,6 @@ "zone": "ZONE_8A", "type": "PLANT", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 3, - "notes": [ - "Be careful not to pour water over the leaves, as this will lead to sunburn." - ] - }, "taskTemplates": [ { "name": "hilling", @@ -136,11 +120,6 @@ "zone": "ZONE_8A", "type": "HARVEST", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [] - }, "taskTemplates": [ { "name": "Harvesting", @@ -167,6 +146,12 @@ "name": "Summertime Onion", "description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.", "image": "onion.jpg", + "wateringCycle": { + "litersPerSqM": 15, + "interval": 4, + "notes": [ + ] + }, "lifecycle": [ { "startDate": "03-15", @@ -174,19 +159,12 @@ "type": "SOW", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 15, - "interval": 4, - "notes": [ - - ] - }, "taskTemplates": [ { - "name": "hilling", + "name": "Plant Sets", "relativeStartDate": 0, "relativeEndDate": 0, - "description": "Mound up the soil around the plant until just the top few leaves show above the soil. ", + "description": "Plant the sets about 5cm deep into the soil.", "interval": null } ] @@ -197,13 +175,6 @@ "type": "PLANT", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 25, - "interval": 3, - "notes": [ - "" - ] - }, "taskTemplates": [ { "name": "hilling", @@ -220,13 +191,6 @@ "type": "HARVEST", "zone": "ZONE_8A", "group": 0, - "wateringCycle": { - "litersPerSqM": 0, - "interval": null, - "notes": [ - - ] - }, "taskTemplates": [ { "name": "Harvesting", diff --git a/src/test/resources/ch/zhaw/gartenverwaltung/models/template-taskdb.json b/src/test/resources/ch/zhaw/gartenverwaltung/models/template-taskdb.json new file mode 100644 index 0000000..32960f8 --- /dev/null +++ b/src/test/resources/ch/zhaw/gartenverwaltung/models/template-taskdb.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file diff --git a/src/test/resources/ch/zhaw/gartenverwaltung/models/test-taskdb.json b/src/test/resources/ch/zhaw/gartenverwaltung/models/test-taskdb.json new file mode 100644 index 0000000..32960f8 --- /dev/null +++ b/src/test/resources/ch/zhaw/gartenverwaltung/models/test-taskdb.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file