diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java index b911f8835e1776fc4233c30af6fcc025177ae0dd..cc178617f94fc1128fc82aebc4a4774269633246 100644 --- a/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java @@ -143,6 +143,7 @@ public class ObservationTimeSeriesBean { public void deleteObservationTimeSeries(Integer id) { ObservationTimeSeries observationTimeSeries = em.find(ObservationTimeSeries.class, id); if (observationTimeSeries != null) { + // The app prevents deletion of time series with observations observationBean.deleteObservationsForObservationTimeSeries(observationTimeSeries); em.remove(observationTimeSeries); } diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java index 92d6b90557429eecf02ee5649c6583fdba5dbd97..7d5a506af769de9b0a6b22a80ae92c1e0c6441e1 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Observation.java +++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java @@ -19,20 +19,7 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; +import javax.persistence.*; import javax.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -41,9 +28,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.FetchType; -import javax.persistence.OneToMany; import javax.validation.constraints.Size; import no.nibio.vips.logic.util.GISEntityUtil; import no.nibio.vips.gis.GISUtil; @@ -62,6 +46,7 @@ import org.hibernate.annotations.TypeDefs; @Table(name = "observation") @XmlRootElement @TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)}) + @NamedQueries({ @NamedQuery(name = "Observation.findAll", query = "SELECT o FROM Observation o"), @NamedQuery(name = "Observation.findByObservationId", query = "SELECT o FROM Observation o WHERE o.observationId = :observationId"), @@ -122,9 +107,18 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse private GISEntityUtil GISEntityUtil; private GISUtil GISUtil; + // Should be defined as an enum (WEB/APP), but PostgreSQLEnumType and hibernate6 seems to be necessary + // https://stackoverflow.com/questions/50818649/hibernate-and-java-and-postgres-enumeratedvalue-enumtype-string-caused-by + private String source; + public Observation() { + this("WEB"); + } + + public Observation(String source) { this.GISEntityUtil = new GISEntityUtil(); this.GISUtil = new GISUtil(); + this.source = source; } public Observation(Integer observationId) { @@ -304,6 +298,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse ", observationIllustrationSet=" + observationIllustrationSet + ", GISEntityUtil=" + GISEntityUtil + ", GISUtil=" + GISUtil + + ", source=" + source + '}'; } @@ -727,4 +722,12 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setIsPositive(Boolean positive) { isPositive = positive; } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } } diff --git a/src/main/java/no/nibio/vips/logic/service/ObservationService.java b/src/main/java/no/nibio/vips/logic/service/ObservationService.java index 4e093d77a7a792cba057ff5ef2e22ad345dba4d1..3b1dacb611c2c75762e4766a591ffba706f5c5c8 100755 --- a/src/main/java/no/nibio/vips/logic/service/ObservationService.java +++ b/src/main/java/no/nibio/vips/logic/service/ObservationService.java @@ -924,11 +924,17 @@ public class ObservationService { return Response.status(Status.NOT_FOUND).build(); } } else { - Observation mergeObs = ((Integer) mapFromApp.get("observationId")) > 0 ? observationBean.getObservation((Integer) mapFromApp.get("observationId")) : new Observation(); - // Trying to sync a non-existing observation - if (mergeObs == null) { - return Response.status(Status.NOT_FOUND).build(); + Integer observationId = (Integer) mapFromApp.get("observationId"); + Observation mergeObs; + if(observationId > 0) { + mergeObs = observationBean.getObservation(observationId); + if (mergeObs == null) { + return Response.status(Status.NOT_FOUND).build(); + } + } else { + mergeObs = new Observation("APP"); } + // Observation time series if(mapFromApp.get("observationTimeSeriesId") != null) { Integer observationTimeSeriesId = (Integer) mapFromApp.get("observationTimeSeriesId"); @@ -942,24 +948,23 @@ public class ObservationService { mergeObs.setTimeOfObservation(oM.convertValue(mapFromApp.get("timeOfObservation"), new TypeReference<Date>() { })); mergeObs.setIsPositive(mapFromApp.get("isPositive") != null ? (Boolean) mapFromApp.get("isPositive") : false); - mergeObs.setUserId(mapFromApp.get("userId") != null ? Integer.valueOf((Integer) mapFromApp.get("userId")) : user.getUserId()); + mergeObs.setUserId(mapFromApp.get("userId") != null ? (Integer) mapFromApp.get("userId") : user.getUserId()); mergeObs.setGeoinfo((String) mapFromApp.get("geoinfo")); mergeObs.setLocationPointOfInterestId(mapFromApp.get("locationPointOfInterestId") != null ? (Integer) mapFromApp.get("locationPointOfInterestId") : null); mergeObs.setObservationHeading(mapFromApp.get("observationHeading") != null ? (String) mapFromApp.get("observationHeading") : null); mergeObs.setObservationText(mapFromApp.get("observationText") != null ? (String) mapFromApp.get("observationText") : null); mergeObs.setBroadcastMessage(mapFromApp.get("broadcastMessage") != null ? (Boolean) mapFromApp.get("broadcastMessage") : false); - mergeObs.setStatusTypeId(Integer.valueOf((Integer) mapFromApp.get("statusTypeId"))); + mergeObs.setStatusTypeId((Integer) mapFromApp.get("statusTypeId")); // If the user has the role of observation approver, change to approved if set to pending if (mergeObs.getStatusTypeId().equals(ObservationStatusType.STATUS_PENDING) && user.isObservationAuthority()) { mergeObs.setStatusTypeId(ObservationStatusType.STATUS_APPROVED); } - mergeObs.setStatusChangedByUserId(mapFromApp.get("statusChangedByUserId") != null ? (Integer) mapFromApp.get("statusChangedByUserId") : null); + mergeObs.setStatusChangedByUserId(mapFromApp.get("userId") != null ? (Integer) mapFromApp.get("userId") : null); mergeObs.setStatusChangedTime(mapFromApp.get("timeOfObservation") != null ? oM.convertValue(mapFromApp.get("timeOfObservation"), new TypeReference<Date>() { }) : null); mergeObs.setStatusRemarks(mapFromApp.get("statusRemarks") != null ? (String) mapFromApp.get("statusRemarks") : null); mergeObs.setIsQuantified(mapFromApp.get("isQuantified") != null ? (Boolean) mapFromApp.get("isQuantified") : false); mergeObs.setLocationIsPrivate(mapFromApp.get("locationIsPrivate") != null ? (Boolean) mapFromApp.get("locationIsPrivate") : false); - Object polygonServiceValue = mapFromApp.get("polygonService"); if(polygonServiceValue != null && !polygonServiceValue.toString().isBlank()) { PolygonService polygonService = oM.convertValue(mapFromApp.get("polygonService"), PolygonService.class); @@ -974,7 +979,7 @@ public class ObservationService { // Input check before storing // Location must be set if ((mergeObs.getGeoinfo() == null || mergeObs.getGeoinfo().trim().isEmpty()) && mergeObs.getLocationPointOfInterestId() == null) { - return Response.status(Status.BAD_REQUEST).entity("The observation is missing location data.").build(); + return Response.status(Status.BAD_REQUEST).entity("{\"error\": \"The observation is missing location data.\"}").type(MediaType.APPLICATION_JSON).build(); } boolean sendNotification = false; @@ -995,7 +1000,6 @@ public class ObservationService { // We need to get an observation Id before storing the illustrations! mergeObs = observationBean.storeObservation(mergeObs); - // ObservationIllustrationSet // Including data that may need to be stored if (mapFromApp.get("observationIllustrationSet") != null) { diff --git a/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java b/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java index e074ee6fcfa1a763a4b025f82ac5594de087dbf5..e0c5d0a0b25b97756abaa9a457cb6b2adb896bbc 100644 --- a/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java +++ b/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java @@ -197,6 +197,7 @@ public class ObservationTimeSeriesService { Boolean isDeleted = (Boolean) mapFromApp.getOrDefault(DELETED, false); if (isDeleted) { // If marked as deleted, delete the observation time series if it exists + // Observations in time series are also deleted, but the app currently prevents this. if (observationTimeSeriesBean.getObservationTimeSeries(otsId) != null) { observationTimeSeriesBean.deleteObservationTimeSeries(otsId); LOGGER.info("ObservationTimeSeries with id={} deleted", otsId);