diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java index bbffd5d12323b07422501bda849ad6122e6979b3..43bad2f883d05ee9a167c90d78ab662bbdf5b93f 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2017 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -18,23 +18,6 @@ package no.nibio.vips.logic.controller.servlet; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -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 org.apache.commons.fileupload2.core.DiskFileItemFactory; -import org.apache.commons.fileupload2.core.FileItem; -import org.apache.commons.fileupload2.core.FileUploadException; -import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload; import jakarta.ejb.EJB; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; @@ -46,15 +29,7 @@ import no.nibio.vips.logic.controller.session.ObservationBean; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.controller.session.PointOfInterestBean; import no.nibio.vips.logic.controller.session.UserBean; -import no.nibio.vips.logic.entity.Observation; -import no.nibio.vips.logic.entity.ObservationFormShortcut; -import no.nibio.vips.logic.entity.ObservationMethod; -import no.nibio.vips.logic.entity.Organism; -import no.nibio.vips.logic.entity.Organization; -import no.nibio.vips.logic.entity.OrganizationGroup; -import no.nibio.vips.logic.entity.PolygonService; -import no.nibio.vips.logic.entity.VipsLogicRole; -import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.entity.*; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import no.nibio.vips.logic.messaging.MessagingBean; import no.nibio.vips.logic.util.Globals; @@ -67,15 +42,25 @@ import no.nibio.web.forms.FormUtil; import no.nibio.web.forms.FormValidation; import no.nibio.web.forms.FormValidationException; import no.nibio.web.forms.FormValidator; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; /** - * @copyright 2014-2022 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + * @copyright 2014-2022 <a href="http://www.nibio.no/">NIBIO</a> */ public class ObservationController extends HttpServlet { - @PersistenceContext(unitName="VIPSLogic-PU") + @PersistenceContext(unitName = "VIPSLogic-PU") EntityManager em; - + @EJB UserBean userBean; @EJB @@ -86,45 +71,39 @@ public class ObservationController extends HttpServlet { OrganismBean organismBean; @EJB PointOfInterestBean pointOfInterestBean; - - /** + + /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. - * @param request servlet request + * + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); String action = request.getParameter("action"); VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user"); // Get the organization groups for the current user List<OrganizationGroup> organizationGroups = null; - if(user.isSuperUser()) - { - organizationGroups = userBean.getOrganizationGroups(); - } - else if(user.isOrganizationAdmin()) - { + if (user.isSuperUser()) { + organizationGroups = userBean.getOrganizationGroups(); + } else if (user.isOrganizationAdmin()) { organizationGroups = userBean.getOrganizationGroups(user.getOrganizationId()); - } - else - { + } else { organizationGroups = userBean.getOrganizationGroups(user); } // Default: View observation list // for everyone - if(request.getServletPath().endsWith("/observation")) - { - if(action == null) - { + if (request.getServletPath().endsWith("/observation")) { + if (action == null) { List<Observation> observations; Integer statusTypeId; Integer pestOrganismId; Set<Integer> organizationGroupId; Boolean viewOthersObservations; - + // Default period is current season Calendar cal = Calendar.getInstance(); cal.setTime(SystemTime.getSystemTime()); @@ -133,92 +112,80 @@ public class ObservationController extends HttpServlet { Date timeOfObservationTo; Boolean userDefinedFrom = false; Boolean userDefinedTo = false; - try - { + try { timeOfObservationFrom = format.parse(request.getParameter("timeOfObservationFrom")); userDefinedFrom = true; - } - catch(NullPointerException | ParseException ex) - { + } catch (NullPointerException | ParseException ex) { cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1, 0, 0, 0); timeOfObservationFrom = cal.getTime(); } - try - { + try { timeOfObservationTo = format.parse(request.getParameter("timeOfObservationTo")); userDefinedTo = true; - } - catch(NullPointerException | ParseException ex) - { + } catch (NullPointerException | ParseException ex) { cal.set(cal.get(Calendar.YEAR), Calendar.DECEMBER, 31, 23, 59, 59); timeOfObservationTo = cal.getTime(); } - + // If only one date is set, the unset date should not limit the data set - if(!userDefinedFrom && userDefinedTo) - { + if (!userDefinedFrom && userDefinedTo) { cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - 100); timeOfObservationFrom = cal.getTime(); } - if(userDefinedFrom && !userDefinedTo) - { + if (userDefinedFrom && !userDefinedTo) { cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 100); timeOfObservationTo = cal.getTime(); } - - try - { - statusTypeId = request.getParameter("statusTypeId") != null ? Integer.valueOf(request.getParameter("statusTypeId")) : -1; - pestOrganismId = request.getParameter("pestOrganismId") != null ? Integer.valueOf(request.getParameter("pestOrganismId")) : -1; + + try { + statusTypeId = request.getParameter("statusTypeId") != null ? + Integer.valueOf(request.getParameter("statusTypeId")) : + -1; + pestOrganismId = request.getParameter("pestOrganismId") != null ? + Integer.valueOf(request.getParameter("pestOrganismId")) : + -1; viewOthersObservations = request.getParameter("viewOthersObservations") != null; - if(request.getParameterValues("organizationGroupId") != null && request.getParameterValues("organizationGroupId").length > 0) - { + if (request.getParameterValues("organizationGroupId") != null && request.getParameterValues( + "organizationGroupId").length > 0) { organizationGroupId = new HashSet<>(); - for(String id:request.getParameterValues("organizationGroupId")) - { + for (String id : request.getParameterValues("organizationGroupId")) { organizationGroupId.add(Integer.valueOf(id)); } - } - else - { + } else { organizationGroupId = null; } - } - catch(NumberFormatException nfe) { + } catch (NumberFormatException nfe) { //nfe.printStackTrace(); statusTypeId = -1; pestOrganismId = -1; viewOthersObservations = false; organizationGroupId = null; } - + // First: Get observations for organization or user - if(viewOthersObservations && userBean.authorizeUser(user, - VipsLogicRole.OBSERVATION_AUTHORITY, - VipsLogicRole.ORGANIZATION_ADMINISTRATOR, - VipsLogicRole.SUPERUSER)) - { - observations = observationBean.getObservations(user.getOrganizationId().getOrganizationId(), timeOfObservationFrom, timeOfObservationTo); - } - else - { - observations = observationBean.getObservationsForUser(user, timeOfObservationFrom, timeOfObservationTo); + if (viewOthersObservations && userBean.authorizeUser(user, + VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)) { + observations = observationBean.getObservations(user.getOrganizationId().getOrganizationId(), + timeOfObservationFrom, timeOfObservationTo); + } else { + observations = + observationBean.getObservationsForUser(user, timeOfObservationFrom, timeOfObservationTo); } - + // Then: Filter on other criteria - if(statusTypeId > 0) - { + if (statusTypeId > 0) { final Integer s = statusTypeId; // Local variables used in lambdas must be effectively final observations = observations.stream(). - filter(obs->obs.getStatusTypeId().equals(s)) - .collect(Collectors.toList()); + filter(obs -> obs.getStatusTypeId().equals(s)) + .collect(Collectors.toList()); } - if(pestOrganismId > 0) - { + if (pestOrganismId > 0) { final Integer p = pestOrganismId; observations = observations.stream() - .filter(obs->obs.getOrganismId().equals(p)) - .collect(Collectors.toList()); + .filter(obs -> obs.getOrganismId().equals(p)) + .collect(Collectors.toList()); } // A bit hairy this one // If the user wants to filter on organization groups @@ -227,407 +194,396 @@ public class ObservationController extends HttpServlet { // If the candiate obs has specified groups that intersect with filter, it's IN // Otherwise it's OUT // If the user has no filter for organization groups, all observations are kept - if(organizationGroupId != null) - { + if (organizationGroupId != null) { final Set<Integer> ogi = organizationGroupId; observations = observations.stream() - .filter((Observation obs) -> { - List<Integer> availableOrganizationGroupIds = observationBean.getOrganizationGroupIds(obs); - if(availableOrganizationGroupIds != null && ! availableOrganizationGroupIds.isEmpty()) - { - if (availableOrganizationGroupIds.stream().anyMatch((gId) -> (ogi.contains(gId)))) { - return true; - } + .filter((Observation obs) -> { + List<Integer> availableOrganizationGroupIds = observationBean.getOrganizationGroupIds(obs); + if (availableOrganizationGroupIds != null && !availableOrganizationGroupIds.isEmpty()) { + if (availableOrganizationGroupIds.stream().anyMatch((gId) -> (ogi.contains(gId)))) { + return true; } - return false; - }) - .collect(Collectors.toList()); + } + return false; + }) + .collect(Collectors.toList()); } - + // Check for form shortcuts - List<ObservationFormShortcut> shortcuts = observationBean.getObservationFormShortcuts(user.getOrganizationId()); - + List<ObservationFormShortcut> shortcuts = + observationBean.getObservationFormShortcuts(user.getOrganizationId()); + Collections.sort(observations); Collections.reverse(observations); //observations.forEach(o->System.out.println(o)); List<Organism> allPests = em.createNamedQuery("Organism.findAllPests").getResultList(); request.setAttribute("shortcuts", shortcuts); - request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, SessionLocaleUtil.getCurrentLocale(request).getLanguage())); - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, + SessionLocaleUtil.getCurrentLocale(request).getLanguage())); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); request.setAttribute("timeOfObservationFrom", userDefinedFrom ? timeOfObservationFrom : null); request.setAttribute("timeOfObservationTo", userDefinedTo ? timeOfObservationTo : null); request.setAttribute("selectedPestOrganismId", pestOrganismId); request.setAttribute("selectedStatusTypeId", statusTypeId); - request.setAttribute("viewOthersObservations",viewOthersObservations); + request.setAttribute("viewOthersObservations", viewOthersObservations); request.setAttribute("organizationGroups", organizationGroups); request.setAttribute("organizationGroupId", organizationGroupId); request.setAttribute("observations", observations); - request.setAttribute("userHasObserverPrivilege", userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)); - request.setAttribute("userIsObservationAuthority", userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)); + request.setAttribute("userHasObserverPrivilege", + userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)); + request.setAttribute("userIsObservationAuthority", + userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)); // If this is a redirect from a controller, with a message to be passed on request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/observationList.ftl").forward(request, response); } // Create a new observation // Authorization: ORGANIZATION ADMIN, OBSERVER or SUPERUSER - else if(action.equals("newObservationForm")) - { - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - try - { - + else if (action.equals("newObservationForm")) { + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { + try { + Observation observation = new Observation(); // See if there are presets on the URL string - if(request.getParameter("cropOrganismId") != null) - { - observation.setCropOrganism(em.find(Organism.class, Integer.valueOf(request.getParameter("cropOrganismId")))); + if (request.getParameter("cropOrganismId") != null) { + observation.setCropOrganism( + em.find(Organism.class, Integer.valueOf(request.getParameter("cropOrganismId")))); } - + List<Organism> allCrops; - if(request.getParameter("organismId") != null) - { + if (request.getParameter("organismId") != null) { Integer organismId = Integer.valueOf(request.getParameter("organismId")); observation.setOrganism(em.find(Organism.class, organismId)); // If pest has been selected, include only associated crops allCrops = organismBean.getPestCrops(organismId); - } - else - { + } else { allCrops = em.createNamedQuery("Organism.findAllCrops").getResultList(); } - + // Get the polygonServices - List<PolygonService> polygonServices = observationBean.getPolygonServicesForOrganization(user.getOrganization_id()); - + List<PolygonService> polygonServices = + observationBean.getPolygonServicesForOrganization(user.getOrganization_id()); + request.setAttribute("observation", observation); request.setAttribute("polygonServices", polygonServices); - request.setAttribute("locationVisibilityFormValue", ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PUBLIC); + request.setAttribute("locationVisibilityFormValue", + ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PUBLIC); request.setAttribute("shortcut", request.getParameter("observationFormShortcutId") != null ? - em.find(ObservationFormShortcut.class, Integer.valueOf(request.getParameter("observationFormShortcutId"))) - : null - ); - request.setAttribute("hideObservationFormMap", request.getParameter("hideObservationFormMap") != null ? request.getParameter("hideObservationFormMap").equals("true") : false); + em.find(ObservationFormShortcut.class, + Integer.valueOf(request.getParameter("observationFormShortcutId"))) + : null + ); + request.setAttribute("hideObservationFormMap", + request.getParameter("hideObservationFormMap") != null ? + request.getParameter("hideObservationFormMap").equals("true") : + false); request.setAttribute("noBroadcast", request.getParameter("noBroadcast") != null); request.setAttribute("mapLayers", userBean.getMapLayerJSONForUser(user)); - request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter()); + request.setAttribute("defaultMapCenter", user.getOrganizationId().getDefaultMapCenter()); request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom()); - request.setAttribute("locationPointOfInterests", pointOfInterestBean.getRelevantPointOfInterestsForUser(user)); + request.setAttribute("locationPointOfInterests", + pointOfInterestBean.getRelevantPointOfInterestsForUser(user)); List<Organism> allPests = em.createNamedQuery("Organism.findAllPests").getResultList(); - request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, SessionLocaleUtil.getCurrentLocale(request).getLanguage())); - request.setAttribute("allCrops", organismBean.sortOrganismsByLocalName(allCrops, SessionLocaleUtil.getCurrentLocale(request).getLanguage())); + request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, + SessionLocaleUtil.getCurrentLocale(request).getLanguage())); + request.setAttribute("allCrops", organismBean.sortOrganismsByLocalName(allCrops, + SessionLocaleUtil.getCurrentLocale(request).getLanguage())); request.setAttribute("selectedOrganizationGroupIds", new ArrayList<>()); // Hierarchy categories - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); - request.setAttribute("observationMethods", em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class).getResultList()); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("observationMethods", + em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class).getResultList()); request.setAttribute("organizationGroups", organizationGroups); request.setAttribute("editAccess", "W"); // User always has edit access to new observation - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - request.setAttribute("statusTypeIds", em.createNamedQuery("ObservationStatusType.findAll").getResultList()); + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { + request.setAttribute("statusTypeIds", + em.createNamedQuery("ObservationStatusType.findAll").getResultList()); } request.getRequestDispatcher("/observationForm.ftl").forward(request, response); - } - catch(NullPointerException | NumberFormatException ex) - { + } catch (NullPointerException | NumberFormatException ex) { response.sendError(500, ExceptionUtil.getStackTrace(ex)); } - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } // Edit an existing observation // Authorization: ORGANIZATION ADMIN, OBSERVER or SUPERUSER - else if(action.equals("editObservationForm")) - { - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - try - { + else if (action.equals("editObservationForm")) { + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)) { + try { Integer observationId = Integer.valueOf(request.getParameter("observationId")); - Observation observation = observationBean.getObservation(observationId);//em.find(Observation.class, observationId); - List<PolygonService> polygonServices = observationBean.getPolygonServicesForOrganization(user.getOrganization_id()); - request.setAttribute("locationVisibilityFormValue", this.getLocationVisibilityFormValue(observation)); + Observation observation = + observationBean.getObservation(observationId);//em.find(Observation.class, observationId); + List<PolygonService> polygonServices = + observationBean.getPolygonServicesForOrganization(user.getOrganization_id()); + request.setAttribute("locationVisibilityFormValue", + this.getLocationVisibilityFormValue(observation)); request.setAttribute("observation", observation); request.setAttribute("polygonServices", polygonServices); request.setAttribute("noBroadcast", request.getParameter("noBroadcast") != null); request.setAttribute("mapLayers", userBean.getMapLayerJSONForUser(user)); //System.out.println(observation.getGeoinfo()); - request.setAttribute("defaultMapCenter",user.getOrganizationId().getDefaultMapCenter()); + request.setAttribute("defaultMapCenter", user.getOrganizationId().getDefaultMapCenter()); request.setAttribute("defaultMapZoom", user.getOrganizationId().getDefaultMapZoom()); List<Organism> allPests = em.createNamedQuery("Organism.findAllPests").getResultList(); - request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, SessionLocaleUtil.getCurrentLocale(request).getLanguage())); + request.setAttribute("allPests", organismBean.sortOrganismsByLocalName(allPests, + SessionLocaleUtil.getCurrentLocale(request).getLanguage())); List<Organism> allCrops = em.createNamedQuery("Organism.findAllCrops").getResultList(); - request.setAttribute("allCrops", organismBean.sortOrganismsByLocalName(allCrops, SessionLocaleUtil.getCurrentLocale(request).getLanguage())); - request.setAttribute("selectedOrganizationGroupIds", observationBean.getOrganizationGroupIds(observation)); + request.setAttribute("allCrops", organismBean.sortOrganismsByLocalName(allCrops, + SessionLocaleUtil.getCurrentLocale(request).getLanguage())); + request.setAttribute("selectedOrganizationGroupIds", + observationBean.getOrganizationGroupIds(observation)); // Hierarchy categories - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); - request.setAttribute("observationMethods", em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class).getResultList()); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("observationMethods", + em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class).getResultList()); request.setAttribute("organizationGroups", organizationGroups); - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - request.setAttribute("statusTypeIds", em.createNamedQuery("ObservationStatusType.findAll").getResultList()); + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { + request.setAttribute("statusTypeIds", + em.createNamedQuery("ObservationStatusType.findAll").getResultList()); } - if(request.getParameter("messageKey") != null) - { - request.setAttribute("messageKey",request.getParameter("messageKey")); + if (request.getParameter("messageKey") != null) { + request.setAttribute("messageKey", request.getParameter("messageKey")); } - + // Determine the edit access String editAccess = "R"; // Read access only - if(observation.getUserId().equals(user.getUserId()) || user.isSuperUser() || user.isOrganizationAdmin()) - { + if (observation.getUserId() + .equals(user.getUserId()) || user.isSuperUser() || user.isOrganizationAdmin()) { editAccess = "W"; - } - else if(user.isObservationAuthority()) - { + } else if (user.isObservationAuthority()) { editAccess = "A"; // Approve } request.setAttribute("editAccess", editAccess); request.getRequestDispatcher("/observationForm.ftl").forward(request, response); - } - catch(NullPointerException | NumberFormatException ex) - { + } catch (NullPointerException | NumberFormatException ex) { response.sendError(500, ex.getMessage() + ": " + ExceptionUtil.getStackTrace(ex)); } - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } // Store an observation // Authorization: ORGANIZATION ADMIN, OBSERVER or SUPERUSER - else if(action.equals("observationFormSubmit")) - { - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - try - { - Map<String,String[]> parameterMap; + else if (action.equals("observationFormSubmit")) { + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)) { + try { + Map<String, String[]> parameterMap; List<FileItem> items = null; - if(JakartaServletFileUpload.isMultipartContent(request)) - { - + if (JakartaServletFileUpload.isMultipartContent(request)) { + // Create a new file upload handler DiskFileItemFactory dfif = DiskFileItemFactory.builder().get(); JakartaServletFileUpload upload = new JakartaServletFileUpload(dfif); // Parse the request items = upload.parseRequest(request); - parameterMap = FormUtil.getParameterMap(items,"UTF-8"); - } - else - { + parameterMap = FormUtil.getParameterMap(items, "UTF-8"); + } else { parameterMap = request.getParameterMap(); } - FormValidation formValidation = FormValidator.validateForm("observationForm", parameterMap, SessionLocaleUtil.getI18nBundle(request), getServletContext()); + FormValidation formValidation = FormValidator.validateForm("observationForm", parameterMap, + SessionLocaleUtil.getI18nBundle(request), getServletContext()); Integer observationId = formValidation.getFormField("observationId").getValueAsInteger(); - Observation observation = observationId > 0 ? em.find(Observation.class, observationId) : new Observation(); + Observation observation = + observationId > 0 ? em.find(Observation.class, observationId) : new Observation(); - if(formValidation.isValid()) - { + if (formValidation.isValid()) { // Storing observation // Only new observations can set the organism - if(observationId <= 0 || user.isSuperUser() || user.isOrganizationAdmin()) - { - observation.setOrganism(em.find(Organism.class, formValidation.getFormField("organismId").getValueAsInteger())); - observation.setCropOrganism(em.find(Organism.class, formValidation.getFormField("cropOrganismId").getValueAsInteger())); + if (observationId <= 0 || user.isSuperUser() || user.isOrganizationAdmin()) { + observation.setOrganism(em.find(Organism.class, + formValidation.getFormField("organismId").getValueAsInteger())); + observation.setCropOrganism(em.find(Organism.class, + formValidation.getFormField("cropOrganismId").getValueAsInteger())); } - observation.setTimeOfObservation(formValidation.getFormField("timeOfObservation").getValueAsTimestamp()); - if(observationId <= 0) - { + observation.setTimeOfObservation( + formValidation.getFormField("timeOfObservation").getValueAsTimestamp()); + if (observationId <= 0) { observation.setUserId(user.getUserId()); - } - else - { + } else { observation.setLastEditedBy(user.getUserId()); } observation.setLastEditedTime(new Date()); - observation.setObservationHeading(formValidation.getFormField("observationHeading").getWebValue()); - observation.setObservationText(formValidation.getFormField("observationText").getWebValue()); + observation.setObservationHeading( + formValidation.getFormField("observationHeading").getWebValue()); + observation.setObservationText( + formValidation.getFormField("observationText").getWebValue()); observation.setObservationData( - formValidation.getFormField("observationData").getWebValue().isEmpty() ? - null - : formValidation.getFormField("observationData").getWebValue() + formValidation.getFormField("observationData").getWebValue().isEmpty() ? + null + : formValidation.getFormField("observationData").getWebValue() ); observation.setIsPositive(formValidation.getFormField("isPositive").getWebValue() != null); - observation.setIsQuantified(formValidation.getFormField("isQuantified").getWebValue() != null); - this.setObservationLocationVisibility(observation, formValidation.getFormField("locationVisibility").getWebValue()); - observation.setBroadcastMessage(formValidation.getFormField("broadcastMessage").getWebValue() != null); + observation.setIsQuantified( + formValidation.getFormField("isQuantified").getWebValue() != null); + this.setObservationLocationVisibility(observation, + formValidation.getFormField("locationVisibility").getWebValue()); + observation.setBroadcastMessage( + formValidation.getFormField("broadcastMessage").getWebValue() != null); - boolean sendNotification = false; + boolean sendNotification = false; // Storing approval status - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { Integer statusTypeId = formValidation.getFormField("statusTypeId").getValueAsInteger(); - if( - observation.getStatusTypeId() == null - || ! observation.getStatusTypeId().equals(statusTypeId) - ) - { + if ( + observation.getStatusTypeId() == null + || !observation.getStatusTypeId().equals(statusTypeId) + ) { observation.setStatusChangedByUserId(user.getUserId()); observation.setStatusChangedTime(SystemTime.getSystemTime()); // Status changed to approved, sending notifications - if(statusTypeId.equals(Observation.STATUS_TYPE_ID_APPROVED) && observation.getBroadcastMessage()) - { + if (statusTypeId.equals( + Observation.STATUS_TYPE_ID_APPROVED) && observation.getBroadcastMessage()) { sendNotification = true; } } observation.setStatusTypeId(statusTypeId); - observation.setStatusRemarks(formValidation.getFormField("statusRemarks").getWebValue()); - } - else if(observation.getStatusTypeId() == null) - { + observation.setStatusRemarks( + formValidation.getFormField("statusRemarks").getWebValue()); + } else if (observation.getStatusTypeId() == null) { observation.setStatusTypeId(Observation.STATUS_TYPE_ID_PENDING); } //observation.setLocation(formValidation.getFormField("location").getValueAsPointWGS84()); //System.out.println(formValidation.getFormField("geoInfo").getWebValue()); - observation.setLocationPointOfInterestId(formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() > 0 ? - formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() : null); - if(formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() > 0) - { - observation.setLocationPointOfInterestId(formValidation.getFormField("locationPointOfInterestId").getValueAsInteger()); + observation.setLocationPointOfInterestId( + formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() > 0 ? + formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() : + null); + if (formValidation.getFormField("locationPointOfInterestId").getValueAsInteger() > 0) { + observation.setLocationPointOfInterestId( + formValidation.getFormField("locationPointOfInterestId").getValueAsInteger()); observation.setGeoinfo(null); - } - else - { + } else { observation.setLocationPointOfInterestId(null); observation.setGeoinfo(formValidation.getFormField("geoInfo").getWebValue()); } - + observation = observationBean.storeObservation(observation); // Image handling // Delete the current illustration String[] deleteIllustrations = parameterMap.get("deleteIllustration"); - if(deleteIllustrations != null && deleteIllustrations.length > 0) - { - observation = observationBean.deleteObservationIllustration(observation, deleteIllustrations); + if (deleteIllustrations != null && deleteIllustrations.length > 0) { + observation = + observationBean.deleteObservationIllustration(observation, deleteIllustrations); } // Store the new illustration (replaces former illustration if not already deleted) - if(items != null) - { - for(FileItem item:items) - { - if(!item.isFormField() && item.getSize() > 0) - { + if (items != null) { + for (FileItem item : items) { + if (!item.isFormField() && item.getSize() > 0) { observation = observationBean.storeObservationIllustration(observation, item); } } } - + // Checking for organization groups - observationBean.storeOrganizationGroupObservationIds(observation, formValidation.getFormField("organizationGroupId").getWebValues()); - + observationBean.storeOrganizationGroupObservationIds(observation, + formValidation.getFormField("organizationGroupId").getWebValues()); + // All transactions finished, we can send notifications // if conditions are met - if(sendNotification && ! - (System.getProperty("DISABLE_MESSAGING_SYSTEM") != null && System.getProperty("DISABLE_MESSAGING_SYSTEM").equals("true")) - ) - { + if (sendNotification && ! + (System.getProperty("DISABLE_MESSAGING_SYSTEM") != null && System.getProperty( + "DISABLE_MESSAGING_SYSTEM").equals("true")) + ) { messagingBean.sendUniversalMessage(observation); } // Redirect to form response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") - .append(ServletUtil.getServerName(request)) - .append("/observation?action=editObservationForm&observationId=").append(observation.getObservationId()) - .append("&messageKey=").append("observationStored").toString() + .append(ServletUtil.getServerName(request)) + .append("/observation?action=editObservationForm&observationId=") + .append(observation.getObservationId()) + .append("&messageKey=").append("observationStored").toString() ); - } - else - { + } else { // Redirect to form with error messages request.setAttribute("formValidation", formValidation); request.setAttribute("observation", observation); List<Organism> allOrganisms = em.createNamedQuery("Organism.findAll").getResultList(); request.setAttribute("allOrganisms", allOrganisms); // Hierarchy categories - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); - request.setAttribute("observationMethods", em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class).getResultList()); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("observationMethods", + em.createNamedQuery("ObservationMethod.findAll", ObservationMethod.class) + .getResultList()); request.getRequestDispatcher("/observationForm.ftl").forward(request, response); } - } - catch(NullPointerException | NumberFormatException | FormValidationException | FileUploadException ex) - { + } catch (NullPointerException | NumberFormatException | FormValidationException | + FileUploadException ex) { response.sendError(500, ExceptionUtil.getStackTrace(ex)); - } - catch(Exception ex) - { + } catch (Exception ex) { ex.printStackTrace(); response.sendError(500, ExceptionUtil.getStackTrace(ex)); } - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } // Authorization: ORGANIZATION ADMIN, OBSERVER or SUPERUSER - else if(action.equals("deleteObservation")) - { - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - try - { + else if (action.equals("deleteObservation")) { + if (userBean.authorizeUser(user, VipsLogicRole.OBSERVER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)) { + try { Integer observationId = Integer.valueOf(request.getParameter("observationId")); observationBean.deleteObservation(observationId); // Redirect to list response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") - .append(ServletUtil.getServerName(request)) - .append("/observation") - .append("?messageKey=").append("observationDeleted").toString() + .append(ServletUtil.getServerName(request)) + .append("/observation") + .append("?messageKey=").append("observationDeleted").toString() ); - } - catch(NullPointerException | NumberFormatException ex) - { + } catch (NullPointerException | NumberFormatException ex) { response.sendError(500, ExceptionUtil.getStackTrace(ex)); } - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } - } - else if(request.getServletPath().endsWith("/map")) - { + } else if (request.getServletPath().endsWith("/map")) { // Only for superusers, organizationadmins and observation authorities - if(userBean.authorizeUser(user, - VipsLogicRole.SUPERUSER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.OBSERVATION_AUTHORITY) - ) - { - try - { - FormValidation formValidation = FormValidator.validateForm("observationMapForm", request, getServletContext()); + if (userBean.authorizeUser(user, + VipsLogicRole.SUPERUSER, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.OBSERVATION_AUTHORITY) + ) { + try { + FormValidation formValidation = + FormValidator.validateForm("observationMapForm", request, getServletContext()); Organization organization = null; - if(user.isSuperUser()){ + if (user.isSuperUser()) { Integer organizationId = formValidation.getFormField("organizationId") != null ? - formValidation.getFormField("organizationId").getValueAsInteger() - :user.getOrganizationId().getOrganizationId(); + formValidation.getFormField("organizationId").getValueAsInteger() + : user.getOrganizationId().getOrganizationId(); organization = em.find(Organization.class, organizationId); request.setAttribute("organizations", userBean.getOrganizations()); request.setAttribute("organizationId", organizationId); - } - else - { + } else { organization = user.getOrganizationId(); request.setAttribute("organizationId", organization.getOrganizationId()); } - if(organization != null) - { - request.setAttribute("defaultMapCenter",organization.getDefaultMapCenter()); + if (organization != null) { + request.setAttribute("defaultMapCenter", organization.getDefaultMapCenter()); request.setAttribute("defaultMapZoom", organization.getDefaultMapZoom()); } @@ -635,121 +591,115 @@ public class ObservationController extends HttpServlet { // from: Default is start of year (jan 1st) Date from; Calendar cal = Calendar.getInstance(TimeZone.getDefault()); - if(!formValidation.getFormField("from").isEmpty()) - { + if (!formValidation.getFormField("from").isEmpty()) { from = formValidation.getFormField("from").getValueAsDate(); - } - else - { + } else { cal.setTime(SystemTime.getSystemTime()); - cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY,1,0,0,0); + cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1, 0, 0, 0); from = cal.getTime(); } request.setAttribute("from", from); // to Date to; - if(!formValidation.getFormField("to").isEmpty()) - { + if (!formValidation.getFormField("to").isEmpty()) { to = formValidation.getFormField("to").getValueAsDate(); - } - else - { + } else { cal.setTime(SystemTime.getSystemTime()); - cal.set(cal.get(Calendar.YEAR), Calendar.DECEMBER,31,23,59,59); + cal.set(cal.get(Calendar.YEAR), Calendar.DECEMBER, 31, 23, 59, 59); to = cal.getTime(); } request.setAttribute("to", to); request.setAttribute("periodDays", new DateUtil().getDaysBetween(from, to)); // pestId - request.setAttribute("pestId", formValidation.getFormField("pestId").isEmpty() ? null : - formValidation.getFormField("pestId").getValueAsInteger() + request.setAttribute("pestId", formValidation.getFormField("pestId").isEmpty() ? null : + formValidation.getFormField("pestId").getValueAsInteger() ); // cropId - request.setAttribute("cropId", formValidation.getFormField("cropId").isEmpty() ? null : - formValidation.getFormField("cropId").getValueAsInteger() + request.setAttribute("cropId", formValidation.getFormField("cropId").isEmpty() ? null : + formValidation.getFormField("cropId").getValueAsInteger() ); // cropCategoryId - request.setAttribute("cropCategoryId", formValidation.getFormField("cropCategoryId").isEmpty() ? null : + request.setAttribute("cropCategoryId", + formValidation.getFormField("cropCategoryId").isEmpty() ? null : formValidation.getFormField("cropCategoryId").getValueAsInteger() ); request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/observationMap.ftl").forward(request, response); - } - catch(FormValidationException | DateUtilException ex) - { + } catch (FormValidationException | DateUtilException ex) { response.sendError(500, ExceptionUtil.getStackTrace(ex)); } - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } - } - + } + public static final String LOCATION_VISIBILITY_FORM_VALUE_PRIVATE = "private"; public static final String LOCATION_VISIBILITY_FORM_VALUE_PUBLIC = "public"; public static final String LOCATION_VISIBILITY_FORM_VALUE_MASK_PREFIX = "mask_"; - - private String getLocationVisibilityFormValue(Observation observation) - { + + private String getLocationVisibilityFormValue(Observation observation) { // Private is private, no matter what - if(observation.getLocationIsPrivate()) - { + if (observation.getLocationIsPrivate()) { return ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PRIVATE; } // Public can either be completely public or masked by a polygon layer // e.g. county borders - if(observation.getPolygonService() == null) - { + if (observation.getPolygonService() == null) { return ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PUBLIC; } - return ObservationController.LOCATION_VISIBILITY_FORM_VALUE_MASK_PREFIX + observation.getPolygonService().getPolygonServiceId(); + return ObservationController.LOCATION_VISIBILITY_FORM_VALUE_MASK_PREFIX + observation.getPolygonService() + .getPolygonServiceId(); } - - private void setObservationLocationVisibility(Observation observation, String formValue) - { + + private void setObservationLocationVisibility(Observation observation, String formValue) { // Private is private, no matter what - observation.setLocationIsPrivate(formValue.equals(ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PRIVATE)); + observation.setLocationIsPrivate( + formValue.equals(ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PRIVATE)); observation.setPolygonService( - // If private or public, set no polygon service - formValue.equals(ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PRIVATE) || formValue.equals(ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PUBLIC) + // If private or public, set no polygon service + formValue.equals(ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PRIVATE) || formValue.equals( + ObservationController.LOCATION_VISIBILITY_FORM_VALUE_PUBLIC) ? null // Otherwise, set selected polygon service - : em.find(PolygonService.class, Integer.valueOf(formValue.split("_")[1])) + : em.find(PolygonService.class, Integer.valueOf(formValue.split("_")[1])) ); } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> - /** + + /** * Handles the HTTP <code>GET</code> method. - * @param request servlet request + * + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); - } + } - /** + /** * Handles the HTTP <code>POST</code> method. - * @param request servlet request + * + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws ServletException, IOException { processRequest(request, response); } - /** + /** * Returns a short description of the servlet. + * * @return a String containing servlet description */ @Override diff --git a/src/main/webapp/templates/observationForm.ftl b/src/main/webapp/templates/observationForm.ftl index 7cfe54dceb8fe570b9a7241f26c08cebaf0785cc..6fb824d1cf636baf17a3e6427a56f0d26518308a 100755 --- a/src/main/webapp/templates/observationForm.ftl +++ b/src/main/webapp/templates/observationForm.ftl @@ -16,225 +16,217 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> - <title><#if observation.observationId?has_content>${i18nBundle.editObservation}<#else>${i18nBundle.newObservation}</#if></title> + <title><#if observation.observationId?has_content>${i18nBundle.editObservation}<#else>${i18nBundle.newObservation}</#if></title> </#macro> <#macro custom_css> - <link rel="stylesheet" href="/css/3rdparty/chosen.min.css"/> - <link rel="stylesheet" type="text/css" href="/css/3rdparty/jquery.datetimepicker.css"/> - <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css?t=20170623"/> - <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol-layerswitcher.css"/> - <link rel="stylesheet" type="text/css" href="/css/map.css"/> + <link rel="stylesheet" href="/css/3rdparty/chosen.min.css"/> + <link rel="stylesheet" type="text/css" href="/css/3rdparty/jquery.datetimepicker.css"/> + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css?t=20170623"/> + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol-layerswitcher.css"/> + <link rel="stylesheet" type="text/css" href="/css/map.css"/> </#macro> <#macro custom_js> <script type="text/javascript" src="/js/3rdparty/chosen.jquery.min.js"></script> - <script type="text/javascript" src="/js/3rdparty/jquery.datetimepicker.js"></script> - <script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script> - <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> + <script type="text/javascript" src="/js/3rdparty/jquery.datetimepicker.js"></script> + <script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script> + <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> <script type="text/javascript" src="/js/3rdparty/jsoneditor.js"></script> - <script type="text/javascript" src="/js/3rdparty/ol.js?t=20170623"></script> + <script type="text/javascript" src="/js/3rdparty/ol.js?t=20170623"></script> <script type="text/javascript" src="js/3rdparty/ol-layerswitcher.js"></script> - - <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> - <script type="text/javascript" src="/js/util.js"></script> - <script type="text/javascript" src="/js/objectGISInfoMap.js?t=20170623"></script> - <script type="text/javascript" src="/js/poiFormMap.js"></script> - <script type="text/javascript"> - var organizationId = ${user.organizationId.organizationId}; + + <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> + <script type="text/javascript" src="/js/util.js"></script> + <script type="text/javascript" src="/js/objectGISInfoMap.js?t=20170623"></script> + <script type="text/javascript" src="/js/poiFormMap.js"></script> + <script type="text/javascript"> + var organizationId = ${user.organizationId.organizationId}; var selectedCropId = <#if observation.cropOrganism?has_content>${observation.cropOrganism.organismId?c}<#else>null</#if>; - $(document).ready(function() { - - - // Make sure that there is a datetime picker present for HTML5 - // date input fields - - $('#timeOfObservation').datetimepicker({ - lang:"no", - dayOfWeekStart: 1, - format: "Y-m-d H:iO", - step: 30 - }); - - - // Load main form definition (for validation) - loadFormDefinition("observationForm"); - - // Initialize the map - // If observation already registered center on location - // Otherwise, center and zoom to organizations's default - <#if observation.location?has_content> - initGisInfoMap([${(observation.location.x?c)!""},${(observation.location.y?c)!""}],10,true); - <#else> - var geoInfo = <#if observation.geoinfo?has_content>${observation.geoinfo}<#else>{}</#if>; - var chooseFromMapLayers = {"chooseFromMapLayers":<#if mapLayers?has_content>${mapLayers}<#else>[]</#if>}; - initGisInfoMap("observationFormMap",[${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},false, geoInfo, chooseFromMapLayers); - </#if> - <#if editAccess!="W"> - GISInfoMap.removeInteraction(draw); - document.getElementById("drawOptions").innerHTML =""; - </#if> - <#if observation.observationData?has_content> - observationData = ${observation.observationData}; - getDataSchema(${observation.organism.organismId}, organizationId); - <#elseif observation.organism?has_content> - // Setting - initObservationData(${observation.organism.organismId},organizationId); - </#if> - - // Activating file selection - $('.btn-file :file').on('fileselect', function(event, numFiles, label) { - - var input = $(this).parents('.input-group').find(':text'), - log = numFiles > 1 ? numFiles + ' files selected' : label; - - if( input.length ) { - input.val(log); - } else { - if( log ) alert(log); - } - - }); - - refreshLocationPointOfInterests(<#if observation.locationPointOfInterestId?has_content>${observation.locationPointOfInterestId}<#else>null</#if>); - <#if ! observation.organism?has_content> - initCropCategories(); - </#if> - // Activating chosen plugin - $(".chosen-select").chosen(); - - // Show all available crops - filterCrops(-1); - }); - - // Adding selected file name to a box - $(document) - .on('change', '.btn-file :file', function() { - var input = $(this), - numFiles = input.get(0).files ? input.get(0).files.length : 1, - label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); - input.trigger('fileselect', [numFiles, label]); - }); - - - // Global for observationData & observationSchema - let observationData = null; + $(document).ready(function () { + + + // Make sure that there is a datetime picker present for HTML5 + // date input fields + + $('#timeOfObservation').datetimepicker({ + lang: "no", + dayOfWeekStart: 1, + format: "Y-m-d H:iO", + step: 30 + }); + + + // Load main form definition (for validation) + loadFormDefinition("observationForm"); + + // Initialize the map + // If observation already registered center on location + // Otherwise, center and zoom to organizations's default + <#if observation.location?has_content> + initGisInfoMap([${(observation.location.x?c)!""}, ${(observation.location.y?c)!""}], 10, true); + <#else> + var geoInfo = <#if observation.geoinfo?has_content>${observation.geoinfo}<#else> + { + } + </#if>; + var chooseFromMapLayers = {"chooseFromMapLayers": <#if mapLayers?has_content>${mapLayers}<#else>[]</#if>}; + initGisInfoMap("observationFormMap", [${defaultMapCenter.x?c}, ${defaultMapCenter.y?c}], ${defaultMapZoom}, false, geoInfo, chooseFromMapLayers); + </#if> + <#if editAccess!="W"> + GISInfoMap.removeInteraction(draw); + document.getElementById("drawOptions").innerHTML = ""; + </#if> + <#if observation.observationData?has_content> + observationData = ${observation.observationData}; + getDataSchema(${observation.organism.organismId}, organizationId); + <#elseif observation.organism?has_content> + // Setting + initObservationData(${observation.organism.organismId}, organizationId); + </#if> + + // Activating file selection + $('.btn-file :file').on('fileselect', function (event, numFiles, label) { + + var input = $(this).parents('.input-group').find(':text'), + log = numFiles > 1 ? numFiles + ' files selected' : label; + + if (input.length) { + input.val(log); + } else { + if (log) alert(log); + } + + }); + + refreshLocationPointOfInterests(<#if observation.locationPointOfInterestId?has_content>${observation.locationPointOfInterestId}<#else>null</#if>); + <#if ! observation.organism?has_content> + initCropCategories(); + </#if> + // Activating chosen plugin + $(".chosen-select").chosen(); + + // Show all available crops + filterCrops(-1); + }); + + // Adding selected file name to a box + $(document) + .on('change', '.btn-file :file', function () { + var input = $(this), + numFiles = input.get(0).files ? input.get(0).files.length : 1, + label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); + input.trigger('fileselect', [numFiles, label]); + }); + + + // Global for observationData & observationSchema + let observationData = null; let observationSchema = null; // Make the quantification fields available const quantificationFields = document.getElementById("quantificationFields"); let editor = null; - function initObservationData(organismId, organizationId) { - $.getJSON( "/rest/observationdata/model/" + organizationId + "/" + organismId, function( json ) { - observationData = json; - getDataSchema(organismId, organizationId); - }); - } - - function getDataSchema(organismId, organizationId) - { - $.getJSON( "/rest/observationdata/schema/" + organizationId + "/" + organismId, buildForm); - } + + function initObservationData(organismId, organizationId) { + $.getJSON("/rest/observationdata/model/" + organizationId + "/" + organismId, function (json) { + observationData = json; + getDataSchema(organismId, organizationId); + }); + } + + function getDataSchema(organismId, organizationId) { + $.getJSON("/rest/observationdata/schema/" + organizationId + "/" + organismId, buildForm); + } // Populate the quantification fields using JSONEditor (https://github.com/json-editor/json-editor) - const buildForm = function(retrievedSchema) - { - //console.info(retrievedSchema); - //console.info(observationData); - observationSchema = retrievedSchema; - // Erasing whatever was there before - if(editor != null) { - editor.destroy(); - } - editor = new JSONEditor(quantificationFields, { - schema: observationSchema, - theme: 'bootstrap4', - disable_edit_json: true, // If true, remove all Edit JSON buttons from objects. - disable_properties: true, // If true, remove all Edit Properties buttons from objects. - remove_button_labels: true, // Display only icons in buttons. This works only if iconlib is set. - disable_collapse: true // Make sure no elements can be collapsed + const buildForm = function (retrievedSchema) { + //console.info(retrievedSchema); + //console.info(observationData); + observationSchema = retrievedSchema; + // Erasing whatever was there before + if (editor != null) { + editor.destroy(); + } + editor = new JSONEditor(quantificationFields, { + schema: observationSchema, + theme: 'bootstrap4', + disable_edit_json: true, // If true, remove all Edit JSON buttons from objects. + disable_properties: true, // If true, remove all Edit Properties buttons from objects. + remove_button_labels: true, // Display only icons in buttons. This works only if iconlib is set. + disable_collapse: true // Make sure no elements can be collapsed + }); + editor.on("ready", () => { + editor.setValue(observationData); + }) + }; + + var updateCropPests = function () { + var theForm = document.getElementById('observationForm'); + var selectedCropId = theForm["cropOrganismId"].options[theForm["cropOrganismId"].options.selectedIndex].value; + // If this is not a new observation, or the selected crop is not in the database, we keep calm + if (theForm["observationId"].value !== "-1" || selectedCropId == "-10") { + return; + } + $.getJSON("/rest/organism/croppest/" + selectedCropId, function (json) { + updateCropPestsCallback(json); + }) + .fail(function () { + alert("Error getting pests for this crop. Please contact system administrator"); }); - editor.on("ready",()=>{editor.setValue(observationData);}) - }; - - var updateCropPests = function(){ - var theForm = document.getElementById('observationForm'); - var selectedCropId = theForm["cropOrganismId"].options[theForm["cropOrganismId"].options.selectedIndex].value; - // If this is not a new observation, or the selected crop is not in the database, we keep calm - if(theForm["observationId"].value !== "-1" || selectedCropId == "-10") - { - return; - } - $.getJSON( "/rest/organism/croppest/" + selectedCropId, function( json ) { - updateCropPestsCallback(json); - }) - .fail(function() { - alert( "Error getting pests for this crop. Please contact system administrator" ); - }); - }; - - var updateCropPestsCallback = function(cropPest) { - var pestList = document.getElementById('observationForm')["organismId"]; - if(cropPest == null) - { - // Need to reorganize pests back to default - var allPests = []; - for(var i=2;i<pestList.options.length;i++) - { - allPests.push(pestList.options[i]); - } - allPests.sort(compareSelectListOptions); - pestList.options.length=2; // Keeping the top two - for(var i=0;i<allPests.length;i++) - { - pestList.options[pestList.options.length] = allPests[i]; - } - } - else - { - var prioritatedPests = []; - var unprioritatedPests = [] - for(var i=2;i<pestList.options.length;i++) - { - if(cropPest.pestOrganismIds.indexOf(parseInt(pestList.options[i].value)) >= 0) - { - //console.log(pestList.options[i].value + " is prioritated"); - prioritatedPests.push(pestList.options[i]); - } - else if(pestList.options[i].value != "-1") // Avoiding the "---" option - { - //console.log(pestList.options[i].value + " is unprioritated"); - unprioritatedPests.push(pestList.options[i]); - } - - } - pestList.options.length=2; // Keeping the top two - for(var i=0;i<prioritatedPests.length;i++) - { - pestList.options[pestList.options.length] = prioritatedPests[i]; - } - pestList.options[pestList.options.length] = new Option("---","-1"); - for(var i=0;i<unprioritatedPests.length;i++) - { - pestList.options[pestList.options.length] = unprioritatedPests[i]; - } - } - }; - - var thePopup; - function addNewLocationPopup() - { - thePopup = window.open("/poi?action=newPoiForm&organizationId=1&returnIdCallback=refreshLocationPointOfInterests"); - } - - var allPois = []; - + }; + + var updateCropPestsCallback = function (cropPest) { + var pestList = document.getElementById('observationForm')["organismId"]; + if (cropPest == null) { + // Need to reorganize pests back to default + var allPests = []; + for (var i = 2; i < pestList.options.length; i++) { + allPests.push(pestList.options[i]); + } + allPests.sort(compareSelectListOptions); + pestList.options.length = 2; // Keeping the top two + for (var i = 0; i < allPests.length; i++) { + pestList.options[pestList.options.length] = allPests[i]; + } + } else { + var prioritatedPests = []; + var unprioritatedPests = [] + for (var i = 2; i < pestList.options.length; i++) { + if (cropPest.pestOrganismIds.indexOf(parseInt(pestList.options[i].value)) >= 0) { + //console.log(pestList.options[i].value + " is prioritated"); + prioritatedPests.push(pestList.options[i]); + } else if (pestList.options[i].value != "-1") // Avoiding the "---" option + { + //console.log(pestList.options[i].value + " is unprioritated"); + unprioritatedPests.push(pestList.options[i]); + } + + } + pestList.options.length = 2; // Keeping the top two + for (var i = 0; i < prioritatedPests.length; i++) { + pestList.options[pestList.options.length] = prioritatedPests[i]; + } + pestList.options[pestList.options.length] = new Option("---", "-1"); + for (var i = 0; i < unprioritatedPests.length; i++) { + pestList.options[pestList.options.length] = unprioritatedPests[i]; + } + } + }; + + var thePopup; + + function addNewLocationPopup() { + thePopup = window.open("/poi?action=newPoiForm&organizationId=1&returnIdCallback=refreshLocationPointOfInterests"); + } + + var allPois = []; + /** * Fetches locations, farms, fields, traps and weather stations, renders the list */ - function refreshLocationPointOfInterests(selectedPointOfInterestId) - { + function refreshLocationPointOfInterests(selectedPointOfInterestId) { const poiTypes = { 0: "${i18nBundle.genericPlaces}", 1: "${i18nBundle.weatherStations}", @@ -242,7 +234,7 @@ 3: "${i18nBundle.fields}", 5: "${i18nBundle.traps}" }; - $.getJSON("/rest/poi/user", function(json) { + $.getJSON("/rest/poi/user", function (json) { const allPois = json; const poiListElement = document.getElementById("locationPointOfInterestId"); poiListElement.options.length = 1; @@ -265,465 +257,480 @@ } showCorrectMap(); }); - } - - - // If locationPointOfInterestId is selected OR observation drawing map is deliberately disabled, - // show map for locations - // If not, show the observation drawing map - var hideObservationFormMap = <#if hideObservationFormMap??>${hideObservationFormMap?c}<#else>false</#if>; - function showCorrectMap(){ - var locationList = document.getElementById("locationPointOfInterestId"); - if(hideObservationFormMap && locationList.options[locationList.options.selectedIndex].value == "-1") - { - document.getElementById("observationFormMap").style.display="none"; - document.getElementById("poiFormMap").style.display="block"; - initLocationMap(null); + } + + + // If locationPointOfInterestId is selected OR observation drawing map is deliberately disabled, + // show map for locations + // If not, show the observation drawing map + var hideObservationFormMap = <#if hideObservationFormMap??>${hideObservationFormMap?c}<#else>false</#if>; + + function showCorrectMap() { + var locationList = document.getElementById("locationPointOfInterestId"); + if (hideObservationFormMap && locationList.options[locationList.options.selectedIndex].value == "-1") { + document.getElementById("observationFormMap").style.display = "none"; + document.getElementById("poiFormMap").style.display = "block"; + initLocationMap(null); + } else if (locationList.options[locationList.options.selectedIndex].value != "-1") { + document.getElementById("observationFormMap").style.display = "none"; + document.getElementById("poiFormMap").style.display = "block"; + initLocationMap(locationList.options[locationList.options.selectedIndex].value); + } else { + document.getElementById("observationFormMap").style.display = "block"; + document.getElementById("poiFormMap").style.display = "none"; + } + } + + function initLocationMap(locationPointOfInterestId) { + if (locationPointOfInterestId != null) { + $.getJSON("/rest/poi/" + locationPointOfInterestId, function (json) { + var poi = json; + if (map === undefined || map === null) { + initMap([poi.longitude, poi.latitude], 10, ${user.organizationId.organizationId}, locationPointOfInterestId, true); + } else { + map.getView().setCenter(ol.proj.transform([poi.longitude, poi.latitude], 'EPSG:4326', map.getView().getProjection().getCode())); + map.getView().setZoom(10); + stationMarker.setPosition(ol.proj.transform([poi.longitude, poi.latitude], 'EPSG:4326', map.getView().getProjection().getCode())); } - else if(locationList.options[locationList.options.selectedIndex].value != "-1") - { - document.getElementById("observationFormMap").style.display="none"; - document.getElementById("poiFormMap").style.display="block"; - initLocationMap(locationList.options[locationList.options.selectedIndex].value); - } - else - { - document.getElementById("observationFormMap").style.display="block"; - document.getElementById("poiFormMap").style.display="none"; - } - } - - function initLocationMap(locationPointOfInterestId) - { - if(locationPointOfInterestId != null) - { - $.getJSON("/rest/poi/" + locationPointOfInterestId, function( json ) { - var poi = json; - if(map === undefined || map === null) - { - initMap([poi.longitude,poi.latitude],10,${user.organizationId.organizationId},locationPointOfInterestId, true); - } - else - { - map.getView().setCenter(ol.proj.transform([poi.longitude,poi.latitude], 'EPSG:4326', map.getView().getProjection().getCode())); - map.getView().setZoom(10); - stationMarker.setPosition(ol.proj.transform([poi.longitude,poi.latitude], 'EPSG:4326', map.getView().getProjection().getCode())); - } - } - ); - } - else - { - initMap([${defaultMapCenter.x?c},${defaultMapCenter.y?c}],${defaultMapZoom},${user.organizationId.organizationId},locationPointOfInterestId, true); - } - } - - function validateGIS(theForm) - { - var locationList = document.getElementById("locationPointOfInterestId"); - var geoInfo = document.getElementById("observationForm")["geoInfo"]; - if(locationList.options[locationList.options.selectedIndex].value == "-1" && (geoInfo.value == "" || geoInfo.value == "{\"type\":\"FeatureCollection\",\"features\":[]}")) - { - alert("${i18nBundle.noMapDataEntered}"); - return false; - } - else - { - return true; - } - } - - var cropCategories = []; - function initCropCategories(){ - $.getJSON("/rest/organism/cropcategory/${user.organizationId.organizationId}" , function( json ) { - cropCategories = json; - renderCropCategories(); - } - ); + } + ); + } else { + initMap([${defaultMapCenter.x?c}, ${defaultMapCenter.y?c}], ${defaultMapZoom}, ${user.organizationId.organizationId}, locationPointOfInterestId, true); + } + } + + function validateGIS(theForm) { + var locationList = document.getElementById("locationPointOfInterestId"); + var geoInfo = document.getElementById("observationForm")["geoInfo"]; + if (locationList.options[locationList.options.selectedIndex].value == "-1" && (geoInfo.value == "" || geoInfo.value == "{\"type\":\"FeatureCollection\",\"features\":[]}")) { + alert("${i18nBundle.noMapDataEntered}"); + return false; + } else { + return true; + } + } + + var cropCategories = []; + + function initCropCategories() { + $.getJSON("/rest/organism/cropcategory/${user.organizationId.organizationId}", function (json) { + cropCategories = json; + renderCropCategories(); } - - function renderCropCategories() { - var cropCategoryIdList = document.getElementById("cropCategoryIdList"); - for(var i in cropCategories) - { - var cropCategory = cropCategories[i]; - // Best effort getting name for crop category - var catName = cropCategory.defaultName; - for(var j in cropCategory.cropCategoryLocalSet) - { - var cLocal = cropCategory.cropCategoryLocalSet[j]; - if(cLocal.cropCategoryLocalPK.locale == "${currentLocale}") - { - catName = cLocal.localName; - } - } - var cOption = new Option(catName,cropCategory.cropCategoryId); - cropCategoryIdList.options[cropCategoryIdList.options.length] = cOption; + ); + } + + function renderCropCategories() { + var cropCategoryIdList = document.getElementById("cropCategoryIdList"); + for (var i in cropCategories) { + var cropCategory = cropCategories[i]; + // Best effort getting name for crop category + var catName = cropCategory.defaultName; + for (var j in cropCategory.cropCategoryLocalSet) { + var cLocal = cropCategory.cropCategoryLocalSet[j]; + if (cLocal.cropCategoryLocalPK.locale == "${currentLocale}") { + catName = cLocal.localName; } } - - /** - * Based on the selected crop category: Put the related crops - * on top of the crops list - */ - function filterCrops(selectedCropCategoryId) - { - // Nothing has been selected, render all in one go - if(selectedCropCategoryId < 0) - { - var cropOptions = []; - for(var j=0;j<cropList.length;j++) - { + var cOption = new Option(catName, cropCategory.cropCategoryId); + cropCategoryIdList.options[cropCategoryIdList.options.length] = cOption; + } + } + + /** + * Based on the selected crop category: Put the related crops + * on top of the crops list + */ + function filterCrops(selectedCropCategoryId) { + // Nothing has been selected, render all in one go + if (selectedCropCategoryId < 0) { + var cropOptions = []; + for (var j = 0; j < cropList.length; j++) { + //var cropOption = cropOrganismIdList.options[j]; + var crop = cropList[j]; + var cropOption = new Option(crop.displayName, crop.organismId); + if (selectedCropId != null && selectedCropId == crop.organismId) { + cropOption.selected = true; + } + cropOptions.push(cropOption); + + } + renderCropList(cropOptions, []); + } else { + // Searching for selected crop category + for (var i in cropCategories) { + var cropCategory = cropCategories[i]; + if (cropCategory.cropCategoryId == parseInt(selectedCropCategoryId)) { + // Filter based on match + var matchingCropOrganismOptions = []; + var theRest = []; + //var cropOrganismIdList = document.getElementById("cropOrganismIdList"); + for (var j = 0; j < cropList.length; j++) { //var cropOption = cropOrganismIdList.options[j]; var crop = cropList[j]; var cropOption = new Option(crop.displayName, crop.organismId); - if(selectedCropId != null && selectedCropId == crop.organismId) - { + if (selectedCropId != null && selectedCropId == crop.organismId) { cropOption.selected = true; } - cropOptions.push(cropOption); - - } - renderCropList(cropOptions, []); - } - else - { - // Searching for selected crop category - for(var i in cropCategories) - { - var cropCategory = cropCategories[i]; - if(cropCategory.cropCategoryId == parseInt(selectedCropCategoryId)) - { - // Filter based on match - var matchingCropOrganismOptions = []; - var theRest = []; - //var cropOrganismIdList = document.getElementById("cropOrganismIdList"); - for(var j=0;j<cropList.length;j++) - { - //var cropOption = cropOrganismIdList.options[j]; - var crop = cropList[j]; - var cropOption = new Option(crop.displayName, crop.organismId); - if(selectedCropId != null && selectedCropId == crop.organismId) - { - cropOption.selected = true; - } - if(cropCategory.cropOrganismIds.indexOf(crop.organismId) >= 0 && cropCategory.maxHierarchyCategoryId >= crop.hierarchyCategoryId) - { - matchingCropOrganismOptions.push(cropOption); - } - else if(crop.organismId > 0) - { - theRest.push(cropOption); - } - } - renderCropList(matchingCropOrganismOptions, theRest); + if (cropCategory.cropOrganismIds.indexOf(crop.organismId) >= 0 && cropCategory.maxHierarchyCategoryId >= crop.hierarchyCategoryId) { + matchingCropOrganismOptions.push(cropOption); + } else if (crop.organismId > 0) { + theRest.push(cropOption); } } + renderCropList(matchingCropOrganismOptions, theRest); } } - - function renderCropList(matchingCropOrganismOptions, theRest) - { - var cropOrganismIdList = document.getElementById("cropOrganismIdList"); - cropOrganismIdList.options.length = 1; - for(var i in matchingCropOrganismOptions) - { - cropOrganismIdList.options[cropOrganismIdList.options.length] = matchingCropOrganismOptions[i]; - } - cropOrganismIdList.options[cropOrganismIdList.options.length] = new Option("----",-1); - for(var i in theRest) - { - cropOrganismIdList.options[cropOrganismIdList.options.length] = theRest[i]; - } - } - <#if noBroadcast> - /** - * In the unlikely event that the user in a pre-filled form decides to - * change the organism, we'll update the observationText and heading - */ - function updateHeadingAndText(organismName) - { - var registrationOfText = "${i18nBundle.registrationOf} " + organismName; - document.getElementById("observationHeading").value = registrationOfText; - document.getElementById("observationText").value = registrationOfText; - } - </#if> - var cropList = [ - <#if ! observation.observationId?has_content || user.isSuperUser() || user.isOrganizationAdmin()> - {organismId: -10, displayName: "${i18nBundle.missingInDatabase}", hierarchyCategoryId: -1}, - <#list allCrops as cropOrganism> - {organismId: ${cropOrganism.organismId?c}, displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId!"-1"}}<#sep>, - </#list> - <#else> - <#list allCrops as cropOrganism> - <#if (observation.cropOrganism?has_content && observation.cropOrganism.organismId == cropOrganism.organismId)> - {organismId: ${cropOrganism.organismId}, displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId}} - </#if> - </#list> - </#if> - ]; - - /** - * Does all the ifs and buts before form can potentially be submitted - */ - function prepareFormSubmit(theForm) - { - // Extract GIS info from OpenLayers - theForm['geoInfo'].value=getFeatures(); - try - { - // If the form is quantified: Inspect the fields and write - // JSON string to the generic form field "observationData"; - if(theForm.isQuantified.checked) - { - const errors = editor.validate(); - if(errors.length) - { - alert(errors); - return false; - } - theForm['observationData'].value=JSON.stringify(editor.getValue()); - } - validateGIS(theForm); - //console.info('validateGIS = ' + (validateGIS(this))); - //return false; // DEBUG setting - return validateForm(theForm) && validateGIS(theForm); // PROD setting - } - catch(e) - { - console.log(e.message); - console.log(e); + } + } + + function renderCropList(matchingCropOrganismOptions, theRest) { + var cropOrganismIdList = document.getElementById("cropOrganismIdList"); + cropOrganismIdList.options.length = 1; + for (var i in matchingCropOrganismOptions) { + cropOrganismIdList.options[cropOrganismIdList.options.length] = matchingCropOrganismOptions[i]; + } + cropOrganismIdList.options[cropOrganismIdList.options.length] = new Option("----", -1); + for (var i in theRest) { + cropOrganismIdList.options[cropOrganismIdList.options.length] = theRest[i]; + } + } + + <#if noBroadcast> + + /** + * In the unlikely event that the user in a pre-filled form decides to + * change the organism, we'll update the observationText and heading + */ + function updateHeadingAndText(organismName) { + var registrationOfText = "${i18nBundle.registrationOf} " + organismName; + document.getElementById("observationHeading").value = registrationOfText; + document.getElementById("observationText").value = registrationOfText; + } + + </#if> + var cropList = [ + <#if ! observation.observationId?has_content || user.isSuperUser() || user.isOrganizationAdmin()> + {organismId: -10, displayName: "${i18nBundle.missingInDatabase}", hierarchyCategoryId: -1}, + <#list allCrops as cropOrganism> + { + organismId: ${cropOrganism.organismId?c}, + displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", + hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId!"-1"} + }<#sep>, + </#list> + <#else> + <#list allCrops as cropOrganism> + <#if (observation.cropOrganism?has_content && observation.cropOrganism.organismId == cropOrganism.organismId)> + { + organismId: ${cropOrganism.organismId}, + displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", + hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId} + } + </#if> + </#list> + </#if> + ]; + + /** + * Does all the ifs and buts before form can potentially be submitted + */ + function prepareFormSubmit(theForm) { + // Extract GIS info from OpenLayers + theForm['geoInfo'].value = getFeatures(); + try { + // If the form is quantified: Inspect the fields and write + // JSON string to the generic form field "observationData"; + if (theForm.isQuantified.checked) { + const errors = editor.validate(); + if (errors.length) { + alert(errors); return false; } + theForm['observationData'].value = JSON.stringify(editor.getValue()); } - </script> + validateGIS(theForm); + //console.info('validateGIS = ' + (validateGIS(this))); + //return false; // DEBUG setting + return validateForm(theForm) && validateGIS(theForm); // PROD setting + } catch (e) { + console.log(e.message); + console.log(e); + return false; + } + } + </script> </#macro> <#macro page_contents> -<div class="singleBlockContainer"> - <p><a href="/observation" class="btn btn-default back" role="button">${i18nBundle.back}</a><#if observation.observationId?has_content><a href="/observation?action=newObservationForm" class="btn btn-default" role="button">${i18nBundle.addNew}</a></#if></p> + <div class="singleBlockContainer"> + <p><a href="/observation" class="btn btn-default back" + role="button">${i18nBundle.back}</a><#if observation.observationId?has_content><a + href="/observation?action=newObservationForm" class="btn btn-default" + role="button">${i18nBundle.addNew}</a></#if></p> <h1><#if observation.observationId?has_content>${i18nBundle.editObservation}<#else>${i18nBundle.newObservation}</#if><#if shortcut?has_content> - ${shortcut.getLocalLabel(currentLocale.language)?lower_case}</#if></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> - <div class="row"> - <div class="col-md-6"> - <#assign formId = "observationForm"> - <form id="${formId}" role="form" action="/observation?action=observationFormSubmit" enctype="multipart/form-data" method="POST" onsubmit="return prepareFormSubmit(this);"> - <!--form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="this['geoInfo'].value=getFeatures();mw.save();console.log(this['observationData']);this['observationData'].value=JSON.stringify(mw.toInspect);return validateForm(this);"--> - <!--form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="this['geoInfo'].value=getFeatures();mw.save();console.log(this['observationData']);this['observationData'].value=JSON.stringify(mw.toInspect);validateForm(this);return false;"--> - <input type="hidden" name="geoInfo" value=""/> - <input type="hidden" name="observationData" value=""/> - <input type="hidden" name="observationId" value="${observation.observationId!"-1"}"/> - <!--button type="button" onclick="var theForm=document.getElementById('observationForm');theForm['geoInfo'].value=getFeatures();try{mw.save();theForm['observationData'].value=JSON.stringify(mw.toInspect);return validateForm(theForm) && validateGIS(theForm);}catch(e){console.log(e.message);console.log(e);return false;}">Test</button--> - <#if observation.user?has_content> - <div class="form-group"> - <label>${i18nBundle.observer}: ${observation.user.firstName} ${observation.user.lastName}</label> - </div> - </#if> - <#if observation.lastEditedByUser?has_content> - <div class="form-group"> - <label>${i18nBundle.lastEditedBy}: ${observation.lastEditedByUser.firstName} ${observation.lastEditedByUser.lastName}</label> - </div> - </#if> - <#if ! observation.organism?has_content> - <div class="form-group"> - <label for="cropCategoryId">${i18nBundle.listSelectedCropCategoryOnTop}</label> - <select class="form-control" id="cropCategoryIdList" name="cropCategoryId" onchange="filterCrops(this.options[this.options.selectedIndex].value);"> + <#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if> + </div> + <#if messageKey?has_content> + <div class="alert alert-success">${i18nBundle(messageKey)}</div> + </#if> + <div class="row"> + <div class="col-md-6"> + <#assign formId = "observationForm"> + <form id="${formId}" role="form" action="/observation?action=observationFormSubmit" + enctype="multipart/form-data" method="POST" onsubmit="return prepareFormSubmit(this);"> + <!--form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="this['geoInfo'].value=getFeatures();mw.save();console.log(this['observationData']);this['observationData'].value=JSON.stringify(mw.toInspect);return validateForm(this);"--> + <!--form id="${formId}" role="form" action="/observation?action=observationFormSubmit" method="POST" onsubmit="this['geoInfo'].value=getFeatures();mw.save();console.log(this['observationData']);this['observationData'].value=JSON.stringify(mw.toInspect);validateForm(this);return false;"--> + <input type="hidden" name="geoInfo" value=""/> + <input type="hidden" name="observationData" value=""/> + <input type="hidden" name="observationId" value="${observation.observationId!"-1"}"/> + <!--button type="button" onclick="var theForm=document.getElementById('observationForm');theForm['geoInfo'].value=getFeatures();try{mw.save();theForm['observationData'].value=JSON.stringify(mw.toInspect);return validateForm(theForm) && validateGIS(theForm);}catch(e){console.log(e.message);console.log(e);return false;}">Test</button--> + <#if observation.user?has_content> + <div class="form-group"> + <label>${i18nBundle.observer} + : ${observation.user.firstName} ${observation.user.lastName}</label> + </div> + </#if> + <#if observation.lastEditedByUser?has_content> + <div class="form-group"> + <label>${i18nBundle.lastEditedBy} + : ${observation.lastEditedByUser.firstName} ${observation.lastEditedByUser.lastName}</label> + </div> + </#if> + <#if ! observation.organism?has_content> + <div class="form-group"> + <label for="cropCategoryId">${i18nBundle.listSelectedCropCategoryOnTop}</label> + <select class="form-control" id="cropCategoryIdList" name="cropCategoryId" + onchange="filterCrops(this.options[this.options.selectedIndex].value);"> <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.cropCategory?lower_case}</option> <!-- Options added by JavaScript function renderCropCategories() --> - </select> - </div> - </#if> - <div class="form-group"> - <label for="cropOrganismId">${i18nBundle.cropOrganismId}</label> - <select class="form-control" id="cropOrganismIdList" name="cropOrganismId" <#if observation.observationId?has_content && ! user.isSuperUser() && ! user.isOrganizationAdmin()>readonly="readonly" <#else> onblur="validateField(this);" onchange="updateCropPests();"</#if>> - <#if ! observation.observationId?has_content || user.isSuperUser() || user.isOrganizationAdmin()> - <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.cropOrganismId?lower_case}</option> - <option value="-10"<#if (observation.cropOrganism?has_content && observation.cropOrganism.organismId == -10)>selected="selected"</#if>>${i18nBundle.missingInDatabase}</option> - </#if> - </select> - <span class="help-block" id="${formId}_cropOrganismId_validation"></span> - </div> - <div class="form-group"> - <label for="organismId">${i18nBundle.organism}</label> - <select class="form-control" name="organismId" <#if observation.organism?has_content && ! user.isSuperUser() && ! user.isOrganizationAdmin()>readonly="readonly"<#else>onchange="<#if noBroadcast>updateHeadingAndText(this.options[this.options.selectedIndex].text);</#if>initObservationData(this.options[this.options.selectedIndex].value,organizationId);" onblur="validateField(this);"</#if>> - <#if ! observation.organism?has_content || user.isSuperUser() || user.isOrganizationAdmin()> - <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.organism?lower_case}</option> - <option value="-10"<#if (observation.organism?has_content && observation.organism.organismId == -10)>selected="selected"</#if>>${i18nBundle.missingInDatabase}</option> - <#list allPests as organism> - <option value="${organism.organismId}" - <#if (observation.organism?has_content && observation.organism.organismId == organism.organismId)>selected="selected"</#if> - >${organism.getLocalName(currentLocale.language)!""} (${organism.latinName!""}) ${hierarchyCategories.getName(organism.hierarchyCategoryId)?upper_case}</option> - </#list> - <#else> - <#list allPests as organism> - <#if (observation.organism?has_content && observation.organism.organismId == organism.organismId)> - <option value="${organism.organismId}" selected="selected">${organism.getLocalName(currentLocale.language)!""} (${organism.latinName!""}) ${hierarchyCategories.getName(organism.hierarchyCategoryId)?upper_case}</option> - </#if> - </#list> - </#if> - </select> - <span class="help-block" id="${formId}_organismId_validation"></span> - - </div> - <div class="form-group"> - <label for="locationPointOfInterestId">${i18nBundle.location} <button role="button" type="button" onclick="addNewLocationPopup();">${i18nBundle.addNew}</button></label> - <select class="form-control" name="locationPointOfInterestId" id="locationPointOfInterestId" onchange="showCorrectMap();" <#if editAccess!="W">readonly="readonly"</#if>> - <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.location?lower_case}</option> - </select> - <span class="help-block" id="${formId}_locationPointOfInterestId_validation"></span> - </div> - <#if editAccess!="W" && observation.locationIsPrivate?has_content && observation.locationIsPrivate == true> - <input type="hidden" name="locationVisibility" value="private"/> - <#else> - <div class="form-group"> - <div class="radio"> - <label> - <input type="radio" name="locationVisibility" value="public" - <#if locationVisibilityFormValue == "public">checked="checked"</#if> - /> - </label> - ${i18nBundle.locationIsPublic} - </div> - <div class="radio"> - - <label> - <input type="radio" name="locationVisibility" value="private" - <#if locationVisibilityFormValue == "private">checked="checked"</#if> - /> - </label> - ${i18nBundle.locationIsPrivate} - </div> - <#list polygonServices as polygonService> - <div class="radio"> - <label> - <input type="radio" name="locationVisibility" value="mask_${polygonService.polygonServiceId}" - <#if locationVisibilityFormValue == "mask_" + polygonService.polygonServiceId>checked="checked"</#if> - /> - ${i18nBundle.maskObservationWith} ${polygonService.polygonServiceName} - </label> - </div> - </#list> - </div> - </#if> - <div class="form-group"> - <label for="organizationGroupId">${i18nBundle.availableFor} ${i18nBundle.organizationGroupList?lower_case}</label> - <select class="form-control chosen-select" name="organizationGroupId" multiple="multiple" data-placeholder="${i18nBundle.all}" <#if editAccess!="W">readonly="readonly"</#if>> - <#list organizationGroups as group> - <option value="${group.organizationGroupId}" <#if selectedOrganizationGroupIds?seq_contains(group.organizationGroupId)> selected="selected"</#if>>${group.groupName}</option> - </#list> - </select> - </div> - <#setting time_zone=user.organizationId.defaultTimeZone!"UTC"> - <div class="form-group"> - <label for="timeOfObservation">${i18nBundle.timeOfObservation}</label> - <input type="text" class="form-control" id="timeOfObservation" name="timeOfObservation" placeholder="${i18nBundle.timeOfObservation}" value="${(observation.timeOfObservation?string("yyyy-MM-dd HH:mmZ"))!.now?string("yyyy-MM-dd HH:mmZ")}" onblur="validateField(this);" <#if editAccess!="W">readonly="readonly"</#if>/> - <span class="help-block" id="${formId}_timeOfObservation_validation"></span> - </div> - <div class="form-group"> - <div class="checkbox"> - <#if editAccess!="W" && observation.isPositive?has_content && observation.isPositive ==true><input type="hidden" name="isPositive" value="true"/></#if> - <label> - <input type="checkbox" name="isPositive"<#if observation.isPositive?has_content && observation.isPositive == false><#else> checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> + </select> + </div> + </#if> + <div class="form-group"> + <label for="cropOrganismId">${i18nBundle.cropOrganismId}</label> + <select class="form-control" id="cropOrganismIdList" name="cropOrganismId" + <#if observation.observationId?has_content && ! user.isSuperUser() && ! user.isOrganizationAdmin()>readonly="readonly" <#else> onblur="validateField(this);" onchange="updateCropPests();"</#if>> + <#if ! observation.observationId?has_content || user.isSuperUser() || user.isOrganizationAdmin()> + <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.cropOrganismId?lower_case}</option> + <option value="-10" + <#if (observation.cropOrganism?has_content && observation.cropOrganism.organismId == -10)>selected="selected"</#if>>${i18nBundle.missingInDatabase}</option> + </#if> + </select> + <span class="help-block" id="${formId}_cropOrganismId_validation"></span> + </div> + <div class="form-group"> + <label for="organismId">${i18nBundle.organism}</label> + <select class="form-control" name="organismId" + <#if observation.organism?has_content && ! user.isSuperUser() && ! user.isOrganizationAdmin()>readonly="readonly" + <#else>onchange="<#if noBroadcast>updateHeadingAndText(this.options[this.options.selectedIndex].text);</#if>initObservationData(this.options[this.options.selectedIndex].value,organizationId);" + onblur="validateField(this);"</#if>> + <#if ! observation.organism?has_content || user.isSuperUser() || user.isOrganizationAdmin()> + <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.organism?lower_case}</option> + <option value="-10" + <#if (observation.organism?has_content && observation.organism.organismId == -10)>selected="selected"</#if>>${i18nBundle.missingInDatabase}</option> + <#list allPests as organism> + <option value="${organism.organismId}" + <#if (observation.organism?has_content && observation.organism.organismId == organism.organismId)>selected="selected"</#if> + >${organism.getLocalName(currentLocale.language)!""} (${organism.latinName!""} + ) ${hierarchyCategories.getName(organism.hierarchyCategoryId)?upper_case}</option> + </#list> + <#else> + <#list allPests as organism> + <#if (observation.organism?has_content && observation.organism.organismId == organism.organismId)> + <option value="${organism.organismId}" + selected="selected">${organism.getLocalName(currentLocale.language)!""} + (${organism.latinName!""} + ) ${hierarchyCategories.getName(organism.hierarchyCategoryId)?upper_case}</option> + </#if> + </#list> + </#if> + </select> + <span class="help-block" id="${formId}_organismId_validation"></span> + + </div> + <div class="form-group"> + <label for="locationPointOfInterestId">${i18nBundle.location} <button role="button" + type="button" + onclick="addNewLocationPopup();">${i18nBundle.addNew}</button> </label> - ${i18nBundle.isPositiveRegistration} + <select class="form-control" name="locationPointOfInterestId" id="locationPointOfInterestId" + onchange="showCorrectMap();" <#if editAccess!="W">readonly="readonly"</#if>> + <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.location?lower_case}</option> + </select> + <span class="help-block" id="${formId}_locationPointOfInterestId_validation"></span> </div> - </div> - <div class="form-group"> - <div class="checkbox"> - <#if editAccess!="W" && observation.isQuantified?has_content && observation.isQuantified ==true><input type="hidden" name="isQuantified" value="true"/></#if> - <label> - <input type="checkbox" name="isQuantified"<#if observation.isQuantified?has_content && observation.isQuantified == false><#else> checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> - </label> - ${i18nBundle.isQuantified} - </div> - </div> - <div class="form-group"> - <fieldset> - <legend>${i18nBundle.observationData}</legend> - <div id="quantificationFields"></div> - </fieldset> - </div> - <#if !noBroadcast> - <div class="form-group"> - <div class="checkbox"> - <#if editAccess!="W" && observation.broadcastMessage?has_content && observation.broadcastMessage ==true><input type="hidden" name="isQuantified" value="true"/></#if> - <label> - <input type="checkbox" name="broadcastMessage"<#if (observation.broadcastMessage?has_content && observation.broadcastMessage == false) || noBroadcast><#else>checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> - </label> - ${i18nBundle.broadcastMessage} - </div> - </div> - - <div class="form-group"> - <label for="observationHeading">${i18nBundle.observationHeading}</label> - <input type="text" class="form-control" name="observationHeading" placeholder="" value="${observation.observationHeading!""}" onblur="validateField(this);" <#if editAccess!="W">readonly="readonly"</#if>/> - <span class="help-block" id="${formId}_observationHeading_validation"></span> + <#if editAccess!="W" && observation.locationIsPrivate?has_content && observation.locationIsPrivate == true> + <input type="hidden" name="locationVisibility" value="private"/> + <#else> + <div class="form-group"> + <div class="radio"> + <label> + <input type="radio" name="locationVisibility" value="public" + <#if locationVisibilityFormValue == "public">checked="checked"</#if> + /> + </label> + ${i18nBundle.locationIsPublic} + </div> + <div class="radio"> + + <label> + <input type="radio" name="locationVisibility" value="private" + <#if locationVisibilityFormValue == "private">checked="checked"</#if> + /> + </label> + ${i18nBundle.locationIsPrivate} </div> - <div class="form-group"> - <label for="observationText">${i18nBundle.observationText}</label> - <textarea class="form-control" name="observationText" placeholder="" <#if editAccess!="W">readonly="readonly"</#if>>${observation.observationText!""}</textarea> - <span class="help-block" id="${formId}_observationText_validation"></span> + <#list polygonServices as polygonService> + <div class="radio"> + <label> + <input type="radio" name="locationVisibility" + value="mask_${polygonService.polygonServiceId}" + <#if locationVisibilityFormValue == "mask_" + polygonService.polygonServiceId>checked="checked"</#if> + /> + ${i18nBundle.maskObservationWith} ${polygonService.polygonServiceName} + </label> + </div> + </#list> + </div> + </#if> + <div class="form-group"> + <label for="organizationGroupId">${i18nBundle.availableFor} ${i18nBundle.organizationGroupList?lower_case}</label> + <select class="form-control chosen-select" name="organizationGroupId" multiple="multiple" + data-placeholder="${i18nBundle.all}" <#if editAccess!="W">readonly="readonly"</#if>> + <#list organizationGroups as group> + <option value="${group.organizationGroupId}" <#if selectedOrganizationGroupIds?seq_contains(group.organizationGroupId)> selected="selected"</#if>>${group.groupName}</option> + </#list> + </select> + </div> + <#setting time_zone=user.organizationId.defaultTimeZone!"UTC"> + <div class="form-group"> + <label for="timeOfObservation">${i18nBundle.timeOfObservation}</label> + <input type="text" class="form-control" id="timeOfObservation" name="timeOfObservation" + placeholder="${i18nBundle.timeOfObservation}" + value="${(observation.timeOfObservation?string("yyyy-MM-dd HH:mmZ"))!.now?string("yyyy-MM-dd HH:mmZ")}" + onblur="validateField(this);" <#if editAccess!="W">readonly="readonly"</#if>/> + <span class="help-block" id="${formId}_timeOfObservation_validation"></span> + </div> + <div class="form-group"> + <div class="checkbox"> + <#if editAccess!="W" && observation.isPositive?has_content && observation.isPositive ==true> + <input type="hidden" name="isPositive" value="true"/></#if> + <label> + <input type="checkbox" + name="isPositive"<#if observation.isPositive?has_content && observation.isPositive == false><#else> checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> + </label> + ${i18nBundle.isPositiveRegistration} + </div> + </div> + <div class="form-group"> + <div class="checkbox"> + <#if editAccess!="W" && observation.isQuantified?has_content && observation.isQuantified ==true> + <input type="hidden" name="isQuantified" value="true"/></#if> + <label> + <input type="checkbox" + name="isQuantified"<#if observation.isQuantified?has_content && observation.isQuantified == false><#else> checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> + </label> + ${i18nBundle.isQuantified} + </div> + </div> + <div class="form-group"> + <fieldset> + <legend>${i18nBundle.observationData}</legend> + <div id="quantificationFields"></div> + </fieldset> + </div> + <#if !noBroadcast> + <div class="form-group"> + <div class="checkbox"> + <#if editAccess!="W" && observation.broadcastMessage?has_content && observation.broadcastMessage ==true> + <input type="hidden" name="isQuantified" value="true"/></#if> + <label> + <input type="checkbox" name="broadcastMessage" + <#if (observation.broadcastMessage?has_content && observation.broadcastMessage == false) || noBroadcast><#else>checked="checked"</#if> <#if editAccess!="W">disabled="disabled"</#if>/> + </label> + ${i18nBundle.broadcastMessage} </div> - <#if observation.observationIllustrationSet?has_content && observation.observationIllustrationSet?size gt 0> - <#list observation.observationIllustrationSet as illustration> - <img src="/static/images/observations/${observation.organismId}/${illustration.observationIllustrationPK.fileName}" alt="TODO: Add describing text" class="img-responsive"/> - <div class="checkbox"> + </div> + + <div class="form-group"> + <label for="observationHeading">${i18nBundle.observationHeading}</label> + <input type="text" class="form-control" name="observationHeading" placeholder="" + value="${observation.observationHeading!""}" onblur="validateField(this);" + <#if editAccess!="W">readonly="readonly"</#if>/> + <span class="help-block" id="${formId}_observationHeading_validation"></span> + </div> + <div class="form-group"> + <label for="observationText">${i18nBundle.observationText}</label> + <textarea class="form-control" name="observationText" placeholder="" + <#if editAccess!="W">readonly="readonly"</#if>>${observation.observationText!""}</textarea> + <span class="help-block" id="${formId}_observationText_validation"></span> + </div> + <#if observation.observationIllustrationSet?has_content && observation.observationIllustrationSet?size gt 0> + <#list observation.observationIllustrationSet as illustration> + <img src="/static/images/observations/${observation.organismId}/${illustration.observationIllustrationPK.fileName}" + alt="TODO: Add describing text" class="img-responsive"/> + <div class="checkbox"> <label> - <input type="checkbox" name="deleteIllustration" value="${illustration.observationIllustrationPK.fileName}"/> - ${i18nBundle.deleteIllustration} + <input type="checkbox" name="deleteIllustration" + value="${illustration.observationIllustrationPK.fileName}"/> + ${i18nBundle.deleteIllustration} </label> - </div> - </#list> - </#if> - <div class="form-group"> - <div class="input-group"> - <label for="illustration"><#if observation.observationIllustrationSet?has_content && observation.observationIllustrationSet?size gt 0>${i18nBundle.addIllustration}<#else>${i18nBundle.newIllustration}</#if></label><br/> - <span class="btn btn-default btn-file">${i18nBundle.browse}<input type="file" name="illustration"></span> - <input type="text" class="form-control" readonly> - </div> - </div> - <#else> - <!-- broadcastMessage is checkbox, omitting it sets it default to false --> - <input type="hidden" id="observationHeading" name="observationHeading" value="<#if observation.organism?has_content>${i18nBundle.registrationOf} ${observation.organism.getLocalName(currentLocale.language)!""} (${observation.organism.latinName!""})</#if>"/> - <input type="hidden" id="observationText" name="observationText" value="<#if observation.organism?has_content>${i18nBundle.registrationOf} ${observation.organism.getLocalName(currentLocale.language)!""} (${observation.organism.latinName!""})</#if>"/> - </#if> <!-- visibility --> - <#if user.isObservationAuthority() || user.isOrganizationAdmin() || user.isSuperUser()> - <div class="form-group"> - <label for="statusTypeId">${i18nBundle.statusTypeId}</label> - <select class="form-control" name="statusTypeId" onblur="validateField(this);"> - <#list statusTypeIds as statusTypeId> - <option value="${statusTypeId.statusTypeId}" - <#if observation.statusTypeId?has_content && observation.statusTypeId == statusTypeId.statusTypeId>selected="selected"</#if> - <#if !observation.statusTypeId?has_content && 3 == statusTypeId.statusTypeId>selected="selected"</#if> - >${i18nBundle("statusTypeIdTitle_" + statusTypeId.statusTypeId)}</option> - </#list> - </select> - <span class="help-block" id="${formId}_statusTypeId_validation"></span> - </div> - <div class="form-group"> - <label for="statusRemarks">${i18nBundle.statusRemarks}</label> - <textarea class="form-control" name="statusRemarks" placeholder="" >${observation.statusRemarks!""}</textarea> - <span class="help-block" id="${formId}_statusRemarks_validation"></span> - </div> - </#if> - <button type="submit" class="btn btn-default">${i18nBundle.submit}</button> - <#if observation.observationId?has_content && editAccess == "W"> - <button type="button" class="btn btn-danger" onclick="if(confirm('${i18nBundle.confirmDelete}')){window.location.href='/observation?action=deleteObservation&observationId=${observation.observationId}';}">${i18nBundle.delete}</button> - </#if> - </form> - </div> - <div class="col-md-6"> - <div id="observationFormMap"></div> <!-- Contents is added dynamically by objectGISInfoMap --> - <div id="poiFormMap" class="map" style="height: 400px;"> - <div id="popover"></div> - </div> - </div> - </div> - <div style="display: none;"><div id="poiMarker" title="Marker"><img src="/public/images/Map_pin_icon_green_small.png"/></div></div> -</div> + </div> + </#list> + </#if> + <div class="form-group"> + <div class="input-group"> + <label for="illustration"><#if observation.observationIllustrationSet?has_content && observation.observationIllustrationSet?size gt 0>${i18nBundle.addIllustration}<#else>${i18nBundle.newIllustration}</#if></label><br/> + <span class="btn btn-default btn-file">${i18nBundle.browse}<input type="file" + name="illustration"></span> + <input type="text" class="form-control" readonly> + </div> + </div> + <#else> + <!-- broadcastMessage is checkbox, omitting it sets it default to false --> + <input type="hidden" id="observationHeading" name="observationHeading" + value="<#if observation.organism?has_content>${i18nBundle.registrationOf} ${observation.organism.getLocalName(currentLocale.language)!""} (${observation.organism.latinName!""})</#if>"/> + <input type="hidden" id="observationText" name="observationText" + value="<#if observation.organism?has_content>${i18nBundle.registrationOf} ${observation.organism.getLocalName(currentLocale.language)!""} (${observation.organism.latinName!""})</#if>"/> + </#if> <!-- visibility --> + <#if user.isObservationAuthority() || user.isOrganizationAdmin() || user.isSuperUser()> + <div class="form-group"> + <label for="statusTypeId">${i18nBundle.statusTypeId}</label> + <select class="form-control" name="statusTypeId" onblur="validateField(this);"> + <#list statusTypeIds as statusTypeId> + <option value="${statusTypeId.statusTypeId}" + <#if observation.statusTypeId?has_content && observation.statusTypeId == statusTypeId.statusTypeId>selected="selected"</#if> + <#if !observation.statusTypeId?has_content && 3 == statusTypeId.statusTypeId>selected="selected"</#if> + >${i18nBundle("statusTypeIdTitle_" + statusTypeId.statusTypeId)}</option> + </#list> + </select> + <span class="help-block" id="${formId}_statusTypeId_validation"></span> + </div> + <div class="form-group"> + <label for="statusRemarks">${i18nBundle.statusRemarks}</label> + <textarea class="form-control" name="statusRemarks" + placeholder="">${observation.statusRemarks!""}</textarea> + <span class="help-block" id="${formId}_statusRemarks_validation"></span> + </div> + </#if> + <button type="submit" class="btn btn-default">${i18nBundle.submit}</button> + <#if observation.observationId?has_content && editAccess == "W"> + <button type="button" class="btn btn-danger" + onclick="if(confirm('${i18nBundle.confirmDelete}')){window.location.href='/observation?action=deleteObservation&observationId=${observation.observationId}';}">${i18nBundle.delete}</button> + </#if> + </form> + </div> + <div class="col-md-6"> + <div id="observationFormMap"></div> <!-- Contents is added dynamically by objectGISInfoMap --> + <div id="poiFormMap" class="map" style="height: 400px;"> + <div id="popover"></div> + </div> + </div> + </div> + <div style="display: none;"> + <div id="poiMarker" title="Marker"><img src="/public/images/Map_pin_icon_green_small.png"/></div> + </div> + </div> </#macro> <@page_html/>