From 166707ce578146b90ef722f8940706de21a34cfe Mon Sep 17 00:00:00 2001
From: Tor-Einar Skog <tor-einar.skog@nibio.no>
Date: Fri, 17 Apr 2020 14:54:29 +0200
Subject: [PATCH] Allowing for deletion of POIs

---
 .../servlet/PointOfInterestController.java    |  6 +-
 .../controller/session/ForecastBean.java      | 19 +++-
 .../controller/session/ObservationBean.java   | 21 ++++-
 .../session/PointOfInterestBean.java          |  7 +-
 .../nibio/vips/logic/entity/Observation.java  |  1 +
 .../vips/logic/i18n/vipslogictexts.properties |  2 +
 .../logic/i18n/vipslogictexts_bs.properties   |  2 +
 .../logic/i18n/vipslogictexts_hr.properties   |  2 +
 .../logic/i18n/vipslogictexts_nb.properties   |  2 +
 .../logic/i18n/vipslogictexts_sr.properties   |  2 +
 .../i18n/vipslogictexts_zh_CN.properties      |  2 +
 .../webapp/templates/poiDeletePreview.ftl     | 92 +++++++++++++++++++
 12 files changed, 150 insertions(+), 8 deletions(-)
 create mode 100644 src/main/webapp/templates/poiDeletePreview.ftl

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 2117a3f0..f829adbe 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,7 @@ 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;
@@ -780,10 +781,10 @@ public class PointOfInterestController extends HttpServlet {
                         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))
@@ -798,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);
                         }
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 0d9baaa5..c7cb8912 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 253d85b3..0dd526fe 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 bfbc6407..3d83a3b3 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
@@ -324,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);
     }
 
@@ -359,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) {
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 321dfbc3..594d1975 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/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
index a5a49fdf..37f6cb51 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -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 c8cb25b4..53cb3d7d 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
@@ -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 74aeaeba..2ec31284 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
@@ -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 7ce392cd..a287d25d 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
@@ -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 6825f3fc..42d27b04 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
@@ -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 e84487e0..66f1011f 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 00000000..bccee456
--- /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/>
-- 
GitLab