From a06df64deebe24dffe0278ba71b6f86b86d15f3b Mon Sep 17 00:00:00 2001
From: Tor-Einar Skog <tor-einar.skog@nibio.no>
Date: Wed, 24 May 2017 11:05:31 -0700
Subject: [PATCH] Made sure all poi names are unique

---
 .../servlet/PointOfInterestController.java    | 14 +++++++++++++-
 .../session/PointOfInterestBean.java          | 14 ++++++++++++++
 .../vips/logic/entity/PointOfInterest.java    |  1 +
 .../vips/logic/service/LogicService.java      |  9 +++++++++
 .../vips/logic/i18n/vipslogictexts.properties |  1 +
 .../logic/i18n/vipslogictexts_bs.properties   |  1 +
 .../logic/i18n/vipslogictexts_hr.properties   |  1 +
 .../logic/i18n/vipslogictexts_nb.properties   |  1 +
 .../logic/i18n/vipslogictexts_sr.properties   |  1 +
 .../i18n/vipslogictexts_zh_CN.properties      |  1 +
 src/main/webapp/templates/poiForm.ftl         | 19 ++++++++++++++++++-
 11 files changed, 61 insertions(+), 2 deletions(-)

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 460e8faf..e0c9a16c 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
@@ -47,6 +47,7 @@ import no.nibio.vips.logic.util.SessionControllerGetter;
 import no.nibio.vips.util.ExceptionUtil;
 import no.nibio.vips.util.ServletUtil;
 import no.nibio.vips.logic.entity.WeatherForecastProvider;
+import no.nibio.vips.logic.i18n.SessionLocaleUtil;
 import no.nibio.vips.logic.util.GISUtil;
 import no.nibio.vips.logic.util.Globals;
 import no.nibio.web.forms.FormField;
@@ -593,7 +594,8 @@ public class PointOfInterestController extends HttpServlet {
                             )
                         {
                             FormValidation formValidation = FormValidator.validateForm("poiForm", request, getServletContext());
-                            if(formValidation.isValid())
+                            Boolean poiNameAlreadyExists = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(formValidation.getFormField("name").getWebValue()) != null;
+                            if(formValidation.isValid() && ! poiNameAlreadyExists)
                             {
                                 // Set values
                                 poi.setName(formValidation.getFormField("name").getWebValue());
@@ -694,15 +696,25 @@ public class PointOfInterestController extends HttpServlet {
                             }
                             else
                             {
+                                if(poiNameAlreadyExists)
+                                {
+                                    FormField poiNameField = formValidation.getFormField("name");
+                                    poiNameField.setValid(false);
+                                    poiNameField.setValidationMessage(SessionLocaleUtil.getI18nBundle(request).getString("nameAlreadyExists"));
+                                }
                                 request.setAttribute("formValidation", formValidation);
                                 request.setAttribute("poi", poi);
                                 request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter());
                                 request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom());
+                                request.setAttribute("returnURL","poi?organizationId=" + user.getOrganizationId().getOrganizationId());
+                                // Finding all external resources where entry is missing
+                                request.setAttribute("unreferencedExternalResources", SessionControllerGetter.getPointOfInterestBean().getUnusedExternalResourcesForPointOfInterest(poi));
                                 request.getSession().setAttribute("availableTimeZones", Globals.availableTimeZones);
                                 request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone());
                                 request.getSession().setAttribute("availableCountries", em.createNamedQuery("Country.findAll").getResultList());
                                 request.getSession().setAttribute("defaultCountryCode", user.getOrganizationId().getCountryCode().getCountryCode());
                                 request.getRequestDispatcher("/poiForm.ftl").forward(request, response);
+                                
                             }
                         }
                         else
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 c8db2dfe..51e459f7 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
@@ -441,5 +441,19 @@ public class PointOfInterestBean {
                 .getResultList();
     }
 
+    public PointOfInterest getPointOfInterest(String poiName) {
+        try
+        {
+            return em.createNamedQuery("PointOfInterest.findByNameCaseInsensitive", PointOfInterest.class)
+                    .setParameter("name", poiName)
+                    .getSingleResult();
+        }
+        catch(NoResultException ex)
+        {
+            return null;
+        }
+                
+    }
+
     
 }
diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
index 81088def..1ad8f99e 100755
--- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
+++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java
@@ -66,6 +66,7 @@ import no.nibio.vips.logic.util.GISUtil;
     @NamedQuery(name = "PointOfInterest.findByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))  ORDER BY p.name ASC"),
     @NamedQuery(name = "PointOfInterest.findForecastLocationsByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.isForecastLocation IS TRUE AND p.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))  ORDER BY p.name ASC"),
     @NamedQuery(name = "PointOfInterest.findByName", query = "SELECT p FROM PointOfInterest p WHERE p.name = :name"),
