Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
afacd2b
fix
ghazwarhili Jul 22, 2026
48fe04b
Merge branch 'main' into export-import-study
ghazwarhili Jul 22, 2026
d846b9a
clean code
ghazwarhili Jul 27, 2026
97c48d3
Merge branch 'main' into export-import-study
ghazwarhili Jul 28, 2026
4e89ced
clean code
ghazwarhili Jul 28, 2026
af818e8
clean code
ghazwarhili Jul 28, 2026
c6e2f3e
add TU
ghazwarhili Jul 29, 2026
046507e
Merge branch 'main' into export-import-study
ghazwarhili Jul 29, 2026
c7a06f8
add stub for directory service
ghazwarhili Jul 29, 2026
92204b4
add stub for cases-alert-threshold
ghazwarhili Jul 29, 2026
4547f1f
fix sonar coverage issues
ghazwarhili Jul 29, 2026
7c917c3
fix sonar issue
ghazwarhili Jul 29, 2026
1370512
fix import
ghazwarhili Jul 29, 2026
59e411b
enhance and clean code
ghazwarhili Aug 5, 2026
f0143af
Merge branch 'main' into export-import-study
ghazwarhili Aug 5, 2026
185e8c8
resolve conflicts
ghazwarhili Aug 5, 2026
e4136a8
add node type
ghazwarhili Aug 5, 2026
28faa63
fix duplicated param
ghazwarhili Aug 6, 2026
27d5681
Merge branch 'main' into export-import-study
ghazwarhili Aug 6, 2026
446d425
code review remarks
ghazwarhili Aug 10, 2026
e90d641
merge main
ghazwarhili Aug 10, 2026
d932a79
fix import workflow
ghazwarhili Aug 11, 2026
72a21e0
clean endpoint
ghazwarhili Aug 14, 2026
14f47b2
enhance TU
ghazwarhili Aug 14, 2026
1b566e8
sonar issues fix
ghazwarhili Aug 14, 2026
6b678dd
fix sonar issues
ghazwarhili Aug 17, 2026
1a02fb5
import study pamaters
ghazwarhili Aug 18, 2026
bf1bee9
Revert "import study pamaters"
ghazwarhili Aug 18, 2026
ef2f631
code review part 1
ghazwarhili Sep 1, 2026
94a6997
fix code review
ghazwarhili Sep 4, 2026
ba0b85d
fix tu
ghazwarhili Sep 4, 2026
48afd93
clean code
ghazwarhili Sep 7, 2026
65686ae
code review part 1
ghazwarhili Sep 10, 2026
43a8d54
code review part 2
ghazwarhili Sep 11, 2026
e88f723
Merge branch 'main' into export-import-study
ghazwarhili Sep 11, 2026
9ee7a75
Merge branch 'main' into export-import-study
ghazwarhili Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions src/main/java/org/gridsuite/explore/server/ExploreController.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.gridsuite.explore.server.dto.CaseInfo;
import org.gridsuite.explore.server.dto.ElementAttributes;
import org.gridsuite.explore.server.dto.PermissionDTO;
import org.gridsuite.explore.server.dto.PermissionType;
import org.gridsuite.explore.server.dto.ReferencingElementInfos;
import org.gridsuite.explore.server.dto.*;
import org.gridsuite.explore.server.services.DirectoryService;
import org.gridsuite.explore.server.services.ExploreService;
import org.gridsuite.explore.server.services.StudyImportService;
import org.gridsuite.explore.server.utils.ContingencyListType;
import org.gridsuite.explore.server.utils.ParametersType;
import org.springframework.http.HttpStatus;
Expand All @@ -41,6 +38,7 @@ public class ExploreController {

// /!\ This query parameter is used by the gateway to control access
private static final String QUERY_PARAM_NAME = "name";
private static final String QUERY_PARAM_STUDY_NAME = "studyName";
private static final String QUERY_PARAM_DESCRIPTION = "description";
private static final String QUERY_PARAM_PARENT_DIRECTORY_ID = "parentDirectoryUuid";

Expand All @@ -49,10 +47,12 @@ public class ExploreController {

private final ExploreService exploreService;
private final DirectoryService directoryService;
private final StudyImportService studyImportService;

public ExploreController(ExploreService exploreService, DirectoryService directoryService) {
public ExploreController(ExploreService exploreService, DirectoryService directoryService, StudyImportService studyImportService) {
this.exploreService = exploreService;
this.directoryService = directoryService;
this.studyImportService = studyImportService;
}

@PostMapping(value = "/explore/studies/{studyName}/cases/{caseUuid}")
Expand Down Expand Up @@ -85,6 +85,20 @@ public ResponseEntity<Void> duplicateStudy(@PathVariable("id") UUID studyId,
return ResponseEntity.ok().build();
}

@PostMapping(value = "/explore/studies/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "Import a study from an archive")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Study import started asynchronously")})
@PreAuthorize("@authorizationService.isAuthorized(#userId, #parentDirectoryUuid, null, T(org.gridsuite.explore.server.dto.PermissionType).WRITE)")
public ResponseEntity<Void> importStudy(@RequestParam(QUERY_PARAM_STUDY_NAME) String studyName,
@RequestPart("archiveFile") MultipartFile archiveFile,
@RequestParam(QUERY_PARAM_DESCRIPTION) String description,
@RequestParam(QUERY_PARAM_PARENT_DIRECTORY_ID) UUID parentDirectoryUuid,
@RequestHeader(QUERY_PARAM_USER_ID) String userId) {
exploreService.assertCanCreateCase(userId);
studyImportService.importStudyArchive(archiveFile, studyName, description, userId, parentDirectoryUuid);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/explore/cases/{caseName}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "create a case")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Case creation request delegated to case server")})
Expand Down Expand Up @@ -672,7 +686,7 @@ public ResponseEntity<Void> hasRight(@PathVariable("elementUuid") UUID elementUu
@ApiResponse(responseCode = "404", description = "The shared element was not found"),
})
public ResponseEntity<List<ReferencingElementInfos>> getReferencingElementInfos(@PathVariable("elementUuid") UUID elementUuid,
@RequestHeader(QUERY_PARAM_USER_ID) String userId) {
@RequestHeader(QUERY_PARAM_USER_ID) String userId) {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
.body(exploreService.getReferencingElementInfos(elementUuid, userId));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.explore.server.dto;

import java.util.UUID;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/
public record CaseExportInfos(
UUID uuid,
String name
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* 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.explore.server.dto;

import java.util.List;
import java.util.UUID;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/
public record NodeTreeExportInfos(
String name,
String type,
UUID modificationGroupUuid,
String buildStatus,
String nodeType,
List<NodeTreeExportInfos> children
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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.explore.server.dto;

import java.util.Map;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/
public record RootNetworkExportInfos(
String name,
String tag,
String caseFormat,
CaseExportInfos caseInfos,
Map<String, Object> importParameters
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* 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.explore.server.dto;

import java.util.List;
import java.util.UUID;

/**
* @author Ghazwa Rehili <ghazwa.rehili at rte-france.com>
*/
public record StudyExportInfos(
UUID studyUuid,
List<RootNetworkExportInfos> rootNetworks,
NodeTreeExportInfos nodeTree
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* Business error codes emitted by the explore service.
*/
public enum ExploreBusinessErrorCode implements BusinessErrorCode {
EXPLORE_MAX_ELEMENTS_EXCEEDED("explore.maxElementsExceeded");
EXPLORE_MAX_ELEMENTS_EXCEEDED("explore.maxElementsExceeded"),
IMPORT_STUDY_FAILED("explore.importStudyFailed");

private final String code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ public ExploreException(ExploreBusinessErrorCode errorCode, String message, Map<
this.businessErrorValues = businessErrorValues != null ? Map.copyOf(businessErrorValues) : Map.of();
}

public ExploreException(ExploreBusinessErrorCode errorCode, String message, Throwable cause) {
super(Objects.requireNonNull(message, "message must not be null"), cause);
this.errorCode = Objects.requireNonNull(errorCode, "errorCode must not be null");
this.businessErrorValues = Map.of();
}

public static ExploreException of(ExploreBusinessErrorCode errorCode, String message, Object... args) {
return new ExploreException(errorCode, args.length == 0 ? message : String.format(message, args));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ protected ExploreBusinessErrorCode getBusinessCode(ExploreException ex) {
protected HttpStatus mapStatus(ExploreBusinessErrorCode errorCode) {
return switch (errorCode) {
case EXPLORE_MAX_ELEMENTS_EXCEEDED -> HttpStatus.FORBIDDEN;
case IMPORT_STUDY_FAILED -> HttpStatus.INTERNAL_SERVER_ERROR;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -57,6 +58,21 @@ UUID importCase(MultipartFile multipartFile) {
return caseUuid;
}

public UUID importCaseFromFile(File file) {
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

body.add("file", new org.springframework.core.io.FileSystemResource(file));

HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(body, headers);
return restTemplate.postForObject(
caseServerBaseUri + "/" + CASE_SERVER_API_VERSION + "/cases",
request,
UUID.class
);
}

void persistCase(UUID caseUuid) {
String path = UriComponentsBuilder.fromPath(DELIMITER + CASE_SERVER_API_VERSION + "/cases/" + caseUuid + "/disableExpiration")
.buildAndExpand()
Expand Down
Loading
Loading