diff --git a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java index d6b0e6a5d..093d9c0da 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/OntologyController.java @@ -201,7 +201,7 @@ public HttpResponse unsubscribeOntology( * @param programId -- Program request information * @return * { - * programId, -- Program that owns the ontology the request program is subscribed to. + * programId, -- Program that owns the ontology the request program may subscribe to. * programName, * subscribed, -- boolean. Whether the requesting program is subscribed to this ontology or not. * editable -- boolean || null. Indicates whether this program can unsubscribe from this ontology or not. Null if not subscribed to this ontology. diff --git a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java index 1c81f2019..e5c261fed 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/TraitController.java @@ -38,7 +38,9 @@ import org.breedinginsight.model.Editable; import org.breedinginsight.model.Program; import org.breedinginsight.model.Trait; +import org.breedinginsight.services.OntologyService; import org.breedinginsight.services.TraitService; +import org.breedinginsight.services.exceptions.BadRequestException; import org.breedinginsight.services.exceptions.DoesNotExistException; import org.breedinginsight.services.exceptions.ValidatorException; import org.breedinginsight.utilities.response.ResponseUtils; @@ -50,6 +52,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; @Slf4j @Controller("/${micronaut.bi.api.version}") @@ -58,13 +61,15 @@ public class TraitController { private TraitService traitService; private SecurityService securityService; private TraitQueryMapper traitQueryMapper; + private OntologyService ontologyService; @Inject public TraitController(TraitService traitService, SecurityService securityService, - TraitQueryMapper traitQueryMapper){ + TraitQueryMapper traitQueryMapper, OntologyService ontologyService){ this.traitService = traitService; this.securityService = securityService; this.traitQueryMapper = traitQueryMapper; + this.ontologyService = ontologyService; } @Get("/programs/{programId}/traits{?traitsQuery*}") @@ -75,7 +80,7 @@ public HttpResponse>> getTraits( @QueryValue @QueryValid(using = TraitQueryMapper.class) @Valid TraitsQuery traitsQuery) { try { - List traits = traitService.getByProgramId(programId, traitsQuery.getFull()); + List traits = ontologyService.getTraitsByProgramId(programId, traitsQuery.getFull()); return ResponseUtils.getQueryResponse(traits, traitQueryMapper, traitsQuery); } catch (DoesNotExistException e) { return HttpResponse.notFound(); @@ -91,7 +96,7 @@ public HttpResponse>> postTraitsSearch( @Body @SearchValid(using = TraitQueryMapper.class) SearchRequest searchRequest) { try { - List traits = traitService.getByProgramId(programId, true); + List traits = ontologyService.getTraitsByProgramId(programId, true); return ResponseUtils.getQueryResponse(traits, traitQueryMapper, searchRequest, queryParams); } catch (DoesNotExistException e) { return HttpResponse.notFound(); @@ -137,7 +142,7 @@ public HttpResponse> getTraitEditable(@PathVariable UUID prog public HttpResponse>> createTraits(@PathVariable UUID programId, @Body @Valid List traits) { AuthenticatedUser actingUser = securityService.getUser(); try { - List createdTraits = traitService.createTraits(programId, traits, actingUser, true); + List createdTraits = ontologyService.createTraits(programId, traits, actingUser, true); List metadataStatus = new ArrayList<>(); // Users query successfully metadataStatus.add(new Status(StatusCode.INFO, "Successful Creation")); @@ -146,6 +151,9 @@ public HttpResponse>> createTraits(@PathVariable UU Metadata metadata = new Metadata(pagination, metadataStatus); Response> response = new Response<>(metadata, new DataResponse<>(createdTraits)); return HttpResponse.ok(response); + } catch (BadRequestException e){ + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.BAD_REQUEST, e.getMessage()); } catch (DoesNotExistException e){ log.info(e.getMessage()); return HttpResponse.notFound(); @@ -162,7 +170,7 @@ public HttpResponse>> createTraits(@PathVariable UU public HttpResponse>> updateTraits(@PathVariable UUID programId, @Body @Valid List traits) { AuthenticatedUser actingUser = securityService.getUser(); try { - List updatedTraits = traitService.updateTraits(programId, traits, actingUser); + List updatedTraits = ontologyService.updateTraits(programId, traits, actingUser); List metadataStatus = new ArrayList<>(); // Users query successfully metadataStatus.add(new Status(StatusCode.INFO, "Successful Creation")); @@ -171,6 +179,9 @@ public HttpResponse>> updateTraits(@PathVariable UU Metadata metadata = new Metadata(pagination, metadataStatus); Response> response = new Response<>(metadata, new DataResponse<>(updatedTraits)); return HttpResponse.ok(response); + } catch (BadRequestException e) { + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.BAD_REQUEST, e.getMessage()); } catch (DoesNotExistException e) { log.info(e.getMessage()); return HttpResponse.notFound(); diff --git a/src/main/java/org/breedinginsight/api/v1/controller/TraitUploadController.java b/src/main/java/org/breedinginsight/api/v1/controller/TraitUploadController.java index a6e04d326..59bbd7280 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/TraitUploadController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/TraitUploadController.java @@ -31,6 +31,7 @@ import org.breedinginsight.api.v1.controller.metadata.AddMetadata; import org.breedinginsight.model.ProgramUpload; import org.breedinginsight.model.Trait; +import org.breedinginsight.services.OntologyService; import org.breedinginsight.services.TraitUploadService; import org.breedinginsight.services.exceptions.*; import org.breedinginsight.utilities.response.ResponseUtils; @@ -47,12 +48,14 @@ public class TraitUploadController { private TraitUploadService traitUploadService; private SecurityService securityService; private TraitQueryMapper traitQueryMapper; + private OntologyService ontologyService; public TraitUploadController(TraitUploadService traitUploadService, SecurityService securityService, - TraitQueryMapper traitQueryMapper) { + TraitQueryMapper traitQueryMapper, OntologyService ontologyService) { this.traitUploadService = traitUploadService; this.securityService = securityService; this.traitQueryMapper = traitQueryMapper; + this.ontologyService = ontologyService; } // only allowing one trait upload to exist (per user per program) so put is more appropriate than post @@ -67,9 +70,12 @@ public HttpResponse> putTraitUpload(@PathVariable UUID p try { AuthenticatedUser actingUser = securityService.getUser(); - ProgramUpload programUpload = traitUploadService.updateTraitUpload(programId, file, actingUser); + ProgramUpload programUpload = ontologyService.updateTraitUpload(programId, file, actingUser); Response response = new Response(programUpload); return HttpResponse.ok(response); + } catch (BadRequestException e) { + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.BAD_REQUEST, e.getMessage()); } catch (DoesNotExistException e) { log.info(e.getMessage()); return HttpResponse.notFound(); @@ -146,11 +152,14 @@ public HttpResponse confirmTraitUpload(@PathVariable UUID programId, @PathVariable UUID traitUploadId) { try { AuthenticatedUser actingUser = securityService.getUser(); - traitUploadService.confirmUpload(programId, traitUploadId, actingUser); + ontologyService.confirmUpload(programId, traitUploadId, actingUser); return HttpResponse.ok(); } catch (DoesNotExistException e) { log.info(e.getMessage()); return HttpResponse.notFound(); + } catch (BadRequestException e) { + log.info(e.getMessage()); + return HttpResponse.status(HttpStatus.BAD_REQUEST, e.getMessage()); } catch (ValidatorException e) { log.info(e.getErrors().toString()); HttpResponse response = HttpResponse.status(HttpStatus.UNPROCESSABLE_ENTITY).body(e.getErrors()); diff --git a/src/main/java/org/breedinginsight/services/OntologyService.java b/src/main/java/org/breedinginsight/services/OntologyService.java index b4687a1cd..537d1c127 100644 --- a/src/main/java/org/breedinginsight/services/OntologyService.java +++ b/src/main/java/org/breedinginsight/services/OntologyService.java @@ -1,6 +1,8 @@ package org.breedinginsight.services; import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; +import io.micronaut.http.multipart.CompletedFileUpload; import io.micronaut.http.server.exceptions.InternalServerException; import org.brapi.v2.model.core.BrAPIProgram; import org.breedinginsight.api.auth.AuthenticatedUser; @@ -11,13 +13,8 @@ import org.breedinginsight.daos.ProgramDAO; import org.breedinginsight.daos.ProgramOntologyDAO; import org.breedinginsight.daos.TraitDAO; -import org.breedinginsight.model.Program; -import org.breedinginsight.model.SharedOntology; -import org.breedinginsight.model.SubscribedOntology; -import org.breedinginsight.model.Trait; -import org.breedinginsight.services.exceptions.DoesNotExistException; -import org.breedinginsight.services.exceptions.UnprocessableEntityException; -import org.breedinginsight.services.exceptions.ValidatorException; +import org.breedinginsight.model.*; +import org.breedinginsight.services.exceptions.*; import javax.inject.Inject; import javax.inject.Singleton; @@ -32,13 +29,15 @@ public class OntologyService { private ProgramOntologyDAO programOntologyDAO; private TraitDAO traitDAO; private TraitService traitService; + private TraitUploadService traitUploadService; @Inject - public OntologyService(ProgramDAO programDAO, ProgramOntologyDAO programOntologyDAO, TraitDAO traitDAO, TraitService traitService) { + public OntologyService(ProgramDAO programDAO, ProgramOntologyDAO programOntologyDAO, TraitDAO traitDAO, TraitService traitService, TraitUploadService traitUploadService) { this.programDAO = programDAO; this.programOntologyDAO = programOntologyDAO; this.traitDAO = traitDAO; this.traitService = traitService; + this.traitUploadService = traitUploadService; } /** @@ -302,6 +301,67 @@ public void unsubscribeOntology(UUID programId, UUID sharingProgramId) throws Do programOntologyDAO.denySharedOntology(sharedOntology); } + public List getTraitsByProgramId(UUID programId, boolean getFullTrait) throws DoesNotExistException { + return traitService.getByProgramId(getSubscribedOntologyProgramId(programId), getFullTrait); + } + + public List updateTraits(UUID programId, List traits, AuthenticatedUser actingUser) + throws DoesNotExistException, HttpStatusException, ValidatorException, BadRequestException { + UUID lookupId = getSubscribedOntologyProgramId(programId); + if(lookupId != programId) { + throw new BadRequestException("Subscribed ontology terms cannot be updated"); + } + + return traitService.updateTraits(lookupId, traits, actingUser); + } + + public List createTraits(UUID programId, List traits, AuthenticatedUser actingUser, Boolean throwDuplicateErrors) + throws DoesNotExistException, ValidatorException, BadRequestException { + UUID lookupId = getSubscribedOntologyProgramId(programId); + if(lookupId != programId) { + throw new BadRequestException("Subscribed ontology terms cannot be created"); + } + + return traitService.createTraits(lookupId, traits, actingUser, throwDuplicateErrors); + } + + public ProgramUpload updateTraitUpload(UUID programId, CompletedFileUpload file, AuthenticatedUser actingUser) + throws DoesNotExistException, UnsupportedTypeException, ValidatorException, AuthorizationException, HttpStatusException, BadRequestException { + UUID lookupId = getSubscribedOntologyProgramId(programId); + if(lookupId != programId) { + throw new BadRequestException("Subscribed ontology terms cannot be imported"); + } + + return traitUploadService.updateTraitUpload(lookupId, file, actingUser); + } + + public void confirmUpload(UUID programId, UUID traitUploadId, AuthenticatedUser actingUser) + throws DoesNotExistException, ValidatorException, BadRequestException { + UUID lookupId = getSubscribedOntologyProgramId(programId); + if(lookupId != programId) { + throw new BadRequestException("Subscribed ontology terms cannot be imported"); + } + + traitUploadService.confirmUpload(lookupId, traitUploadId, actingUser); + } + + public UUID getSubscribedOntologyProgramId(UUID programId) throws DoesNotExistException { + // get shared ontology programs + List subscriptionOptions = getSubscribeOntologyOptions(programId); + + // check if we are subscribed to one of the programs + SubscribedOntology subscribedOntology = null; + for (SubscribedOntology sharingProgram : subscriptionOptions) { + if (sharingProgram.getSubscribed()) { + subscribedOntology = sharingProgram; + } + } + + UUID lookupId = subscribedOntology == null ? programId : subscribedOntology.getProgramId(); + + return lookupId; + } + public List getSubscribeOntologyOptions(UUID programId) throws DoesNotExistException { Program program = getProgram(programId); diff --git a/src/main/java/org/breedinginsight/services/exceptions/BadRequestException.java b/src/main/java/org/breedinginsight/services/exceptions/BadRequestException.java new file mode 100644 index 000000000..ac9b0080e --- /dev/null +++ b/src/main/java/org/breedinginsight/services/exceptions/BadRequestException.java @@ -0,0 +1,25 @@ +/* + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.breedinginsight.services.exceptions; + +public class BadRequestException extends Exception { + + public BadRequestException(String message) { + super(message); + } +}