From d5f9a21a560b71052bf7314f9926da18126ebc05 Mon Sep 17 00:00:00 2001 From: Florent MILLOT <75525996+flomillot@users.noreply.github.com> Date: Sat, 10 Oct 2026 17:04:48 +0200 Subject: [PATCH 1/6] Make root network applicabilities explicit Signed-off-by: Florent MILLOT <75525996+flomillot@users.noreply.github.com> --- .../service/NetworkModificationService.java | 3 ++- .../service/NetworkModificationTreeService.java | 6 ++++-- .../service/RootNetworkNodeInfoService.java | 2 +- .../study/server/service/RootNetworkService.java | 6 ++++++ .../service/NetworkModificationServiceTest.java | 15 +++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index 5b7230896..f55ad82e3 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -589,13 +589,14 @@ private NetworkModificationsResult duplicateModifications(UUID targetGroupUuid, ).getBody(); } - public void duplicateModificationsGroup(UUID sourceGroupUuid, UUID groupUuid, UUID newNodeUuid, UUID studyUuid, String userId) { + public void duplicateModificationsGroup(UUID sourceGroupUuid, UUID groupUuid, UUID newNodeUuid, UUID studyUuid, List rootNetworkTags, String userId) { Objects.requireNonNull(groupUuid); Objects.requireNonNull(sourceGroupUuid); var path = UriComponentsBuilder.fromPath("groups/{uuid}/duplicate") .queryParam(QUERY_PARAM_GROUP_UUID, groupUuid) .queryParam(QUERY_PARAM_NODE_CONTAINER_UUID, newNodeUuid) .queryParam(QUERY_PARAM_STUDY_ROOT_CONTAINER_UUID, studyUuid) + .queryParam(QUERY_PARAM_ROOT_NETWORK_TAGS, rootNetworkTags) .buildAndExpand(sourceGroupUuid) .toUriString(); diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java index c8303b920..a828bca22 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java @@ -248,7 +248,8 @@ private UUID duplicateNode(UUID nodeToCopyUuid, UUID anchorNodeUuid, InsertMode ); // Then we create the modification group and recreate references - networkModificationService.duplicateModificationsGroup(modificationGroupUuid, newGroupUuid, node.getId(), studyUuid, userId); + networkModificationService.duplicateModificationsGroup(modificationGroupUuid, newGroupUuid, node.getId(), studyUuid, + rootNetworkService.getStudyRootNetworkTags(studyUuid), userId); return node.getId(); } @@ -560,7 +561,8 @@ public UUID cloneStudyTree(AbstractNode nodeToDuplicate, UUID nodeParentId, Stud nextParentId = duplicateNode(newStudyEntity, nodeParentId, model, InsertMode.CHILD).getId(); - networkModificationService.duplicateModificationsGroup(modificationGroupToDuplicateId, newModificationGroupId, nextParentId, newStudyEntity.getId(), userId); + networkModificationService.duplicateModificationsGroup(modificationGroupToDuplicateId, newModificationGroupId, nextParentId, newStudyEntity.getId(), + rootNetworkService.getStudyRootNetworkTags(newStudyEntity.getId()), userId); } else { // when cloning studyTree, we don't clone root node // if cloning the whole study, the root node is previously created diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java index c57077df9..1a569a9cb 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java @@ -591,7 +591,7 @@ public ModificationApplicationContext getNetworkModificationApplicationContext(U rootNetworkUuid).orElseThrow(() -> new StudyException(NOT_FOUND, ROOT_NETWORK_NOT_FOUND)); String variantId = rootNetworkNodeInfoEntity.getVariantId(); UUID reportUuid = rootNetworkNodeInfoEntity.getModificationReports().get(nodeUuid); - return new ModificationApplicationContext(networkUuid, variantId, reportUuid, nodeUuid, rootNetworkNodeInfoEntity.getRootNetwork().getApplicabilityTag()); + return new ModificationApplicationContext(networkUuid, variantId, reportUuid, nodeUuid, rootNetworkNodeInfoEntity.getRootNetwork().getTag()); } private List getReportUuids(RootNetworkNodeInfo rootNetworkNodeInfo) { diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java index 045916e74..df020d3b0 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java @@ -394,6 +394,12 @@ public List getStudyRootNetwork(StudyEntity study) { return study.getRootNetworks(); } + public List getStudyRootNetworkTags(UUID studyUuid) { + return rootNetworkRepository.findAllByStudyId(studyUuid).stream() + .map(RootNetworkEntity::getTag) + .toList(); + } + public List getStudyRootNetworkIds(UUID studyUuid) { return rootNetworkRepository.findAllByStudyId(studyUuid).stream() .map(RootNetworkEntity::getId) diff --git a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java index 03dc64771..0d94a827d 100644 --- a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java @@ -240,6 +240,21 @@ void testDeleteRootNetworkTags() { verifyNoMoreInteractions(restTemplate); } + @Test + void testDuplicateModificationsGroupAssociatesTheRootNetworkTags() { + UUID sourceGroupUuid = UUID.randomUUID(); + UUID groupUuid = UUID.randomUUID(); + UUID nodeUuid = UUID.randomUUID(); + UUID studyUuid = UUID.randomUUID(); + String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/groups/" + sourceGroupUuid + "/duplicate" + + "?groupUuid=" + groupUuid + "&nodeContainerUuid=" + nodeUuid + "&studyRootContainerUuid=" + studyUuid + + "&rootNetworkTags=PH1&rootNetworkTags=PH2"; + + networkModificationService.duplicateModificationsGroup(sourceGroupUuid, groupUuid, nodeUuid, studyUuid, List.of("PH1", "PH2"), "userId"); + + verify(restTemplate).exchange(eq(expectedUrl), eq(HttpMethod.POST), org.mockito.ArgumentMatchers.>any(), eq(Void.class)); + } + @Test void testAssertReferencedModificationsAreWritable() { UUID groupUuid = UUID.randomUUID(); From cadab4abd32fa5b8e039c0703ee13d073f5d02de Mon Sep 17 00:00:00 2001 From: Florent MILLOT <75525996+flomillot@users.noreply.github.com> Date: Sat, 10 Oct 2026 17:40:39 +0200 Subject: [PATCH 2/6] Fix the mono root network context tag test Signed-off-by: Florent MILLOT <75525996+flomillot@users.noreply.github.com> --- .../server/rootnetworks/RootNetworkApplicabilityTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java index 34f5ffc44..811f2a6b8 100644 --- a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java +++ b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java @@ -214,7 +214,7 @@ void testApplicationContextCarriesRootNetworkTag() { } @Test - void testMonoRootStudyCarriesNoRootNetworkTag() { + void testMonoRootStudyBuildCarriesNoRootNetworkTag() { StudyEntity studyEntity = TestUtils.createDummyStudy(NETWORK_UUID, CASE_UUID, CASE_NAME, CASE_FORMAT, REPORT_UUID); studyEntity.setMonoRoot(true); studyRepository.save(studyEntity); @@ -228,7 +228,9 @@ void testMonoRootStudyCarriesNoRootNetworkTag() { ArgumentCaptor buildInfosCaptor = ArgumentCaptor.captor(); verify(networkModificationService).buildNode(any(UUID.class), any(UUID.class), buildInfosCaptor.capture(), isNull()); assertNull(buildInfosCaptor.getValue().getRootNetworkTag()); - assertNull(rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), firstNode.getId(), NETWORK_UUID).rootNetworkTag()); + // whereas the modifications written are associated with the real tag, for the study to turn multi root network later + assertEquals(rootNetworkEntity.getTag(), + rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), firstNode.getId(), NETWORK_UUID).rootNetworkTag()); } @Test From 4bf34443349edcfcc2c432e223e670ab6ef286fb Mon Sep 17 00:00:00 2001 From: Florent MILLOT <75525996+flomillot@users.noreply.github.com> Date: Tue, 13 Oct 2026 20:28:56 +0200 Subject: [PATCH 3/6] Refuse root network tags the shared modifications the user cannot write on miss Signed-off-by: Florent MILLOT <75525996+flomillot@users.noreply.github.com> --- .../server/controller/StudyController.java | 11 +++--- .../dto/SharedModificationsWriteAccess.java | 18 ++++++++++ .../service/NetworkModificationService.java | 23 ++++++++---- .../study/server/service/StudyService.java | 31 +++++++++------- .../RootNetworkApplicabilityTest.java | 35 ++++++++++--------- .../NetworkModificationServiceTest.java | 35 +++++++++++++------ .../server/studycontroller/StudyTestBase.java | 1 + .../study/server/utils/TestUtils.java | 5 +++ .../server/utils/wiremock/WireMockStubs.java | 7 ++++ 9 files changed, 115 insertions(+), 51 deletions(-) create mode 100644 src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index c22a7b131..f424c0ade 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -949,11 +949,12 @@ public ResponseEntity> getAvailableSvgComponentLibraries() { return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(libraries); } - @GetMapping(value = "/studies/{studyUuid}/network-modifications/references/exists") - @Operation(summary = "Whether the study contains a shared modification, including nested in its composites") - @ApiResponse(responseCode = "200", description = "true if at least one shared modification is found") - public ResponseEntity hasSharedModifications(@PathVariable("studyUuid") UUID studyUuid) { - return ResponseEntity.ok().body(studyService.hasSharedModifications(studyUuid)); + @GetMapping(value = "/studies/{studyUuid}/network-modifications/references/write-access") + @Operation(summary = "Whether the study contains shared modifications, including nested in its composites, and, if so, whether the user can write on all of them") + @ApiResponse(responseCode = "200", description = "The write access on the shared modifications was returned") + public ResponseEntity getSharedModificationsWriteAccess(@PathVariable("studyUuid") UUID studyUuid, + @RequestHeader(HEADER_USER_ID) String userId) { + return ResponseEntity.ok().body(studyService.getSharedModificationsWriteAccess(studyUuid, userId)); } @GetMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network-modifications", produces = MediaType.TEXT_PLAIN_VALUE) diff --git a/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java b/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java new file mode 100644 index 000000000..d57a90cbd --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.study.server.dto; + +/** + * Whether a user can write on the shared modifications of a study. + * + * @author Florent MILLOT + */ +public enum SharedModificationsWriteAccess { + NO_SHARED_MODIFICATION, + ALL_WRITABLE, + SOME_NOT_WRITABLE +} diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index f55ad82e3..52f205bb8 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -14,6 +14,7 @@ import org.gridsuite.study.server.dto.BuildInfos; import org.gridsuite.study.server.dto.ModificationReference; import org.gridsuite.study.server.dto.NodeReceiver; +import org.gridsuite.study.server.dto.SharedModificationsWriteAccess; import org.gridsuite.study.server.dto.modification.*; import org.gridsuite.study.server.dto.workflow.AbstractWorkflowInfos; import org.springframework.beans.factory.annotation.Autowired; @@ -405,7 +406,7 @@ public void updateRootNetworkApplicability(List modificationsUuids, String /** * Renames a root network tag in the applicabilities held by the modifications of the given groups. */ - public void renameRootNetworkTag(List groupUuids, String oldTag, String newTag) { + public void renameRootNetworkTag(List groupUuids, String oldTag, String newTag, String userId) { Objects.requireNonNull(oldTag); Objects.requireNonNull(newTag); if (CollectionUtils.isEmpty(groupUuids)) { @@ -421,6 +422,7 @@ public void renameRootNetworkTag(List groupUuids, String oldTag, String ne HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); + headers.set(HEADER_USER_ID, userId); restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(headers), Void.class); } @@ -743,16 +745,25 @@ public boolean hasModificationReferences(List containerUuids) { return Boolean.TRUE.equals(restTemplate.getForObject(getNetworkModificationServerURI(false) + path, Boolean.class)); } + public SharedModificationsWriteAccess getReferencedModificationsWriteAccess(List containerUuids, String userId) { + String path = UriComponentsBuilder.fromPath(CONTAINERS + DELIMITER + "references/write-access") + .queryParam(UUIDS, containerUuids) + .build().toUriString(); + return restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.GET, + userIdEntity(userId), SharedModificationsWriteAccess.class).getBody(); + } + /** - * Asserts that the user may write on every shared modification the given containers point to, directly or through - * other shared modifications. Throws when they cannot. + * Asserts that the shared modifications the user cannot write on, among the ones the given containers point to, are + * all associated with the given root network tags. Throws a forbidden error when they are not. */ - public void assertReferencedModificationsAreWritable(List containerUuids, String userId) { - if (containerUuids.isEmpty()) { + public void assertRootNetworkTagsAllowed(List containerUuids, List rootNetworkTags, String userId) { + if (rootNetworkTags.isEmpty() || containerUuids.isEmpty()) { return; } - String path = UriComponentsBuilder.fromPath(CONTAINERS + DELIMITER + "references/authorized") + String path = UriComponentsBuilder.fromPath(CONTAINERS + DELIMITER + "root-network-tags/authorized") .queryParam(UUIDS, containerUuids) + .queryParam("tags", rootNetworkTags) .build().toUriString(); restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.GET, userIdEntity(userId), Void.class); diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index 1a651c2c3..66be7f35e 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -337,6 +337,9 @@ public void deleteRootNetworks(UUID studyUuid, List rootNetworksUuids, Str @Transactional public RootNetworkRequestInfos createRootNetworkRequest(UUID studyUuid, RootNetworkInfos rootNetworkInfos, String userId) { rootNetworkService.assertCanCreateRootNetwork(studyUuid, rootNetworkInfos.getName(), rootNetworkInfos.getTag()); + if (rootNetworkInfos.getTag() != null) { + assertCanAddRootNetworkTag(studyUuid, rootNetworkInfos.getTag(), userId); + } StudyEntity studyEntity = getStudy(studyUuid); rootNetworkInfos.setId(UUID.randomUUID()); @@ -393,33 +396,35 @@ private void invalidatePreviousRootNetworkNodeTree(StudyEntity studyEntity) { invalidateNodeTree(studyEntity.getId(), rootNodeUuid, studyEntity.getFirstRootNetwork().getId()); } - private void updateRootNetworkBasicInfos(UUID studyUuid, RootNetworkInfos rootNetworkInfos, boolean updateCase) { + private void updateRootNetworkBasicInfos(UUID studyUuid, RootNetworkInfos rootNetworkInfos, boolean updateCase, String userId) { String previousTag = rootNetworkService.getRootNetworkTag(rootNetworkInfos.getId()); rootNetworkService.updateRootNetwork(rootNetworkInfos, updateCase); // the entity says what the tag really became, unlike the DTO String newTag = rootNetworkService.getRootNetworkTag(rootNetworkInfos.getId()); - renameRootNetworkTagInApplicabilities(studyUuid, previousTag, newTag); + renameRootNetworkTagInApplicabilities(studyUuid, previousTag, newTag, userId); postRootNetworkUpdate(studyUuid, rootNetworkInfos.getId(), updateCase); } - private void renameRootNetworkTagInApplicabilities(UUID studyUuid, String previousTag, String newTag) { + private void renameRootNetworkTagInApplicabilities(UUID studyUuid, String previousTag, String newTag, String userId) { if (previousTag == null || previousTag.equals(newTag)) { return; } - networkModificationService.renameRootNetworkTag(getStudyModificationGroupUuids(studyUuid), previousTag, newTag); + networkModificationService.renameRootNetworkTag(getStudyModificationGroupUuids(studyUuid), previousTag, newTag, userId); } /** - * Renaming a tag rewrites the applicabilities the shared modifications of the study contain for every study - * referencing them: only a user allowed to write on all of them may do it. + * A root network tag of a study must be associated with all its shared modifications: the ones the user cannot + * write on, which they cannot associate with a new tag, must already be. */ - private void assertCanRenameRootNetworkTag(UUID studyUuid, String userId) { - networkModificationService.assertReferencedModificationsAreWritable(getStudyModificationGroupUuids(studyUuid), userId); + private void assertCanAddRootNetworkTag(UUID studyUuid, String newTag, String userId) { + networkModificationService.assertRootNetworkTagsAllowed(getStudyModificationGroupUuids(studyUuid), List.of(newTag), userId); } - public boolean hasSharedModifications(UUID studyUuid) { + public SharedModificationsWriteAccess getSharedModificationsWriteAccess(UUID studyUuid, String userId) { List groupUuids = getStudyModificationGroupUuids(studyUuid); - return !groupUuids.isEmpty() && networkModificationService.hasModificationReferences(groupUuids); + return groupUuids.isEmpty() + ? SharedModificationsWriteAccess.NO_SHARED_MODIFICATION + : networkModificationService.getReferencedModificationsWriteAccess(groupUuids, userId); } private List getStudyModificationGroupUuids(UUID studyUuid) { @@ -433,7 +438,7 @@ public void updateRootNetworkRequest(UUID studyUuid, RootNetworkInfos rootNetwor rootNetworkService.assertCanModifyRootNetwork(studyUuid, rootNetworkInfos.getId(), rootNetworkInfos.getName(), rootNetworkInfos.getTag()); String newTag = rootNetworkInfos.getTag(); if (newTag != null && !newTag.equals(rootNetworkService.getRootNetworkTag(rootNetworkInfos.getId()))) { - assertCanRenameRootNetworkTag(studyUuid, userId); + assertCanAddRootNetworkTag(studyUuid, newTag, userId); } StudyEntity studyEntity = getStudy(studyUuid); @@ -441,7 +446,7 @@ public void updateRootNetworkRequest(UUID studyUuid, RootNetworkInfos rootNetwor RootNetworkRequestEntity requestEntity = rootNetworkService.insertModificationRequest(studyEntity.getId(), rootNetworkInfos, userId); updateRootNetworkCaseInfos(studyEntity.getId(), rootNetworkInfos, userId, requestEntity); } else { - updateRootNetworkBasicInfos(studyEntity.getId(), rootNetworkInfos, false); + updateRootNetworkBasicInfos(studyEntity.getId(), rootNetworkInfos, false, userId); } notificationService.emitElementUpdated(studyUuid, userId); } @@ -460,7 +465,7 @@ private void updateRootNetworkCaseInfos(UUID studyUuid, RootNetworkInfos rootNet @Transactional public void modifyRootNetwork(UUID studyUuid, RootNetworkInfos rootNetworkInfos, String userId) { invalidateStudyRootNetwork(studyUuid, rootNetworkInfos.getId(), userId, true); - updateRootNetworkBasicInfos(studyUuid, rootNetworkInfos, true); + updateRootNetworkBasicInfos(studyUuid, rootNetworkInfos, true, userId); } private void postRootNetworkUpdate(UUID studyUuid, UUID rootNetworkUuid, boolean updateCase) { diff --git a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java index 811f2a6b8..8d6663bab 100644 --- a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java +++ b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java @@ -39,6 +39,7 @@ import java.util.*; +import static org.gridsuite.study.server.StudyConstants.HEADER_USER_ID; import static org.gridsuite.study.server.utils.TestUtils.createModificationNodeInfo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -275,20 +276,20 @@ void testRenamingARootNetworkTagCarriesTheApplicabilitiesAlong() throws Exceptio updateRootNetwork(studyEntity.getId(), rootNetworkUuid, ROOT_NETWORK_TAG_2); ArgumentCaptor> groupUuidsCaptor = ArgumentCaptor.captor(); - verify(networkModificationService, times(1)).renameRootNetworkTag(groupUuidsCaptor.capture(), eq(ROOT_NETWORK_TAG_1), eq(ROOT_NETWORK_TAG_2)); + verify(networkModificationService, times(1)).renameRootNetworkTag(groupUuidsCaptor.capture(), eq(ROOT_NETWORK_TAG_1), eq(ROOT_NETWORK_TAG_2), eq(USER_ID)); assertEquals(Set.of(firstNode.getModificationGroupUuid(), secondNode.getModificationGroupUuid()), Set.copyOf(groupUuidsCaptor.getValue())); // an update carrying no tag at all leaves it as it was, so it is not a rename updateRootNetwork(studyEntity.getId(), rootNetworkUuid, null); - verify(networkModificationService, times(1)).renameRootNetworkTag(any(), any(), any()); + verify(networkModificationService, times(1)).renameRootNetworkTag(any(), any(), any(), any()); // and neither is an update carrying the tag the root network already has updateRootNetwork(studyEntity.getId(), rootNetworkUuid, ROOT_NETWORK_TAG_2); - verify(networkModificationService, times(1)).renameRootNetworkTag(any(), any(), any()); + verify(networkModificationService, times(1)).renameRootNetworkTag(any(), any(), any(), any()); } @Test - void testRenamingARootNetworkTagNeedsWritePermissionOnTheSharedModifications() throws Exception { + void testRenamingARootNetworkTagNeedsTheSharedModificationsTheUserCannotWriteOnToBeAssociatedWithIt() throws Exception { StudyEntity studyEntity = TestUtils.createDummyStudy(NETWORK_UUID, CASE_UUID, CASE_NAME, CASE_FORMAT, REPORT_UUID); studyRepository.save(studyEntity); UUID rootNetworkUuid = studyService.getExistingBasicRootNetworkInfos(studyEntity.getId()).getFirst().rootNetworkUuid(); @@ -296,9 +297,9 @@ void testRenamingARootNetworkTagNeedsWritePermissionOnTheSharedModifications() t NodeEntity rootNode = networkModificationTreeService.createRoot(studyEntity); NetworkModificationNode firstNode = networkModificationTreeService.createNode(studyEntity, rootNode.getIdNode(), createModificationNodeInfo(NODE_1_NAME), InsertMode.AFTER, null); - // the study points to a shared modification the user is not allowed to write on + // the study points to a shared modification the user is not allowed to write on, and not associated with the new tag doThrow(HttpClientErrorException.create(HttpStatus.FORBIDDEN, "Forbidden", null, null, null)) - .when(networkModificationService).assertReferencedModificationsAreWritable(List.of(firstNode.getModificationGroupUuid()), USER_ID); + .when(networkModificationService).assertRootNetworkTagsAllowed(List.of(firstNode.getModificationGroupUuid()), List.of(ROOT_NETWORK_TAG_2), USER_ID); UUID studyUuid = studyEntity.getId(); RootNetworkInfos renamingTagInfos = RootNetworkInfos.builder().id(rootNetworkUuid).tag(ROOT_NETWORK_TAG_2).build(); @@ -306,33 +307,35 @@ void testRenamingARootNetworkTagNeedsWritePermissionOnTheSharedModifications() t // neither the tag nor the applicabilities are touched assertEquals(ROOT_NETWORK_TAG_1, rootNetworkService.getRootNetworkTag(rootNetworkUuid)); - verify(networkModificationService, never()).renameRootNetworkTag(any(), any(), any()); + verify(networkModificationService, never()).renameRootNetworkTag(any(), any(), any(), any()); // an update keeping the tag is no rename, so it needs no permission updateRootNetwork(studyUuid, rootNetworkUuid, ROOT_NETWORK_TAG_1); - verify(networkModificationService, times(1)).assertReferencedModificationsAreWritable(any(), any()); + verify(networkModificationService, times(1)).assertRootNetworkTagsAllowed(any(), any(), any()); } @Test - void testHasSharedModifications() throws Exception { + void testGetSharedModificationsWriteAccess() throws Exception { StudyEntity studyEntity = TestUtils.createDummyStudy(NETWORK_UUID, CASE_UUID, CASE_NAME, CASE_FORMAT, REPORT_UUID); studyRepository.save(studyEntity); UUID studyUuid = studyEntity.getId(); // a study with no modification node contains no shared modification, and the server is not even asked - assertFalse(hasSharedModifications(studyUuid)); - verify(networkModificationService, never()).hasModificationReferences(any()); + assertEquals(SharedModificationsWriteAccess.NO_SHARED_MODIFICATION, getSharedModificationsWriteAccess(studyUuid)); + verify(networkModificationService, never()).getReferencedModificationsWriteAccess(any(), any()); NodeEntity rootNode = networkModificationTreeService.createRoot(studyEntity); NetworkModificationNode firstNode = networkModificationTreeService.createNode(studyEntity, rootNode.getIdNode(), createModificationNodeInfo(NODE_1_NAME), InsertMode.AFTER, null); - doReturn(true).when(networkModificationService).hasModificationReferences(List.of(firstNode.getModificationGroupUuid())); + doReturn(SharedModificationsWriteAccess.SOME_NOT_WRITABLE).when(networkModificationService) + .getReferencedModificationsWriteAccess(List.of(firstNode.getModificationGroupUuid()), USER_ID); - assertTrue(hasSharedModifications(studyUuid)); + assertEquals(SharedModificationsWriteAccess.SOME_NOT_WRITABLE, getSharedModificationsWriteAccess(studyUuid)); } - private boolean hasSharedModifications(UUID studyUuid) throws Exception { - return Boolean.parseBoolean(mockMvc.perform(get("/v1/studies/{studyUuid}/network-modifications/references/exists", studyUuid)) - .andExpect(status().isOk()).andReturn().getResponse().getContentAsString()); + private SharedModificationsWriteAccess getSharedModificationsWriteAccess(UUID studyUuid) throws Exception { + return objectMapper.readValue(mockMvc.perform(get("/v1/studies/{studyUuid}/network-modifications/references/write-access", studyUuid) + .header(HEADER_USER_ID, USER_ID)) + .andExpect(status().isOk()).andReturn().getResponse().getContentAsString(), SharedModificationsWriteAccess.class); } @Test diff --git a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java index 0d94a827d..1b05e3bbd 100644 --- a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.gridsuite.study.server.RemoteServicesProperties; import org.gridsuite.study.server.dto.ModificationReference; +import org.gridsuite.study.server.dto.SharedModificationsWriteAccess; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -213,12 +214,12 @@ void testRenameRootNetworkTag() { String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/network-modifications/root-network-tag" + "?groupUuids=" + firstGroupUuid + "&groupUuids=" + secondGroupUuid + "&oldTag=PH1&newTag=PH2"; - networkModificationService.renameRootNetworkTag(List.of(firstGroupUuid, secondGroupUuid), "PH1", "PH2"); + networkModificationService.renameRootNetworkTag(List.of(firstGroupUuid, secondGroupUuid), "PH1", "PH2", USER_ID); verify(restTemplate).exchange(eq(expectedUrl), eq(HttpMethod.PUT), org.mockito.ArgumentMatchers.>any(), eq(Void.class)); // there is nothing to rename without a group - networkModificationService.renameRootNetworkTag(List.of(), "PH1", "PH2"); + networkModificationService.renameRootNetworkTag(List.of(), "PH1", "PH2", USER_ID); verifyNoMoreInteractions(restTemplate); } @@ -256,19 +257,18 @@ void testDuplicateModificationsGroupAssociatesTheRootNetworkTags() { } @Test - void testAssertReferencedModificationsAreWritable() { + void testAssertRootNetworkTagsAllowed() { UUID groupUuid = UUID.randomUUID(); - String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/containers/references/authorized?uuids=" + groupUuid; - - networkModificationService.assertReferencedModificationsAreWritable(List.of(groupUuid), USER_ID); - - // the server needs the user to tell whether the shared modifications are writable HttpHeaders headers = new HttpHeaders(); headers.set(HEADER_USER_ID, USER_ID); - verify(restTemplate).exchange(expectedUrl, HttpMethod.GET, new HttpEntity<>(headers), Void.class); - // there is nothing to check without a container - networkModificationService.assertReferencedModificationsAreWritable(List.of(), USER_ID); + networkModificationService.assertRootNetworkTagsAllowed(List.of(groupUuid), List.of("PH1", "PH2"), USER_ID); + verify(restTemplate).exchange(NETWORK_MODIFICATION_SERVER_URI + "/v1/containers/root-network-tags/authorized?uuids=" + groupUuid + + "&tags=PH1&tags=PH2", HttpMethod.GET, new HttpEntity<>(headers), Void.class); + + // there is nothing to check without a tag, or without a container to check it on + networkModificationService.assertRootNetworkTagsAllowed(List.of(groupUuid), List.of(), USER_ID); + networkModificationService.assertRootNetworkTagsAllowed(List.of(), List.of("PH1"), USER_ID); verifyNoMoreInteractions(restTemplate); } @@ -282,6 +282,19 @@ void testHasModificationReferences() { verify(restTemplate).getForObject(eq(expectedUrl), eq(Boolean.class)); } + @Test + void testGetReferencedModificationsWriteAccess() { + UUID groupUuid = UUID.randomUUID(); + String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/containers/references/write-access?uuids=" + groupUuid; + HttpHeaders headers = new HttpHeaders(); + headers.set(HEADER_USER_ID, USER_ID); + when(restTemplate.exchange(expectedUrl, HttpMethod.GET, new HttpEntity<>(headers), SharedModificationsWriteAccess.class)) + .thenReturn(ResponseEntity.ok(SharedModificationsWriteAccess.SOME_NOT_WRITABLE)); + + assertThat(networkModificationService.getReferencedModificationsWriteAccess(List.of(groupUuid), USER_ID)) + .isEqualTo(SharedModificationsWriteAccess.SOME_NOT_WRITABLE); + } + private void expectUserIdIsForwarded(String expectedUrl) { HttpHeaders headers = new HttpHeaders(); headers.set(HEADER_USER_ID, USER_ID); diff --git a/src/test/java/org/gridsuite/study/server/studycontroller/StudyTestBase.java b/src/test/java/org/gridsuite/study/server/studycontroller/StudyTestBase.java index ee089e5d6..55672f8ba 100644 --- a/src/test/java/org/gridsuite/study/server/studycontroller/StudyTestBase.java +++ b/src/test/java/org/gridsuite/study/server/studycontroller/StudyTestBase.java @@ -395,6 +395,7 @@ void setup() { singleLineDiagramService.setSingleLineDiagramServerBaseUri(baseUrl); directoryService.setDirectoryServerServerBaseUri(baseUrl); networkModificationService.setNetworkModificationServerBaseUri(baseUrl); + wireMockStubs.stubRootNetworkTagsAllowed(); } protected UUID getRootNodeUuid(UUID studyUuid) { diff --git a/src/test/java/org/gridsuite/study/server/utils/TestUtils.java b/src/test/java/org/gridsuite/study/server/utils/TestUtils.java index 6e55e267e..83ff20e29 100644 --- a/src/test/java/org/gridsuite/study/server/utils/TestUtils.java +++ b/src/test/java/org/gridsuite/study/server/utils/TestUtils.java @@ -28,6 +28,7 @@ import org.gridsuite.study.server.service.StudyServerExecutionService; import org.gridsuite.study.server.utils.assertions.Assertions; import org.gridsuite.study.server.utils.wiremock.UserAdminServerStubs; +import org.gridsuite.study.server.utils.wiremock.WireMockStubs; import org.junit.platform.commons.util.StringUtils; import org.mockito.stubbing.Answer; import org.springframework.cloud.stream.binder.test.OutputDestination; @@ -384,6 +385,8 @@ public static void assertWiremockServerRequestsEmptyThenShutdown(WireMockServer // Remove quota operation consume/release requests that are auto-stubbed and do not need explicit verification wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_CONSUME_URL_PATTERN)).build()); wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_RELEASE_URL_PATTERN)).build()); + // Remove the root network tags checks on the shared modifications, auto-stubbed as well + wireMockServer.removeServeEventsMatching(WireMock.getRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); var requests = wireMockServer.findAll(WireMock.anyRequestedFor(WireMock.anyUrl())); assertEquals(0, requests.size(), "Unverified WireMock requests found:\n" + requests.stream() .map(r -> "URL: " + r.getUrl() + ", Method: " + r.getMethod() + ", Body: " + r.getBodyAsString() + ", Params: " + r.getQueryParams()) @@ -399,6 +402,8 @@ public static void assertWiremockServerRequestsEmptyThenClear(WireMockServer wir // Remove quota operation consume/release requests that are auto-stubbed and do not need explicit verification wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_CONSUME_URL_PATTERN)).build()); wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_RELEASE_URL_PATTERN)).build()); + // Remove the root network tags checks on the shared modifications, auto-stubbed as well + wireMockServer.removeServeEventsMatching(WireMock.getRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); assertEquals(0, wireMockServer.findAll(WireMock.anyRequestedFor(WireMock.anyUrl())).size()); } finally { wireMockServer.resetAll(); diff --git a/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java b/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java index f878c5f8d..9e2d71e58 100644 --- a/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java +++ b/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java @@ -45,6 +45,7 @@ public class WireMockStubs { private static final String URI_NETWORK_MODIFICATION_GROUPS = "/v1/groups"; private static final String URI_NETWORK_MODIFICATION_CONTAINERS = "/v1/containers"; + public static final String ROOT_NETWORK_TAGS_AUTHORIZED_URL = URI_NETWORK_MODIFICATION_CONTAINERS + "/root-network-tags/authorized"; public static final String FIRST_VARIANT_ID = "first_variant_id"; @@ -171,6 +172,12 @@ public void verifyNetworkElementsIdsPost(UUID stubUuid, String networkUuid, Stri requestBody); } + public UUID stubRootNetworkTagsAllowed() { + return wireMock.stubFor(WireMock.get(WireMock.urlPathEqualTo(ROOT_NETWORK_TAGS_AUTHORIZED_URL)) + .willReturn(WireMock.ok()) + ).getId(); + } + public UUID stubNetworkModificationCountGet(String groupUuid, Integer expectedCount) { return wireMock.stubFor(WireMock.get(WireMock.urlPathMatching(URI_NETWORK_MODIFICATION_CONTAINERS + DELIMITER + groupUuid + "/network-modifications-count")) .withQueryParam(QUERY_PARAM_STASHED, WireMock.equalTo("false")) From 32143dddd67f73b249b0985fb1edd7534a977ae0 Mon Sep 17 00:00:00 2001 From: Florent MILLOT <75525996+flomillot@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:47:05 +0200 Subject: [PATCH 4/6] Tell whether the user can write on all, some or none of the shared modifications Signed-off-by: Florent MILLOT <75525996+flomillot@users.noreply.github.com> --- .../gridsuite/study/server/controller/StudyController.java | 2 +- .../study/server/dto/SharedModificationsWriteAccess.java | 3 ++- .../server/rootnetworks/RootNetworkApplicabilityTest.java | 4 ++-- .../study/server/service/NetworkModificationServiceTest.java | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index f424c0ade..ebefb5c88 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -950,7 +950,7 @@ public ResponseEntity> getAvailableSvgComponentLibraries() { } @GetMapping(value = "/studies/{studyUuid}/network-modifications/references/write-access") - @Operation(summary = "Whether the study contains shared modifications, including nested in its composites, and, if so, whether the user can write on all of them") + @Operation(summary = "Whether the study contains shared modifications, including nested in its composites, and, if so, whether the user can write on all, some or none of them") @ApiResponse(responseCode = "200", description = "The write access on the shared modifications was returned") public ResponseEntity getSharedModificationsWriteAccess(@PathVariable("studyUuid") UUID studyUuid, @RequestHeader(HEADER_USER_ID) String userId) { diff --git a/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java b/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java index d57a90cbd..2887b1e97 100644 --- a/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java +++ b/src/main/java/org/gridsuite/study/server/dto/SharedModificationsWriteAccess.java @@ -14,5 +14,6 @@ public enum SharedModificationsWriteAccess { NO_SHARED_MODIFICATION, ALL_WRITABLE, - SOME_NOT_WRITABLE + SOME_WRITABLE, + NONE_WRITABLE } diff --git a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java index 8d6663bab..0367d4d12 100644 --- a/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java +++ b/src/test/java/org/gridsuite/study/server/rootnetworks/RootNetworkApplicabilityTest.java @@ -326,10 +326,10 @@ void testGetSharedModificationsWriteAccess() throws Exception { NodeEntity rootNode = networkModificationTreeService.createRoot(studyEntity); NetworkModificationNode firstNode = networkModificationTreeService.createNode(studyEntity, rootNode.getIdNode(), createModificationNodeInfo(NODE_1_NAME), InsertMode.AFTER, null); - doReturn(SharedModificationsWriteAccess.SOME_NOT_WRITABLE).when(networkModificationService) + doReturn(SharedModificationsWriteAccess.NONE_WRITABLE).when(networkModificationService) .getReferencedModificationsWriteAccess(List.of(firstNode.getModificationGroupUuid()), USER_ID); - assertEquals(SharedModificationsWriteAccess.SOME_NOT_WRITABLE, getSharedModificationsWriteAccess(studyUuid)); + assertEquals(SharedModificationsWriteAccess.NONE_WRITABLE, getSharedModificationsWriteAccess(studyUuid)); } private SharedModificationsWriteAccess getSharedModificationsWriteAccess(UUID studyUuid) throws Exception { diff --git a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java index 1b05e3bbd..52c6070a3 100644 --- a/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/NetworkModificationServiceTest.java @@ -289,10 +289,10 @@ void testGetReferencedModificationsWriteAccess() { HttpHeaders headers = new HttpHeaders(); headers.set(HEADER_USER_ID, USER_ID); when(restTemplate.exchange(expectedUrl, HttpMethod.GET, new HttpEntity<>(headers), SharedModificationsWriteAccess.class)) - .thenReturn(ResponseEntity.ok(SharedModificationsWriteAccess.SOME_NOT_WRITABLE)); + .thenReturn(ResponseEntity.ok(SharedModificationsWriteAccess.NONE_WRITABLE)); assertThat(networkModificationService.getReferencedModificationsWriteAccess(List.of(groupUuid), USER_ID)) - .isEqualTo(SharedModificationsWriteAccess.SOME_NOT_WRITABLE); + .isEqualTo(SharedModificationsWriteAccess.NONE_WRITABLE); } private void expectUserIdIsForwarded(String expectedUrl) { From 507dbbbd5351c586a874ba83feb615a0f64818f1 Mon Sep 17 00:00:00 2001 From: Florent MILLOT Date: Thu, 22 Oct 2026 12:13:53 +0200 Subject: [PATCH 5/6] Send the root network tags check in the request body Signed-off-by: Florent MILLOT --- .../server/dto/RootNetworkTagsCheckInfos.java | 16 ++++++++++++++++ .../NetworkModificationRestService.java | 9 +++------ .../NetworkModificationServiceTest.java | 6 ++++-- .../gridsuite/study/server/utils/TestUtils.java | 4 ++-- .../server/utils/wiremock/WireMockStubs.java | 2 +- 5 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/gridsuite/study/server/dto/RootNetworkTagsCheckInfos.java diff --git a/src/main/java/org/gridsuite/study/server/dto/RootNetworkTagsCheckInfos.java b/src/main/java/org/gridsuite/study/server/dto/RootNetworkTagsCheckInfos.java new file mode 100644 index 000000000..3256a94d1 --- /dev/null +++ b/src/main/java/org/gridsuite/study/server/dto/RootNetworkTagsCheckInfos.java @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.study.server.dto; + +import java.util.List; +import java.util.UUID; + +/** + * Modifications to check against root network tags. + */ +public record RootNetworkTagsCheckInfos(List containerUuids, List tags) { +} diff --git a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java index be15c7ac4..cf3a1c799 100644 --- a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java +++ b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java @@ -14,6 +14,7 @@ import org.gridsuite.study.server.dto.BuildInfos; import org.gridsuite.study.server.dto.ModificationReference; import org.gridsuite.study.server.dto.NodeReceiver; +import org.gridsuite.study.server.dto.RootNetworkTagsCheckInfos; import org.gridsuite.study.server.dto.SharedModificationsWriteAccess; import org.gridsuite.study.server.dto.modification.*; import org.gridsuite.study.server.dto.workflow.AbstractWorkflowInfos; @@ -762,12 +763,8 @@ public void assertRootNetworkTagsAllowed(List containerUuids, List if (rootNetworkTags.isEmpty() || containerUuids.isEmpty()) { return; } - String path = UriComponentsBuilder.fromPath(CONTAINERS + DELIMITER + "root-network-tags/authorized") - .queryParam(UUIDS, containerUuids) - .queryParam("tags", rootNetworkTags) - .build().toUriString(); - - restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.GET, userIdEntity(userId), Void.class); + restTemplate.exchange(getNetworkModificationServerURI(false) + CONTAINERS + DELIMITER + "root-network-tags/authorized", + HttpMethod.POST, userIdEntity(userId, new RootNetworkTagsCheckInfos(containerUuids, rootNetworkTags)), Void.class); } /** diff --git a/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java index 785c7ab68..de2ab2e93 100644 --- a/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.gridsuite.study.server.RemoteServicesProperties; import org.gridsuite.study.server.dto.ModificationReference; +import org.gridsuite.study.server.dto.RootNetworkTagsCheckInfos; import org.gridsuite.study.server.dto.SharedModificationsWriteAccess; import org.gridsuite.study.server.service.RootNetworkService; import org.junit.jupiter.api.BeforeEach; @@ -265,10 +266,11 @@ void testAssertRootNetworkTagsAllowed() { UUID groupUuid = UUID.randomUUID(); HttpHeaders headers = new HttpHeaders(); headers.set(HEADER_USER_ID, USER_ID); + headers.setContentType(MediaType.APPLICATION_JSON); networkModificationService.assertRootNetworkTagsAllowed(List.of(groupUuid), List.of("PH1", "PH2"), USER_ID); - verify(restTemplate).exchange(NETWORK_MODIFICATION_SERVER_URI + "/v1/containers/root-network-tags/authorized?uuids=" + groupUuid - + "&tags=PH1&tags=PH2", HttpMethod.GET, new HttpEntity<>(headers), Void.class); + verify(restTemplate).exchange(NETWORK_MODIFICATION_SERVER_URI + "/v1/containers/root-network-tags/authorized", HttpMethod.POST, + new HttpEntity<>(new RootNetworkTagsCheckInfos(List.of(groupUuid), List.of("PH1", "PH2")), headers), Void.class); // there is nothing to check without a tag, or without a container to check it on networkModificationService.assertRootNetworkTagsAllowed(List.of(groupUuid), List.of(), USER_ID); diff --git a/src/test/java/org/gridsuite/study/server/utils/TestUtils.java b/src/test/java/org/gridsuite/study/server/utils/TestUtils.java index 83ff20e29..4b8be7e2d 100644 --- a/src/test/java/org/gridsuite/study/server/utils/TestUtils.java +++ b/src/test/java/org/gridsuite/study/server/utils/TestUtils.java @@ -386,7 +386,7 @@ public static void assertWiremockServerRequestsEmptyThenShutdown(WireMockServer wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_CONSUME_URL_PATTERN)).build()); wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_RELEASE_URL_PATTERN)).build()); // Remove the root network tags checks on the shared modifications, auto-stubbed as well - wireMockServer.removeServeEventsMatching(WireMock.getRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); + wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); var requests = wireMockServer.findAll(WireMock.anyRequestedFor(WireMock.anyUrl())); assertEquals(0, requests.size(), "Unverified WireMock requests found:\n" + requests.stream() .map(r -> "URL: " + r.getUrl() + ", Method: " + r.getMethod() + ", Body: " + r.getBodyAsString() + ", Params: " + r.getQueryParams()) @@ -403,7 +403,7 @@ public static void assertWiremockServerRequestsEmptyThenClear(WireMockServer wir wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_CONSUME_URL_PATTERN)).build()); wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathMatching(UserAdminServerStubs.QUOTA_RELEASE_URL_PATTERN)).build()); // Remove the root network tags checks on the shared modifications, auto-stubbed as well - wireMockServer.removeServeEventsMatching(WireMock.getRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); + wireMockServer.removeServeEventsMatching(WireMock.postRequestedFor(WireMock.urlPathEqualTo(WireMockStubs.ROOT_NETWORK_TAGS_AUTHORIZED_URL)).build()); assertEquals(0, wireMockServer.findAll(WireMock.anyRequestedFor(WireMock.anyUrl())).size()); } finally { wireMockServer.resetAll(); diff --git a/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java b/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java index 9e2d71e58..010c367af 100644 --- a/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java +++ b/src/test/java/org/gridsuite/study/server/utils/wiremock/WireMockStubs.java @@ -173,7 +173,7 @@ public void verifyNetworkElementsIdsPost(UUID stubUuid, String networkUuid, Stri } public UUID stubRootNetworkTagsAllowed() { - return wireMock.stubFor(WireMock.get(WireMock.urlPathEqualTo(ROOT_NETWORK_TAGS_AUTHORIZED_URL)) + return wireMock.stubFor(WireMock.post(WireMock.urlPathEqualTo(ROOT_NETWORK_TAGS_AUTHORIZED_URL)) .willReturn(WireMock.ok()) ).getId(); } From 1dcac44f430db79ae0dd5124c999b4f53996a6b4 Mon Sep 17 00:00:00 2001 From: Florent MILLOT Date: Thu, 22 Oct 2026 15:05:37 +0200 Subject: [PATCH 6/6] Shorten the root network tags check comment Signed-off-by: Florent MILLOT --- .../networkmodification/NetworkModificationRestService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java index cf3a1c799..0507250e7 100644 --- a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java +++ b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java @@ -756,8 +756,7 @@ public SharedModificationsWriteAccess getReferencedModificationsWriteAccess(List } /** - * Asserts that the shared modifications the user cannot write on, among the ones the given containers point to, are - * all associated with the given root network tags. Throws a forbidden error when they are not. + * Throws forbidden when the unwritable shared modifications involved miss some of the tags. */ public void assertRootNetworkTagsAllowed(List containerUuids, List rootNetworkTags, String userId) { if (rootNetworkTags.isEmpty() || containerUuids.isEmpty()) {