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 c6c2b59e6..e1fdaa6b4 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -1686,9 +1686,10 @@ public ResponseEntity buildNode(@Parameter(description = "Study uuid") @Pa @ApiResponse(responseCode = "403", description = "The study node is not a model node")}) public ResponseEntity unbuildNode(@Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid, @Parameter(description = "rootNetworkUuid") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid, - @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid) { + @Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid, + @RequestHeader(HEADER_USER_ID) String userId) { studyService.assertNoBlockedNodeInTree(nodeUuid, rootNetworkUuid); - studyService.unbuildStudyNode(studyUuid, nodeUuid, rootNetworkUuid); + studyService.unbuildStudyNode(studyUuid, nodeUuid, rootNetworkUuid, userId); return ResponseEntity.ok().build(); } @@ -1696,11 +1697,12 @@ public ResponseEntity unbuildNode(@Parameter(description = "Study uuid") @ @Operation(summary = "unbuild all study nodes in all root networks") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "All study nodes has been unbuilt in all root networks"), @ApiResponse(responseCode = "404", description = "The study or node doesn't exist")}) - public ResponseEntity unbuildAllNodes(@Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid) { + public ResponseEntity unbuildAllNodes(@Parameter(description = "Study uuid") @PathVariable("studyUuid") UUID studyUuid, + @RequestHeader(HEADER_USER_ID) String userId) { UUID rootNodeUuid = networkModificationTreeService.getStudyRootNodeUuid(studyUuid); try { studyService.assertNoBlockedNodeInStudy(studyUuid, rootNodeUuid); - studyService.unbuildNodeTree(studyUuid, rootNodeUuid, true); + studyService.unbuildNodeTree(studyUuid, rootNodeUuid, true, userId); } finally { studyService.unblockNodeTree(studyUuid, rootNodeUuid); } 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 d3ab24899..7f1002192 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -1830,6 +1830,7 @@ private void buildNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull networkModificationTreeService.updateNodeBuildStatus(nodeUuid, rootNetworkUuid, NodeBuildStatus.from(BuildStatus.NOT_BUILT)); throw e; } + notificationService.emitElementUpdated(studyUuid, userId); } @Transactional @@ -1879,7 +1880,7 @@ public void assertNoMaxBuilds(@NonNull UUID studyUuid, @NonNull UUID rootNetwork } @Transactional - public void unbuildStudyNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid) { + public void unbuildStudyNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid, @NonNull String userId) { if (networkModificationTreeService.getNodeBuildStatus(nodeUuid, rootNetworkUuid).isNotBuilt()) { return; } @@ -1892,16 +1893,18 @@ public void unbuildStudyNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @N } else { invalidateNode(studyUuid, nodeUuid, rootNetworkUuid); } + notificationService.emitElementUpdated(studyUuid, userId); } @Transactional - public void unbuildNodeTree(@NonNull UUID studyUuid, UUID rootNodeUuid, boolean withBlockNodes) { + public void unbuildNodeTree(@NonNull UUID studyUuid, UUID rootNodeUuid, boolean withBlockNodes, @NonNull String userId) { InvalidateNodeTreeParameters invalidateNodeTreeParameters = withBlockNodes ? InvalidateNodeTreeParameters.ALL_WITH_BLOCK_NODES : InvalidateNodeTreeParameters.ALL; List> futures = getStudy(studyUuid).getRootNetworks().stream().map(rn -> studyServerExecutionService.runAsync(() -> invalidateNodeTree(studyUuid, rootNodeUuid, rn.getId(), invalidateNodeTreeParameters)) ).toList(); CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join(); + notificationService.emitElementUpdated(studyUuid, userId); } public void stopBuild(@NonNull UUID nodeUuid, UUID rootNetworkUuid) { diff --git a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java index 512048ef7..a9bf239f9 100644 --- a/src/main/java/org/gridsuite/study/server/service/SupervisionService.java +++ b/src/main/java/org/gridsuite/study/server/service/SupervisionService.java @@ -84,6 +84,8 @@ public class SupervisionService { private final RootNetworkService rootNetworkService; + private static final String SUPERVISION_USER = "Supervision"; + public SupervisionService(StudyService studyService, NetworkModificationTreeService networkModificationTreeService, RootNetworkNodeInfoRepository rootNetworkNodeInfoRepository, @@ -358,7 +360,7 @@ private Integer deletePccMinResults() { public void unbuildAllNodes(UUID studyUuid) { AtomicReference startTime = new AtomicReference<>(); startTime.set(System.nanoTime()); - studyService.unbuildNodeTree(studyUuid, networkModificationTreeService.getStudyRootNodeUuid(studyUuid), false); + studyService.unbuildNodeTree(studyUuid, networkModificationTreeService.getStudyRootNodeUuid(studyUuid), false, SUPERVISION_USER); LOGGER.trace("Nodes builds deletion for study {} in : {} seconds", studyUuid, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); } diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationUnitTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationUnitTest.java index c392e0610..338247b5e 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationUnitTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationUnitTest.java @@ -57,6 +57,7 @@ import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_WORKFLOW_INFOS; import static org.gridsuite.study.server.StudyConstants.QUERY_PARAM_WORKFLOW_TYPE; import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; +import static org.gridsuite.study.server.utils.TestUtils.ELEMENT_UPDATE_DESTINATION; import static org.gridsuite.study.server.utils.TestUtils.checkUpdateStatusMessagesReceived; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -161,7 +162,7 @@ void unbuildNode() { UUID firstRootNetworkUuid = studyTestUtils.getOneRootNetworkUuid(studyUuid); // Unbuild security node without LF -> no children invalidation - studyController.unbuildNode(studyUuid, firstRootNetworkUuid, node1Uuid); + studyController.unbuildNode(studyUuid, firstRootNetworkUuid, node1Uuid, USER_ID_HEADER); /* rootNode * | * node1 @@ -176,11 +177,12 @@ void unbuildNode() { assertNodeBuildStatus(node4Uuid, BuildStatus.BUILT); checkUpdateBuildStateMessageReceived(studyUuid, List.of(node1Uuid)); checkUpdateStatusMessagesReceived(studyUuid, node1Uuid, output); + checkElementUpdatedMessageSent(studyUuid, USER_ID_HEADER); Mockito.verify(networkService).deleteVariants(NETWORK_UUID, List.of(VARIANT_1)); // Unbuild security node with LF -> children invalidation when(rootNetworkNodeInfoService.isLoadflowDone(node2Uuid, firstRootNetworkUuid)).thenReturn(true); - studyController.unbuildNode(studyUuid, firstRootNetworkUuid, node2Uuid); + studyController.unbuildNode(studyUuid, firstRootNetworkUuid, node2Uuid, USER_ID_HEADER); /* rootNode * | * node1 @@ -195,6 +197,7 @@ void unbuildNode() { assertNodeBuildStatus(node4Uuid, BuildStatus.NOT_BUILT); checkUpdateBuildStateMessageReceived(studyUuid, List.of(node2Uuid, node4Uuid)); checkUpdateStatusMessagesReceived(studyUuid, node2Uuid, output); + checkElementUpdatedMessageSent(studyUuid, USER_ID_HEADER); Mockito.verify(networkService).deleteVariants(NETWORK_UUID, List.of(VARIANT_4, VARIANT_2)); } @@ -271,7 +274,7 @@ void unbuildAllNodes() { UUID rootNodeUuid = networkModificationTreeService.getStudyRootNodeUuid(studyUuid); List rootNetworkUuids = rootNetworkService.getRootNetworkInfosWithLinksInfos(studyUuid).stream().map(RootNetworkInfos::getId).toList(); - studyController.unbuildAllNodes(studyUuid); + studyController.unbuildAllNodes(studyUuid, USER_ID_HEADER); ArgumentCaptor rootNetworkUuidCaptor = ArgumentCaptor.forClass(UUID.class); verify(networkModificationTreeService, times(2)).invalidateNodeTree(eq(rootNodeUuid), rootNetworkUuidCaptor.capture(), eq(InvalidateNodeTreeParameters.ALL_WITH_BLOCK_NODES)); @@ -280,6 +283,7 @@ void unbuildAllNodes() { // one for each root network checkUpdateBuildStateMessageReceived(studyUuid, List.of(node1Uuid, node2Uuid, node4Uuid)); checkUpdateBuildStateMessageReceived(studyUuid, List.of(node1Uuid, node2Uuid, node4Uuid)); + checkElementUpdatedMessageSent(studyUuid, USER_ID_HEADER); } private void updateNetworkModificationActivationStatus(List networkModificationUuids, UUID nodeWithModification, List childrenNodes, List nodesToUnbuild, boolean activated) { @@ -437,6 +441,12 @@ private void setupWithTwoRootNetwork() { node4Uuid = node4.getIdNode(); } + private void checkElementUpdatedMessageSent(UUID elementUuid, String userId) { + Message message = output.receive(TIMEOUT, ELEMENT_UPDATE_DESTINATION); + assertEquals(elementUuid, message.getHeaders().get(NotificationService.HEADER_ELEMENT_UUID)); + assertEquals(userId, message.getHeaders().get(NotificationService.HEADER_MODIFIED_BY)); + } + @AfterEach void tearDown() { List destinations = List.of(STUDY_UPDATE_DESTINATION);