+    @NamedQuery(name = "PointOfInterest.findByNameCaseInsensitive", query = "SELECT p FROM PointOfInterest p WHERE lower(p.name) = lower(:name)"),
     //@NamedQuery(name = "PointOfInterest.findByLongitude", query = "SELECT p FROM PointOfInterest p WHERE p.longitude = :longitude"),
     //@NamedQuery(name = "PointOfInterest.findByLatitude", query = "SELECT p FROM PointOfInterest p WHERE p.latitude = :latitude"),
     //@NamedQuery(name = "PointOfInterest.findByAltitude", query = "SELECT p FROM PointOfInterest p WHERE p.altitude = :altitude"),
diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java
index fd408e04..c68cfc90 100755
--- a/src/main/java/no/nibio/vips/logic/service/LogicService.java
+++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java
@@ -369,6 +369,15 @@ public class LogicService {
         return Response.ok().entity(retVal).build();
     }
     
+    @GET
+    @Path("poi/name/{poiName}")
+    @Produces("application/json;charset=UTF-8")
+    public Response getPoiByName(@PathParam("poiName") String poiName)
+    {
+        PointOfInterest retVal = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(poiName);
+        return retVal != null ? Response.ok().entity(retVal).build() : Response.noContent().build();
+    }
+    
     @GET
     @Path("poi/user/")
     @Produces("application/json;charset=UTF-8")
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 1868bb39..373038dc 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -441,3 +441,4 @@ isRequiredField=Required field
 crops=Crops
 unknownOrganismId=Unknown Organism Id
 vipsLogicRole_7=Organism editor
+nameAlreadyExists=The name already exists
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 dc6f450a..b5beee4a 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
@@ -441,3 +441,4 @@ isRequiredField=Required field
 crops=Crops
 unknownOrganismId=Unknown Organism Id
 vipsLogicRole_7=Organism editor
+nameAlreadyExists=The name already exists
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 0b9d1157..dfc93238 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
@@ -440,3 +440,4 @@ isRequiredField=Required field
 crops=Crops
 unknownOrganismId=Unknown Organism Id
 vipsLogicRole_7=Organism editor
+nameAlreadyExists=The name already exists
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 216d3ba0..3cea3335 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
@@ -441,3 +441,4 @@ isRequiredField=Obligatorisk felt
 crops=Kulturer
 unknownOrganismId=Ukjent organismeId
 vipsLogicRole_7=Organismeredakt\u00f8r
+nameAlreadyExists=Navnet er allerede i bruk
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 8e3b9971..cca159c3 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
@@ -441,3 +441,4 @@ isRequiredField=Required field
 crops=Crops
 unknownOrganismId=Unknown Organism Id
 vipsLogicRole_7=Organism editor
+nameAlreadyExists=The name already exists
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 6c324faa..4dfd6a77 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
@@ -438,3 +438,4 @@ isRequiredField=Required field
 crops=Crops
 unknownOrganismId=Unknown Organism Id
 vipsLogicRole_7=Organism editor
+nameAlreadyExists=The name already exists
diff --git a/src/main/webapp/templates/poiForm.ftl b/src/main/webapp/templates/poiForm.ftl
index a72bfaa1..80bc9bd0 100755
--- a/src/main/webapp/templates/poiForm.ftl
+++ b/src/main/webapp/templates/poiForm.ftl
@@ -41,6 +41,23 @@
 			initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},${user.organizationId.organizationId},${poi.pointOfInterestId!"null"});
 			</#if>
 		});
+                
+                // POI name must be unique
+                function checkPoiNameAvailability(poiNameField)
+                {
+                    var poiName = poiNameField.value;
+                    if(poiName.length > 0)
+                    {
+                        $.getJSON( "/rest/poi/name/" + poiName)
+                            .done(function(json, status, jx){
+                                if(jx.status==200)
+                                {
+                                    var theForm = document.getElementById("poiForm");
+                                    invalidizeField(poiNameField, theForm, "${i18nBundle.nameAlreadyExists}",null);
+                                }
+                            });
+                    }
+                }
 	</script>
 </#macro>
 <#macro page_contents>
@@ -61,7 +78,7 @@
 			  <input type="hidden" name="pointOfInterestId" value="${poi.pointOfInterestId!"-1"}"/>
 			  <div class="form-group">
 			    <label for="name">${i18nBundle.name}</label>
-			    <input type="text" class="form-control" name="name" placeholder="${i18nBundle.name}" value="${(poi.name)!""}" onblur="validateField(this);"/>
+			    <input type="text" class="form-control" name="name" placeholder="${i18nBundle.name}" value="${(poi.name)!""}" onblur="validateField(this); checkPoiNameAvailability(this);"/>
 			    <span class="help-block" id="${formId}_name_validation"></span>
 			  </div>
 			  <div class="form-group">
-- 
GitLab