diff --git a/roda-core/roda-core/src/main/java/org/roda/core/model/ModelService.java b/roda-core/roda-core/src/main/java/org/roda/core/model/ModelService.java index e068fbd6db..e8e6752685 100644 --- a/roda-core/roda-core/src/main/java/org/roda/core/model/ModelService.java +++ b/roda-core/roda-core/src/main/java/org/roda/core/model/ModelService.java @@ -859,7 +859,8 @@ public BinaryVersion revertDescriptiveMetadataVersion(String aipId, String repre BinaryVersion currentVersion = storage.createBinaryVersion(binaryPath, properties); storage.revertBinaryVersion(binaryPath, versionId); - notifyDescriptiveMetadataUpdated(retrieveDescriptiveMetadata(aipId, descriptiveMetadataId)).failOnError(); + notifyDescriptiveMetadataUpdated(retrieveDescriptiveMetadata(aipId, representationId, descriptiveMetadataId)) + .failOnError(); return currentVersion; } diff --git a/roda-core/roda-core/src/main/resources/config/roda-permissions.properties b/roda-core/roda-core/src/main/resources/config/roda-permissions.properties index 1fee10511d..a3c40eaf6a 100644 --- a/roda-core/roda-core/src/main/resources/config/roda-permissions.properties +++ b/roda-core/roda-core/src/main/resources/config/roda-permissions.properties @@ -43,6 +43,10 @@ core.permissions.org.roda.wui.api.v2.controller.AIPController.retrieveRepresenta core.permissions.org.roda.wui.api.v2.controller.AIPController.createRepresentationDescriptiveMetadata = CREATE core.permissions.org.roda.wui.api.v2.controller.AIPController.isAIPMetadataSimilar = READ core.permissions.org.roda.wui.api.v2.controller.AIPController.isRepresentationMetadataSimilar = READ +core.permissions.org.roda.wui.api.v2.controller.AIPController.retrieveAIPDescriptiveMetadataVersions = READ +core.permissions.org.roda.wui.api.v2.controller.AIPController.revertAIPDescriptiveMetadataVersion = UPDATE +core.permissions.org.roda.wui.api.v2.controller.AIPController.retrieveRepresentationDescriptiveMetadataVersions = READ +core.permissions.org.roda.wui.api.v2.controller.AIPController.revertRepresentationDescriptiveMetadataVersion = UPDATE # Representation permissions core.permissions.org.roda.wui.api.v2.controller.RepresentationController.createRepresentation = CREATE diff --git a/roda-core/roda-core/src/main/resources/config/roda-roles.properties b/roda-core/roda-core/src/main/resources/config/roda-roles.properties index dd5bba7917..0474ea2731 100644 --- a/roda-core/roda-core/src/main/resources/config/roda-roles.properties +++ b/roda-core/roda-core/src/main/resources/config/roda-roles.properties @@ -50,9 +50,11 @@ core.roles.org.roda.wui.api.v2.controller.AIPController.createRepresentationDesc core.roles.org.roda.wui.api.v2.controller.AIPController.updateAIPDescriptiveMetadataFile = descriptive_metadata.update core.roles.org.roda.wui.api.v2.controller.AIPController.updateRepresentationDescriptiveMetadataFile = descriptive_metadata.update core.roles.org.roda.wui.api.v2.controller.AIPController.retrieveRepresentationDescriptiveMetadataVersions = descriptive_metadata.read +core.roles.org.roda.wui.api.v2.controller.AIPController.revertRepresentationDescriptiveMetadataVersion = descriptive_metadata.update core.roles.org.roda.wui.api.v2.controller.AIPController.isAIPMetadataSimilar = descriptive_metadata.read core.roles.org.roda.wui.api.v2.controller.AIPController.isRepresentationMetadataSimilar = descriptive_metadata.read - +core.roles.org.roda.wui.api.v2.controller.AIPController.retrieveAIPDescriptiveMetadataVersions = descriptive_metadata.read +core.roles.org.roda.wui.api.v2.controller.AIPController.revertAIPDescriptiveMetadataVersion = descriptive_metadata.update # Transferred resource roles core.roles.org.roda.wui.api.v2.controller.TransferredResourceController.createTransferredResourcesFolder = transfer.create diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/controller/AIPController.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/controller/AIPController.java index 330e913cd1..ee629b22d9 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/controller/AIPController.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/controller/AIPController.java @@ -153,7 +153,7 @@ public List suggest(@RequestBody SuggestRequest suggestRequest) { return indexService.suggest(suggestRequest, IndexedAIP.class, requestContext); } - @GetMapping(path = "/{id}/representation/{representation-id}/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @GetMapping(path = "/{id}/representations/{representation-id}/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) @Operation(summary = "Downloads representation", description = "Download a particular representation", responses = { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ResponseEntity.class))), @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), @@ -386,46 +386,6 @@ ResponseEntity retrieveAIPDescriptiveMetadataHTML( } } - @GetMapping(path = "/{id}/representations/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/html", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - @Operation(summary = "Retrieves descriptive metadata result", responses = { - @ApiResponse(responseCode = "200", description = "Returns an object ", content = @Content(schema = @Schema(implementation = ResponseEntity.class))), - @ApiResponse(responseCode = "401", description = "Unauthorized access", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), - @ApiResponse(responseCode = "403", description = "Forbidden", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), - @ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))),}) - ResponseEntity retrieveRepresentationDescriptiveMetadataHTML( - @Parameter(description = "The AIP identifier", required = true) @PathVariable(name = "id") String aipId, - @Parameter(description = "The representation identifier", required = true) @PathVariable(name = "representation-id") String representationId, - @Parameter(description = "The descriptive metadata identifier", required = true) @PathVariable(name = "descriptive-metadata-id") String descriptiveMetadataId, - @Parameter(description = "The language to be used for internationalization", content = @Content(schema = @Schema(defaultValue = "en", implementation = String.class))) @RequestParam(name = "lang", defaultValue = "en", required = false) String localeString) { - ControllerAssistant controllerAssistant = new ControllerAssistant() {}; - RequestContext requestContext = RequestUtils.parseHTTPRequest(request); - LogEntryState state = LogEntryState.SUCCESS; - - try { - // check user permissions - controllerAssistant.checkRoles(requestContext.getUser()); - - IndexedRepresentation representation = RodaCoreFactory.getIndexService().retrieve(IndexedRepresentation.class, - IdUtils.getRepresentationId(aipId, representationId), RodaConstants.REPRESENTATION_FIELDS_TO_RETURN); - controllerAssistant.checkObjectPermissions(requestContext.getUser(), representation); - - // delegate - StreamResponse streamResponse = representationService.retrieveRepresentationDescriptiveMetadata(aipId, - representationId, descriptiveMetadataId, localeString); - return ApiUtils.okResponse(streamResponse, null); - } catch (AuthorizationDeniedException e) { - state = LogEntryState.UNAUTHORIZED; - throw new RESTException(e); - } catch (RequestNotValidException | GenericException | NotFoundException e) { - state = LogEntryState.FAILURE; - throw new RESTException(e); - } finally { - controllerAssistant.registerAction(requestContext, state, RodaConstants.CONTROLLER_AIP_ID_PARAM, aipId, - RodaConstants.CONTROLLER_REPRESENTATION_ID_PARAM, representationId, RodaConstants.CONTROLLER_METADATA_ID_PARAM, - descriptiveMetadataId); - } - } - @GetMapping(path = "{id}/download/documentation", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) @Operation(summary = "Downloads documentation", description = "Download AIP documentation", responses = { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ResponseEntity.class))), @@ -596,6 +556,89 @@ public ResponseEntity downloadAIP( } } + @GetMapping(path = "/{id}/representations/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/download", produces = MediaType.APPLICATION_XML_VALUE) + @Operation(summary = "Retrieves representation's descriptive metadata", description = "Retrieves the representation's XML descriptive metadata", responses = { + @ApiResponse(responseCode = "200", description = "Returns an object ", content = @Content(schema = @Schema(implementation = ResponseEntity.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized access", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), + @ApiResponse(responseCode = "403", description = "Forbidden", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), + @ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))),}) + ResponseEntity downloadRepresentationDescriptiveMetadata( + @Parameter(description = "The AIP identifier", required = true) @PathVariable(name = "id") String aipId, + @Parameter(description = "The AIP's representation identifier", required = true) @PathVariable(name = "representation-id") String representationId, + @Parameter(description = "The descriptive metadata identifier", required = true) @PathVariable(name = "descriptive-metadata-id") String descriptiveMetadataId, + @Parameter(description = "The version identifier") @RequestParam(name = "version-id", required = false) String versionId) { + ControllerAssistant controllerAssistant = new ControllerAssistant() {}; + RequestContext requestContext = RequestUtils.parseHTTPRequest(request); + LogEntryState state = LogEntryState.SUCCESS; + + try { + // check user permissions + controllerAssistant.checkRoles(requestContext.getUser()); + + // check object permissions + IndexedRepresentation indexedRepresentation = RodaCoreFactory.getIndexService().retrieve( + IndexedRepresentation.class, IdUtils.getRepresentationId(aipId, representationId), + RodaConstants.REPRESENTATION_FIELDS_TO_RETURN); + controllerAssistant.checkObjectPermissions(requestContext.getUser(), indexedRepresentation); + + // delegate + StreamResponse streamResponse = aipService.downloadRepresentationDescriptiveMetadata(aipId, representationId, + descriptiveMetadataId, versionId); + return ApiUtils.okResponse(streamResponse); + } catch (AuthorizationDeniedException e) { + state = LogEntryState.UNAUTHORIZED; + throw new RESTException(e); + } catch (RequestNotValidException | GenericException | NotFoundException e) { + state = LogEntryState.FAILURE; + throw new RESTException(e); + } finally { + controllerAssistant.registerAction(requestContext, state, RodaConstants.CONTROLLER_AIP_ID_PARAM, aipId, + RodaConstants.CONTROLLER_METADATA_ID_PARAM, descriptiveMetadataId); + } + } + + @GetMapping(path = "/{id}/representations/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/html", produces = MediaType.TEXT_HTML_VALUE) + @Operation(summary = "Retrieves representation's descriptive metadata", description = "Retrieves the representation's descriptive metadata with the visualization template applied and internationalized", responses = { + @ApiResponse(responseCode = "200", description = "Returns an object ", content = @Content(schema = @Schema(implementation = ResponseEntity.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized access", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), + @ApiResponse(responseCode = "403", description = "Forbidden", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), + @ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))),}) + ResponseEntity retrieveRepresentationDescriptiveMetadataHTML( + @Parameter(description = "The AIP identifier", required = true) @PathVariable(name = "id") String aipId, + @Parameter(description = "The AIP's representation identifier", required = true) @PathVariable(name = "representation-id") String representationId, + @Parameter(description = "The representation's descriptive metadata identifier", required = true) @PathVariable(name = "descriptive-metadata-id") String descriptiveMetadataId, + @Parameter(description = "The version identifier") @RequestParam(name = "version-id", required = false) String versionId, + @Parameter(description = "The language to be used for internationalization", content = @Content(schema = @Schema(defaultValue = "en", implementation = String.class))) @RequestParam(name = "lang", defaultValue = "en", required = false) String localeString) { + ControllerAssistant controllerAssistant = new ControllerAssistant() {}; + RequestContext requestContext = RequestUtils.parseHTTPRequest(request); + LogEntryState state = LogEntryState.SUCCESS; + + try { + // check user permissions + controllerAssistant.checkRoles(requestContext.getUser()); + + // check object permissions + IndexedRepresentation indexedRepresentation = RodaCoreFactory.getIndexService().retrieve( + IndexedRepresentation.class, IdUtils.getRepresentationId(aipId, representationId), + RodaConstants.REPRESENTATION_FIELDS_TO_RETURN); + controllerAssistant.checkObjectPermissions(requestContext.getUser(), indexedRepresentation); + + // delegate + StreamResponse streamResponse = aipService.retrieveRepresentationDescriptiveMetadata(aipId, representationId, + descriptiveMetadataId, versionId, localeString); + return ApiUtils.okResponse(streamResponse); + } catch (AuthorizationDeniedException e) { + state = LogEntryState.UNAUTHORIZED; + throw new RESTException(e); + } catch (RequestNotValidException | GenericException | NotFoundException e) { + state = LogEntryState.FAILURE; + throw new RESTException(e); + } finally { + controllerAssistant.registerAction(requestContext, state, RodaConstants.CONTROLLER_AIP_ID_PARAM, aipId, + RodaConstants.CONTROLLER_METADATA_ID_PARAM, descriptiveMetadataId); + } + } + @Override public DescriptiveMetadata createRepresentationDescriptiveMetadata(String aipId, String representationId, @RequestBody CreateDescriptiveMetadataRequest createDescriptiveMetadataRequest) { diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/services/AIPService.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/services/AIPService.java index d7393a5e33..d3f177568c 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/services/AIPService.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/api/v2/services/AIPService.java @@ -149,6 +149,52 @@ public StreamResponse retrieveAIPDescriptiveMetadata(String aipId, String metada return new StreamResponse(stream); } + public StreamResponse downloadRepresentationDescriptiveMetadata(String aipId, String representationId, + String metadataId, String versionId) + throws AuthorizationDeniedException, RequestNotValidException, NotFoundException, GenericException { + ModelService modelService = RodaCoreFactory.getModelService(); + Binary descriptiveMetadataBinary; + if (versionId == null) { + descriptiveMetadataBinary = modelService.retrieveDescriptiveMetadataBinary(aipId, representationId, metadataId); + + } else { + StoragePath storagePath = ModelUtils.getDescriptiveMetadataStoragePath(aipId, representationId, metadataId); + BinaryVersion binaryVersion = modelService.getStorage().getBinaryVersion(storagePath, versionId); + descriptiveMetadataBinary = binaryVersion.getBinary(); + } + + return new StreamResponse( + new BinaryConsumesOutputStream(descriptiveMetadataBinary, RodaConstants.MEDIA_TYPE_APPLICATION_XML)); + } + + public StreamResponse retrieveRepresentationDescriptiveMetadata(String aipId, String representationId, + String metadataId, String versionId, String localeString) + throws AuthorizationDeniedException, RequestNotValidException, NotFoundException, GenericException { + ModelService model = RodaCoreFactory.getModelService(); + Binary descriptiveMetadataBinary; + if (versionId != null) { + StoragePath storagePath = ModelUtils.getDescriptiveMetadataStoragePath(aipId, representationId, metadataId); + BinaryVersion binaryVersion = model.getStorage().getBinaryVersion(storagePath, versionId); + descriptiveMetadataBinary = binaryVersion.getBinary(); + } else { + descriptiveMetadataBinary = model.retrieveDescriptiveMetadataBinary(aipId, representationId, metadataId); + } + + String filename = descriptiveMetadataBinary.getStoragePath().getName() + HTML_EXT; + DescriptiveMetadata descriptiveMetadata = model.retrieveDescriptiveMetadata(aipId, representationId, metadataId); + String htmlDescriptive = HTMLUtils.descriptiveMetadataToHtml(descriptiveMetadataBinary, + descriptiveMetadata.getType(), descriptiveMetadata.getVersion(), ServerTools.parseLocale(localeString)); + + ConsumesOutputStream stream = new DefaultConsumesOutputStream(filename, RodaConstants.MEDIA_TYPE_APPLICATION_XML, + out -> { + PrintStream printStream = new PrintStream(out); + printStream.print(htmlDescriptive); + printStream.close(); + }); + + return new StreamResponse(stream); + } + public List getAncestors(IndexedAIP indexedAIP, User user) throws GenericException { return RodaCoreFactory.getIndexService().retrieveAncestors(indexedAIP, user, new ArrayList<>()); } diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/client/browse/DescriptiveMetadataHistory.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/client/browse/DescriptiveMetadataHistory.java index 8b20b5c62b..72866f4cc5 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/client/browse/DescriptiveMetadataHistory.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/client/browse/DescriptiveMetadataHistory.java @@ -102,7 +102,7 @@ public void resolve(List historyTokens, final AsyncCallback call if (throwable != null) { AsyncCallbackUtils.defaultFailureTreatment(throwable); } else { - DescriptiveMetadataHistory widget = new DescriptiveMetadataHistory(aipId, null, + DescriptiveMetadataHistory widget = new DescriptiveMetadataHistory(aipId, representationId, descriptiveMetadataId, result); callback.onSuccess(widget); } @@ -284,7 +284,7 @@ private void getDescriptiveMetadata(final String aipId, final String representat SafeUri uri; if (inHTML) { if (representationId != null) { - uri = RestUtils.createRepresentationDescriptiveMetadataHTMLUri(aipId, representationId, descId); + uri = RestUtils.createRepresentationDescriptiveMetadataHTMLUri(aipId, representationId, descId, versionKey); } else { uri = RestUtils.createDescriptiveMetadataHTMLUri(aipId, descId, versionKey); } @@ -401,7 +401,8 @@ public void onSuccess(Boolean result) { AsyncCallbackUtils.defaultFailureTreatment(error); } else { Toast.showInfo(messages.dialogDone(), messages.versionReverted()); - HistoryUtils.newHistory(BrowseTop.RESOLVER, aipId, representationId); + HistoryUtils.newHistory(BrowseTop.RESOLVER, RodaConstants.RODA_OBJECT_REPRESENTATION, aipId, + representationId); } }); } diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/client/services/AIPRestService.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/client/services/AIPRestService.java index be1bc7b077..23c59953d9 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/client/services/AIPRestService.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/client/services/AIPRestService.java @@ -236,7 +236,7 @@ DescriptiveMetadata revertAIPDescriptiveMetadataVersion( @Parameter(description = "The descriptive metadata identifier", required = true) @PathVariable(name = "descriptive-metadata-id") String descriptiveMetadataId, @Parameter(description = "The version identifier", required = true) @PathVariable(name = "version-id") String versionId); - @RequestMapping(path = "/{id}/representation/{representation-id}metadata/descriptive/{descriptive-metadata-id}/versions/{version-id}/revert", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) + @RequestMapping(path = "/{id}/representation/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/versions/{version-id}/revert", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Reverts representation descriptive metadata to the an older version", description = "Reverts representation descriptive metadata to the an older version", responses = { @ApiResponse(responseCode = "200", description = "Reverted descriptive metadata"), @ApiResponse(responseCode = "401", description = "Unauthorized access", content = @Content(schema = @Schema(implementation = ErrorResponseMessage.class))), diff --git a/roda-ui/roda-wui/src/main/java/org/roda/wui/common/client/tools/RestUtils.java b/roda-ui/roda-wui/src/main/java/org/roda/wui/common/client/tools/RestUtils.java index 2f461db7ac..076da33cf3 100644 --- a/roda-ui/roda-wui/src/main/java/org/roda/wui/common/client/tools/RestUtils.java +++ b/roda-ui/roda-wui/src/main/java/org/roda/wui/common/client/tools/RestUtils.java @@ -232,8 +232,12 @@ public static SafeUri createRepresentationDescriptiveMetadataDownloadUri(String public static SafeUri createRepresentationDescriptiveMetadataHTMLUri(String aipId, String representationId, String descId) { + return createRepresentationDescriptiveMetadataHTMLUri(aipId, representationId, descId, null); + } - // api/v2/aips/{id}/representations/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/html + public static SafeUri createRepresentationDescriptiveMetadataHTMLUri(String aipId, String representationId, + String descId, String versionId) { + // api/v2/aips/{id}/representations/{representation-id}/metadata/descriptive/{descriptive-metadata-id}/html?lang=en&version-id={versionId} StringBuilder b = new StringBuilder(); // base uri @@ -246,6 +250,12 @@ public static SafeUri createRepresentationDescriptiveMetadataHTMLUri(String aipI b.append(RodaConstants.API_QUERY_START).append(RodaConstants.API_QUERY_KEY_LANG) .append(RodaConstants.API_QUERY_ASSIGN_SYMBOL).append(LocaleInfo.getCurrentLocale().getLocaleName()); + // version + if (versionId != null) { + b.append(RodaConstants.API_QUERY_SEP).append("version-id").append(RodaConstants.API_QUERY_ASSIGN_SYMBOL) + .append(URL.encodeQueryString(versionId)); + } + return UriUtils.fromSafeConstant(b.toString()); }