diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java index 3e1904b4aa949108fd7fbda58a82fde921e2532b..92568c8866de3a3c9a483d2eea0fb1df3f009ffe 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java @@ -55,7 +55,7 @@ import no.nibio.web.forms.FormValidator; /** * Handles form configuration actions - * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class ForecastConfigurationController extends HttpServlet { @@ -377,27 +377,26 @@ public class ForecastConfigurationController extends HttpServlet { } } // Delete forecast configuration - // Authorization: SUPERUSERS and ORGANIZATION ADMINS + // Authorization: SUPERUSERS and ORGANIZATION ADMINS OR regular users owning the forecast config else if(action.equals("deleteForecastConfiguration")) { - if(userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) + Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); + ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); + if( + userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) + || user.getUserId().equals(forecastConfiguration.getVipsLogicUserId().getUserId()) + ) { + // Only superusers can delete forecasts from other organizations + if(! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) + { + response.sendError(403,"Access not authorized"); // HTTP Forbidden + return; + } try { - Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); - ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); - - // Only superusers can delete forecasts from other organizations - if(! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden - } - else - { - forecastBean.deleteForecastConfiguration(forecastConfigurationId); - response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/forecastConfiguration?").append("&messageKey=").append("forecastConfigurationDeleted").toString()); - - } + forecastBean.deleteForecastConfiguration(forecastConfigurationId); + response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/forecastConfiguration?").append("&messageKey=").append("forecastConfigurationDeleted").toString()); } catch(NullPointerException | NumberFormatException ex) { diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java index 836dec4e5263e08412ccce70bdb80fd30c83f80d..f829adbef049020735e1c595390dd289eab2d645 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java @@ -51,6 +51,11 @@ import no.nibio.vips.util.ServletUtil; import no.nibio.vips.logic.entity.WeatherForecastProvider; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import no.nibio.vips.gis.GISUtil; +import no.nibio.vips.logic.entity.Observation; +import no.nibio.vips.logic.entity.PointOfInterestType; +import no.nibio.vips.logic.entity.PointOfInterestTypeFarm; +import no.nibio.vips.logic.entity.PointOfInterestTypeField; +import no.nibio.vips.logic.entity.helpers.PointOfInterestFactory; import no.nibio.vips.logic.util.Globals; import no.nibio.vips.logic.util.SystemTime; import no.nibio.web.forms.FormField; @@ -530,7 +535,6 @@ public class PointOfInterestController extends HttpServlet { request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom()); request.getSession().setAttribute("availableTimeZones", SystemTime.getAvailableTimeZones()); request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone()); - request.getSession().setAttribute("weatherForecastProviders", em.createNamedQuery("WeatherForecastProvider.findAll").getResultList()); request.getSession().setAttribute("availableCountries", em.createNamedQuery("Country.findAll").getResultList()); request.getSession().setAttribute("defaultCountryCode", user.getOrganizationId().getCountryCode().getCountryCode()); request.getSession().setAttribute("groups", user.isSuperUser() || user.isOrganizationAdmin() ? SessionControllerGetter.getUserBean().getOrganizationGroups(user.getOrganizationId()) @@ -615,22 +619,22 @@ public class PointOfInterestController extends HttpServlet { { try { + FormValidation formValidation = FormValidator.validateForm("poiForm", request, getServletContext()); Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId")); PointOfInterest poi = pointOfInterestId > 0 ? em.find(PointOfInterest.class, pointOfInterestId) - : new PointOfInterest(); + : PointOfInterestFactory.getPointOfInterest(formValidation.getFormField("pointOfInterestTypeId").getValueAsInteger()); if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) || poi.getPointOfInterestId() == null || Objects.equals(user.getUserId(), poi.getUserId().getUserId()) ) { - FormValidation formValidation = FormValidator.validateForm("poiForm", request, getServletContext()); Boolean poiNameAlreadyExists = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(formValidation.getFormField("name").getWebValue()) != null; // Only store if valid form data and NOT a new poi with an existing poiName if(formValidation.isValid() && !(poi.getPointOfInterestId() == null && poiNameAlreadyExists)) { // Set values - poi.setName(formValidation.getFormField("name").getWebValue()); + poi.setName(formValidation.getFormField("name").getWebValue()); // A POI is per default not a forecast location. Only superusers and orgadmins // may change the status if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) @@ -763,20 +767,24 @@ public class PointOfInterestController extends HttpServlet { } else if(action.equals("deletePoiPreview")) { - if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) + Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId")); + PointOfInterest poi = em.find(PointOfInterest.class, pointOfInterestId); + if( + SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) + || user.getUserId().equals(poi.getUserId().getUserId()) + ) { try { - Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId")); - PointOfInterest poi = em.find(PointOfInterest.class, pointOfInterestId); + // Are there forecasts attached to this location List<ForecastConfiguration> forecastConfigurations = SessionControllerGetter.getForecastBean().getForecastConfigurationsByLocation(poi); // TODO: Are there observations attached to this location? - + List<Observation> observations = SessionControllerGetter.getObservationBean().getObservationsByLocation(poi); // // If no strings attached, delete immediately - if(forecastConfigurations.isEmpty()) + if(forecastConfigurations.isEmpty() && observations.isEmpty()) { response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") .append(ServletUtil.getServerName(request)) @@ -791,6 +799,7 @@ public class PointOfInterestController extends HttpServlet { request.setAttribute("poi", poi); request.setAttribute("forecastConfigurations", forecastConfigurations); // TODO Set observations + request.setAttribute("observations", observations); request.setAttribute("modelInformation", modelInformationMap); request.getRequestDispatcher("/poiDeletePreview.ftl").forward(request, response); } @@ -807,12 +816,15 @@ public class PointOfInterestController extends HttpServlet { } else if(action.equals("deletePoi")) { - if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) + Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId")); + PointOfInterest poi = em.find(PointOfInterest.class, pointOfInterestId); + if( + SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) + || user.getUserId().equals(poi.getUserId().getUserId()) + ) { try { - Integer pointOfInterestId = Integer.valueOf(request.getParameter("pointOfInterestId")); - //PointOfInterestWeatherStation weatherStation = em.find(PointOfInterestWeatherStation.class, pointOfInterestId); SessionControllerGetter.getPointOfInterestBean().deletePoi(pointOfInterestId); response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") .append(ServletUtil.getServerName(request)) diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java index 0d9baaa5d081598562f8adb41c7b198325b68777..c7cb8912884ce0f4898d2974c5260e10deb53089 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java @@ -415,7 +415,7 @@ public class ForecastBean { * Deletes all forecasts and results from the given weather station * @param weatherStation */ - public void deleteForecastConfigurations(PointOfInterestWeatherStation weatherStation) + public void deleteForecastConfigurationsForWeatherStation(PointOfInterestWeatherStation weatherStation) { List<ForecastConfiguration> forecastConfigurations = this.getForecastConfigurationsByWeatherStation(weatherStation); for(ForecastConfiguration forecastConfiguration:forecastConfigurations) @@ -427,6 +427,22 @@ public class ForecastBean { } } + /** + * Deletes all forecasts and results from the given location + * @param weatherStation + */ + public void deleteForecastConfigurationsForLocation(PointOfInterest location) + { + List<ForecastConfiguration> forecastConfigurations = this.getForecastConfigurationsByLocation(location); + for(ForecastConfiguration forecastConfiguration:forecastConfigurations) + { + em.createNativeQuery("DELETE FROM forecast_result WHERE forecast_configuration_id=:forecastConfigurationId") + .setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()) + .executeUpdate(); + em.remove(forecastConfiguration); + } + } + /** * Fetches one specific forecast configuration * @param forecastConfigurationId @@ -1230,4 +1246,5 @@ public class ForecastBean { .setParameter("year", year) .getResultList(); } + } diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java index 253d85b352e8efa899724c0fdc88e187ffe75bec..0dd526fecccc7521f3358f8a9d217bfb0ee92934 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java @@ -25,14 +25,12 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; -import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TimeZone; import java.util.stream.Collectors; import javax.ejb.Stateless; import javax.persistence.EntityManager; @@ -60,7 +58,7 @@ import org.wololo.geojson.FeatureCollection; import org.wololo.geojson.GeoJSONFactory; /** - * @copyright 2014-2018 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2014-2020 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ @Stateless @@ -749,4 +747,21 @@ public class ObservationBean { .getResultList(); } + public List<Observation> getObservationsByLocation(PointOfInterest poi) { + return em.createNativeQuery("SELECT * FROM Observation WHERE location_point_of_interest_id=:locationPointOfInterestId", Observation.class) + .setParameter("locationPointOfInterestId", poi.getPointOfInterestId()) + .getResultList(); + } + + /** + * Part of the cleaning up dependencies procedure for when deleting a POI + * @param poi + */ + public void deleteObservationsForLocation(PointOfInterest poi) { + em.createNamedQuery("Observation.findByLocationPointOfInterestId", Observation.class) + .setParameter("locationPointOfInterestId", poi.getPointOfInterestId()) + .getResultList().stream() + .forEach(obs -> em.remove(obs)); + } + } diff --git a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java index 0ae305bfb937c69b7275b388dc53e8658d256255..3d83a3b3161151017d5617305c626be38275e9f6 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; +import java.util.stream.Collectors; import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.persistence.EntityManager; @@ -174,7 +175,7 @@ public class PointOfInterestBean { } else { - if(Objects.equals(pointOfInterestTypeId, PointOfInterestType.POINT_OF_INTEREST_TYPE_WEATHER_STATION)) + if(pointOfInterestTypeId != null && pointOfInterestTypeId == PointOfInterestType.POINT_OF_INTEREST_TYPE_WEATHER_STATION) { pois.addAll(this.getWeatherstationsForOrganization(em.find(Organization.class, organizationId),true)); } @@ -323,7 +324,7 @@ public class PointOfInterestBean { public void deleteWeatherStation(Integer pointOfInterestId) { PointOfInterestWeatherStation weatherStation = em.find(PointOfInterestWeatherStation.class, pointOfInterestId); - SessionControllerGetter.getForecastBean().deleteForecastConfigurations(weatherStation); + SessionControllerGetter.getForecastBean().deleteForecastConfigurationsForWeatherStation(weatherStation); em.remove(weatherStation); } @@ -358,7 +359,10 @@ public class PointOfInterestBean { } public void deletePoi(Integer pointOfInterestId) { - em.remove(em.find(PointOfInterest.class, pointOfInterestId)); + PointOfInterest poi = em.find(PointOfInterest.class, pointOfInterestId); + SessionControllerGetter.getForecastBean().deleteForecastConfigurationsForLocation(poi); + SessionControllerGetter.getObservationBean().deleteObservationsForLocation(poi); + em.remove(poi); } public List<PointOfInterest> getRelevantPointOfInterestsForUser(VipsLogicUser user) { @@ -410,8 +414,14 @@ public class PointOfInterestBean { } } catch(NoResultException ex) {} - // Getting all weather stations for user's organization - retVal.addAll(this.getWeatherstationsForOrganization(user.getOrganizationId(), Boolean.TRUE)); + // Getting all weather stations for user's organization. Need to avoid + // double catching of privately owned weather station + retVal.addAll(this.getWeatherstationsForOrganization(user.getOrganizationId(), Boolean.TRUE) + .stream() + .filter(weatherStation -> ! weatherStation.getUserId().getUserId().equals(user.getUserId())) + .collect(Collectors.toList()) + ); + } Collections.sort(retVal); return retVal; diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java index 321dfbc3c0a652ff564c95b4651f7b11a7e977d9..594d19751645e761dab01d4746f07074c67cd0c2 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Observation.java +++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java @@ -67,6 +67,7 @@ import org.hibernate.annotations.TypeDefs; @NamedQuery(name = "Observation.findByObservationId", query = "SELECT o FROM Observation o WHERE o.observationId = :observationId"), @NamedQuery(name = "Observation.findByUserId", query = "SELECT o FROM Observation o WHERE o.userId IN(:userId)"), @NamedQuery(name = "Observation.findByLastEditedBy", query = "SELECT o FROM Observation o WHERE o.lastEditedBy IN(:lastEditedBy)"), + @NamedQuery(name = "Observation.findByLocationPointOfInterestId", query = "SELECT o FROM Observation o WHERE o.locationPointOfInterestId = :locationPointOfInterestId"), @NamedQuery(name = "Observation.findByStatusChangedByUserId", query = "SELECT o FROM Observation o WHERE o.statusChangedByUserId IN(:statusChangedByUserId)"), @NamedQuery(name = "Observation.findByUserIdAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(:userId)"), @NamedQuery(name = "Observation.findByUserIdAndStatusTypeId", query = "SELECT o FROM Observation o WHERE o.userId IN(:userId) AND o.statusTypeId= :statusTypeId"), diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java index 986e02a14b29b15c301e8f88c60622a1dff4f880..ee2a94eb7e1e161b21f607f2ae00262224637869 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java @@ -60,7 +60,10 @@ public class PointOfInterestType implements Serializable { private String defaultName; // Hard coded stuff - public final static Integer POINT_OF_INTEREST_TYPE_WEATHER_STATION = 1; + public static final int POINT_OF_INTEREST_TYPE_WEATHER_STATION = 1; + public static final int POINT_OF_INTEREST_TYPE_FARM = 2; + public static final int POINT_OF_INTEREST_TYPE_FIELD = 3; + public static final int POINT_OF_INTEREST_TYPE_REGION = 4; public PointOfInterestType() { } diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java new file mode 100644 index 0000000000000000000000000000000000000000..2ba5ad333f48cd9664c4bde85e4bdd0425bddf6d --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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.entity; + +import java.io.Serializable; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@DiscriminatorValue("2") +@Table(name = "point_of_interest_farm") +public class PointOfInterestTypeFarm extends PointOfInterest implements Serializable { + +} diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java new file mode 100644 index 0000000000000000000000000000000000000000..651a43246a6b66c233a624bef0640d62d7edcd49 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 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.entity; + +import java.io.Serializable; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +@Entity +@DiscriminatorValue("3") +@Table(name = "point_of_interest_field") +public class PointOfInterestTypeField extends PointOfInterest implements Serializable { + +} diff --git a/src/main/java/no/nibio/vips/logic/entity/helpers/PointOfInterestFactory.java b/src/main/java/no/nibio/vips/logic/entity/helpers/PointOfInterestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..9cd70d815bef8d1624832a26b67a7c88f2c78290 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/entity/helpers/PointOfInterestFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 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.entity.helpers; + +import no.nibio.vips.logic.entity.PointOfInterest; +import no.nibio.vips.logic.entity.PointOfInterestType; +import no.nibio.vips.logic.entity.PointOfInterestTypeFarm; +import no.nibio.vips.logic.entity.PointOfInterestTypeField; +import no.nibio.vips.logic.entity.PointOfInterestTypeRegion; +import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; + +/** + * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class PointOfInterestFactory { + public static PointOfInterest getPointOfInterest(Integer pointOfInterestTypeId) + { + switch(pointOfInterestTypeId){ + case PointOfInterestType.POINT_OF_INTEREST_TYPE_WEATHER_STATION: + return new PointOfInterestWeatherStation(); + case PointOfInterestType.POINT_OF_INTEREST_TYPE_FARM: + return new PointOfInterestTypeFarm(); + case PointOfInterestType.POINT_OF_INTEREST_TYPE_FIELD: + return new PointOfInterestTypeField(); + case PointOfInterestType.POINT_OF_INTEREST_TYPE_REGION: + return new PointOfInterestTypeRegion(); + default: + return new PointOfInterest(); + } + } +} diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/BremiaLactucaeModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/BremiaLactucaeModelPreprocessor.java index 067c032c6c1a625f5ea01a681951db5e2f4c1579..50092ba5691771c04600203fea5f1e3edc0f631e 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/BremiaLactucaeModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/BremiaLactucaeModelPreprocessor.java @@ -51,7 +51,7 @@ public class BremiaLactucaeModelPreprocessor extends ModelRunPreprocessor { List<WeatherObservation> observations; - + try { observations = wdsUtil.getWeatherObservations( weatherStation, diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java index e5d12c74f1ba7c07b4a861dcd82ccea81fe081cc..8589b8b8ec00ffaabac4a2100694c3a0771ff856 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java @@ -21,8 +21,10 @@ package no.nibio.vips.logic.scheduling.model.preprocessor; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.stream.Collectors; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.entity.ForecastConfiguration; @@ -64,7 +66,8 @@ public class DOWNCASTModelPreprocessor extends ModelRunPreprocessor{ }, configuration.getDateStartInTimeZone(), configuration.getDateEndInTimeZone()); - observations = wUtil.checkForAndFixHourlyTimeSeriesHoles(observations); + + observations = wUtil.checkForAndFixHourlyTimeSeriesHolesMultiParameter(observations); List<WeatherObservation> BTg = wUtil.filterWeatherObservationsByParameter(observations, new HashSet(Arrays.asList(WeatherElements.LEAF_WETNESS_DURATION_GROUND_LEVEL))); List<WeatherObservation> BT = wUtil.filterWeatherObservationsByParameter(observations, new HashSet(Arrays.asList(WeatherElements.LEAF_WETNESS_DURATION))); List<WeatherObservation> UM = wUtil.filterWeatherObservationsByParameter(observations, new HashSet(Arrays.asList(WeatherElements.RELATIVE_HUMIDITY_MEAN))); diff --git a/src/main/resources/db/migration/V6__POI_types_added.sql b/src/main/resources/db/migration/V6__POI_types_added.sql new file mode 100644 index 0000000000000000000000000000000000000000..359c4ec5f256285bcca3cbb9406735ebd6a17c6d --- /dev/null +++ b/src/main/resources/db/migration/V6__POI_types_added.sql @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 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/>. + * + */ +/** + * Author: Tor-Einar Skog <tor-einar.skog@nibio.no> + * Created: Feb 28, 2020 + */ + +-- Create POI type farm as entity +CREATE TABLE public.point_of_interest_farm ( + point_of_interest_id INTEGER REFERENCES public.point_of_interest(point_of_interest_id) PRIMARY KEY REFERENCES public.point_of_interest(point_of_interest_id) +); + +-- Create POI type field as entity +CREATE TABLE public.point_of_interest_field ( + point_of_interest_id INTEGER REFERENCES public.point_of_interest(point_of_interest_id) PRIMARY KEY REFERENCES public.point_of_interest(point_of_interest_id) +); 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 2d48b985cbf55739a4817aec7e660702b809b1c7..37f6cb51a729d50eb3bbd296c354d66e619ad6fe 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties @@ -395,7 +395,7 @@ editPoi=Edit Point Of Interest newPoi=New Point Of Interest pointOfInterestType=Point of Interest Type poiStored=Poi was stored -pointOfInterestType_0=General +pointOfInterestType_0=Unspecified noMapDataEntered=No map data entered DELIARFOBS=Delia radicum/floralis observation model DELIARFOBY=Delia radicum/floralis observation model for young crops @@ -488,3 +488,5 @@ task_RunForecastConfigurationsByIdTask_description=Run all forecast configuratio forecastConfigurationIds=Forecast configuration ids locationIsPublic=Location is public maskObservationWith=Mask observation with +deletePoi=Delete point of interest +deletePoiPreviewExplanation=The point of interest that you want to delete has the resources below connected to it. When you delete the POI, you also delete these resources. 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 0561c01c42c1261f11905aeb12ab700d0068c0cd..53cb3d7d4bad5ce955e41cf5be4a285e5c9badeb 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties @@ -395,7 +395,7 @@ editPoi=Edit Point Of Interest newPoi=New Point Of Interest pointOfInterestType=Point of Interest Type poiStored=Poi was stored -pointOfInterestType_0=General +pointOfInterestType_0=Unspecified noMapDataEntered=No map data entered DELIARFOBS=Delia radicum/floralis observation model DELIARFOBY=Delia radicum/floralis observation model for young crops @@ -488,3 +488,5 @@ task_RunForecastConfigurationsByIdTask_description=Run all forecast configuratio forecastConfigurationIds=Forecast configuration ids locationIsPublic=Location is public maskObservationWith=Mask observation with +deletePoi=Delete point of interest +deletePoiPreviewExplanation= 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 f65732a6e8f0ea86adbd29bee4d259a3a2e79009..2ec31284a14ffe5f3d3077a1236159d0f4c9ebcc 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties @@ -394,7 +394,7 @@ editPoi=Edit Point Of Interest newPoi=New Point Of Interest pointOfInterestType=Point of Interest Type poiStored=Poi was stored -pointOfInterestType_0=General +pointOfInterestType_0=Unspecified noMapDataEntered=No map data entered DELIARFOBS=Delia radicum/floralis observation model DELIARFOBY=Delia radicum/floralis observation model for young crops @@ -487,3 +487,5 @@ task_RunForecastConfigurationsByIdTask_description=Run all forecast configuratio forecastConfigurationIds=Forecast configuration ids locationIsPublic=Location is public maskObservationWith=Mask observation with +deletePoi=Delete point of interest +deletePoiPreviewExplanation= 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 eb49190f24cc27a030be0db8b5373364a2a4527c..a287d25dfb13e98e0de96eb7a9850d97cb45a111 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties @@ -395,7 +395,7 @@ editPoi=Rediger sted newPoi=Nytt sted pointOfInterestType=Stedstype poiStored=Stedet ble lagret -pointOfInterestType_0=Generelt +pointOfInterestType_0=Uspesifisert noMapDataEntered=Kartdata ikke registrert DELIARFOBS=Stor og liten k\u00e5lflue - observasjonsmodell DELIARFOBY=Stor og liten k\u00e5lflue - observasjonsmodell i nyplantede felt @@ -488,3 +488,5 @@ task_RunForecastConfigurationsByIdTask_description=Kj\u00f8r alle varlser som ko forecastConfigurationIds=Varseloppsett (id'er) locationIsPublic=Lokaliteten kan vises offentlig maskObservationWith=Masker observasjonen med +deletePoi=Slett sted +deletePoiPreviewExplanation=Stedet du \u00f8nsker \u00e5 slette har knyttet til seg de ressursene som er nevnt nedenfor. N\u00e5r du sletter stedet, vil ogs\u00e5 disse ressursene bli slettet. 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 a755739ad04bbed171da270c0554a374e3bb228b..42d27b048f77754edf471e80804098813aeab032 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties @@ -395,7 +395,7 @@ editPoi=Edit Point Of Interest newPoi=New Point Of Interest pointOfInterestType=Point of Interest Type poiStored=Poi was stored -pointOfInterestType_0=General +pointOfInterestType_0=Unspecified noMapDataEntered=No map data entered DELIARFOBS=Delia radicum/floralis observation model DELIARFOBY=Delia radicum/floralis observation model for young crops @@ -488,3 +488,5 @@ task_RunForecastConfigurationsByIdTask_description=Run all forecast configuratio forecastConfigurationIds=Forecast configuration ids locationIsPublic=Location is public maskObservationWith=Mask observation with +deletePoi=Delete point of interest +deletePoiPreviewExplanation= diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties index e84487e09c973081d1ad1f79cc6d4646f5958d34..66f1011fec6990220ed23fb980ca76ebc33abb42 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties @@ -485,3 +485,5 @@ task_RunForecastConfigurationsByIdTask_description=Run all forecast configuratio forecastConfigurationIds=Forecast configuration ids locationIsPublic=Location is public maskObservationWith=Mask observation with +deletePoi=Delete point of interest +deletePoiPreviewExplanation= diff --git a/src/main/webapp/templates/poiDeletePreview.ftl b/src/main/webapp/templates/poiDeletePreview.ftl new file mode 100644 index 0000000000000000000000000000000000000000..bccee4564c1d02ca082c914c6203c68f1855483c --- /dev/null +++ b/src/main/webapp/templates/poiDeletePreview.ftl @@ -0,0 +1,92 @@ +<#-- + Copyright (c) 2015 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/>. +--><#include "master.ftl"> +<#macro page_head> + <title>${i18nBundle.deletePoi}</title> +</#macro> +<#macro custom_css> + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ > +</#macro> +<#macro custom_js> + <script type="text/javascript" src="/js/constants.js"></script> + <script type="text/javascript" src="/js/resourcebundle.js"></script> + <script type="text/javascript" src="/js/validateForm.js"></script> +</#macro> +<#macro page_contents> +<div class="singleBlockContainer"> + <p><a href="${returnURL}" class="btn btn-default cancel" role="button">${i18nBundle.cancel}</a></p> + <h1>${i18nBundle.deletePoi} ${poi.name}</h1> + <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>> + <#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if> + </div> + <#if messageKey?has_content> + <div class="alert alert-success">${i18nBundle(messageKey)}</div> + </#if> + <p>${i18nBundle.deletePoiPreviewExplanation}</p> + <h2>${i18nBundle.forecasts}</h2> + <table class="table table-striped"> + <thead> + <th>${i18nBundle.modelId}</th> + <th>${i18nBundle.dateStart}</th> + <th>${i18nBundle.dateEnd}</th> + <th></th> + </thead> + <tbody> + <#list forecastConfigurations as forecastConfiguration> + <tr> + <td> + <#if i18nBundle.containsKey(forecastConfiguration.modelId)> + ${i18nBundle[forecastConfiguration.modelId]} + <#else> + ${modelInformation[forecastConfiguration.modelId].defaultName} + </#if> + </td> + <td>${forecastConfiguration.dateStart}</td> + <td>${forecastConfiguration.dateEnd}</td> + <td><a href="/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=${forecastConfiguration.forecastConfigurationId}" target="new">${i18nBundle.edit}</a></td> + </tr> + </#list> + </tbody> + </table> + <h2>${i18nBundle.observations}</h2> + <table class="table table-striped"> + <thead> + <th>${i18nBundle.timeOfObservation}</th> + <th>${i18nBundle.cropOrganismId}</th> + <th>${i18nBundle.pestOrganismId}</th> + <th>${i18nBundle.observationHeading}</th> + <th></th> + </thead> + <tbody> + <#list observations as observation> + <tr> + <td>${observation.timeOfObservation}</td> + <td>${observation.cropOrganism.latinName}</td> + <td>${observation.organism.latinName}</td> + <td>${observation.observationHeading}</td> + <td><a href="/observation?action=editObservationForm&observationId=${observation.observationId}" target="new">${i18nBundle.edit}</a></td> + </tr> + </#list> + </tbody> + </table> + <p> + <a href="${returnURL}" class="btn btn-default cancel" role="button">${i18nBundle.cancel}</a> + <button type="button" class="btn btn-danger" onclick="if(confirm('${i18nBundle.confirmDelete}')){window.location.href='/poi?action=deletePoi&pointOfInterestId=${poi.pointOfInterestId}';}">${i18nBundle.deletePoi}</button> + </p> +</div> +</#macro> +<@page_html/> diff --git a/src/main/webapp/templates/poiForm.ftl b/src/main/webapp/templates/poiForm.ftl index 0ed6cab663e7a1f7f1a4831c9f5b139a5fa62aa6..ca9d861cbbc6fc50ecc1c8ace26822f8b0a9278c 100755 --- a/src/main/webapp/templates/poiForm.ftl +++ b/src/main/webapp/templates/poiForm.ftl @@ -85,9 +85,11 @@ <label for="pointOfInterestTypeId">${i18nBundle.pointOfInterestType}</label> <select class="form-control" name="pointOfInterestTypeId" onblur="validateField(this);"> <#list 0..3 as pointOfInterestTypeId> + <#if pointOfInterestTypeId != 1> <option value="${pointOfInterestTypeId}"<#if poi.pointOfInterestTypeId?has_content && pointOfInterestTypeId == poi.pointOfInterestTypeId > selected="selected"</#if>>${i18nBundle["pointOfInterestType_" + pointOfInterestTypeId]}</option> + </#if> </#list> </select> <span class="help-block" id="${formId}_pointOfInterestTypeId_validation"></span> @@ -111,18 +113,6 @@ <label for="altitude">${i18nBundle.altitude} (${i18nBundle.meter})</label> <input type="number" class="form-control" name="altitude" placeholder="${i18nBundle.altitude}" value="${(poi.altitude?c)!""}" onblur="validateField(this);"/> <span class="help-block" id="${formId}_altitude_validation"></span> - </div> - <div class="form-group"> - <label for="weatherForecastProviderId">${i18nBundle.weatherForecastProvider}</label> - <select class="form-control" name="weatherForecastProviderId" onblur="validateField(this);"> - <option value="-1">${i18nBundle.none} ${i18nBundle.weatherForecastProvider?lower_case} - <#list weatherForecastProviders as weatherForecastProvider> - <option value="${weatherForecastProvider.weatherForecastProviderId}" - <#if poi.weatherForecastProviderId?has_content && poi.weatherForecastProviderId.weatherForecastProviderId == weatherForecastProvider.weatherForecastProviderId>selected="selected"</#if> - >${weatherForecastProvider.name}</option> - </#list> - </select> - <span class="help-block" id="${formId}_weatherForecastProviderId_validation"></span> </div> <div class="form-group"> <label for="timeZone">${i18nBundle.timeZone}</label>