Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private StudyConstants() {
public static final String QUERY_PARAM_ONLY_STASHED = "onlyStashed";
public static final String QUERY_PARAM_STASHED = "stashed";
public static final String QUERY_PARAM_ACTIVATED = "activated";
public static final String QUERY_PARAM_DESCRIPTION = "description";
public static final String PATH_PARAM_PARAMETERS = "parameters";
public static final String DYNA_FLOW_PROVIDER = "DynaFlow";
public static final String DYNAWO_PROVIDER = "Dynawo";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.study.server.StudyApi;
import org.gridsuite.study.server.StudyConstants.ModificationsActionType;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.dto.*;
import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos;
Expand Down Expand Up @@ -1403,17 +1404,17 @@ public ResponseEntity<Void> stashNetworkModifications(@Parameter(description = "
return ResponseEntity.ok().build();
}

@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network-modifications", params = "activated")
@Operation(summary = "Update 'activated' value for a network modifications for a node")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update the activation status for network modifications on a node"), @ApiResponse(responseCode = "404", description = "The study/node is not found")})
public ResponseEntity<Void> updateNetworkModificationsActivation(@Parameter(description = "Study UUID") @PathVariable("studyUuid") UUID studyUuid,
@Parameter(description = "Node UUID") @PathVariable("nodeUuid") UUID nodeUuid,
@Parameter(description = "Network modification UUIDs") @RequestParam("uuids") List<UUID> networkModificationUuids,
@Parameter(description = "New activated value") @RequestParam(name = "activated", required = true) Boolean activated,
@RequestHeader(HEADER_USER_ID) String userId) {
@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network-modifications")
@Operation(summary = "Updates the metadata of a network modification")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@Operation(summary = "Updates the metadata of a network modification")
@Operation(summary = "Updates metadata of a network modification")

small thing

@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Update the metadata of a network modification"), @ApiResponse(responseCode = "404", description = "The study/node is not found")})
public ResponseEntity<Void> updateNetworkModificationsMetadata(@Parameter(description = "Study UUID") @PathVariable("studyUuid") UUID studyUuid,
@Parameter(description = "Node UUID") @PathVariable("nodeUuid") UUID nodeUuid,
@Parameter(description = "Network modification UUIDs") @RequestParam("uuids") List<UUID> networkModificationUuids,
@RequestBody NetworkModificationMetadata metadata,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertCanUpdateModifications(studyUuid, nodeUuid);
studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid);
studyService.updateNetworkModificationsActivation(studyUuid, nodeUuid, networkModificationUuids, userId, activated);
studyService.updateNetworkModificationsMetadata(studyUuid, nodeUuid, networkModificationUuids, userId, metadata);
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright (c) 2025, 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.modification;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
* @author Mathieu Deharbe <mathieu.deharbe at rte-france.com>
*
* Metadata of the network modifications used in gridstudy tree view
*/
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Schema(description = "Modification metadata")
public class NetworkModificationMetadata {
@Schema(description = "If the modification is activated")
Boolean activated;
@Schema(description = "Modification description")
String description;
@Schema(description = "Modification type")
String type;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.gridsuite.study.server.dto.BuildInfos;
import org.gridsuite.study.server.dto.NodeReceiver;
import org.gridsuite.study.server.dto.modification.ModificationApplicationContext;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
import org.gridsuite.study.server.dto.modification.NetworkModificationsResult;
import org.gridsuite.study.server.dto.workflow.AbstractWorkflowInfos;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -175,21 +176,20 @@ public void stashModifications(UUID groupUUid, List<UUID> modificationsUuids) {
restTemplate.exchange(path, HttpMethod.PUT, httpEntity, Void.class);
}

public void updateModificationsActivation(UUID groupUUid, List<UUID> modificationsUuids, boolean activated) {
public void updateModificationsMetadata(UUID groupUUid, List<UUID> modificationsUuids, NetworkModificationMetadata metadata) {
Objects.requireNonNull(groupUUid);
Objects.requireNonNull(modificationsUuids);
var path = UriComponentsBuilder
.fromUriString(getNetworkModificationServerURI(false) + NETWORK_MODIFICATIONS_PATH)
.queryParam(UUIDS, modificationsUuids)
.queryParam(GROUP_UUID, groupUUid)
.queryParam(QUERY_PARAM_ACTIVATED, activated)
.buildAndExpand()
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<BuildInfos> httpEntity = new HttpEntity<>(headers);
HttpEntity<NetworkModificationMetadata> httpEntity = new HttpEntity<>(metadata, headers);
restTemplate.exchange(path, HttpMethod.PUT, httpEntity, Void.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.gridsuite.filter.globalfilter.GlobalFilter;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.study.server.StudyConstants;
import org.gridsuite.study.server.dto.modification.*;
import org.gridsuite.study.server.dto.voltageinit.ContextInfos;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.dto.*;
Expand All @@ -31,10 +32,6 @@
import org.gridsuite.study.server.dto.dynamicsimulation.event.EventInfos;
import org.gridsuite.study.server.dto.elasticsearch.EquipmentInfos;
import org.gridsuite.study.server.dto.impacts.SimpleElementImpact;
import org.gridsuite.study.server.dto.modification.ModificationApplicationContext;
import org.gridsuite.study.server.dto.modification.ModificationsSearchResultByNode;
import org.gridsuite.study.server.dto.modification.NetworkModificationResult;
import org.gridsuite.study.server.dto.modification.NetworkModificationsResult;
import org.gridsuite.study.server.dto.sequence.NodeSequenceType;
import org.gridsuite.study.server.dto.voltageinit.parameters.StudyVoltageInitParameters;
import org.gridsuite.study.server.dto.voltageinit.parameters.VoltageInitParametersInfos;
Expand Down Expand Up @@ -2189,16 +2186,18 @@ public void stashNetworkModifications(UUID studyUuid, UUID nodeUuid, List<UUID>
}

@Transactional
public void updateNetworkModificationsActivation(UUID studyUuid, UUID nodeUuid, List<UUID> modificationsUuids, String userId, boolean activated) {
public void updateNetworkModificationsMetadata(UUID studyUuid, UUID nodeUuid, List<UUID> modificationsUuids, String userId, NetworkModificationMetadata metadata) {
List<UUID> childrenUuids = networkModificationTreeService.getChildrenUuids(nodeUuid);
notificationService.emitStartModificationEquipmentNotification(studyUuid, nodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
try {
if (!networkModificationTreeService.getStudyUuidForNodeId(nodeUuid).equals(studyUuid)) {
throw new StudyException(NOT_ALLOWED);
}
UUID groupId = networkModificationTreeService.getModificationGroupUuid(nodeUuid);
networkModificationService.updateModificationsActivation(groupId, modificationsUuids, activated);
invalidateNodeTree(studyUuid, nodeUuid);
networkModificationService.updateModificationsMetadata(groupId, modificationsUuids, metadata);
if (metadata.getActivated() != null) {
invalidateNodeTree(studyUuid, nodeUuid);
}
} finally {
notificationService.emitEndModificationEquipmentNotification(studyUuid, nodeUuid, childrenUuids);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.gridsuite.study.server.controller.StudyController;
import org.gridsuite.study.server.dto.BuildInfos;
import org.gridsuite.study.server.dto.RootNetworkIndexationStatus;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
import org.gridsuite.study.server.dto.workflow.RerunLoadFlowInfos;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.networkmodificationtree.dto.BuildStatus;
Expand Down Expand Up @@ -93,6 +94,7 @@ class NetworkModificationUnitTest {
private static final String CASE_LOADFLOW_UUID_STRING = "11a91c11-2c2d-83bb-b45f-20b83e4ef00c";
private static final UUID CASE_LOADFLOW_UUID = UUID.fromString(CASE_LOADFLOW_UUID_STRING);
private static final UUID NETWORK_UUID = UUID.fromString("38400000-8cf0-11bd-b23e-10b96e4ef00d");
private static final String USER_ID_HEADER = "userId";

private static final String SHOULD_NOT_RETURN_NULL_MESSAGE = "Should not return null here";

Expand Down Expand Up @@ -226,6 +228,30 @@ private void assertNodeBuildStatus(UUID nodeUuid, BuildStatus buildStatus) {
assertEquals(buildStatus, rootNetworkNodeInfoEntity.getNodeBuildStatus().getLocalBuildStatus());
}

@Test
void updateDescription() {
UUID modificationUuid = UUID.randomUUID();
List<UUID> childrenNodes = List.of(node2Uuid, node4Uuid, node3Uuid);

NetworkModificationMetadata metadata = new NetworkModificationMetadata(null, "new description", null);
studyController.updateNetworkModificationsMetadata(studyUuid, node1Uuid, List.of(modificationUuid), metadata, USER_ID_HEADER);

checkModificationUpdatedMessageReceived(studyUuid, node1Uuid, childrenNodes, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
checkModificationUpdatedMessageReceived(studyUuid, node1Uuid, childrenNodes, NotificationService.MODIFICATIONS_UPDATING_FINISHED);

NetworkModificationNodeInfoEntity node1Infos = networkModificationNodeInfoRepository.findById(node1Uuid).orElseThrow(() -> new UnsupportedOperationException(SHOULD_NOT_RETURN_NULL_MESSAGE));
Mockito.verify(restTemplate, Mockito.times(1)).exchange(
matches(".*network-modifications\\?uuids=" + modificationUuid +
"&groupUuid=" + node1Infos.getModificationGroupUuid().toString()),
eq(HttpMethod.PUT),
argThat(n -> {
assertNotNull(n.getBody());
return n.getBody().equals(metadata);
}),
eq(Void.class)
);
}

@Test
void activateNetworkModificationTest() {
List<UUID> modificationToDeactivateUuids = List.of(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID());
Expand All @@ -245,7 +271,7 @@ void buildNodeWithWorkflowInfos() throws JsonProcessingException {
UUID networkUuid = UUID.randomUUID();
BuildInfos buildInfos = new BuildInfos();
RerunLoadFlowInfos rerunLoadFlowInfos = RerunLoadFlowInfos.builder()
.userId("userId")
.userId(USER_ID_HEADER)
.withRatioTapChangers(true)
.loadflowResultUuid(UUID.randomUUID())
.build();
Expand All @@ -261,7 +287,8 @@ void buildNodeWithWorkflowInfos() throws JsonProcessingException {
}

private void updateNetworkModificationActivationStatus(List<UUID> networkModificationUuids, UUID nodeWithModification, List<UUID> childrenNodes, List<UUID> nodesToUnbuild, boolean activated) {
studyController.updateNetworkModificationsActivation(studyUuid, node1Uuid, networkModificationUuids, activated, "userId");
NetworkModificationMetadata metadata = new NetworkModificationMetadata(activated, null, null);
studyController.updateNetworkModificationsMetadata(studyUuid, node1Uuid, networkModificationUuids, metadata, USER_ID_HEADER);

checkModificationUpdatedMessageReceived(studyUuid, nodeWithModification, childrenNodes, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS);
checkUpdateBuildStateMessageReceived(studyUuid, nodesToUnbuild);
Expand All @@ -270,9 +297,14 @@ private void updateNetworkModificationActivationStatus(List<UUID> networkModific

NetworkModificationNodeInfoEntity node1Infos = networkModificationNodeInfoRepository.findById(node1Uuid).orElseThrow(() -> new UnsupportedOperationException(SHOULD_NOT_RETURN_NULL_MESSAGE));
Mockito.verify(restTemplate, Mockito.times(1)).exchange(
matches(".*network-modifications\\?" + networkModificationUuids.stream().map(uuid -> "uuids=" + uuid.toString() + "&").collect(Collectors.joining()) +
"groupUuid=" + node1Infos.getModificationGroupUuid().toString() + "&" +
"activated=" + activated), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class));
matches(".*network-modifications\\?" + networkModificationUuids.stream().map(uuid -> "uuids=" + uuid.toString() + "&").collect(Collectors.joining()) +
"groupUuid=" + node1Infos.getModificationGroupUuid().toString()),
eq(HttpMethod.PUT),
argThat(n -> {
assertNotNull(n.getBody());
return n.getBody().equals(metadata);
}),
eq(Void.class));
}

private void checkModificationUpdatedMessageReceived(UUID studyUuid, UUID nodeUuid, List<UUID> childrenNodeUuids, String notificationType) {
Expand Down