From 7f8a96e2630adf6a392f516b2f4bfea99624ca61 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Wed, 19 Feb 2025 13:03:51 -0500 Subject: [PATCH 01/12] Update workflow status API to check if user can view record (and is an editor) instead or checking owner --- .../org/fao/geonet/api/records/MetadataWorkflowApi.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index ce1fd6fa888..50b6855fdfc 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -248,10 +248,11 @@ public MetadataWorkflowStatusResponse getStatus( ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); ServiceContext context = ApiUtils.createServiceContext(request, locale.getISO3Language()); - // --- only allow the owner of the record to set its status - if (!accessManager.isOwner(context, String.valueOf(metadata.getId()))) { - throw new SecurityException( - messages.getString("api.metadata.status.errorGetStatusNotAllowed")); + try { + ApiUtils.canViewRecord(metadataUuid, approved, request); + } catch (SecurityException e) { + Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); + throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); } MetadataStatus recordStatus = metadataStatus.getStatus(metadata.getId()); From a23590d62b44abab65bbf9d41e73cef53ee42a1a Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Wed, 19 Feb 2025 13:05:46 -0500 Subject: [PATCH 02/12] Change message to multilingual --- .../fao/geonet/api/records/MetadataWorkflowApi.java | 13 ++++++++----- .../classes/org/fao/geonet/api/Messages.properties | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 50b6855fdfc..8370b667bba 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -180,13 +180,13 @@ public List getRecordStatusHistory( @RequestParam(required = false, defaultValue = "true") Boolean approved, HttpServletRequest request) throws Exception { ServiceContext context = ApiUtils.createServiceContext(request); - + ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); AbstractMetadata metadata; try { metadata = ApiUtils.canViewRecord(metadataUuid, approved, request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); } String sortField = SortUtils.createPath(MetadataStatus_.changeDate); @@ -212,12 +212,13 @@ public List getRecordStatusHistoryByType( @RequestParam(required = false, defaultValue = "true") Boolean approved, HttpServletRequest request) throws Exception { ServiceContext context = ApiUtils.createServiceContext(request); + ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); AbstractMetadata metadata; try { metadata = ApiUtils.canViewRecord(metadataUuid, approved, request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); } String sortField = SortUtils.createPath(MetadataStatus_.changeDate); @@ -252,7 +253,7 @@ public MetadataWorkflowStatusResponse getStatus( ApiUtils.canViewRecord(metadataUuid, approved, request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); } MetadataStatus recordStatus = metadataStatus.getStatus(metadata.getId()); @@ -1246,6 +1247,8 @@ private MetadataStatus getMetadataStatus(String uuidOrInternalId, int statusId, private String getValidatedStateText(MetadataStatus metadataStatus, State state, HttpServletRequest request, HttpSession httpSession) throws Exception { + ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); + if (!StatusValueType.event.equals(metadataStatus.getStatusValue().getType()) || !ArrayUtils.contains(supportedRestoreStatuses, StatusValue.Events.fromId(metadataStatus.getStatusValue().getId()))) { throw new NotAllowedException("Unsupported action on status type '" + metadataStatus.getStatusValue().getType() @@ -1282,7 +1285,7 @@ private String getValidatedStateText(MetadataStatus metadataStatus, State state, ApiUtils.canEditRecord(metadataStatus.getUuid(), request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); } catch (ResourceNotFoundException e) { // If metadata record does not exists then it was deleted so // we will only allow the administrator, owner to view the contents diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties index c2e89994dce..d3afb77a5e8 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties @@ -184,6 +184,7 @@ api.exception.unsatisfiedRequestParameter.description=Unsatisfied request parame exception.maxUploadSizeExceeded=Maximum upload size of {0} exceeded. exception.maxUploadSizeExceeded.description=The request was rejected because its size ({0}) exceeds the configured maximum ({1}). exception.maxUploadSizeExceededUnknownSize.description=The request was rejected because its size exceeds the configured maximum ({0}). +exception.notAllowed.cannotView=Operation not allowed. User needs to be able to view the resource. exception.resourceNotFound.metadata=Metadata not found exception.resourceNotFound.metadata.description=Metadata with UUID ''{0}'' not found. exception.resourceNotFound.resource=Metadata resource ''{0}'' not found From bf00c52d4033230b98a3ba8ccbcb087d6ca3b77f Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Wed, 19 Feb 2025 13:29:14 -0500 Subject: [PATCH 03/12] remove unused messages --- core/src/test/resources/org/fao/geonet/api/Messages.properties | 1 - .../test/resources/org/fao/geonet/api/Messages_fre.properties | 1 - .../WEB-INF/classes/org/fao/geonet/api/Messages.properties | 1 - .../WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties | 1 - .../WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties | 1 - 5 files changed, 5 deletions(-) diff --git a/core/src/test/resources/org/fao/geonet/api/Messages.properties b/core/src/test/resources/org/fao/geonet/api/Messages.properties index 8c09a2d1398..6888b6391ab 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages.properties @@ -242,7 +242,6 @@ api.metadata.share.errorMetadataNotApproved=The metadata '%s' it's not approved, api.metadata.share.ErrorUserNotAllowedToPublish=User not allowed to publish the metadata %s. %s api.metadata.share.strategy.groupOwnerOnly=You need to be administrator, or reviewer of the metadata group. api.metadata.share.strategy.reviewerInGroup=You need to be administrator, or reviewer of the metadata group or reviewer with edit privilege on the metadata. -api.metadata.status.errorGetStatusNotAllowed=Only the owner of the metadata can get the status. User is not the owner of the metadata. api.metadata.status.errorSetStatusNotAllowed=Only the owner of the metadata can set the status of this record. User is not the owner of the metadata. feedback_subject_userFeedback=User feedback diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index db0fc9f14e1..87cbe5d5d22 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -235,7 +235,6 @@ api.metadata.share.errorMetadataNotApproved=La fiche '%s' n'est pas approuv\u00E api.metadata.share.ErrorUserNotAllowedToPublish=L'utilisateur n'est pas autoris\u00E9 \u00E0 publier la fiche %s. %s api.metadata.share.strategy.groupOwnerOnly=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche. api.metadata.share.strategy.reviewerInGroup=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche ou relecteur avec un privil\u00E8ge de modification sur les fiches. -api.metadata.status.errorGetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut obtenir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es api.metadata.status.errorSetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut d\u00E9finir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es feedback_subject_userFeedback=Commentaire de l'utilisateur diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties index d3afb77a5e8..e9b04b02a6d 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties @@ -251,7 +251,6 @@ api.metadata.share.errorMetadataNotApproved=The metadata '%s' is not approved, c api.metadata.share.ErrorUserNotAllowedToPublish=User not allowed to publish the metadata %s. %s api.metadata.share.strategy.groupOwnerOnly=You need to be administrator, or reviewer of the metadata group. api.metadata.share.strategy.reviewerInGroup=You need to be administrator, or reviewer of the metadata group or reviewer with edit privilege on the metadata. -api.metadata.status.errorGetStatusNotAllowed=Only the owner of the metadata can get the status. User is not the owner of the metadata. api.metadata.status.errorSetStatusNotAllowed=Only the owner of the metadata can set the status of this record. User is not the owner of the metadata. feedback_subject_userFeedback=User feedback diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties index d42721e4b0d..cbb7513b069 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties @@ -250,7 +250,6 @@ api.metadata.share.errorMetadataNotApproved=Het metadata record '%s' is niet goe api.metadata.share.ErrorUserNotAllowedToPublish=De gebruiker mag metadata record %s niet publiceren. %s api.metadata.share.strategy.groupOwnerOnly=Je moet een beheerder zijn of een reviewer van de metadata groep. api.metadata.share.strategy.reviewerInGroup=Je moet een beheerder zijn of een reviewer van de metadata groep, of een reviewer met privileges om de metadata te bewerken. -api.metadata.status.errorGetStatusNotAllowed=Alleen de eigenaar van de metadata kan de status opvragen. De gebruiker is geen eigenaar van de metadata. api.metadata.status.errorSetStatusNotAllowed=Alleen de eigenaar van de metadata kan de status wijzigen. De gebruiker is geen eigenaar van de metadata. feedback_subject_userFeedback=Gebruikersfeedback diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties index a52fec3dc97..6ffa4ac37d2 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties @@ -243,7 +243,6 @@ api.metadata.share.errorMetadataNotApproved=La fiche '%s' n'est pas approuv\u00E api.metadata.share.ErrorUserNotAllowedToPublish=L'utilisateur n'est pas autoris\u00E9 \u00E0 publier la fiche %s. %s api.metadata.share.strategy.groupOwnerOnly=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche. api.metadata.share.strategy.reviewerInGroup=Vous devez \u00EAtre administrateur ou relecteur du groupe de la fiche ou relecteur avec un privil\u00E8ge de modification sur les fiches. -api.metadata.status.errorGetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut obtenir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es api.metadata.status.errorSetStatusNotAllowed=Seul le propri\u00E9taire des m\u00E9tadonn\u00E9es peut d\u00E9finir le statut de cet enregistrement. L'utilisateur n'est pas le propri\u00E9taire des m\u00E9tadonn\u00E9es feedback_subject_userFeedback=Commentaire de l'utilisateur From 949a3c9d8bcda9af52ff608fc52d48e244363bc2 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Wed, 19 Feb 2025 15:10:33 -0500 Subject: [PATCH 04/12] Update check to follow "minimum user profile allowed to view metadata history" logic --- .../api/records/MetadataWorkflowApi.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 8370b667bba..e49596472e7 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -234,7 +234,7 @@ public List getRecordStatusHistoryByType( @io.swagger.v3.oas.annotations.Operation(summary = "Get last workflow status for a record", description = "") @RequestMapping(value = "/{metadataUuid}/status/workflow/last", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE}) - @PreAuthorize("hasAuthority('Editor')") + @PreAuthorize("hasAuthority('RegisteredUser')") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Record status."), @ApiResponse(responseCode = "403", description = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_EDIT)}) @ResponseStatus(HttpStatus.OK) @@ -249,11 +249,26 @@ public MetadataWorkflowStatusResponse getStatus( ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); ServiceContext context = ApiUtils.createServiceContext(request, locale.getISO3Language()); - try { - ApiUtils.canViewRecord(metadataUuid, approved, request); - } catch (SecurityException e) { - Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); + Profile profile = context.getUserSession().getProfile(); + String allowedProfileLevel = org.apache.commons.lang3.StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_HISTORY_ACCESS_LEVEL), Profile.Editor.toString()); + Profile allowedAccessLevelProfile = Profile.valueOf(allowedProfileLevel); + + if (profile != Profile.Administrator) { + if (allowedAccessLevelProfile == Profile.RegisteredUser) { + try { + ApiUtils.canViewRecord(metadataUuid, approved, request); + } catch (SecurityException e) { + Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); + } + } else { + try { + ApiUtils.canEditRecord(metadataUuid, approved, request); + } catch (SecurityException e) { + Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotEdit")); + } + } } MetadataStatus recordStatus = metadataStatus.getStatus(metadata.getId()); From f15a70b7f3ef621b44d8f37f0dcab9835a85ebb6 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Wed, 19 Feb 2025 15:28:10 -0500 Subject: [PATCH 05/12] Add missing messages --- core/src/test/resources/org/fao/geonet/api/Messages.properties | 2 ++ .../test/resources/org/fao/geonet/api/Messages_fre.properties | 2 ++ .../WEB-INF/classes/org/fao/geonet/api/Messages.properties | 1 + .../WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties | 2 ++ .../WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties | 2 ++ 5 files changed, 9 insertions(+) diff --git a/core/src/test/resources/org/fao/geonet/api/Messages.properties b/core/src/test/resources/org/fao/geonet/api/Messages.properties index 6888b6391ab..4d77e4b96ec 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages.properties @@ -178,6 +178,8 @@ api.exception.unsatisfiedRequestParameter.description=Unsatisfied request parame exception.maxUploadSizeExceeded=Maximum upload size of {0} exceeded. exception.maxUploadSizeExceeded.description=The request was rejected because its size ({0}) exceeds the configured maximum ({1}). exception.maxUploadSizeExceededUnknownSize.description=The request was rejected because its size exceeds the configured maximum ({0}). +exception.notAllowed.cannotEdit=Operation not allowed. User needs to be able to edit the resource. +exception.notAllowed.cannotView=Operation not allowed. User needs to be able to view the resource. exception.resourceNotFound.metadata=Metadata not found exception.resourceNotFound.metadata.description=Metadata with UUID ''{0}'' not found. exception.resourceNotFound.resource=Metadata resource ''{0}'' not found diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index 87cbe5d5d22..934a5bff990 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -173,6 +173,8 @@ api.exception.unsatisfiedRequestParameter.description=Param\u00E8tre de demande exception.maxUploadSizeExceeded=La taille maximale du t\u00E9l\u00E9chargement de {0} a \u00E9t\u00E9 exc\u00E9d\u00E9e. exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille ({0}) exc\u00E8de le maximum configur\u00E9 ({1}). exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). +exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. +exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. exception.resourceNotFound.resource=Ressource ''{0}'' introuvable diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties index e9b04b02a6d..24318e8f98f 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties @@ -184,6 +184,7 @@ api.exception.unsatisfiedRequestParameter.description=Unsatisfied request parame exception.maxUploadSizeExceeded=Maximum upload size of {0} exceeded. exception.maxUploadSizeExceeded.description=The request was rejected because its size ({0}) exceeds the configured maximum ({1}). exception.maxUploadSizeExceededUnknownSize.description=The request was rejected because its size exceeds the configured maximum ({0}). +exception.notAllowed.cannotEdit=Operation not allowed. User needs to be able to edit the resource. exception.notAllowed.cannotView=Operation not allowed. User needs to be able to view the resource. exception.resourceNotFound.metadata=Metadata not found exception.resourceNotFound.metadata.description=Metadata with UUID ''{0}'' not found. diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties index cbb7513b069..3690e5cbbc4 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties @@ -184,6 +184,8 @@ api.exception.unsatisfiedRequestParameter.description=Niet-voldane verzoeksparam exception.maxUploadSizeExceeded=Maximale uploadgrootte van {0} is overschreden. exception.maxUploadSizeExceeded.description=Het verzoek werd afgewezen omdat de grootte ({0}) het ingestelde maximum ({1}) overschrijdt. exception.maxUploadSizeExceededUnknownSize.description=Het verzoek afgewezen omdat de grootte het ingestelde maximum ({0}) overschrijdt. +exception.notAllowed.cannotEdit=Bewerking niet toegestaan. De gebruiker moet de bron kunnen bewerken. +exception.notAllowed.cannotView=Actie niet toegestaan. Gebruiker moet de bron kunnen bekijken. exception.resourceNotFound.metadata=Metadata niet gevonden exception.resourceNotFound.metadata.description=Metadata met UUID ''{0}'' niet gevonden. exception.resourceNotFound.resource=Metadatabron ''{0}'' niet gevonden diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties index 6ffa4ac37d2..9d62b0dc561 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties @@ -179,6 +179,8 @@ api.exception.unsatisfiedRequestParameter.description=Param\u00E8tre de demande exception.maxUploadSizeExceeded=La taille maximale du t\u00E9l\u00E9chargement de {0} a \u00E9t\u00E9 exc\u00E9d\u00E9e. exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille ({0}) exc\u00E8de le maximum configur\u00E9 ({1}). exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). +exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. +exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. exception.resourceNotFound.resource=Ressource ''{0}'' introuvable From 76ec96d7b5219ed1ee945e9e08cd528192c26d52 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Thu, 20 Feb 2025 09:55:14 -0500 Subject: [PATCH 06/12] Fix minimum profile not enforced --- .../org/fao/geonet/api/Messages.properties | 7 +++ .../fao/geonet/api/Messages_fre.properties | 7 +++ .../api/records/MetadataWorkflowApi.java | 58 ++++++++++++++----- .../org/fao/geonet/api/Messages.properties | 7 +++ .../fao/geonet/api/Messages_dut.properties | 7 +++ .../fao/geonet/api/Messages_fre.properties | 7 +++ 6 files changed, 80 insertions(+), 13 deletions(-) diff --git a/core/src/test/resources/org/fao/geonet/api/Messages.properties b/core/src/test/resources/org/fao/geonet/api/Messages.properties index 4d77e4b96ec..8ccbe179c8b 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages.properties @@ -180,6 +180,7 @@ exception.maxUploadSizeExceeded.description=The request was rejected because its exception.maxUploadSizeExceededUnknownSize.description=The request was rejected because its size exceeds the configured maximum ({0}). exception.notAllowed.cannotEdit=Operation not allowed. User needs to be able to edit the resource. exception.notAllowed.cannotView=Operation not allowed. User needs to be able to view the resource. +exception.notAllowed.mustBeProfileOrOwner=Operation not allowed. User must be ''{0}'' or the owner of the resource. exception.resourceNotFound.metadata=Metadata not found exception.resourceNotFound.metadata.description=Metadata with UUID ''{0}'' not found. exception.resourceNotFound.resource=Metadata resource ''{0}'' not found @@ -253,3 +254,9 @@ audit.revision=Updated by %s on %s:\n\ audit.revision.field.set=- Field '%s' set to '%s' audit.revision.field.unset=- Field '%s' unset audit.revision.field.updated=- Field '%s' changed from '%s' to '%s' + +UserAdmin=User administrator +Administrator=Administrator +Editor=Editor +RegisteredUser=Registered user +Reviewer=Reviewer diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index 934a5bff990..b4f8f81b92d 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -175,6 +175,7 @@ exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00 exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. +exception.notAllowed.mustBeProfileOrOwner=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit être ''{0}'' ou le propri\u00E9taire de la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. exception.resourceNotFound.resource=Ressource ''{0}'' introuvable @@ -246,3 +247,9 @@ audit.revision=Mise \u00E0 jour par %s le %s:\n\ audit.revision.field.set=- Champ '%s' d\u00E9fini \u00E0 '%s' audit.revision.field.unset=- Champ '%s' d\u00E9sactiv\u00E9 audit.revision.field.updated=- Champ '%s' modifi\u00E9 de '%s' \u00E0 '%s' + +UserAdmin=Administrateur d'utilisateurs +Administrator=Administrateur +Editor=\u00C9diteur +RegisteredUser=Utilisateur enregistr\u00E9 +Reviewer=Relecteur diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index e49596472e7..b6de20dea00 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -82,6 +82,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import java.text.MessageFormat; import java.util.*; import java.util.stream.Collectors; @@ -249,19 +250,34 @@ public MetadataWorkflowStatusResponse getStatus( ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); ServiceContext context = ApiUtils.createServiceContext(request, locale.getISO3Language()); - Profile profile = context.getUserSession().getProfile(); - String allowedProfileLevel = org.apache.commons.lang3.StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_HISTORY_ACCESS_LEVEL), Profile.Editor.toString()); - Profile allowedAccessLevelProfile = Profile.valueOf(allowedProfileLevel); + // If the user does not own the record check if they meet the minimum profile + if (!accessManager.isOwner(context, String.valueOf(metadata.getId()))) { + Profile userProfile = context.getUserSession().getProfile(); + String minimumAllowedProfileName = StringUtils.defaultIfBlank( + settingManager.getValue(Settings.METADATA_HISTORY_ACCESS_LEVEL), + Profile.Editor.toString() + ); + Profile minimumAllowedProfile = Profile.valueOf(minimumAllowedProfileName); + + if (!minimumAllowedProfile.getProfileAndAllParents().contains(userProfile)) { + // If the user profile is not at least the minimum profile, then the user is not allowed to view record workflow status + String message = MessageFormat.format( + messages.getString("exception.notAllowed.mustBeProfileOrOwner"), + messages.getString(minimumAllowedProfileName)); + Log.debug(API.LOG_MODULE_NAME, message); + throw new NotAllowedException(message); + } - if (profile != Profile.Administrator) { - if (allowedAccessLevelProfile == Profile.RegisteredUser) { + if (minimumAllowedProfile == Profile.RegisteredUser) { + // If the minimum profile is RegisteredUser, then the user must be able to view the record to view the workflow status try { ApiUtils.canViewRecord(metadataUuid, approved, request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); } - } else { + } else if (minimumAllowedProfile == Profile.Editor) { + // If the minimum profile is Editor, then the user must be able to edit the record to view the workflow status try { ApiUtils.canEditRecord(metadataUuid, approved, request); } catch (SecurityException e) { @@ -737,12 +753,20 @@ public List getWorkflowStatusByType( Integer size, HttpServletRequest request) throws Exception { ServiceContext context = ApiUtils.createServiceContext(request); + ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); - Profile profile = context.getUserSession().getProfile(); - String allowedProfileLevel = org.apache.commons.lang.StringUtils.defaultIfBlank(settingManager.getValue(Settings.METADATA_HISTORY_ACCESS_LEVEL), Profile.Editor.toString()); - Profile allowedAccessLevelProfile = Profile.valueOf(allowedProfileLevel); - - if (profile != Profile.Administrator) { + Profile userProfile = context.getUserSession().getProfile(); + String minimumAllowedProfileName = StringUtils.defaultIfBlank( + settingManager.getValue(Settings.METADATA_HISTORY_ACCESS_LEVEL), + Profile.Editor.toString() + ); + Profile minimumAllowedProfile = Profile.valueOf(minimumAllowedProfileName); + boolean isMinimumAllowedProfile = minimumAllowedProfile.getProfileAndAllParents().contains(userProfile); + String mustBeProfileOrOwnerMessage = MessageFormat.format( + messages.getString("exception.notAllowed.mustBeProfileOrOwner"), + messages.getString(minimumAllowedProfileName)); + + if (userProfile != Profile.Administrator) { if (CollectionUtils.isEmpty(recordIdentifier) && CollectionUtils.isEmpty(uuid)) { throw new NotAllowedException( @@ -751,8 +775,12 @@ public List getWorkflowStatusByType( if (!CollectionUtils.isEmpty(recordIdentifier)) { for (Integer recordId : recordIdentifier) { + if (!isMinimumAllowedProfile && !accessManager.isOwner(context, String.valueOf(recordId))) { + Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); + throw new NotAllowedException(mustBeProfileOrOwnerMessage); + } try { - if (allowedAccessLevelProfile == Profile.RegisteredUser) { + if (minimumAllowedProfile == Profile.RegisteredUser) { ApiUtils.canViewRecord(String.valueOf(recordId), request); } else { ApiUtils.canEditRecord(String.valueOf(recordId), request); @@ -765,8 +793,12 @@ public List getWorkflowStatusByType( } if (!CollectionUtils.isEmpty(uuid)) { for (String recordId : uuid) { + if (!isMinimumAllowedProfile && !accessManager.isOwner(context, recordId)) { + Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); + throw new NotAllowedException(mustBeProfileOrOwnerMessage); + } try { - if (allowedAccessLevelProfile == Profile.RegisteredUser) { + if (minimumAllowedProfile == Profile.RegisteredUser) { ApiUtils.canViewRecord(recordId, request); } else { ApiUtils.canEditRecord(recordId, request); diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties index 24318e8f98f..5342645d531 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties @@ -186,6 +186,7 @@ exception.maxUploadSizeExceeded.description=The request was rejected because its exception.maxUploadSizeExceededUnknownSize.description=The request was rejected because its size exceeds the configured maximum ({0}). exception.notAllowed.cannotEdit=Operation not allowed. User needs to be able to edit the resource. exception.notAllowed.cannotView=Operation not allowed. User needs to be able to view the resource. +exception.notAllowed.mustBeProfileOrOwner=Operation not allowed. User must be ''{0}'' or the owner of the resource. exception.resourceNotFound.metadata=Metadata not found exception.resourceNotFound.metadata.description=Metadata with UUID ''{0}'' not found. exception.resourceNotFound.resource=Metadata resource ''{0}'' not found @@ -261,3 +262,9 @@ audit.revision=Updated by %s on %s:\n\ audit.revision.field.set=- Field '%s' set to '%s' audit.revision.field.unset=- Field '%s' unset audit.revision.field.updated=- Field '%s' changed from '%s' to '%s' + +UserAdmin=User administrator +Administrator=Administrator +Editor=Editor +RegisteredUser=Registered user +Reviewer=Reviewer diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties index 3690e5cbbc4..952bdb2f67d 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties @@ -186,6 +186,7 @@ exception.maxUploadSizeExceeded.description=Het verzoek werd afgewezen omdat de exception.maxUploadSizeExceededUnknownSize.description=Het verzoek afgewezen omdat de grootte het ingestelde maximum ({0}) overschrijdt. exception.notAllowed.cannotEdit=Bewerking niet toegestaan. De gebruiker moet de bron kunnen bewerken. exception.notAllowed.cannotView=Actie niet toegestaan. Gebruiker moet de bron kunnen bekijken. +exception.notAllowed.mustBeProfileOrOwner=Actie niet toegestaan. Gebruiker moet ''{0}'' of de eigenaar van de bron zijn. exception.resourceNotFound.metadata=Metadata niet gevonden exception.resourceNotFound.metadata.description=Metadata met UUID ''{0}'' niet gevonden. exception.resourceNotFound.resource=Metadatabron ''{0}'' niet gevonden @@ -261,3 +262,9 @@ audit.revision=Gewijzigd door %s op %s:\n\ audit.revision.field.set=- Veld '%s' ingesteld op '%s' audit.revision.field.unset=- Veld '%s' gewist audit.revision.field.updated=- Veld '%s' gewijzigd van '%s' naar '%s' + +UserAdmin=Gebruiker beheerder +Administrator=Beheerder +Editor=Uitgever +RegisteredUser=Geregistreerde gebruiker +Reviewer=Bekijker diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties index 9d62b0dc561..a343860900e 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties @@ -181,6 +181,7 @@ exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00 exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. +exception.notAllowed.mustBeProfileOrOwner=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit être ''{0}'' ou le propri\u00E9taire de la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. exception.resourceNotFound.resource=Ressource ''{0}'' introuvable @@ -254,3 +255,9 @@ audit.revision=Mise \u00E0 jour par %s le %s:\n\ audit.revision.field.set=- Champ '%s' d\u00E9fini \u00E0 '%s' audit.revision.field.unset=- Champ '%s' d\u00E9sactiv\u00E9 audit.revision.field.updated=- Champ '%s' modifi\u00E9 de '%s' \u00E0 '%s' + +UserAdmin=Administrateur d'utilisateurs +Administrator=Administrateur +Editor=\u00C9diteur +RegisteredUser=Utilisateur enregistr\u00E9 +Reviewer=Relecteur From 1d90af42fed4d9b96de2011fc67b0a09bdd95e84 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Thu, 20 Feb 2025 12:12:04 -0500 Subject: [PATCH 07/12] Fix cannot get status when user cannot edit --- .../java/org/fao/geonet/api/records/MetadataWorkflowApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index b6de20dea00..9146de7a0aa 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -245,7 +245,7 @@ public MetadataWorkflowStatusResponse getStatus( @Parameter(description = "Use approved version or not", example = "true") @RequestParam(required = false, defaultValue = "true") Boolean approved, HttpServletRequest request) throws Exception { - AbstractMetadata metadata = ApiUtils.canEditRecord(metadataUuid, approved, request); + AbstractMetadata metadata = metadataUtils.findOneByUuid(metadataUuid); Locale locale = languageUtils.parseAcceptLanguage(request.getLocales()); ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); ServiceContext context = ApiUtils.createServiceContext(request, locale.getISO3Language()); From 9d82676dfe22bb2b4295794a317720a589daedb4 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Thu, 20 Feb 2025 12:14:55 -0500 Subject: [PATCH 08/12] Move logic to reusable methods --- .../api/records/MetadataWorkflowApi.java | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 9146de7a0aa..8efeb12a4ef 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -261,30 +261,12 @@ public MetadataWorkflowStatusResponse getStatus( if (!minimumAllowedProfile.getProfileAndAllParents().contains(userProfile)) { // If the user profile is not at least the minimum profile, then the user is not allowed to view record workflow status - String message = MessageFormat.format( - messages.getString("exception.notAllowed.mustBeProfileOrOwner"), - messages.getString(minimumAllowedProfileName)); + String message = getMustBeProfileOrOwnerMessage(minimumAllowedProfileName, messages); Log.debug(API.LOG_MODULE_NAME, message); throw new NotAllowedException(message); } - if (minimumAllowedProfile == Profile.RegisteredUser) { - // If the minimum profile is RegisteredUser, then the user must be able to view the record to view the workflow status - try { - ApiUtils.canViewRecord(metadataUuid, approved, request); - } catch (SecurityException e) { - Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); - } - } else if (minimumAllowedProfile == Profile.Editor) { - // If the minimum profile is Editor, then the user must be able to edit the record to view the workflow status - try { - ApiUtils.canEditRecord(metadataUuid, approved, request); - } catch (SecurityException e) { - Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); - throw new NotAllowedException(messages.getString("exception.notAllowed.cannotEdit")); - } - } + checkUserCanSeeHistory(minimumAllowedProfile, metadataUuid, messages, request); } MetadataStatus recordStatus = metadataStatus.getStatus(metadata.getId()); @@ -762,9 +744,7 @@ public List getWorkflowStatusByType( ); Profile minimumAllowedProfile = Profile.valueOf(minimumAllowedProfileName); boolean isMinimumAllowedProfile = minimumAllowedProfile.getProfileAndAllParents().contains(userProfile); - String mustBeProfileOrOwnerMessage = MessageFormat.format( - messages.getString("exception.notAllowed.mustBeProfileOrOwner"), - messages.getString(minimumAllowedProfileName)); + String mustBeProfileOrOwnerMessage = getMustBeProfileOrOwnerMessage(minimumAllowedProfileName, messages); if (userProfile != Profile.Administrator) { if (CollectionUtils.isEmpty(recordIdentifier) && @@ -779,16 +759,7 @@ public List getWorkflowStatusByType( Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); throw new NotAllowedException(mustBeProfileOrOwnerMessage); } - try { - if (minimumAllowedProfile == Profile.RegisteredUser) { - ApiUtils.canViewRecord(String.valueOf(recordId), request); - } else { - ApiUtils.canEditRecord(String.valueOf(recordId), request); - } - - } catch (SecurityException e) { - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_EDIT); - } + checkUserCanSeeHistory(minimumAllowedProfile, String.valueOf(recordId), messages, request); } } if (!CollectionUtils.isEmpty(uuid)) { @@ -797,16 +768,7 @@ public List getWorkflowStatusByType( Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); throw new NotAllowedException(mustBeProfileOrOwnerMessage); } - try { - if (minimumAllowedProfile == Profile.RegisteredUser) { - ApiUtils.canViewRecord(recordId, request); - } else { - ApiUtils.canEditRecord(recordId, request); - } - - } catch (SecurityException e) { - throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_EDIT); - } + checkUserCanSeeHistory(minimumAllowedProfile, recordId, messages, request); } } } @@ -1414,4 +1376,46 @@ private void changeMetadataStatus(ServiceContext context, AbstractMetadata metad sa.onStatusChange(listOfStatusChange, true); } + /** + * Constructs a message indicating that the user must have a specific profile or be the owner to perform an action. + * + * @param messages The resource bundle containing localized messages. + * @param minimumAllowedProfileName The name of the minimum allowed profile. + * @return A formatted message indicating the required profile or ownership. + */ + private String getMustBeProfileOrOwnerMessage(String minimumAllowedProfileName, ResourceBundle messages) { + return MessageFormat.format( + messages.getString("exception.notAllowed.mustBeProfileOrOwner"), + messages.getString(minimumAllowedProfileName) + ); + } + + /** + * Checks if the user has the necessary permissions to view the history of a record. + * + * @param minimumAllowedProfile The minimum profile required to view the history. + * @param recordId The ID of the record. + * @param messages The resource bundle containing localized messages. + * @param request The HTTP request object. + * @throws Exception If the user does not have the necessary permissions. + */ + private void checkUserCanSeeHistory(Profile minimumAllowedProfile, String recordId, ResourceBundle messages, HttpServletRequest request) throws Exception { + if (minimumAllowedProfile == Profile.RegisteredUser) { + // If the minimum profile is RegisteredUser, then the user must be able to view the record + try { + ApiUtils.canViewRecord(recordId, request); + } catch (SecurityException e) { + Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotView")); + } + } else if (minimumAllowedProfile == Profile.Editor) { + // If the minimum profile is Editor, then the user must be able to edit the record + try { + ApiUtils.canEditRecord(recordId, request); + } catch (SecurityException e) { + Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); + throw new NotAllowedException(messages.getString("exception.notAllowed.cannotEdit")); + } + } + } } From b42bfcce0cbca8710dc7aae7176b31887b033b07 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Thu, 20 Feb 2025 12:15:22 -0500 Subject: [PATCH 09/12] Fix french messages --- .../test/resources/org/fao/geonet/api/Messages_fre.properties | 4 ++-- .../classes/org/fao/geonet/api/Messages_fre.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index b4f8f81b92d..4c65f3cb65c 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -173,8 +173,8 @@ api.exception.unsatisfiedRequestParameter.description=Param\u00E8tre de demande exception.maxUploadSizeExceeded=La taille maximale du t\u00E9l\u00E9chargement de {0} a \u00E9t\u00E9 exc\u00E9d\u00E9e. exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille ({0}) exc\u00E8de le maximum configur\u00E9 ({1}). exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). -exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. -exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. +exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L'utilisateur doit pouvoir modifier la ressource. +exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L'utilisateur doit pouvoir visualiser la ressource. exception.notAllowed.mustBeProfileOrOwner=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit être ''{0}'' ou le propri\u00E9taire de la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties index a343860900e..69bb9bb77c1 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties @@ -179,8 +179,8 @@ api.exception.unsatisfiedRequestParameter.description=Param\u00E8tre de demande exception.maxUploadSizeExceeded=La taille maximale du t\u00E9l\u00E9chargement de {0} a \u00E9t\u00E9 exc\u00E9d\u00E9e. exception.maxUploadSizeExceeded.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille ({0}) exc\u00E8de le maximum configur\u00E9 ({1}). exception.maxUploadSizeExceededUnknownSize.description=La demande a \u00E9t\u00E9 refus\u00E9e car sa taille exc\u00E8de le maximum configur\u00E9 ({0}). -exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir modifier la ressource. -exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit pouvoir visualiser la ressource. +exception.notAllowed.cannotEdit=Op\u00E9ration non autoris\u00E9e. L'utilisateur doit pouvoir modifier la ressource. +exception.notAllowed.cannotView=Op\u00E9ration non autoris\u00E9e. L'utilisateur doit pouvoir visualiser la ressource. exception.notAllowed.mustBeProfileOrOwner=Op\u00E9ration non autoris\u00E9e. L''utilisateur doit être ''{0}'' ou le propri\u00E9taire de la ressource. exception.resourceNotFound.metadata=Fiches introuvables exception.resourceNotFound.metadata.description=La fiche ''{0}'' est introuvable. From 2ec157f4a00078214ce298c87f3ee23d18b675ca Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Fri, 21 Feb 2025 09:47:32 -0500 Subject: [PATCH 10/12] Update messages to use translated profile name from json --- .../test/resources/org/fao/geonet/api/Messages.properties | 6 ------ .../resources/org/fao/geonet/api/Messages_fre.properties | 6 ------ .../org/fao/geonet/api/records/MetadataWorkflowApi.java | 8 +++++++- .../classes/org/fao/geonet/api/Messages.properties | 6 ------ .../classes/org/fao/geonet/api/Messages_dut.properties | 6 ------ .../classes/org/fao/geonet/api/Messages_fre.properties | 6 ------ 6 files changed, 7 insertions(+), 31 deletions(-) diff --git a/core/src/test/resources/org/fao/geonet/api/Messages.properties b/core/src/test/resources/org/fao/geonet/api/Messages.properties index 8ccbe179c8b..f8bf6b86e79 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages.properties @@ -254,9 +254,3 @@ audit.revision=Updated by %s on %s:\n\ audit.revision.field.set=- Field '%s' set to '%s' audit.revision.field.unset=- Field '%s' unset audit.revision.field.updated=- Field '%s' changed from '%s' to '%s' - -UserAdmin=User administrator -Administrator=Administrator -Editor=Editor -RegisteredUser=Registered user -Reviewer=Reviewer diff --git a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties index 4c65f3cb65c..575315c2b72 100644 --- a/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties +++ b/core/src/test/resources/org/fao/geonet/api/Messages_fre.properties @@ -247,9 +247,3 @@ audit.revision=Mise \u00E0 jour par %s le %s:\n\ audit.revision.field.set=- Champ '%s' d\u00E9fini \u00E0 '%s' audit.revision.field.unset=- Champ '%s' d\u00E9sactiv\u00E9 audit.revision.field.updated=- Champ '%s' modifi\u00E9 de '%s' \u00E0 '%s' - -UserAdmin=Administrateur d'utilisateurs -Administrator=Administrateur -Editor=\u00C9diteur -RegisteredUser=Utilisateur enregistr\u00E9 -Reviewer=Relecteur diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 8efeb12a4ef..96ea7456c51 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -58,6 +58,8 @@ import org.fao.geonet.kernel.metadata.StatusChangeType; import org.fao.geonet.kernel.search.EsSearchManager; import org.fao.geonet.kernel.search.IndexingMode; +import org.fao.geonet.kernel.search.Translator; +import org.fao.geonet.kernel.search.TranslatorFactory; import org.fao.geonet.kernel.setting.SettingManager; import org.fao.geonet.kernel.setting.Settings; import org.fao.geonet.languages.FeedbackLanguages; @@ -161,6 +163,9 @@ public class MetadataWorkflowApi { @Autowired RoleHierarchy roleHierarchy; + @Autowired + TranslatorFactory translatorFactory; + // The restore function currently supports these states static final StatusValue.Events[] supportedRestoreStatuses = StatusValue.Events.getSupportedRestoreStatuses(); @@ -1384,9 +1389,10 @@ private void changeMetadataStatus(ServiceContext context, AbstractMetadata metad * @return A formatted message indicating the required profile or ownership. */ private String getMustBeProfileOrOwnerMessage(String minimumAllowedProfileName, ResourceBundle messages) { + Translator jsonLocTranslator = translatorFactory.getTranslator("apploc:", messages.getLocale().getISO3Language()); return MessageFormat.format( messages.getString("exception.notAllowed.mustBeProfileOrOwner"), - messages.getString(minimumAllowedProfileName) + jsonLocTranslator.translate(minimumAllowedProfileName) ); } diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties index 5342645d531..b8c9e0f1d70 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages.properties @@ -262,9 +262,3 @@ audit.revision=Updated by %s on %s:\n\ audit.revision.field.set=- Field '%s' set to '%s' audit.revision.field.unset=- Field '%s' unset audit.revision.field.updated=- Field '%s' changed from '%s' to '%s' - -UserAdmin=User administrator -Administrator=Administrator -Editor=Editor -RegisteredUser=Registered user -Reviewer=Reviewer diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties index 952bdb2f67d..54ebe1ac825 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_dut.properties @@ -262,9 +262,3 @@ audit.revision=Gewijzigd door %s op %s:\n\ audit.revision.field.set=- Veld '%s' ingesteld op '%s' audit.revision.field.unset=- Veld '%s' gewist audit.revision.field.updated=- Veld '%s' gewijzigd van '%s' naar '%s' - -UserAdmin=Gebruiker beheerder -Administrator=Beheerder -Editor=Uitgever -RegisteredUser=Geregistreerde gebruiker -Reviewer=Bekijker diff --git a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties index 69bb9bb77c1..5aa133b5323 100644 --- a/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties +++ b/web/src/main/webapp/WEB-INF/classes/org/fao/geonet/api/Messages_fre.properties @@ -255,9 +255,3 @@ audit.revision=Mise \u00E0 jour par %s le %s:\n\ audit.revision.field.set=- Champ '%s' d\u00E9fini \u00E0 '%s' audit.revision.field.unset=- Champ '%s' d\u00E9sactiv\u00E9 audit.revision.field.updated=- Champ '%s' modifi\u00E9 de '%s' \u00E0 '%s' - -UserAdmin=Administrateur d'utilisateurs -Administrator=Administrateur -Editor=\u00C9diteur -RegisteredUser=Utilisateur enregistr\u00E9 -Reviewer=Relecteur From a86144cd98be48e669a7835976d5db7e1c1d50ad Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Fri, 21 Feb 2025 10:27:40 -0500 Subject: [PATCH 11/12] Fix record not found not handled correctly --- .../java/org/fao/geonet/api/records/MetadataWorkflowApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 96ea7456c51..92f3008e1de 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -250,7 +250,7 @@ public MetadataWorkflowStatusResponse getStatus( @Parameter(description = "Use approved version or not", example = "true") @RequestParam(required = false, defaultValue = "true") Boolean approved, HttpServletRequest request) throws Exception { - AbstractMetadata metadata = metadataUtils.findOneByUuid(metadataUuid); + AbstractMetadata metadata = ApiUtils.getRecord(metadataUuid); Locale locale = languageUtils.parseAcceptLanguage(request.getLocales()); ResourceBundle messages = ApiUtils.getMessagesResourceBundle(request.getLocales()); ServiceContext context = ApiUtils.createServiceContext(request, locale.getISO3Language()); From bae0649ab9bf87697ca9dae3ccdde46d4abb8e89 Mon Sep 17 00:00:00 2001 From: tylerjmchugh Date: Fri, 21 Feb 2025 11:06:41 -0500 Subject: [PATCH 12/12] Handle record not found for getWorkflowStatusByType --- .../org/fao/geonet/api/records/MetadataWorkflowApi.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java index 92f3008e1de..582fafccb37 100644 --- a/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java +++ b/services/src/main/java/org/fao/geonet/api/records/MetadataWorkflowApi.java @@ -760,7 +760,9 @@ public List getWorkflowStatusByType( if (!CollectionUtils.isEmpty(recordIdentifier)) { for (Integer recordId : recordIdentifier) { - if (!isMinimumAllowedProfile && !accessManager.isOwner(context, String.valueOf(recordId))) { + // Handle record not found + AbstractMetadata metadata = ApiUtils.getRecord(String.valueOf(recordId)); + if (!isMinimumAllowedProfile && !accessManager.isOwner(context, metadata.getSourceInfo())) { Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); throw new NotAllowedException(mustBeProfileOrOwnerMessage); } @@ -769,7 +771,9 @@ public List getWorkflowStatusByType( } if (!CollectionUtils.isEmpty(uuid)) { for (String recordId : uuid) { - if (!isMinimumAllowedProfile && !accessManager.isOwner(context, recordId)) { + // Handle record not found + AbstractMetadata metadata = ApiUtils.getRecord(recordId); + if (!isMinimumAllowedProfile && !accessManager.isOwner(context, metadata.getSourceInfo())) { Log.debug(API.LOG_MODULE_NAME, mustBeProfileOrOwnerMessage); throw new NotAllowedException(mustBeProfileOrOwnerMessage); }