Commit f98c0009 authored by LAVENIER's avatar LAVENIER
Browse files

[fix] Fix landing deletion (delete trip before, using a HqlQuery)

parent d8968d01
......@@ -27,6 +27,9 @@ import net.sumaris.core.model.data.Landing;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.LandingVO;
import net.sumaris.core.vo.filter.LandingFilterVO;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Collection;
import java.util.Optional;
......@@ -37,6 +40,7 @@ public interface LandingRepository extends
Optional<Landing> findByTripId(Integer tripId);
void deleteByIdIn(Collection<Integer> landingIds);
@Modifying
@Query("delete from Landing l where l.id in (:ids)")
void deleteByIds(@Param("ids") Collection<Integer> ids);
}
......@@ -27,13 +27,24 @@ import net.sumaris.core.model.data.Trip;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.TripVO;
import net.sumaris.core.vo.filter.TripFilterVO;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Collection;
public interface TripRepository extends
RootDataRepository<Trip, TripVO, TripFilterVO, DataFetchOptions>,
TripSpecifications {
@Query("select p.id from Trip t inner join t.program p where t.id = :id")
int getProgramIdById(@Param("id") int id);
@Modifying
@Query("delete from Trip t where t.id in (select l.trip.id from Landing l where l.id = :landingId)")
void deleteByLandingId(@Param("landingId") int landingId);
@Modifying
@Query("delete from Trip t where t.id in (select l.trip.id from Landing l where l.id in (:landingIds))")
void deleteByLandingIds(@Param("landingIds") Collection<Integer> landingIds);
}
......@@ -23,10 +23,7 @@ package net.sumaris.core.service.data;
*/
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.*;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.dao.administration.programStrategy.ProgramRepository;
import net.sumaris.core.dao.data.MeasurementDao;
......@@ -36,7 +33,6 @@ import net.sumaris.core.dao.data.operation.OperationGroupRepository;
import net.sumaris.core.dao.data.trip.TripRepository;
import net.sumaris.core.dao.referential.metier.MetierRepository;
import net.sumaris.core.dao.technical.Page;
import net.sumaris.core.dao.technical.Pageables;
import net.sumaris.core.exception.SumarisTechnicalException;
import net.sumaris.core.service.data.vessel.VesselService;
import net.sumaris.core.util.Beans;
......@@ -294,7 +290,12 @@ public class AggregatedLandingServiceImpl implements AggregatedLandingService {
}
if (!landingIdsToRemove.isEmpty()) {
// Delete remaining landings
landingRepository.deleteByIdIn(landingIdsToRemove);
// Delete linked trips
tripRepository.deleteByLandingIds(landingIdsToRemove);
// Delete landing
landingRepository.deleteByIds(landingIdsToRemove);
// Add the observed location to check list
observationIdsToCheck.add(observedLocation.getId());
}
......@@ -382,7 +383,7 @@ public class AggregatedLandingServiceImpl implements AggregatedLandingService {
landings = getLandings(observedLocationId);
}
// Delete landings
landingRepository.deleteByIdIn(Beans.collectIds(landings));
landingRepository.deleteByIds(Beans.collectIds(landings));
// Delete observed location
observedLocationRepository.deleteById(observedLocationId);
......
......@@ -50,6 +50,9 @@ public interface LandingService {
@Transactional(readOnly = true)
LandingVO get(Integer id);
@Transactional(readOnly = true)
LandingVO get(Integer landingId, DataFetchOptions fetchOptions);
List<LandingVO> saveAllByObservedLocationId(int observedLocationId, List<LandingVO> data);
LandingVO save(LandingVO data);
......
......@@ -23,7 +23,9 @@ package net.sumaris.core.service.data;
*/
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.dao.data.MeasurementDao;
import net.sumaris.core.dao.data.landing.LandingRepository;
......@@ -35,13 +37,13 @@ import net.sumaris.core.event.config.ConfigurationUpdatedEvent;
import net.sumaris.core.event.entity.EntityDeleteEvent;
import net.sumaris.core.event.entity.EntityInsertEvent;
import net.sumaris.core.event.entity.EntityUpdateEvent;
import net.sumaris.core.model.data.IMeasurementEntity;
import net.sumaris.core.model.data.Landing;
import net.sumaris.core.model.data.LandingMeasurement;
import net.sumaris.core.model.data.Trip;
import net.sumaris.core.model.referential.pmfm.MatrixEnum;
import net.sumaris.core.service.data.vessel.VesselService;
import net.sumaris.core.util.Beans;
import net.sumaris.core.util.DataBeans;
import net.sumaris.core.util.Dates;
import net.sumaris.core.vo.data.*;
import net.sumaris.core.vo.data.sample.SampleVO;
import net.sumaris.core.vo.filter.LandingFilterVO;
......@@ -51,6 +53,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
......@@ -66,6 +70,9 @@ public class LandingServiceImpl implements LandingService {
@Autowired
protected TripService tripService;
@Autowired
protected VesselService vesselService;
@Autowired
protected TripRepository tripRepository;
......@@ -112,8 +119,32 @@ public class LandingServiceImpl implements LandingService {
}
@Override
public LandingVO get(Integer landingId) {
return landingRepository.get(landingId);
public LandingVO get(Integer id) {
return get(id, DataFetchOptions.DEFAULT);
}
@Override
public LandingVO get(Integer id, @NonNull DataFetchOptions fetchOptions) {
LandingVO target = landingRepository.get(id, fetchOptions);
// Fetch children (disabled by default)
if (fetchOptions.isWithChildrenEntities()) {
target.setVesselSnapshot(vesselService.getSnapshotByIdAndDate(target.getVesselSnapshot().getId(), Dates.resetTime(target.getDateTime())));
target.setSamples(sampleService.getAllByLandingId(id));
if (target.getTripId() != null) {
TripVO trip = tripService.get(target.getTripId(), fetchOptions);
target.setTrip(trip);
}
}
// Measurements
if (fetchOptions.isWithMeasurementValues()) {
target.setMeasurements(measurementDao.getLandingMeasurements(id));
}
return target;
}
@Override
......@@ -166,32 +197,19 @@ public class LandingServiceImpl implements LandingService {
@Override
public void delete(int id) {
log.info("Delete Landing#{} {trash: {}}", id, enableTrash);
// Create events (before deletion, to be able to join VO)
Landing toDelete = null;
LandingVO deletedVO = null;
Integer tripId = null;
if (enableTrash) {
toDelete = landingRepository.getById(id);
deletedVO = landingRepository.toVO(toDelete);
tripId = deletedVO.getTripId();
if (tripId != null) {
deletedVO.setTrip(tripRepository.get(tripId)); // TODO full VO loading
}
}
LandingVO eventData = enableTrash ? get(id, DataFetchOptions.FULL_GRAPH) : null;
if (tripId != null) {
tripRepository.deleteById(tripId);
}
// Delete linked trips
tripRepository.deleteByLandingId(id);
// Apply deletion
if (toDelete == null)
landingRepository.deleteById(id);
else
landingRepository.delete(toDelete);
// Delete landing
landingRepository.deleteByIds(ImmutableList.of(id));
// Publish events
publisher.publishEvent(new EntityDeleteEvent(id, Landing.class.getSimpleName(), deletedVO));
publisher.publishEvent(new EntityDeleteEvent(id, Landing.class.getSimpleName(), eventData));
}
@Override
......
......@@ -35,6 +35,9 @@ import net.sumaris.core.dao.data.observedLocation.ObservedLocationRepository;
import net.sumaris.core.dao.data.trip.TripRepository;
import net.sumaris.core.dao.technical.Page;
import net.sumaris.core.dao.technical.SortDirection;
import net.sumaris.core.event.config.ConfigurationEvent;
import net.sumaris.core.event.config.ConfigurationReadyEvent;
import net.sumaris.core.event.config.ConfigurationUpdatedEvent;
import net.sumaris.core.event.entity.EntityDeleteEvent;
import net.sumaris.core.event.entity.EntityInsertEvent;
import net.sumaris.core.event.entity.EntityUpdateEvent;
......@@ -55,6 +58,7 @@ import net.sumaris.core.vo.referential.MetierVO;
import net.sumaris.core.vo.referential.ReferentialVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.Collection;
......@@ -83,6 +87,7 @@ public class TripServiceImpl implements TripService {
private final ReferentialService referentialService;
private final FishingAreaService fishingAreaService;
private final VesselService vesselService;
private boolean enableTrash = false;
public TripServiceImpl(MeasurementDao measurementDao, SumarisConfiguration configuration, TripRepository tripRepository, SaleService saleService, ExpectedSaleService expectedSaleService,
OperationService operationService, OperationGroupService operationGroupService, PhysicalGearService physicalGearService, ApplicationEventPublisher publisher,
......@@ -105,6 +110,11 @@ public class TripServiceImpl implements TripService {
this.referentialService = referentialService;
}
@EventListener({ConfigurationReadyEvent.class, ConfigurationUpdatedEvent.class})
public void onConfigurationReady(ConfigurationEvent event) {
this.enableTrash = event.getConfiguration().enableEntityTrash();
}
@Override
public List<TripVO> findAll(TripFilterVO filter, int offset, int size, String sortAttribute,
SortDirection sortDirection, DataFetchOptions fieldOptions) {
......@@ -123,7 +133,7 @@ public class TripServiceImpl implements TripService {
@Override
public TripVO get(int id) {
return get(id, DataFetchOptions.builder().build());
return get(id, DataFetchOptions.DEFAULT);
}
@Override
......@@ -142,7 +152,7 @@ public class TripServiceImpl implements TripService {
fillTripLandingLinks(target);
// Operation groups
if (target.getLanding() != null) {
if (target.getLandingId() != null || target.getLanding() != null) {
target.setOperationGroups(operationGroupService.findAllByTripId(id, fetchOptions));
target.setMetiers(operationGroupService.getMetiersByTripId(id));
}
......@@ -173,7 +183,11 @@ public class TripServiceImpl implements TripService {
Preconditions.checkNotNull(target.getId());
landingRepository.findByTripId(target.getId()).ifPresent(landing -> {
target.setLanding(landingRepository.toVO(landing, DataFetchOptions.builder().withRecorderDepartment(false).withObservers(false).build()));
target.setLandingId(landing.getId());
// Should be not fetch here
//target.setLanding(landingRepository.toVO(landing, DataFetchOptions.builder().withRecorderDepartment(false).withObservers(false).build()));
if (landing.getObservedLocation() != null) {
target.setObservedLocationId(landing.getObservedLocation().getId());
}
......@@ -332,7 +346,6 @@ public class TripServiceImpl implements TripService {
@Override
public void delete(int id) {
boolean enableTrash = configuration.enableEntityTrash();
log.info("Delete Trip#{} {trash: {}}", id, enableTrash);
TripVO eventData = enableTrash ?
......
......@@ -52,7 +52,7 @@ public class DataFetchOptions implements IDataFetchOptions {
private boolean withObservers = true;
@Builder.Default
private boolean withChildrenEntities = false;
private boolean withChildrenEntities = false; // Important: should be disabled by default (see TripService or LandingService)
@Builder.Default
private boolean withMeasurementValues = false;
......
......@@ -29,28 +29,22 @@ import com.google.common.collect.Maps;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.execution.SubscriptionExecutionStrategy;
import graphql.schema.GraphQLSchema;
import lombok.extern.slf4j.Slf4j;
import net.sumaris.core.event.config.ConfigurationEvent;
import net.sumaris.core.event.config.ConfigurationEventListener;
import net.sumaris.core.event.config.ConfigurationReadyEvent;
import net.sumaris.core.event.config.ConfigurationUpdatedEvent;
import net.sumaris.core.service.technical.ConfigurationService;
import net.sumaris.server.config.SumarisServerConfiguration;
import net.sumaris.core.util.Beans;
import net.sumaris.server.exception.ErrorCodes;
import net.sumaris.server.http.security.AuthService;
import net.sumaris.server.util.security.AuthTokenVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.ehcache.spi.service.ServiceConfiguration;
import org.nuiton.i18n.I18n;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
......@@ -65,10 +59,10 @@ import org.springframework.web.socket.handler.TextWebSocketHandler;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j
public class SubscriptionWebSocketHandler extends TextWebSocketHandler {
......@@ -160,8 +154,11 @@ public class SubscriptionWebSocketHandler extends TextWebSocketHandler {
protected void handleInitConnection(WebSocketSession session, Map<String, Object> request) {
// When not ready, force to stop the security chain
if (!this.ready) {
// TODO: use session locale ?
throw new AuthenticationServiceException(I18n.t("sumaris.error.starting"));
// Get user locale, from the session headers
Locale locale = Beans.getStream(session.getHandshakeHeaders().getAcceptLanguageAsLocales())
.findFirst()
.orElse(I18n.getDefaultLocale());
throw new AuthenticationServiceException(I18n.l(locale, "sumaris.error.starting"));
}
Map<String, Object> payload = (Map<String, Object>) request.get("payload");
......
......@@ -225,6 +225,18 @@ public class DataGraphQLService {
return result;
}
@GraphQLQuery(name = "landing", description = "Get trip's landing")
public LandingVO getTripLanding(@GraphQLContext TripVO trip) {
if (trip.getLanding() != null) return trip.getLanding();
if (trip.getLandingId() == null) return null;
LandingVO target = landingService.get(trip.getLandingId());
// Avoid trip to be reload from landing (in GraphQL fragment)
target.setTrip(trip);
return target;
}
@GraphQLMutation(name = "saveTrip", description = "Create or update a trip")
@IsUser
public TripVO saveTrip(@GraphQLNonNull @GraphQLArgument(name = "trip") TripVO trip,
......@@ -900,7 +912,12 @@ public class DataGraphQLService {
public TripVO getTripByLanding(@GraphQLContext LandingVO landing) {
if (landing.getTrip() != null) return landing.getTrip(); // Used updated entity, if exists (e.g. when saving)
if (landing.getTripId() == null) return null;
return tripService.get(landing.getTripId());
TripVO target = tripService.get(landing.getTripId());
// Avoid landing to be reload from trip (in GraphQL fragment)
target.setLanding(landing);
return target;
}
@GraphQLMutation(name = "saveLanding", description = "Create or update an landing")
......@@ -1190,6 +1207,7 @@ public class DataGraphQLService {
return measurementService.getObservedLocationMeasurementsMap(observedLocation.getId());
}
// Landing
@GraphQLQuery(name = "measurementValues", description = "Get measurement values (as a key/value map, using pmfmId as key)")
public Map<Integer, String> getLandingMeasurementsMap(@GraphQLContext LandingVO landing) {
if (landing.getMeasurementValues() != null) {
......@@ -1228,7 +1246,9 @@ public class DataGraphQLService {
// Add vessel if need
vesselGraphQLService.fillVesselSnapshot(trip, fields);
if (fields.contains(StringUtils.slashing(TripVO.Fields.LANDING, LandingVO.Fields.ID)) || fields.contains(TripVO.Fields.OBSERVED_LOCATION_ID)) {
if (fields.contains(StringUtils.slashing(TripVO.Fields.LANDING, LandingVO.Fields.ID))
|| fields.contains(TripVO.Fields.LANDING_ID)
|| fields.contains(TripVO.Fields.OBSERVED_LOCATION_ID)) {
tripService.fillTripLandingLinks(trip);
}
}
......
......@@ -83,4 +83,4 @@ sumaris.server.mail.subject.prefix=[%s]
sumaris.server.person.register.confirm.success=Confirm registration of user {%s}
sumaris.server.started=Application is running on port\: {%s}
sumaris.server.subscription.getRequest=Received WS subscription request\: %s
sumaris.error.starting=Pod is starting. Please wait...
\ No newline at end of file
sumaris.error.starting=Pod is starting. Please wait...
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment