From fe5044d9c81080a3097a6c8360b212cec7692916 Mon Sep 17 00:00:00 2001 From: Derek Vince Date: Fri, 8 Mar 2024 11:45:06 -0500 Subject: [PATCH] 2947 feat improve error logging from the back end to the client (#2955) --- packages/client/hmi-client/src/api/api.ts | 49 ++++++++----- .../src/components/dataset/tera-dataset.vue | 7 +- .../documents/tera-document-asset.vue | 3 +- .../src/components/model/tera-model.vue | 1 - .../widgets/tera-common-modal-dialogs.vue | 2 - .../components/tera-search-results-list.vue | 6 -- .../project/components/tera-model-modal.vue | 2 - .../src/page/project/tera-project.vue | 2 - .../hmi-client/src/services/artifact.ts | 10 +-- .../client/hmi-client/src/services/code.ts | 16 ++--- .../client/hmi-client/src/services/data.ts | 4 -- .../client/hmi-client/src/services/dataset.ts | 3 - .../src/services/document-assets.ts | 10 +-- .../hmi-client/src/services/knowledge.ts | 3 +- .../hmi-client/src/types/ServerError.ts | 8 +++ .../tera-model-from-document-drilldown.vue | 2 - .../dataservice/ArtifactController.java | 17 ++--- .../dataservice/AssetController.java | 35 ++++----- .../dataservice/ConceptController.java | 72 ++++++++----------- .../dataservice/DatasetController.java | 22 +++--- .../DecapodesConfigurationController.java | 59 ++++++--------- .../DecapodesContextController.java | 60 ++++++---------- .../dataservice/DocumentController.java | 4 +- .../dataservice/EquationController.java | 4 +- .../dataservice/FrameworkController.java | 47 +++++------- .../ModelConfigurationController.java | 6 +- .../dataservice/ModelController.java | 18 ++--- .../NotebookSessionController.java | 12 ++-- .../dataservice/ProjectController.java | 30 ++++---- 29 files changed, 204 insertions(+), 310 deletions(-) create mode 100644 packages/client/hmi-client/src/types/ServerError.ts diff --git a/packages/client/hmi-client/src/api/api.ts b/packages/client/hmi-client/src/api/api.ts index 106209db19..f851ca7b56 100644 --- a/packages/client/hmi-client/src/api/api.ts +++ b/packages/client/hmi-client/src/api/api.ts @@ -1,7 +1,7 @@ -import { ToastSummaries } from '@/services/toast'; import { logger } from '@/utils/logger'; -import axios, { AxiosHeaders } from 'axios'; +import axios, { AxiosError, AxiosHeaders } from 'axios'; import { EventSource } from 'extended-eventsource'; +import { ServerError } from '@/types/ServerError'; import { Ref, ref } from 'vue'; import useAuthStore from '../stores/auth'; @@ -28,28 +28,39 @@ API.interceptors.request.use( API.interceptors.response.use( (response) => response, - (error) => { - const msg = error.response.data; - const status = error.response.status; - switch (status) { - case 500: - logger.error(msg.toString(), { - showToast: false, - toastTitle: `${ToastSummaries.SERVICE_UNAVAILABLE} (${status})` - }); - break; - default: - logger.error(msg.toString(), { - showToast: false, - toastTitle: `${ToastSummaries.NETWORK_ERROR} (${status})` - }); - } - if (status === 401) { + (error: AxiosError) => { + if (error.status === 401) { // redirect to login const auth = useAuthStore(); auth.keycloak?.login({ redirectUri: window.location.href }); + } else { + let message = error.message; + let title = `${error.response?.statusText} (${error.response?.status})`; + if (error?.response?.data) { + const responseError: ServerError = error.response.data as ServerError; + + // check to see if the 'message' property is set. If it is, set message to that value. + // If not, check the 'trace' property and extract the error from that. + // It will be the substring between the first set of quotations marks. + if (responseError.message) { + message = responseError.message; + } else if (responseError.trace) { + // extract the substring between the first set of quotation marks and use that + const start = responseError.trace.indexOf('"'); + const end = responseError.trace.indexOf('"', start + 1); + message = responseError.trace.substring(start + 1, end); + } + + message = message ?? 'An Error occurred'; + title = `${responseError.error} (${responseError.status})`; + } + + logger.error(message, { + showToast: true, + toastTitle: title + }); } return null; } diff --git a/packages/client/hmi-client/src/components/dataset/tera-dataset.vue b/packages/client/hmi-client/src/components/dataset/tera-dataset.vue index a3ac1b488f..89508b51ae 100644 --- a/packages/client/hmi-client/src/components/dataset/tera-dataset.vue +++ b/packages/client/hmi-client/src/components/dataset/tera-dataset.vue @@ -45,7 +45,7 @@ diff --git a/packages/client/hmi-client/src/page/data-explorer/components/tera-search-results-list.vue b/packages/client/hmi-client/src/page/data-explorer/components/tera-search-results-list.vue index 82de4ecac2..5858e3f3cf 100644 --- a/packages/client/hmi-client/src/page/data-explorer/components/tera-search-results-list.vue +++ b/packages/client/hmi-client/src/page/data-explorer/components/tera-search-results-list.vue @@ -172,12 +172,6 @@ const projectOptions = computed(() => [ } if (response) logger.info(`Added ${assetName} to ${project.name}`); - else { - // TODO: 'response' here is just an id, and we've lost the error message by this point. We may want to - // eventually pass up the error code and message to this point in the code so that we can show the user - // more helpful information than just "failed". - logger.error(`Failed adding ${assetName} to ${project.name}`); - } isAdding.value = false; } diff --git a/packages/client/hmi-client/src/page/project/components/tera-model-modal.vue b/packages/client/hmi-client/src/page/project/components/tera-model-modal.vue index 0df8bd5ec1..eb466040cb 100644 --- a/packages/client/hmi-client/src/page/project/components/tera-model-modal.vue +++ b/packages/client/hmi-client/src/page/project/components/tera-model-modal.vue @@ -44,7 +44,6 @@ import { } from '@/services/model'; import { useProjects } from '@/composables/project'; import { addAsset } from '@/services/project'; -import { logger } from '@/utils/logger'; import { useToastService } from '@/services/toast'; const props = defineProps<{ @@ -95,7 +94,6 @@ async function updateModelName() { await useProjects().refresh(); if (!response) { - logger.error('Could not save asset to project'); return; } diff --git a/packages/client/hmi-client/src/page/project/tera-project.vue b/packages/client/hmi-client/src/page/project/tera-project.vue index 4f72111c5d..981cbb3684 100644 --- a/packages/client/hmi-client/src/page/project/tera-project.vue +++ b/packages/client/hmi-client/src/page/project/tera-project.vue @@ -156,10 +156,8 @@ async function removeAsset(assetRoute: AssetRoute) { openAsset({ assetId: '', pageType: ProjectPages.OVERVIEW }); } logger.info(`${assetRoute.assetId} was removed.`, { showToast: true }); - return; } } - logger.error(`Failed to remove ${assetRoute.assetId}`, { showToast: true }); } const openWorkflow = async () => { diff --git a/packages/client/hmi-client/src/services/artifact.ts b/packages/client/hmi-client/src/services/artifact.ts index 1740d29b42..b1934e0673 100644 --- a/packages/client/hmi-client/src/services/artifact.ts +++ b/packages/client/hmi-client/src/services/artifact.ts @@ -1,7 +1,6 @@ import type { Artifact } from '@/types/Types'; import API from '@/api/api'; import { Ref } from 'vue'; -import { logger } from '@/utils/logger'; /** * This is a helper function to take an arbitrary file from a github repo and create a new artifact from it @@ -38,8 +37,7 @@ async function createNewArtifactFromGithubFile( } ); - if (!urlResponse || urlResponse.status >= 400) { - logger.error(`Failed to upload artifact from github: ${urlResponse}`); + if (!urlResponse) { return null; } @@ -127,8 +125,7 @@ async function getArtifactFileAsText(artifactId: string, fileName: string): Prom {} ); - if (!response || response.status >= 400) { - logger.error('Error getting artifact file as text'); + if (!response) { return null; } @@ -143,8 +140,7 @@ async function getArtifactArrayBuffer( responseType: 'arraybuffer' }); - if (!response || response.status >= 400) { - logger.error('Error getting file download url'); + if (!response) { return null; } diff --git a/packages/client/hmi-client/src/services/code.ts b/packages/client/hmi-client/src/services/code.ts index d2b3d3161f..804e9c1807 100644 --- a/packages/client/hmi-client/src/services/code.ts +++ b/packages/client/hmi-client/src/services/code.ts @@ -2,13 +2,11 @@ import API from '@/api/api'; import type { Code } from '@/types/Types'; import { ProgrammingLanguage } from '@/types/Types'; import { Ref } from 'vue'; -import { logger } from '@/utils/logger'; async function getCodeAsset(codeAssetId: string): Promise { const response = await API.get(`/code-asset/${codeAssetId}`); - if (!response || response.status >= 400) { - logger.error('Error getting code file as text'); + if (!response) { return null; } @@ -32,8 +30,7 @@ async function updateCodeAsset( } const response = await API.put(`/code-asset/${code.id}`, code); - if (!response || response.status >= 400) { - logger.error('Error updating code asset'); + if (!response) { return null; } @@ -46,8 +43,7 @@ async function getCodeFileAsText(codeAssetId: string, fileName: string): Promise {} ); - if (!response || response.status >= 400) { - logger.error('Error getting code file as text'); + if (!response) { return null; } @@ -104,8 +100,7 @@ async function uploadCodeToProjectFromGithub( } ); - if (!urlResponse || urlResponse.status >= 400) { - logger.error(`Failed to upload code from github: ${urlResponse}`); + if (!urlResponse) { return null; } @@ -137,8 +132,7 @@ async function uploadCodeFromGithubRepo( } ); - if (!urlResponse || urlResponse.status >= 400) { - logger.error(`Failed to upload code from github: ${urlResponse}`); + if (!urlResponse) { return null; } diff --git a/packages/client/hmi-client/src/services/data.ts b/packages/client/hmi-client/src/services/data.ts index 37499428d3..98b5847746 100644 --- a/packages/client/hmi-client/src/services/data.ts +++ b/packages/client/hmi-client/src/services/data.ts @@ -451,10 +451,6 @@ const getRelatedDocuments = async (docid: string): Promise => { } if (status === 204) { logger.error('Request received successfully, but there are no documents'); - } else if (status === 400) { - logger.error('Query must contain a docid'); - } else if (status === 500) { - logger.error('An error occurred retrieving documents'); } } return [] as Document[]; diff --git a/packages/client/hmi-client/src/services/dataset.ts b/packages/client/hmi-client/src/services/dataset.ts index edcfc13a70..0e4068ef9d 100644 --- a/packages/client/hmi-client/src/services/dataset.ts +++ b/packages/client/hmi-client/src/services/dataset.ts @@ -206,9 +206,6 @@ async function createDatasetFromSimulationResult( if (response && response.status === 201) { return true; } - logger.error(`Unable to create dataset from simulation result ${response.status}`, { - toastTitle: 'TDS - Simulation' - }); return false; } catch (error) { logger.error( diff --git a/packages/client/hmi-client/src/services/document-assets.ts b/packages/client/hmi-client/src/services/document-assets.ts index 1f04cc6a82..02a56eeedc 100644 --- a/packages/client/hmi-client/src/services/document-assets.ts +++ b/packages/client/hmi-client/src/services/document-assets.ts @@ -94,7 +94,6 @@ async function createNewDocumentFromGithubFile( ); if (!urlResponse || urlResponse.status >= 400) { - logger.error(`Failed to upload document from github: ${urlResponse}`); return null; } @@ -166,8 +165,7 @@ async function getDocumentFileAsText(documentId: string, fileName: string): Prom {} ); - if (!response || response.status >= 400) { - logger.error('Error getting document file as text'); + if (!response) { return null; } @@ -183,8 +181,7 @@ async function getEquationFromImageUrl( {} ); - if (!response || response.status >= 400) { - logger.error('Error getting equation from image url'); + if (!response) { return null; } @@ -219,8 +216,7 @@ async function createDocumentFromXDD( } ); - if (!response || response.status >= 400) { - logger.error('Error upload file from doi'); + if (!response) { return null; } diff --git a/packages/client/hmi-client/src/services/knowledge.ts b/packages/client/hmi-client/src/services/knowledge.ts index f4e2c686a5..ad8b652bc3 100644 --- a/packages/client/hmi-client/src/services/knowledge.ts +++ b/packages/client/hmi-client/src/services/knowledge.ts @@ -1,4 +1,4 @@ -import API, { Poller, PollerState, PollResponse, PollerResult } from '@/api/api'; +import API, { Poller, PollerResult, PollerState, PollResponse } from '@/api/api'; import { AxiosError, AxiosResponse } from 'axios'; import type { Code, Dataset, ExtractionResponse, Model } from '@/types/Types'; import { logger } from '@/utils/logger'; @@ -68,7 +68,6 @@ export const equationsToAMR = async ( return response.data.result; } } - logger.error(`Equations to AMR request failed`, { toastTitle: 'Error - Knowledge Middleware' }); } catch (error: unknown) { logger.error(error, { showToast: false }); } diff --git a/packages/client/hmi-client/src/types/ServerError.ts b/packages/client/hmi-client/src/types/ServerError.ts new file mode 100644 index 0000000000..395104aaf0 --- /dev/null +++ b/packages/client/hmi-client/src/types/ServerError.ts @@ -0,0 +1,8 @@ +export interface ServerError { + timestamp: string; + status: number; + error: string; + message?: string; + path: string; + trace: string; +} diff --git a/packages/client/hmi-client/src/workflow/ops/model-from-document/tera-model-from-document-drilldown.vue b/packages/client/hmi-client/src/workflow/ops/model-from-document/tera-model-from-document-drilldown.vue index c4bf0b9f86..552e4538d7 100644 --- a/packages/client/hmi-client/src/workflow/ops/model-from-document/tera-model-from-document-drilldown.vue +++ b/packages/client/hmi-client/src/workflow/ops/model-from-document/tera-model-from-document-drilldown.vue @@ -135,7 +135,6 @@ import Image from 'primevue/image'; import { equationsToAMR } from '@/services/knowledge'; import Button from 'primevue/button'; import Dropdown from 'primevue/dropdown'; -import { logger } from '@/utils/logger'; import { generateModelCard, getModel, updateModel } from '@/services/model'; import TeraOperatorPlaceholder from '@/components/operator/tera-operator-placeholder.vue'; import { useProjects } from '@/composables/project'; @@ -300,7 +299,6 @@ async function onRun() { const res = await equationsToAMR('latex', equations, clonedState.value.modelFramework); if (!res) { - logger.error('Error creating AMR'); return; } diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ArtifactController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ArtifactController.java index 017c0e0680..2532f0a891 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ArtifactController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ArtifactController.java @@ -62,7 +62,7 @@ public ResponseEntity> getArtifacts( try { return ResponseEntity.ok(artifactService.getAssets(page, pageSize)); } catch (final Exception e) { - final String error = "Unable to get artifacts"; + final String error = "An error occurred while retrieving artifacts"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -82,7 +82,7 @@ public ResponseEntity createArtifact(@RequestBody final Artifact artif try { return ResponseEntity.status(HttpStatus.CREATED).body(artifactService.createAsset(artifact)); } catch (final Exception e) { - final String error = "Unable to create artifact"; + final String error = "An error occurred while creating artifact"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -96,15 +96,15 @@ public ResponseEntity createArtifact(@RequestBody final Artifact artif @Operation(summary = "Gets an artifact by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Artifact retrieved.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Artifact.class))), - @ApiResponse(responseCode = "204", description = "Artifact not found", content = @Content), + @ApiResponse(responseCode = "404", description = "Artifact not found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the artifact", content = @Content) }) public ResponseEntity getArtifact(@PathVariable("id") final UUID artifactId) { try { final Optional artifact = artifactService.getAsset(artifactId); - return artifact.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); + return artifact.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final Exception e) { - final String error = "Unable to get artifact"; + final String error = "An error occurred while retrieving artifact"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -117,7 +117,6 @@ public ResponseEntity getArtifact(@PathVariable("id") final UUID artif @Operation(summary = "Updates an artifact") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Artifact updated.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Artifact.class))), - @ApiResponse(responseCode = "204", description = "Artifact not found", content = @Content), @ApiResponse(responseCode = "404", description = "Artifact not found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue updating the artifact", content = @Content) }) @@ -130,7 +129,7 @@ public ResponseEntity updateArtifact( final Optional updated = artifactService.updateAsset(artifact); return updated.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final Exception e) { - final String error = "Unable to update artifact"; + final String error = "An error occurred while updating artifact"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -352,7 +351,9 @@ private ResponseEntity uploadArtifactHelper(final UUID artifactId, fina } catch (final Exception e) { log.error("Unable to PUT artifact data", e); - return ResponseEntity.internalServerError().build(); + throw new ResponseStatusException( + org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, + "Unable to PUT artifact data"); } } diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/AssetController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/AssetController.java index 78668f212b..ba8b941e07 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/AssetController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/AssetController.java @@ -1,18 +1,5 @@ package software.uncharted.terarium.hmiserver.controller.dataservice; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; @@ -21,6 +8,11 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import software.uncharted.terarium.hmiserver.models.dataservice.AssetType; import software.uncharted.terarium.hmiserver.models.dataservice.project.Project; import software.uncharted.terarium.hmiserver.models.dataservice.project.ProjectAsset; @@ -32,6 +24,9 @@ import software.uncharted.terarium.hmiserver.utils.rebac.askem.RebacProject; import software.uncharted.terarium.hmiserver.utils.rebac.askem.RebacUser; +import java.util.Optional; +import java.util.UUID; + @RequestMapping("/assets") @RestController @Slf4j @@ -52,7 +47,7 @@ public class AssetController { * searched. If the asset name is available, * a 204 No Content response is returned. If the asset name is not available, a * 409 Conflict response is returned. - * + * * @param assetType Asset type to check * @param assetName Asset name to check * @param projectId Project ID to limit the search to (optional) @@ -70,15 +65,15 @@ public class AssetController { @ApiResponse(responseCode = "500", description = "Unable to verify project permissions") }) public ResponseEntity verifyAssetNameAvailability( - @PathVariable("asset-type") AssetType assetType, - @PathVariable("asset-name") String assetName, - @RequestParam(name = "project-id", required = false) UUID projectId) { + @PathVariable("asset-type") final AssetType assetType, + @PathVariable("asset-name") final String assetName, + @RequestParam(name = "project-id", required = false) final UUID projectId) { if (projectId == null) { final Optional asset = projectAssetService.getProjectAssetByNameAndType(assetName, assetType); if (asset.isPresent()) { - throw new ResponseStatusException(HttpStatus.CONFLICT, "Asset name is not available"); + throw new ResponseStatusException(HttpStatus.CONFLICT, "Asset name is already in use"); } else { return ResponseEntity.noContent().build(); } @@ -105,9 +100,9 @@ public ResponseEntity verifyAssetNameAvailability( throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User does not have permission to access this project"); } - } catch (ResponseStatusException e) { + } catch (final ResponseStatusException e) { throw e; // Like any responsible fisher, we're going to catch and release! - } catch (Exception e) { + } catch (final Exception e) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Unable to verify project permissions"); } diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ConceptController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ConceptController.java index 98ec18ca70..5812de4575 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ConceptController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ConceptController.java @@ -1,23 +1,5 @@ package software.uncharted.terarium.hmiserver.controller.dataservice; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; @@ -26,6 +8,11 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted; import software.uncharted.terarium.hmiserver.models.dataservice.TaggableType; import software.uncharted.terarium.hmiserver.models.dataservice.concept.ConceptFacetSearchResponse; @@ -35,6 +22,10 @@ import software.uncharted.terarium.hmiserver.security.Roles; import software.uncharted.terarium.hmiserver.service.data.ConceptService; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + @RequestMapping("/concepts") @RestController @Slf4j @@ -56,9 +47,10 @@ public ResponseEntity> searchConcept( @RequestParam("curie") final String curie) { try { return ResponseEntity.ok(conceptService.searchConcept(curie)); - } catch (RuntimeException e) { + } catch (final RuntimeException e) { log.error("Unable to get search concept", e); - return ResponseEntity.internalServerError().build(); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, + "Unable to get search concept"); } } @@ -74,7 +66,7 @@ public ResponseEntity createConcept( try { return ResponseEntity.status(HttpStatus.CREATED).body(conceptService.createConcept(concept)); - } catch (Exception e) { + } catch (final Exception e) { final String error = "Unable to create concept"; log.error(error, e); throw new ResponseStatusException( @@ -87,17 +79,16 @@ public ResponseEntity createConcept( @Operation(summary = "Search concept definitions by term") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Concepts found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Concept.class)))), - @ApiResponse(responseCode = "204", description = "There are no concepts found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving concepts from the data store", content = @Content) }) @Secured(Roles.USER) public ResponseEntity> searchConceptDefinitions( - @RequestParam("term") String term, - @RequestParam(name = "limit", defaultValue = "100") Integer limit, - @RequestParam(name = "offset", defaultValue = "100") Integer offset) { + @RequestParam("term") final String term, + @RequestParam(name = "limit", defaultValue = "100") final Integer limit, + @RequestParam(name = "offset", defaultValue = "100") final Integer offset) { try { return ResponseEntity.ok(conceptService.searchConceptDefinitions(term, limit, offset)); - } catch (Exception e) { + } catch (final Exception e) { final String error = "Unable to search concept definitions"; log.error(error, e); throw new ResponseStatusException( @@ -111,14 +102,13 @@ public ResponseEntity> searchConceptDefinitions( @Operation(summary = "Gets concept by curie string") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Concept found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Concept.class))), - @ApiResponse(responseCode = "204", description = "There was no concept found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the concept from the data store", content = @Content) }) public ResponseEntity getConceptDefinition( @PathVariable("curie") final String curie) { try { return ResponseEntity.ok(conceptService.getConceptDefinition(curie)); - } catch (Exception e) { + } catch (final Exception e) { final String error = "Unable to get concept definition"; log.error(error, e); throw new ResponseStatusException( @@ -132,19 +122,16 @@ public ResponseEntity getConceptDefinition( @Operation(summary = "Gets concept by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Concept found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Concept.class))), - @ApiResponse(responseCode = "204", description = "There was no concept found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no concept found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the concept from the data store", content = @Content) }) public ResponseEntity getConcept( @PathVariable("id") final UUID id) { try { - Optional concept = conceptService.getConcept(id); - if (concept.isPresent()) { - return ResponseEntity.ok(concept.get()); - } - return ResponseEntity.notFound().build(); - } catch (Exception e) { + final Optional concept = conceptService.getConcept(id); + return concept.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + } catch (final Exception e) { final String error = "Unable to get concept"; log.error(error, e); throw new ResponseStatusException( @@ -168,7 +155,7 @@ public ResponseEntity deleteConcept( try { conceptService.deleteConcept(id); return ResponseEntity.ok(new ResponseDeleted("Concept", id)); - } catch (Exception e) { + } catch (final Exception e) { final String error = "Unable to delete concept"; log.error(error, e); throw new ResponseStatusException( @@ -182,19 +169,17 @@ public ResponseEntity deleteConcept( @Operation(summary = "Update a concept") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Concept updated.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = OntologyConcept.class))), + @ApiResponse(responseCode = "404", description = "Concept could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue updating the concept", content = @Content) }) public ResponseEntity updateConcept( @PathVariable("id") final UUID id, - @RequestBody OntologyConcept concept) { + @RequestBody final OntologyConcept concept) { try { concept.setId(id); final Optional updated = conceptService.updateConcept(concept); - if (updated.isEmpty()) { - return ResponseEntity.noContent().build(); - } - return ResponseEntity.ok(updated.get()); - } catch (RuntimeException e) { + return updated.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + } catch (final RuntimeException e) { final String error = "Unable to update concept"; log.error(error, e); throw new ResponseStatusException( @@ -208,7 +193,6 @@ public ResponseEntity updateConcept( @Operation(summary = "Faceted search for concepts") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Concepts found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Concept.class)))), - @ApiResponse(responseCode = "204", description = "There are no concepts found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving concepts from the data store", content = @Content) }) public ResponseEntity searchConceptsUsingFacets( @@ -216,7 +200,7 @@ public ResponseEntity searchConceptsUsingFacets( @RequestParam(value = "curies", required = false) final List curies) { try { return ResponseEntity.ok(conceptService.searchConceptsUsingFacets(types, curies)); - } catch (RuntimeException e) { + } catch (final RuntimeException e) { final String error = "Unable to search concepts using facets"; log.error(error, e); throw new ResponseStatusException( diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DatasetController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DatasetController.java index b4e560074d..d4fa0d932b 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DatasetController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DatasetController.java @@ -75,7 +75,6 @@ public class DatasetController { @Operation(summary = "Gets all datasets") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Datasets found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Dataset.class)))), - @ApiResponse(responseCode = "204", description = "There are no datasets found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving datasets from the data store", content = @Content) }) public ResponseEntity> getDatasets( @@ -138,7 +137,6 @@ public ResponseEntity> getDatasets( error); } } - @PostMapping @Secured(Roles.USER) @Operation(summary = "Create a new dataset") @@ -164,7 +162,7 @@ public ResponseEntity createDataset(@RequestBody final Dataset dataset) @Operation(summary = "Gets dataset by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Dataset found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Dataset.class))), - @ApiResponse(responseCode = "204", description = "There was no dataset found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no dataset found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the dataset from the data store", content = @Content) }) public ResponseEntity getDataset(@PathVariable("id") final UUID id) { @@ -177,7 +175,7 @@ public ResponseEntity getDataset(@PathVariable("id") final UUID id) { log.error(error, e); // This doesn't actually warrant a 500 since its just column metadata, so we'll let it pass. } - return dataset.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); + return dataset.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final IOException e) { final String error = "Unable to get dataset"; log.error(error, e); @@ -232,7 +230,6 @@ private Optional extractColumnsAsNeededAndSave(final Optional @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Delete dataset", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Dataset could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) public ResponseEntity deleteDataset( @@ -275,12 +272,6 @@ ResponseEntity updateDataset( } } - @ExceptionHandler - @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.BAD_REQUEST) - public void handle(final Exception e) { - log.info("Returning HTTP 400 Bad Request", e); - } - @GetMapping("/{id}/download-csv") @Secured(Roles.USER) @Operation(summary = "Download dataset CSV") @@ -588,7 +579,9 @@ private ResponseEntity uploadCSVAndUpdateColumns(final UUID data } catch (final Exception e) { log.error("Unable to PUT csv data", e); - return ResponseEntity.internalServerError().build(); + throw new ResponseStatusException( + org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, + "Unable to PUT csv data"); } } @@ -671,7 +664,6 @@ private static CsvColumnStats getStats(final List aCol) { @Operation(summary = "Gets a preview of the data asset") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Dataset preview.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = JsonNode.class))), - @ApiResponse(responseCode = "404", description = "Dataset could not be found to create a preview for", content = @Content), @ApiResponse(responseCode = "415", description = "Dataset cannot be previewed", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue generating the preview", content = @Content) }) @@ -695,7 +687,9 @@ public ResponseEntity getPreview( } return climateDataProxy.previewEsgf(id.toString(), null, null, null); } catch (final IOException ioe) { - return ResponseEntity.status(415).build(); + throw new ResponseStatusException( + org.springframework.http.HttpStatus.valueOf(415), + "Unable to open file"); } } } catch (final Exception e) { diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesConfigurationController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesConfigurationController.java index cb19229f51..5813245f53 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesConfigurationController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesConfigurationController.java @@ -1,36 +1,25 @@ package software.uncharted.terarium.hmiserver.controller.dataservice; -import java.io.IOException; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted; import software.uncharted.terarium.hmiserver.models.dataservice.multiphysics.DecapodesConfiguration; import software.uncharted.terarium.hmiserver.security.Roles; import software.uncharted.terarium.hmiserver.service.data.DecapodesConfigurationService; +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + @RequestMapping("/decapodes-configurations") @RestController @Slf4j @@ -47,19 +36,16 @@ public class DecapodesConfigurationController { @ApiResponse(responseCode = "204", description = "There was no decapodes configuration found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the decapodes configuration from the data store", content = @Content) }) - ResponseEntity getDecapodesConfiguration(@PathVariable("id") UUID id) { + ResponseEntity getDecapodesConfiguration(@PathVariable("id") final UUID id) { try { // Fetch the decapodes configuration from the data-service - Optional configuration = decapodesConfigurationService.getDecapodesConfiguration(id); - if (configuration.isEmpty()) { - return ResponseEntity.noContent().build(); - } + final Optional configuration = decapodesConfigurationService.getDecapodesConfiguration(id); + return configuration.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); // Return the configuration - return ResponseEntity.ok(configuration.get()); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to get decapodes configuration"; log.error(error, e); throw new ResponseStatusException( @@ -73,20 +59,18 @@ ResponseEntity getDecapodesConfiguration(@PathVariable(" @Operation(summary = "Update a decapodes configuration") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Decapodes configuraiton updated.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = DecapodesConfiguration.class))), + @ApiResponse(responseCode = "404", description = "DecapodesConfiguration could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue updating the decapodes configuration", content = @Content) }) ResponseEntity updateDecapodesConfiguration( - @PathVariable("id") UUID id, - @RequestBody DecapodesConfiguration configuration) { + @PathVariable("id") final UUID id, + @RequestBody final DecapodesConfiguration configuration) { try { configuration.setId(id); final Optional updated = decapodesConfigurationService.updateDecapodesConfiguration(configuration); - if (updated.isEmpty()) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(updated.get()); - } catch (IOException e) { + return updated.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + } catch (final IOException e) { final String error = "Unable to update decapodes configuration"; log.error(error, e); throw new ResponseStatusException( @@ -101,16 +85,15 @@ ResponseEntity updateDecapodesConfiguration( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted decapodes configuration", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "DecapodesConfiguration could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) ResponseEntity deleteDecapodesConfiguration( - @PathVariable("id") UUID id) { + @PathVariable("id") final UUID id) { try { decapodesConfigurationService.deleteDecapodesConfiguration(id); return ResponseEntity.ok(new ResponseDeleted("DecapodesConfiguration", id)); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to delete decapodes configuration"; log.error(error, e); throw new ResponseStatusException( @@ -132,7 +115,7 @@ ResponseEntity createDecapodesConfiguration( try { config = decapodesConfigurationService.createDecapodesConfiguration(config); return ResponseEntity.status(HttpStatus.CREATED).body(config); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to create decapodes configuration"; log.error(error, e); throw new ResponseStatusException( diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesContextController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesContextController.java index 13d1dc4c6c..69caa8aa67 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesContextController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DecapodesContextController.java @@ -1,36 +1,25 @@ package software.uncharted.terarium.hmiserver.controller.dataservice; -import java.io.IOException; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted; import software.uncharted.terarium.hmiserver.models.dataservice.multiphysics.DecapodesContext; import software.uncharted.terarium.hmiserver.security.Roles; import software.uncharted.terarium.hmiserver.service.data.DecapodesContextService; +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + @RequestMapping("/decapodes-contexts") @RestController @Slf4j @@ -44,21 +33,18 @@ public class DecapodesContextController { @Operation(summary = "Gets a decapodes context by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Decapodes context found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = DecapodesContext.class))), - @ApiResponse(responseCode = "204", description = "There was no decapodes context found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no decapodes context found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the decapodes context from the data store", content = @Content) }) - ResponseEntity getDecapodesContext(@PathVariable("id") UUID id) { + ResponseEntity getDecapodesContext(@PathVariable("id") final UUID id) { try { // Fetch the decapodes context from the data-service - Optional context = decapodesContextService.getDecapodesContext(id); - if (context.isEmpty()) { - return ResponseEntity.noContent().build(); - } + final Optional context = decapodesContextService.getDecapodesContext(id); + return context.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); - return ResponseEntity.ok(context.get()); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to get decapodes context"; log.error(error, e); throw new ResponseStatusException( @@ -75,17 +61,14 @@ ResponseEntity getDecapodesContext(@PathVariable("id") UUID id @ApiResponse(responseCode = "500", description = "There was an issue updating the decapodes context", content = @Content) }) ResponseEntity updateDecapodesContext( - @PathVariable("id") UUID id, - @RequestBody DecapodesContext context) { + @PathVariable("id") final UUID id, + @RequestBody final DecapodesContext context) { try { context.setId(id); final Optional updated = decapodesContextService.updateDecapodesContext(context); - if (updated.isEmpty()) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(updated.get()); - } catch (IOException e) { + return updated.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); + } catch (final IOException e) { final String error = "Unable to update decapodes context"; log.error(error, e); throw new ResponseStatusException( @@ -100,16 +83,15 @@ ResponseEntity updateDecapodesContext( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted decapodes context", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "DecapodesContext could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) ResponseEntity deleteDecapodesContext( - @PathVariable("id") UUID id) { + @PathVariable("id") final UUID id) { try { decapodesContextService.deleteDecapodesContext(id); return ResponseEntity.ok(new ResponseDeleted("DecapodesContext", id)); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to delete decapodes context"; log.error(error, e); throw new ResponseStatusException( @@ -131,7 +113,7 @@ ResponseEntity createDecapodesContext( try { context = decapodesContextService.createDecapodesContext(context); return ResponseEntity.status(HttpStatus.CREATED).body(context); - } catch (IOException e) { + } catch (final IOException e) { final String error = "Unable to create decapodes context"; log.error(error, e); throw new ResponseStatusException( diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DocumentController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DocumentController.java index c9c99f6fcb..59bb39a278 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DocumentController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/DocumentController.java @@ -87,7 +87,6 @@ public class DocumentController { @Operation(summary = "Gets all documents") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Documents found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = DocumentAsset.class)))), - @ApiResponse(responseCode = "204", description = "There are no documents found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving documents from the data store", content = @Content) }) public ResponseEntity> getDocuments( @@ -170,7 +169,7 @@ public ResponseEntity updateDocument( @Operation(summary = "Gets document by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Document found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = DocumentAsset.class))), - @ApiResponse(responseCode = "204", description = "There was no document found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no document found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the document from the data store", content = @Content) }) public ResponseEntity getDocument( @@ -271,7 +270,6 @@ public ResponseEntity getDownloadURL( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Delete document", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Document could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) public ResponseEntity deleteDocument( diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/EquationController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/EquationController.java index 78cf8c831d..e276ce07b7 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/EquationController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/EquationController.java @@ -48,7 +48,6 @@ public class EquationController { @Operation(summary = "Gets all equations") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Equations found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Equation.class)))), - @ApiResponse(responseCode = "204", description = "There are no equations found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving equations from the data store", content = @Content) }) ResponseEntity> getEquations( @@ -104,7 +103,7 @@ ResponseEntity createEquation(@RequestBody Equation equation) { @Operation(summary = "Gets equation by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Equation found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Equation.class))), - @ApiResponse(responseCode = "204", description = "There was no equation found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no equation found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the equation from the data store", content = @Content) }) ResponseEntity getEquation(@PathVariable("id") final UUID id) { @@ -165,7 +164,6 @@ ResponseEntity updateEquation( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted equation", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Equation could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) ResponseEntity deleteEquation(@PathVariable("id") final UUID id) { diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/FrameworkController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/FrameworkController.java index 559d8794ee..844dcf7154 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/FrameworkController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/FrameworkController.java @@ -1,34 +1,25 @@ package software.uncharted.terarium.hmiserver.controller.dataservice; -import java.util.Optional; -import java.util.UUID; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.server.ResponseStatusException; - import com.fasterxml.jackson.databind.ObjectMapper; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted; import software.uncharted.terarium.hmiserver.models.dataservice.model.ModelFramework; import software.uncharted.terarium.hmiserver.security.Roles; import software.uncharted.terarium.hmiserver.service.data.FrameworkService; +import java.util.Optional; +import java.util.UUID; + @RequestMapping("/models") @RestController @Transactional @@ -44,11 +35,10 @@ public class FrameworkController { @Operation(summary = "Create a new model framework") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Model framework created.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelFramework.class))), - @ApiResponse(responseCode = "500", description = "There was an issue creating the framework", content = @Content) }) ResponseEntity createFramework( @RequestBody final ModelFramework framework) { - ModelFramework modelFramework = frameworkService.createFramework(framework); + final ModelFramework modelFramework = frameworkService.createFramework(framework); return ResponseEntity.status(HttpStatus.CREATED).body(modelFramework); } @@ -58,13 +48,12 @@ ResponseEntity createFramework( @Operation(summary = "Gets a model framework by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model framework found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelFramework.class))), - @ApiResponse(responseCode = "204", description = "There was no framework found", content = @Content), - @ApiResponse(responseCode = "500", description = "There was an issue retrieving the framework from the data store", content = @Content) + @ApiResponse(responseCode = "404", description = "There was no framework found", content = @Content), }) ResponseEntity getFramework( - @PathVariable("id") UUID id) { + @PathVariable("id") final UUID id) { - Optional framework = frameworkService.getFramework(id); + final Optional framework = frameworkService.getFramework(id); if (framework.isEmpty()) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, String.format("Document %s not found", id)); } @@ -76,11 +65,11 @@ ResponseEntity getFramework( @Operation(summary = "Update a model framework") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model framework updated.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelFramework.class))), - @ApiResponse(responseCode = "500", description = "There was an issue updating the framework", content = @Content) + @ApiResponse(responseCode = "404", description = "There was no framework found", content = @Content), }) ResponseEntity updateFramework( - @PathVariable("id") UUID id, - @RequestBody ModelFramework framework) { + @PathVariable("id") final UUID id, + @RequestBody final ModelFramework framework) { framework.setId(id); final Optional updated = frameworkService.updateFramework(framework); @@ -95,12 +84,10 @@ ResponseEntity updateFramework( @Operation(summary = "Deletes an model framework") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted framework", content = { - @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Model framework could not be found", content = @Content), - @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) + @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }) }) ResponseEntity deleteFramework( - @PathVariable("id") UUID id) { + @PathVariable("id") final UUID id) { frameworkService.deleteFramework(id); return ResponseEntity.ok(new ResponseDeleted("ModelFramework", id)); diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelConfigurationController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelConfigurationController.java index c61e4961b7..70a2525cff 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelConfigurationController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelConfigurationController.java @@ -37,7 +37,6 @@ public class ModelConfigurationController { @Operation(summary = "Gets all model configurations") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model configuration found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelConfiguration.class)))), - @ApiResponse(responseCode = "204", description = "There are no configuration found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving configuration from the data store", content = @Content) }) public ResponseEntity> getModelConfigurations( @@ -81,7 +80,7 @@ public ResponseEntity createModelConfiguration(@RequestBody @Operation(summary = "Gets a model configuration by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model configuration found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelConfiguration.class))), - @ApiResponse(responseCode = "204", description = "There was no configuration found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no configuration found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the configuration from the data store", content = @Content) }) public ResponseEntity getModelConfiguration( @@ -90,7 +89,7 @@ public ResponseEntity getModelConfiguration( try { final Optional modelConfiguration = modelConfigurationService .getAsset(id); - return modelConfiguration.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); + return modelConfiguration.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final IOException e) { final String error = "Unable to get model configuration"; log.error(error, e); @@ -132,7 +131,6 @@ public ResponseEntity updateModelConfiguration( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted configuration", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Model configuration could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) public ResponseEntity deleteModelConfiguration( diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelController.java index 4dee0f7804..cbac5e95c0 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ModelController.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; @@ -55,7 +54,6 @@ public class ModelController { @Operation(summary = "Gets all model descriptions") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model descriptions found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelDescription.class)))), - @ApiResponse(responseCode = "204", description = "There are no descriptions found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving descriptions from the data store", content = @Content) }) public ResponseEntity> listModels( @@ -78,7 +76,7 @@ public ResponseEntity> listModels( @Operation(summary = "Gets a model description by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model description found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelDescription.class))), - @ApiResponse(responseCode = "204", description = "There was no description found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no description found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the description from the data store", content = @Content) }) ResponseEntity getDescription( @@ -86,7 +84,7 @@ ResponseEntity getDescription( try { final Optional model = modelService.getDescription(id); - return model.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); + return model.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final IOException e) { final String error = "Unable to get model description"; log.error(error, e); @@ -101,7 +99,6 @@ ResponseEntity getDescription( @Operation(summary = "Gets a model by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Model.class))), - @ApiResponse(responseCode = "204", description = "There was no model found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the model from the data store", content = @Content) }) ResponseEntity getModel(@PathVariable("id") final UUID id) { @@ -163,7 +160,6 @@ ResponseEntity getModel(@PathVariable("id") final UUID id) { @Operation(summary = "Search models with a query") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Models found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = Model.class)))), - @ApiResponse(responseCode = "204", description = "There are no models found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving models from the data store", content = @Content) }) public ResponseEntity> searchModels( @@ -213,7 +209,6 @@ ResponseEntity updateModel( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted model", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "Model could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) ResponseEntity deleteModel( @@ -258,7 +253,6 @@ ResponseEntity createModel( @Operation(summary = "Gets all model configurations for a model") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Model configurations found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ModelConfiguration.class)))), - @ApiResponse(responseCode = "204", description = "There are no configurations found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving configurations from the data store", content = @Content) }) ResponseEntity> getModelConfigurationsForModelId( @@ -271,7 +265,7 @@ ResponseEntity> getModelConfigurationsForModelId( modelConfigurations.forEach(config -> { final JsonNode configuration = objectMapper.valueToTree(config.getConfiguration()); - + // check if configuration has a metadata field, if it doesnt make it an empty object if (configuration.get("metadata") == null) { ((ObjectNode) configuration).putObject("metadata"); @@ -285,7 +279,7 @@ ResponseEntity> getModelConfigurationsForModelId( documentQueryParams.setTypes(List.of(ProvenanceType.DOCUMENT)); final Set documentIds = provenanceSearchService.modelConfigFromDocument(documentQueryParams); - List documentSourceNames = new ArrayList(); + final List documentSourceNames = new ArrayList<>(); documentIds.forEach(documentId -> { try { // Fetch the Document extractions @@ -307,7 +301,7 @@ ResponseEntity> getModelConfigurationsForModelId( datasetQueryParams.setTypes(List.of(ProvenanceType.DATASET)); final Set datasetIds = provenanceSearchService.modelConfigFromDataset(datasetQueryParams); - List datasetSourceNames = new ArrayList(); + final List datasetSourceNames = new ArrayList<>(); datasetIds.forEach(datasetId -> { try { // Fetch the Document extractions @@ -323,7 +317,7 @@ ResponseEntity> getModelConfigurationsForModelId( }); - List sourceNames = new ArrayList(); + final List sourceNames = new ArrayList<>(); sourceNames.addAll(documentSourceNames); sourceNames.addAll(datasetSourceNames); diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/NotebookSessionController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/NotebookSessionController.java index e38e430569..401512e497 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/NotebookSessionController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/NotebookSessionController.java @@ -48,7 +48,6 @@ public class NotebookSessionController { @Operation(summary = "Gets all sessions") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "NotebookSessions found.", content = @Content(array = @ArraySchema(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = NotebookSession.class)))), - @ApiResponse(responseCode = "204", description = "There are no sessions found and no errors occurred", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving sessions from the data store", content = @Content) }) ResponseEntity> getNotebookSessions( @@ -104,16 +103,16 @@ ResponseEntity createNotebookSession(@RequestBody final Noteboo @Operation(summary = "Gets session by ID") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "NotebookSession found.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = NotebookSession.class))), - @ApiResponse(responseCode = "204", description = "There was no session found", content = @Content), + @ApiResponse(responseCode = "404", description = "There was no session found", content = @Content), @ApiResponse(responseCode = "500", description = "There was an issue retrieving the session from the data store", content = @Content) }) ResponseEntity getNotebookSession(@PathVariable("id") final UUID id) { try { final Optional session = sessionService.getAsset(id); - return session.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.noContent().build()); + return session.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final IOException e) { - final String error = "Unable to get session"; + final String error = "Unable to get notebook session"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -145,7 +144,7 @@ ResponseEntity updateNotebookSession( final Optional updated = sessionService.updateAsset(session); return updated.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } catch (final IOException e) { - final String error = "Unable to update session"; + final String error = "Unable to update notebook session"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, @@ -187,7 +186,6 @@ ResponseEntity cloneNotebookSession( @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted session", content = { @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class)) }), - @ApiResponse(responseCode = "404", description = "NotebookSession could not be found", content = @Content), @ApiResponse(responseCode = "500", description = "An error occurred while deleting", content = @Content) }) ResponseEntity deleteNotebookSession(@PathVariable("id") final UUID id) { @@ -196,7 +194,7 @@ ResponseEntity deleteNotebookSession(@PathVariable("id") final sessionService.deleteAsset(id); return ResponseEntity.ok(new ResponseDeleted("NotebookSession", id)); } catch (final IOException e) { - final String error = "Unable to delete session"; + final String error = "Unable to delete noteboko session"; log.error(error, e); throw new ResponseStatusException( org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR, diff --git a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ProjectController.java b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ProjectController.java index 6361781587..934b87049d 100644 --- a/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ProjectController.java +++ b/packages/server/src/main/java/software/uncharted/terarium/hmiserver/controller/dataservice/ProjectController.java @@ -82,7 +82,9 @@ public ResponseEntity> getProjects( projectIds = rebacUser.lookupProjects(); } catch (final Exception e) { log.error("Error getting projects which a user can read", e); - return ResponseEntity.internalServerError().build(); + throw new ResponseStatusException( + HttpStatus.INTERNAL_SERVER_ERROR, + "Error getting projects which a user can read"); } if (projectIds == null || projectIds.isEmpty()) { return ResponseEntity.noContent().build(); @@ -106,7 +108,7 @@ public ResponseEntity> getProjects( project.setPublicProject(rebacProject.isPublic()); project.setUserPermission(rebacUser.getPermissionFor(rebacProject)); - List contributors = getContributors(rebacProject); + final List contributors = getContributors(rebacProject); final List assets = projectAssetService.findActiveAssetsForProject(project.getId(), assetTypes); @@ -143,7 +145,7 @@ private class Contributor { String name; Schema.Relationship permission; - Contributor(String name, Schema.Relationship permission) { + Contributor(final String name, final Schema.Relationship permission) { this.name = name; this.permission = permission; } @@ -155,25 +157,25 @@ private class Contributor { * @param rebacProject the Project to collect RebacPermissionRelationships of. * @return List of Users and Groups who have edit capability of the rebacProject */ - private List getContributors(RebacProject rebacProject) { - Map contributorMap = new HashMap<>(); + private List getContributors(final RebacProject rebacProject) { + final Map contributorMap = new HashMap<>(); try { - List permissionRelationships = rebacProject.getPermissionRelationships(); - for (RebacPermissionRelationship permissionRelationship : permissionRelationships) { - Schema.Relationship relationship = permissionRelationship.getRelationship(); + final List permissionRelationships = rebacProject.getPermissionRelationships(); + for (final RebacPermissionRelationship permissionRelationship : permissionRelationships) { + final Schema.Relationship relationship = permissionRelationship.getRelationship(); // Ensure the relationship is capable of editing the project if (relationship.equals(Schema.Relationship.CREATOR) || relationship.equals(Schema.Relationship.ADMIN) || relationship.equals(Schema.Relationship.WRITER)) { if (permissionRelationship.getSubjectType().equals(Schema.Type.USER)) { - PermissionUser user = reBACService.getUser(permissionRelationship.getSubjectId()); - String name = user.getFirstName() + " " + user.getLastName(); + final PermissionUser user = reBACService.getUser(permissionRelationship.getSubjectId()); + final String name = user.getFirstName() + " " + user.getLastName(); if (!contributorMap.containsKey(name)) { contributorMap.put(name, new Contributor(name, relationship)); } } else if (permissionRelationship.getSubjectType().equals(Schema.Type.GROUP)) { - PermissionGroup group = reBACService.getGroup(permissionRelationship.getSubjectId()); + final PermissionGroup group = reBACService.getGroup(permissionRelationship.getSubjectId()); if (!contributorMap.containsKey(group.getName())) { contributorMap.put(group.getName(), new Contributor(group.getName(), relationship)); } @@ -210,9 +212,9 @@ public ResponseEntity getProject( if (rebacUser.canRead(rebacProject)) { final Optional project = projectService.getProject(id); if (project.isPresent()) { - List authors = new ArrayList<>(); - List contributors = getContributors(rebacProject); - for (Contributor contributor : contributors) { + final List authors = new ArrayList<>(); + final List contributors = getContributors(rebacProject); + for (final Contributor contributor : contributors) { authors.add(contributor.name); }