From 6ffb6124343056dcd4cbb69c5ec2aed745b7f133 Mon Sep 17 00:00:00 2001 From: Tor-Einar Skog <tor-einar.skog@bioforsk.no> Date: Fri, 22 Jan 2016 13:36:37 +0100 Subject: [PATCH] First complete version of notification subscription system --- nb-configuration.xml | 9 +- .../NotificationSubscriptionController.java | 30 +- .../nibio/vips/logic/entity/Organization.java | 16 ++ .../vips/logic/messaging/ForecastEvent.java | 125 +++++++++ ...ForecastEventNotificationSubscription.java | 131 +++++++++ .../messaging/ForecastNotificationLog.java | 127 +++++++++ .../messaging/ForecastNotificationLogPK.java | 118 ++++++++ .../vips/logic/messaging/MessagingBean.java | 262 +++++++++++++++--- .../scheduling/VipsLogicTaskFactory.java | 7 +- .../SendForecastEventNotificationsTask.java | 67 +++++ .../vips/logic/i18n/vipslogictexts.properties | 6 + .../logic/i18n/vipslogictexts_bs.properties | 6 + .../logic/i18n/vipslogictexts_hr.properties | 6 + .../logic/i18n/vipslogictexts_nb.properties | 6 + .../logic/i18n/vipslogictexts_sr.properties | 6 + src/main/webapp/WEB-INF/glassfish-web.xml | 10 + .../notificationSubscriptionForm.ftl | 46 ++- .../messaging/UniversalMessagingTest.java | 2 +- 18 files changed, 916 insertions(+), 64 deletions(-) create mode 100644 src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java create mode 100644 src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java create mode 100644 src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java create mode 100644 src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java create mode 100644 src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java create mode 100644 src/main/webapp/WEB-INF/glassfish-web.xml diff --git a/nb-configuration.xml b/nb-configuration.xml index 05a987a7..d096f3f9 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -16,7 +16,14 @@ Any value defined here will override the pom.xml file value but is only applicab <netbeans.hint.j2eeVersion>1.5</netbeans.hint.j2eeVersion> <org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type>ide</org-netbeans-modules-maven-jaxws.rest_2e_config_2e_type> <org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder>js</org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder> - <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>JBoss4</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server> <netbeans.hint.license>nibio_open_source_license.ftl</netbeans.hint.license> + <org-netbeans-modules-css-prep.sass_2e_compiler_2e_options/> + <org-netbeans-modules-css-prep.less_2e_mappings>/less:/css</org-netbeans-modules-css-prep.less_2e_mappings> + <org-netbeans-modules-css-prep.less_2e_enabled>false</org-netbeans-modules-css-prep.less_2e_enabled> + <org-netbeans-modules-css-prep.sass_2e_mappings>/scss:/css</org-netbeans-modules-css-prep.sass_2e_mappings> + <org-netbeans-modules-css-prep.sass_2e_enabled>false</org-netbeans-modules-css-prep.sass_2e_enabled> + <org-netbeans-modules-css-prep.less_2e_compiler_2e_options/> + <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server> + <org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language> </properties> </project-shared-configuration> diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java index 66a41c55..fcd93445 100644 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java @@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.VipsLogicRole; import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.messaging.ForecastEventNotificationSubscription; import no.nibio.vips.logic.messaging.MessageNotificationSubscription; import no.nibio.vips.logic.messaging.UniversalMessageFormat; import no.nibio.vips.logic.util.SessionControllerGetter; @@ -79,13 +80,14 @@ public class NotificationSubscriptionController extends HttpServlet { { viewUser = user; } - MessageNotificationSubscription subscription = SessionControllerGetter.getMessagingBean().getMessageNotificationSubscription(viewUser.getUserId()); - request.setAttribute("messageNotificationSubscription",subscription); - request.setAttribute("userCropIds", subscription != null ? subscription.getCropIds() : new Integer[0]); - request.setAttribute("userMessageTagIds", subscription != null ? subscription.getMessageTagIds() : new Integer[0]); + MessageNotificationSubscription messageNotificationSubscription = SessionControllerGetter.getMessagingBean().getMessageNotificationSubscription(viewUser.getUserId()); + request.setAttribute("messageNotificationSubscription",messageNotificationSubscription); + ForecastEventNotificationSubscription forecastEventNotificationSubscription = SessionControllerGetter.getMessagingBean().getForecastEventNotificationSubscription(viewUser.getUserId()); + request.setAttribute("forecastEventNotificationSubscription",forecastEventNotificationSubscription); request.setAttribute("viewUser", viewUser); request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList()); request.setAttribute("messageTagSet", em.createNamedQuery("MessageTag.findAll").getResultList()); + request.setAttribute("weatherStationIds", SessionControllerGetter.getPointOfInterestBean().getWeatherstationsForUser(viewUser)); request.setAttribute("universalMessageFormats", SessionControllerGetter.getMessagingBean().getAllUniversalMessageFormats()); request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/notificationSubscriptionForm.ftl").forward(request, response); @@ -103,12 +105,20 @@ public class NotificationSubscriptionController extends HttpServlet { { viewUser = user; } - MessageNotificationSubscription subscription = new MessageNotificationSubscription(); - subscription.setUniversalMessageFormatId(Integer.valueOf(request.getParameter("universalMessageFormatId"))); - subscription.setCropIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("cropOrganismIds"))); - subscription.setMessageTagIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("messageTagIds"))); - subscription.setUserId(viewUser.getUserId()); - SessionControllerGetter.getMessagingBean().storeMessageNotificationSubscription(subscription); + MessageNotificationSubscription mSubscription = new MessageNotificationSubscription(); + mSubscription.setUniversalMessageFormatId(Integer.valueOf(request.getParameter("messageN_universalMessageFormatId"))); + mSubscription.setCropIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("messageN_cropOrganismIds"))); + mSubscription.setMessageTagIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("messageN_messageTagIds"))); + mSubscription.setUserId(viewUser.getUserId()); + SessionControllerGetter.getMessagingBean().storeMessageNotificationSubscription(mSubscription); + + ForecastEventNotificationSubscription fSubscription = new ForecastEventNotificationSubscription(); + fSubscription.setUniversalMessageFormatId(Integer.valueOf(request.getParameter("forecastN_universalMessageFormatId"))); + fSubscription.setCropIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("forecastN_cropOrganismIds"))); + fSubscription.setWeatherStationIds(FormUtil.getIdsFromMultipleSelect(request.getParameterValues("forecastN_weatherStationIds"))); + fSubscription.setUserId(viewUser.getUserId()); + SessionControllerGetter.getMessagingBean().storeForecastEventNotificationSubscription(fSubscription); + // Redirect to form with confirmation message response.sendRedirect(new StringBuilder("http://") .append(ServletUtil.getServerName(request)) diff --git a/src/main/java/no/nibio/vips/logic/entity/Organization.java b/src/main/java/no/nibio/vips/logic/entity/Organization.java index 8957d074..1f2db83f 100644 --- a/src/main/java/no/nibio/vips/logic/entity/Organization.java +++ b/src/main/java/no/nibio/vips/logic/entity/Organization.java @@ -102,6 +102,8 @@ public class Organization implements Serializable { private String defaultLocale; @OneToMany(mappedBy = "organizationId") private Set<VipsLogicUser> vipsLogicUserSet; + @Column(name = "vipsweb_url") + private String vipswebUrl; public Organization() { } @@ -295,4 +297,18 @@ public class Organization implements Serializable { this.defaultVipsCoreUserId = defaultVipsCoreUserId; } + /** + * @return the vipswebUrl + */ + public String getVipswebUrl() { + return vipswebUrl; + } + + /** + * @param vipswebUrl the vipswebUrl to set + */ + public void setVipswebUrl(String vipswebUrl) { + this.vipswebUrl = vipswebUrl; + } + } diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java new file mode 100644 index 00000000..8ad75d14 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.nibio.vips.logic.messaging; + +import java.io.Serializable; +import java.util.Set; +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "forecast_event", schema = "messaging") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "ForecastEvent.findAll", query = "SELECT f FROM ForecastEvent f"), + @NamedQuery(name = "ForecastEvent.findByForecastEventId", query = "SELECT f FROM ForecastEvent f WHERE f.forecastEventId = :forecastEventId"), + @NamedQuery(name = "ForecastEvent.findByEventName", query = "SELECT f FROM ForecastEvent f WHERE f.eventName = :eventName"), + @NamedQuery(name = "ForecastEvent.findByEventDescription", query = "SELECT f FROM ForecastEvent f WHERE f.eventDescription = :eventDescription")}) +public class ForecastEvent implements Serializable { + + public final static Integer TO_RED = 1; + public final static Integer GREEN_TO_YELLOW = 2; + + private static final long serialVersionUID = 1L; + @Id + @Basic(optional = false) + @NotNull + @Column(name = "forecast_event_id") + private Integer forecastEventId; + @Size(max = 255) + @Column(name = "event_name") + private String eventName; + @Size(max = 2147483647) + @Column(name = "event_description") + private String eventDescription; + + + public ForecastEvent() { + } + + public ForecastEvent(Integer forecastEventId) { + this.forecastEventId = forecastEventId; + } + + public Integer getForecastEventId() { + return forecastEventId; + } + + public void setForecastEventId(Integer forecastEventId) { + this.forecastEventId = forecastEventId; + } + + public String getEventName() { + return eventName; + } + + public void setEventName(String eventName) { + this.eventName = eventName; + } + + public String getEventDescription() { + return eventDescription; + } + + public void setEventDescription(String eventDescription) { + this.eventDescription = eventDescription; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (forecastEventId != null ? forecastEventId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof ForecastEvent)) { + return false; + } + ForecastEvent other = (ForecastEvent) object; + if ((this.forecastEventId == null && other.forecastEventId != null) || (this.forecastEventId != null && !this.forecastEventId.equals(other.forecastEventId))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.nibio.vips.logic.messaging.ForecastEvent[ forecastEventId=" + forecastEventId + " ]"; + } + +} diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java new file mode 100644 index 00000000..9e729435 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.nibio.vips.logic.messaging; + +import java.util.List; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import no.nibio.vips.logic.util.IntegerArrayUserType; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "forecast_event_notification_subscription", schema = "messaging") +@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) +public class ForecastEventNotificationSubscription { + + private static final long serialVersionUID = 1L; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Basic(optional = false) + @Column(name = "user_id") + private Integer userId; + + @Column(name = "universal_message_format_id") + private Integer universalMessageFormatId; + + @Type(type = "IntegerArray") + @Column(name = "weather_station_ids") + private Integer[] weatherStationIds; + + @Type(type = "IntegerArray") + @Column(name = "crop_ids") + private Integer[] cropIds; + + /** + * @return the userId + */ + public Integer getUserId() { + return userId; + } + + /** + * @param userId the userId to set + */ + public void setUserId(Integer userId) { + this.userId = userId; + } + + /** + * @return the universalMessageFormatId + */ + public Integer getUniversalMessageFormatId() { + return universalMessageFormatId; + } + + /** + * @param universalMessageFormatId the universalMessageFormatId to set + */ + public void setUniversalMessageFormatId(Integer universalMessageFormatId) { + this.universalMessageFormatId = universalMessageFormatId; + } + + /** + * @return the weatherStationIds + */ + public Integer[] getWeatherStationIds() { + return weatherStationIds; + } + + /** + * @param weatherStationIds the weatherStationIds to set + */ + public void setWeatherStationIds(Integer[] weatherStationIds) { + this.weatherStationIds = weatherStationIds; + } + + /** + * Convenience method + * @param weatherStationIds + */ + public void setWeatherStationIds(List<Integer> weatherStationIds) + { + this.weatherStationIds = weatherStationIds.toArray(new Integer[weatherStationIds.size()]); + } + + /** + * @return the cropIds + */ + public Integer[] getCropIds() { + return cropIds; + } + + /** + * @param cropIds the cropIds to set + */ + public void setCropIds(Integer[] cropIds) { + this.cropIds = cropIds; + } + + public void setCropIds(List<Integer> cropIds) + { + this.cropIds = cropIds.toArray(new Integer[cropIds.size()]); + } +} diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java new file mode 100644 index 00000000..a1f97004 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.nibio.vips.logic.messaging; + +import java.io.Serializable; +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@Table(name = "forecast_notification_log", schema = "messaging") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "ForecastNotificationLog.findAll", query = "SELECT f FROM ForecastNotificationLog f"), + @NamedQuery(name = "ForecastNotificationLog.findByForecastConfigurationId", query = "SELECT f FROM ForecastNotificationLog f WHERE f.forecastNotificationLogPK.forecastConfigurationId = :forecastConfigurationId"), + @NamedQuery(name = "ForecastNotificationLog.findByForecastEventId", query = "SELECT f FROM ForecastNotificationLog f WHERE f.forecastNotificationLogPK.forecastEventId = :forecastEventId"), + @NamedQuery(name = "ForecastNotificationLog.findByEventDate", query = "SELECT f FROM ForecastNotificationLog f WHERE f.forecastNotificationLogPK.eventDate = :eventDate"), + @NamedQuery(name = "ForecastNotificationLog.findByPK", query = "SELECT f FROM ForecastNotificationLog f WHERE f.forecastNotificationLogPK.eventDate = :eventDate AND f.forecastNotificationLogPK.forecastEventId = :forecastEventId AND f.forecastNotificationLogPK.forecastConfigurationId = :forecastConfigurationId"), + @NamedQuery(name = "ForecastNotificationLog.findByCreatedTime", query = "SELECT f FROM ForecastNotificationLog f WHERE f.createdTime = :createdTime")}) +public class ForecastNotificationLog implements Serializable { + + private static final long serialVersionUID = 1L; + @EmbeddedId + protected ForecastNotificationLogPK forecastNotificationLogPK; + @Column(name = "created_time") + @Temporal(TemporalType.TIMESTAMP) + private Date createdTime; + @Column(name = "universal_message_id") + private Integer universalMessageId; + + + public ForecastNotificationLog() { + } + + public ForecastNotificationLog(ForecastNotificationLogPK forecastNotificationLogPK) { + this.forecastNotificationLogPK = forecastNotificationLogPK; + } + + public ForecastNotificationLog(Long forecastConfigurationId, int forecastEvent, Date eventDate) { + this.forecastNotificationLogPK = new ForecastNotificationLogPK(forecastConfigurationId, forecastEvent, eventDate); + } + + public ForecastNotificationLogPK getForecastNotificationLogPK() { + return forecastNotificationLogPK; + } + + public void setForecastNotificationLogPK(ForecastNotificationLogPK forecastNotificationLogPK) { + this.forecastNotificationLogPK = forecastNotificationLogPK; + } + + public Date getCreatedTime() { + return createdTime; + } + + public void setCreatedTime(Date createdTime) { + this.createdTime = createdTime; + } + + + @Override + public int hashCode() { + int hash = 0; + hash += (forecastNotificationLogPK != null ? forecastNotificationLogPK.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof ForecastNotificationLog)) { + return false; + } + ForecastNotificationLog other = (ForecastNotificationLog) object; + if ((this.forecastNotificationLogPK == null && other.forecastNotificationLogPK != null) || (this.forecastNotificationLogPK != null && !this.forecastNotificationLogPK.equals(other.forecastNotificationLogPK))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.nibio.vips.logic.messaging.ForecastNotificationLog[ forecastNotificationLogPK=" + forecastNotificationLogPK + " ]"; + } + + /** + * @return the universalMessageId + */ + public Integer getUniversalMessageId() { + return universalMessageId; + } + + /** + * @param universalMessageId the universalMessageId to set + */ + public void setUniversalMessageId(Integer universalMessageId) { + this.universalMessageId = universalMessageId; + } + +} diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java new file mode 100644 index 00000000..eda72b87 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.nibio.vips.logic.messaging; + +import java.io.Serializable; +import java.util.Date; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Embeddable +public class ForecastNotificationLogPK implements Serializable { + + @Basic(optional = false) + @NotNull + @Column(name = "forecast_configuration_id") + private Long forecastConfigurationId; + @Basic(optional = false) + @NotNull + @Column(name = "forecast_event_id") + private int forecastEventId; + @Basic(optional = false) + @NotNull + @Column(name = "event_date") + @Temporal(TemporalType.DATE) + private Date eventDate; + + public ForecastNotificationLogPK() { + } + + public ForecastNotificationLogPK(Long forecastConfigurationId, int forecastEventId, Date eventDate) { + this.forecastConfigurationId = forecastConfigurationId; + this.forecastEventId = forecastEventId; + this.eventDate = eventDate; + } + + public Long getForecastConfigurationId() { + return forecastConfigurationId; + } + + public void setForecastConfigurationId(Long forecastConfigurationId) { + this.forecastConfigurationId = forecastConfigurationId; + } + + public int getForecastEventId() { + return forecastEventId; + } + + public void setForecastEventId(int forecastEventId) { + this.forecastEventId = forecastEventId; + } + + public Date getEventDate() { + return eventDate; + } + + public void setEventDate(Date eventDate) { + this.eventDate = eventDate; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (long) forecastConfigurationId; + hash += (int) forecastEventId; + hash += (eventDate != null ? eventDate.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object object) { + // TODO: Warning - this method won't work in the case the id fields are not set + if (!(object instanceof ForecastNotificationLogPK)) { + return false; + } + ForecastNotificationLogPK other = (ForecastNotificationLogPK) object; + if (this.forecastConfigurationId != other.forecastConfigurationId) { + return false; + } + if (this.forecastEventId != other.forecastEventId) { + return false; + } + if ((this.eventDate == null && other.eventDate != null) || (this.eventDate != null && !this.eventDate.equals(other.eventDate))) { + return false; + } + return true; + } + + @Override + public String toString() { + return "no.nibio.vips.logic.messaging.ForecastNotificationLogPK[ forecastConfigurationId=" + forecastConfigurationId + ", forecastEvent=" + forecastEventId + ", eventDate=" + eventDate + " ]"; + } + +} diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java index 618644e2..71155571 100644 --- a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java +++ b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java @@ -21,21 +21,30 @@ package no.nibio.vips.logic.messaging; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.icu.text.MessageFormat; +import com.ibm.icu.util.ULocale; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.ResourceBundle; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; -import javax.persistence.TemporalType; import javax.ws.rs.core.Response; +import no.nibio.vips.entity.Result; +import no.nibio.vips.logic.entity.ForecastConfiguration; +import no.nibio.vips.logic.entity.ForecastResult; import no.nibio.vips.logic.entity.Message; import no.nibio.vips.logic.entity.MessageLocale; import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.util.Globals; import no.nibio.vips.logic.util.RESTAuthenticator; import no.nibio.vips.logic.util.SessionControllerGetter; +import no.nibio.vips.logic.util.SystemTime; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; @@ -49,41 +58,6 @@ public class MessagingBean { @PersistenceContext(unitName="VIPSLogic-PU") EntityManager em; - public void testStoreUniversalMessage() - { - List<VipsLogicUser> allUsers=SessionControllerGetter.getUserBean().getAllUsers(); - Message m = SessionControllerGetter.getMessageBean().getMessage(5); - MessageLocale ml = m.getLocalMessage("nn"); - UniversalMessage um = new UniversalMessage( - "nn",ml.getHeading(), ml.getLeadParagraph(), ml.getBody(), "http://localhost:8000/messages/" + m.getMessageId() - ); - um.setExpiresAt(new Date()); - List<MessageRecipient> distributionList = new ArrayList<>(); - for(VipsLogicUser user : allUsers) - { - MessageRecipient r = new MessageRecipient( - String.valueOf(user.getUserId()), - user.getFirstName() + " " + user.getLastName(), - "Mail", - user.getEmail(), - user.getPreferredLocale() - ); - distributionList.add(r); - } - um.setDistributionList(distributionList); - //em.persist(um); - - List<UniversalMessage> ums = em.createNamedQuery("UniversalMessage.findAll").getResultList(); - for(UniversalMessage uMe : ums) - { - for(MessageLocalVersion lv:uMe.getMessageLocalVersionObjects()) - { - System.out.println(lv.getMsgSubject()); - } - - } - } - public void sendUniversalMessage(Message message) { String msgDownloadUrlTpl = "http://www.vips-landbruk.no/"; @@ -105,11 +79,11 @@ public class MessagingBean { } - public void sendUniversalMessage(UniversalMessage uMessage) + public UniversalMessage sendUniversalMessage(UniversalMessage uMessage) { if(uMessage.getDistributionListObjects().isEmpty()) { - return; + return uMessage; } // Store it @@ -126,21 +100,25 @@ public class MessagingBean { try { - //System.out.println(new ObjectMapper().writeValueAsString(um)); - Response r = umClient.sendMessage(new ObjectMapper().writeValueAsString(uMessage)); - - // TODO: Handle result + //System.out.println(new ObjectMapper().writeValueAsString(um)); + Response r = umClient.sendMessage(new ObjectMapper().writeValueAsString(uMessage)); - String result = r.readEntity(String.class); + // TODO: Handle result + + String result = r.readEntity(String.class); + System.out.println(result); } catch(JsonProcessingException ex) { // Handle error } + + return uMessage; } private List<MessageRecipient> getMessageNotificationSubscribers(Message message) { + // TODO??? also filter by crops?? Query q = em.createNativeQuery( "SELECT \n" + " u.preferred_locale,\n" + @@ -191,4 +169,202 @@ public class MessagingBean { { return em.createNamedQuery("UniversalMessageFormat.findAll").getResultList(); } + + // For getting all available notification translations + public final static String[] AVAILABLE_FORECAST_NOTIFICATION_LOCALES = {"nb","en"}; + + public void sendForecastEventNotifications() + { + // Find forecast configurations with a change from green to yellow or [all colors] to red + // in the future, and when that is + // Meaning: Create a list of forecast_notification_logs items + // First: Find all forecast configurations with results for the next 10 days + Date systemTime = SystemTime.getSystemTime(); + Calendar cal = Calendar.getInstance(); + cal.setTime(systemTime); + cal.add(Calendar.DATE, 10); + Date in10Days = cal.getTime(); + List<ForecastConfiguration> forecastConfigurations = em.createNativeQuery( + "SELECT * FROM public.forecast_configuration f " + + "WHERE f.forecast_configuration_id IN (" + + " SELECT forecast_configuration_id FROM forecast_result WHERE result_valid_time between :dateStart AND :dateEnd" + + ")", + ForecastConfiguration.class + ) + .setParameter("dateStart", systemTime) + .setParameter("dateEnd", in10Days) + .getResultList(); + + List<ForecastNotificationLog> newNotifications = new ArrayList<>(); + ForecastEvent toRed = em.find(ForecastEvent.class, ForecastEvent.TO_RED); + ForecastEvent greenToYellow = em.find(ForecastEvent.class, ForecastEvent.GREEN_TO_YELLOW); + ForecastEvent currentEvent = null; + for(ForecastConfiguration conf:forecastConfigurations) + { + List<ForecastResult> results = em.createNamedQuery("ForecastResult.findByForecastConfigurationId", ForecastResult.class) + .setParameter("forecastConfigurationId", conf.getForecastConfigurationId()) + .getResultList(); + + Integer previousWarningStatus = Result.WARNING_STATUS_NO_WARNING; + + // There may be several new events for the next few days. + // If you find a NEW TO_RED event first, skip the rest + // If you find a NEW GREEN_TO_YELLOW event first, add it and search for a new TO_RED event + for(ForecastResult result:results) + { + if(result.getResultValidTime().before(systemTime) || result.getResultValidTime().after(in10Days)) + { + continue; + } + // TO_RED event detected + if( + result.getWarningStatus().equals(Result.WARNING_STATUS_HIGH_RISK) + && !previousWarningStatus.equals(Result.WARNING_STATUS_HIGH_RISK) + ) + { + currentEvent = toRed; + } + // GREEN_TO_YELLOW event detehcted + else if( + result.getWarningStatus().equals(Result.WARNING_STATUS_MINOR_RISK) + && ! previousWarningStatus.equals(Result.WARNING_STATUS_MINOR_RISK) + && ! previousWarningStatus.equals(Result.WARNING_STATUS_HIGH_RISK) + ) + { + currentEvent = greenToYellow; + } + else + { + currentEvent = null; + } + + if(currentEvent != null) + { + ForecastNotificationLogPK pk = new ForecastNotificationLogPK( + conf.getForecastConfigurationId(), + currentEvent.getForecastEventId(), + result.getResultValidTime() + ); + + // Could not find same event. We persist it so we won't + // have any more of the same events the same day + if(em.find(ForecastNotificationLog.class, pk) == null) + { + ForecastNotificationLog newNotification = new ForecastNotificationLog(pk); + newNotification.setCreatedTime(SystemTime.getSystemTime()); + em.persist(newNotification); + newNotifications.add(newNotification); + } + if(currentEvent.getForecastEventId().equals(ForecastEvent.TO_RED)) + { + break; + } + } + previousWarningStatus = result.getWarningStatus(); + } + } + + SimpleDateFormat format = new SimpleDateFormat(Globals.defaultDateFormat); + + // For the new ones: Create and send Universal messages + for(ForecastNotificationLog newNotification:newNotifications) + { + ForecastConfiguration fConf = em.find(ForecastConfiguration.class, newNotification.getForecastNotificationLogPK().getForecastConfigurationId()); + UniversalMessage uMessage = new UniversalMessage(); + // Get all translations for this, create allMessageLocalVersions + for(String locale:MessagingBean.AVAILABLE_FORECAST_NOTIFICATION_LOCALES) + { + ResourceBundle localBundle = ResourceBundle.getBundle("no.nibio.vips.logic.i18n.vipslogictexts",new ULocale(locale).toLocale()); + String headingTemplate = localBundle.getString("forecastNotificationMessageHeadingTpl_" + + newNotification.getForecastNotificationLogPK().getForecastEventId() + ); + String bodyTemplate = localBundle.getString("forecastNotificationMessageBodyTpl_" + + newNotification.getForecastNotificationLogPK().getForecastEventId() + ); + + // Template is as follows (in English): + // Forecast warning status has turned to high risk of infection + //for {0} in {1} at location {2} at date {3}. Model: {4}. To + //read details, please visit: {5} + String detailsUrl = fConf.getVipsLogicUserId().getOrganizationId().getVipswebUrl() + "forecasts/" + fConf.getForecastConfigurationId(); + Object[] templateParts = { + fConf.getPestOrganismId().getLocalName(locale), + fConf.getCropOrganismId().getLocalName(locale), + fConf.getLocationPointOfInterestId().getName(), + format.format(newNotification.getForecastNotificationLogPK().getEventDate()), + detailsUrl + }; + + uMessage.addMessageLocalVersion(locale, headingTemplate, "",MessageFormat.format(bodyTemplate, templateParts),detailsUrl); + + } + uMessage.setDistributionList(this.getForecastEventNotificationSubscribers(fConf)); + cal.setTime(systemTime); + cal.add(Calendar.DATE, 1); + uMessage.setExpiresAt(cal.getTime()); + + this.sendUniversalMessage(uMessage); + // If sending was successful, we also store the universalMessage id in the events + if(uMessage.getUniversalMessageId() != null) + { + newNotification.setUniversalMessageId(uMessage.getUniversalMessageId()); + } + // Otherwise, we remove the events! + else + { + em.remove(newNotification); + } + } + } + + public List<MessageRecipient> getForecastEventNotificationSubscribers(ForecastConfiguration config) + { + Query q = em.createNativeQuery( + "SELECT \n" + + " u.preferred_locale,\n" + + " umf.format_name AS type,\n" + + " CASE fns.universal_message_format_id " + + " WHEN " + UniversalMessageFormat.FORMAT_EMAIL + " THEN u.email " + + " WHEN " + UniversalMessageFormat.FORMAT_SMS + " THEN u.phone " + + " ELSE '' " + + " END AS msg_delivery_address, \n" + // Needs update as more options are added + " u.first_name || ' ' || u.last_name AS name,\n" + + " u.user_id AS recipient_id\n" + + "FROM public.vips_logic_user u, messaging.forecast_event_notification_subscription fns, messaging.universal_message_format umf \n" + + "WHERE fns.user_id=u.user_id\n" + + "AND fns.universal_message_format_id = umf.universal_message_format_id\n" + + "AND u.user_id IN (\n" + + " SELECT user_id FROM messaging.forecast_event_notification_subscription\n" + + " WHERE :weatherStationId = ANY(weather_station_ids) \n" + + " AND :cropOrganismId = ANY(crop_ids)" + + ");\n", + MessageRecipient.class); + + q.setParameter("weatherStationId", config.getWeatherStationPointOfInterestId().getPointOfInterestId()); + q.setParameter("cropOrganismId", config.getCropOrganismId().getOrganismId()); + + return q.getResultList(); + } + + public ForecastEventNotificationSubscription getForecastEventNotificationSubscription(Integer userId) { + Query q = em.createNativeQuery( + "SELECT * FROM messaging.forecast_event_notification_subscription m " + + "WHERE m.user_id=:userId", + ForecastEventNotificationSubscription.class + ).setParameter("userId", userId); + try + { + return (ForecastEventNotificationSubscription) q.getSingleResult(); + } + catch(NoResultException ex) + { + return null; + } + } + + public void storeForecastEventNotificationSubscription(ForecastEventNotificationSubscription subscription) + { + em.merge(subscription); + } + } diff --git a/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java b/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java index 2726028e..580320af 100644 --- a/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import no.nibio.vips.logic.scheduling.tasks.DeleteAllExpiredUserUuidsTask; import no.nibio.vips.logic.scheduling.tasks.RunAllForecastConfigurationsTask; +import no.nibio.vips.logic.scheduling.tasks.SendForecastEventNotificationsTask; import no.nibio.vips.logic.scheduling.tasks.UpdateForecastResultCacheTableTask; import no.nibio.vips.logic.scheduling.tasks.UpdateForecastSummaryTableTask; import no.nibio.vips.logic.scheduling.tasks.UpdateModelInformationTask; @@ -41,8 +42,9 @@ public class VipsLogicTaskFactory { public static final int UPDATE_FORECAST_RESULT_CACHE_TABLE_TASK = 3; public static final int UPDATE_FORECAST_SUMMARY_TABLE_TASK = 4; public static final int DELETE_ALL_EXPIRED_UUIDS_TASK = 5; + public static final int SEND_FORECAST_EVENT_NOTIFICATIONS_TASK = 6; - private final static int[] ALL_TASK_IDS = {1,2,3,4,5}; + private final static int[] ALL_TASK_IDS = {1,2,3,4,5,6}; private static List<VipsLogicTask> allTasksList; private static Map<String,VipsLogicTask> allTasksMap; @@ -72,6 +74,9 @@ public class VipsLogicTaskFactory { case DELETE_ALL_EXPIRED_UUIDS_TASK: retVal = new DeleteAllExpiredUserUuidsTask(); break; + case SEND_FORECAST_EVENT_NOTIFICATIONS_TASK: + retVal = new SendForecastEventNotificationsTask(); + break; default: return null; } diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java new file mode 100644 index 00000000..fdb10062 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + * + * This file is part of VIPSLogic. + * VIPSLogic is free software: you can redistribute it and/or modify + * it under the terms of the NIBIO Open Source License as published by + * NIBIO, either version 1 of the License, or (at your option) any + * later version. + * + * VIPSLogic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * NIBIO Open Source License for more details. + * + * You should have received a copy of the NIBIO Open Source License + * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * + */ + +package no.nibio.vips.logic.scheduling.tasks; + +import it.sauronsoftware.cron4j.TaskExecutionContext; +import no.nibio.vips.logic.scheduling.VipsLogicTask; +import no.nibio.vips.logic.scheduling.VipsLogicTaskFactory; +import no.nibio.vips.logic.util.SessionControllerGetter; +import no.nibio.web.forms.FormField; + +/** + * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class SendForecastEventNotificationsTask extends VipsLogicTask { + + @Override + public String getConfigFormDefinition(String language) { + String retVal = "{" + + " \"fields\":[" + + " {" + + " \"name\":\"factoryId\"," + + " \"dataType\":\"" + FormField.DATA_TYPE_INTEGER + "\"," + + " \"fieldType\":\"" + FormField.FIELD_TYPE_HIDDEN + "\"," + + " \"webValue\":[\"" + VipsLogicTaskFactory.SEND_FORECAST_EVENT_NOTIFICATIONS_TASK + "\"]" + + " }" + + " ]}"; + return retVal; + } + + @Override + public void execute(TaskExecutionContext tec) throws RuntimeException { + tec.setCompleteness(0d); + SessionControllerGetter.getMessagingBean().sendForecastEventNotifications(); + tec.setCompleteness(1d); + } + + @Override + public boolean supportsStatusTracking() + { + return true; + } + + @Override + public boolean supportsCompletenessTracking() + { + return true; + } + +} diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties index 1a8499fd..1c5c2ffa 100644 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties @@ -304,3 +304,9 @@ notificationSubscriptionDescription=You can subscribe to different kinds of noti messageFormat=Message format Mail=Email Sms=SMS +forecastNotificationMessageBodyTpl_1=Forecast warning status has turned to high risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageBodyTpl_2=Forecast warning status has turned to moderate risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageHeadingTpl_1=Notification of high risk of infection +forecastNotificationMessageHeadingTpl_2=Notification of moderate infection risk +task_SendForecastEventNotificationsTask_name=Send forecast event notifications +task_SendForecastEventNotificationsTask_description=Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties index e5d8895c..40de134a 100644 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties @@ -304,3 +304,9 @@ notificationSubscriptionDescription=You can subscribe to different kinds of noti messageFormat=Message format Mail=Email Sms=SMS +forecastNotificationMessageBodyTpl_1=Forecast warning status has turned to high risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageBodyTpl_2=Forecast warning status has turned to moderate risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageHeadingTpl_1=Notification of high risk of infection +forecastNotificationMessageHeadingTpl_2=Notification of moderate infection risk +task_SendForecastEventNotificationsTask_name=Send forecast event notifications +task_SendForecastEventNotificationsTask_description=Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties index 7d7af415..31c5b62f 100644 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties @@ -303,3 +303,9 @@ notificationSubscriptionDescription=You can subscribe to different kinds of noti messageFormat=Message format Mail=Email Sms=SMS +forecastNotificationMessageBodyTpl_1=Forecast warning status has turned to high risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageBodyTpl_2=Forecast warning status has turned to high risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageHeadingTpl_1=Notification of high risk of infection +forecastNotificationMessageHeadingTpl_2=Notification of moderate infection risk +task_SendForecastEventNotificationsTask_name=Send forecast event notifications +task_SendForecastEventNotificationsTask_description=Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties index f948f783..9ad1df42 100644 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties @@ -304,3 +304,9 @@ notificationSubscriptionDescription=Du kan abonnere p\u00e5 ulike typer meldinge messageFormat=Meldingsformat Mail=E-post Sms=SMS +forecastNotificationMessageBodyTpl_1=Varselstatus er endret til h\u00f8y infeksjonsrisiko for {0} i {1} ved {2}, tidspunkt {3}. Modell: {4}. For \u00e5 lese detaljer, vennligst bes\u00f8k:{5} +forecastNotificationMessageBodyTpl_2=Varselstatus er endret til moderat infeksjonsrisiko for {0} i {1} ved {2}, tidspunkt {3}. Modell: {4}. For \u00e5 lese detaljer, vennligst bes\u00f8k:{5} +forecastNotificationMessageHeadingTpl_1=Melding om h\u00f8y infeksjonsrisiko +forecastNotificationMessageHeadingTpl_2=Melding om moderat infeksjonsrisiko +task_SendForecastEventNotificationsTask_name=Send meldinger om endringer i varsel +task_SendForecastEventNotificationsTask_description=Ser om varsler har endret set til GUL eller R\u00d8D status. I tilfelle s\u00f8kes abonnenter opp og meldinger blir distribuert. diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties index a16fa416..b9ed7c4b 100644 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties @@ -304,3 +304,9 @@ notificationSubscriptionDescription=You can subscribe to different kinds of noti messageFormat=Message format Mail=Email Sms=SMS +forecastNotificationMessageBodyTpl_1=Forecast warning status has turned to high risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageBodyTpl_2=Forecast warning status has turned to moderate risk of infection for {0} in {1} at location {2} at date {3}. Model: {4}. To read details, please visit: {5} +forecastNotificationMessageHeadingTpl_1=Notification of high risk of infection +forecastNotificationMessageHeadingTpl_2=Notification of moderate infection risk +task_SendForecastEventNotificationsTask_name=Send forecast event notifications +task_SendForecastEventNotificationsTask_description=Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications diff --git a/src/main/webapp/WEB-INF/glassfish-web.xml b/src/main/webapp/WEB-INF/glassfish-web.xml new file mode 100644 index 00000000..13e0059f --- /dev/null +++ b/src/main/webapp/WEB-INF/glassfish-web.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> +<glassfish-web-app error-url=""> + <class-loader delegate="true"/> + <jsp-config> + <property name="keepgenerated" value="true"> + <description>Keep a copy of the generated servlet class' java code.</description> + </property> + </jsp-config> +</glassfish-web-app> diff --git a/src/main/webapp/templates/notificationSubscriptionForm.ftl b/src/main/webapp/templates/notificationSubscriptionForm.ftl index 09c35eee..14f32cd0 100644 --- a/src/main/webapp/templates/notificationSubscriptionForm.ftl +++ b/src/main/webapp/templates/notificationSubscriptionForm.ftl @@ -50,8 +50,8 @@ <input type="hidden" name="userId" value="${viewUser.userId}"/> <h2>${i18nBundle.messageNotifications}</h2> <div class="form-group"> - <label for="universalMessageFormatId">${i18nBundle.messageFormat}</label> - <select name="universalMessageFormatId" onblur="validateField(this);"> + <label for="messageN_universalMessageFormatId">${i18nBundle.messageFormat}</label> + <select name="messageN_universalMessageFormatId" onblur="validateField(this);"> <#list universalMessageFormats as format> <option value="${format.universalMessageFormatId}" <#if messageNotificationSubscription.universalMessageFormatId == format.universalMessageFormatId> selected="selected"</#if> @@ -60,26 +60,56 @@ </select> </div> <div class="form-group"> - <label for="cropOrganismIds">${i18nBundle.cropOrganismIds}</label> - <select class="form-control chosen-select" name="cropOrganismIds" onblur="validateField(this);" multiple="multiple"> + <label for="messageN_cropOrganismIds">${i18nBundle.cropOrganismIds}</label> + <select class="form-control chosen-select" name="messageN_cropOrganismIds" onblur="validateField(this);" multiple="multiple"> <#list allCrops?sort_by("latinName") as organism> <option value="${organism.organismId}" - <#if userCropIds?seq_contains(organism.organismId)> selected="selected"</#if> + <#if messageNotificationSubscription.cropIds?seq_contains(organism.organismId)> selected="selected"</#if> >${organism.latinName!""} / ${organism.tradeName!""} / ${organism.getLocalName(currentLocale.language)!""}</option> </#list> </select> </div> <div class="form-group"> - <label for="messageTagIds">${i18nBundle.messageTags}</label> - <select class="form-control chosen-select" name="messageTagIds" onblur="validateField(this);" multiple="multiple"> + <label for="messageN_messageTagIds">${i18nBundle.messageTags}</label> + <select class="form-control chosen-select" name="messageN_messageTagIds" onblur="validateField(this);" multiple="multiple"> <#list messageTagSet as messageTag> <option value="${messageTag.messageTagId}" - <#if userMessageTagIds?seq_contains(messageTag.messageTagId)> selected="selected"</#if> + <#if messageNotificationSubscription.messageTagIds?seq_contains(messageTag.messageTagId)> selected="selected"</#if> >${(messageTag.getLocalName(currentLocale))!messageTag.defaultTagName}</option> </#list> </select> </div> <h2>${i18nBundle.forecastNotifications}</h2> + <div class="form-group"> + <label for="forecastN_universalMessageFormatId">${i18nBundle.messageFormat}</label> + <select name="forecastN_universalMessageFormatId" onblur="validateField(this);"> + <#list universalMessageFormats as format> + <option value="${format.universalMessageFormatId}" + <#if messageNotificationSubscription.universalMessageFormatId == format.universalMessageFormatId> selected="selected"</#if> + >${i18nBundle(format.formatName)}</option> + </#list> + </select> + </div> + <div class="form-group"> + <label for="forecastN_cropOrganismIds">${i18nBundle.cropOrganismIds}</label> + <select class="form-control chosen-select" name="forecastN_cropOrganismIds" multiple="multiple"> + <#list allCrops?sort_by("latinName") as organism> + <option value="${organism.organismId}" + <#if forecastEventNotificationSubscription.cropIds?seq_contains(organism.organismId)> selected="selected"</#if> + >${organism.latinName!""} / ${organism.tradeName!""} / ${organism.getLocalName(currentLocale.language)!""}</option> + </#list> + </select> + </div> + <div class="form-group"> + <label for="forecastN_weatherStationIds">${i18nBundle.weatherStations}</label> + <select class="form-control chosen-select" name="forecastN_weatherStationIds" multiple="multiple"> + <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.weatherStations?lower_case}</option> + <#list weatherStationIds?sort_by("name") as poi> + <option value="${poi.pointOfInterestId}"<#if forecastEventNotificationSubscription.weatherStationIds?seq_contains(poi.pointOfInterestId)> selected="selected"</#if>>${poi.name}</option> + </#list> + </select> + <span class="help-block" id="${formId}_weatherStationPointOfInterestId_validation"></span> + </div> <p>Under construction</p> <button type="submit" class="btn btn-default">${i18nBundle.submit}</button> </form> diff --git a/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java b/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java index 25805a70..2f8d3d4d 100644 --- a/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java +++ b/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java @@ -146,7 +146,7 @@ public class UniversalMessagingTest { result = r.readEntity(String.class); - //System.out.println(result); + System.out.println(result); assertEquals(200,r.getStatus()); //Response r = umClient.sendMessage(um); } -- GitLab