Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class UserAdminApplicationProps {
* Value returned by {@link UserAdminController#getCasesAlertThreshold()}.
* Default: {@code 90}
*/
private Integer casesAlertThreshold;
private Integer casesAlertThreshold = 90;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedBuilds()} if {@code null}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
@Operation(summary = "Record connection attempt")
@ApiResponse(responseCode = "200", description = "Connection attempt recorded")
public ResponseEntity<Void> recordConnectionAttempt(@PathVariable("sub") String sub,
@RequestParam(value = "isConnectionAccepted") boolean isConnectionAccepted) {
@RequestParam(value = "isConnectionAccepted") boolean isConnectionAccepted) {
service.recordConnectionAttempt(sub, isConnectionAccepted);
return ResponseEntity.ok().build();
}
Expand All @@ -118,122 +118,35 @@
return ResponseEntity.ok(service.getUserGroups(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-cases")
@Operation(summary = "Get the user's max allowed cases")
@ApiResponse(responseCode = "200", description = "The user max allowed cases created")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxStudies(@PathVariable("sub") String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedCases(sub));
}

@GetMapping(value = "/cases-alert-threshold")
@Operation(summary = "Get the cases alert threshold")
@ApiResponse(responseCode = "200", description = "The cases alert threshold")
public ResponseEntity<Integer> getCasesAlertThreshold() {
return ResponseEntity.ok().body(service.getCasesAlertThreshold());
}

@GetMapping(value = "/users/{sub}/profile/max-builds")
@Operation(summary = "Get the user's max allowed builds")
@ApiResponse(responseCode = "200", description = "The user max allowed builds")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedBuilds(@PathVariable("sub") String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedBuilds(sub));
}

@GetMapping(value = "/connections", produces = {MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "get the connections", description = "Access restricted to users of type: `admin`")
@ApiResponse(responseCode = "200", description = "The connections list")
public ResponseEntity<List<UserConnection>> getConnections() {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(service.getConnections());
}

@GetMapping(value = "/users/{sub}/profile/max-loadflow")
@Operation(summary = "Get the user's max allowed loadflows")
@ApiResponse(responseCode = "200", description = "The user max allowed loadflows")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedLoadflows(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedLoadflows(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-security")
@Operation(summary = "Get the user's max allowed security analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed security analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedSecurity(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedSecurity(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-sensitivity")
@Operation(summary = "Get the user's max allowed sensitivity analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed sensitivity analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedSensitivity(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedSensitivity(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-shortcircuit")
@Operation(summary = "Get the user's max allowed short circuit analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed short circuit analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedShortCircuit(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedShortCircuit(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-voltage-init")
@Operation(summary = "Get the user's max allowed voltage init analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed voltage init analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedVoltageInit(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedVoltageInit(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-pcc-min")
@Operation(summary = "Get the user's max allowed pcc min analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed pcc min analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedPccMin(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedPccMin(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-state-estimation")
@Operation(summary = "Get the user's max allowed state estimation analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed state estimation analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedStateEstimation(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedStateEstimation(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-balance-adjustement")
@Operation(summary = "Get the user's max allowed balance adjustement analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed balance adjustement analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedBalanceAdjustement(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedBalanceAdjustement(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-dynamic-simulation")
@Operation(summary = "Get the user's max allowed dynamic simulation analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed dynamic simulation analysis")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedDynamicSimulation(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedDynamicSimulation(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-dynamic-security")
@Operation(summary = "Get the user's max allowed dynamic security analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed dynamic security analysis")
@Deprecated

Check warning on line 135 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add 'since' and/or 'forRemoval' arguments to the @Deprecated annotation.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh3&open=AZ83mvvxjxbuwFodETh3&pullRequest=103
@GetMapping(value = "/users/{sub}/profile/max-cases")
@Operation(summary = "Get the user's max allowed cases")
@ApiResponse(responseCode = "200", description = "The user max allowed cases created")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedDynamicSecurity(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedDynamicSecurity(sub));
public ResponseEntity<Integer> getUserProfileMaxStudies(@PathVariable("sub") String sub) {

Check warning on line 140 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the missing @deprecated Javadoc tag.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh5&open=AZ83mvvxjxbuwFodETh5&pullRequest=103

Check warning on line 140 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh4&open=AZ83mvvxjxbuwFodETh4&pullRequest=103
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedCases(sub));
}

@GetMapping(value = "/users/{sub}/profile/max-dynamic-margin")
@Operation(summary = "Get the user's max allowed dynamic margin analysis")
@ApiResponse(responseCode = "200", description = "The user max allowed dynamic margin analysis")
@Deprecated

Check warning on line 144 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add 'since' and/or 'forRemoval' arguments to the @Deprecated annotation.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh6&open=AZ83mvvxjxbuwFodETh6&pullRequest=103
@GetMapping(value = "/users/{sub}/profile/max-builds")
@Operation(summary = "Get the user's max allowed builds")
@ApiResponse(responseCode = "200", description = "The user max allowed builds")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedDynamicMargin(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedDynamicMargin(sub));
public ResponseEntity<Integer> getUserProfileMaxAllowedBuilds(@PathVariable("sub") String sub) {

Check warning on line 149 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add the missing @deprecated Javadoc tag.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh8&open=AZ83mvvxjxbuwFodETh8&pullRequest=103

Check warning on line 149 in src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ83mvvxjxbuwFodETh7&open=AZ83mvvxjxbuwFodETh7&pullRequest=103
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedBuilds(sub));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* 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.useradmin.server.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.gridsuite.useradmin.server.UserAdminApi;
import org.gridsuite.useradmin.server.dto.*;
import org.gridsuite.useradmin.server.service.UserQuotaService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;
import java.util.UUID;

/**
* @author Ghiles Abdellah {@literal <ghiles.abdellah at rte-france.com>}
*/
@RestController
@RequestMapping(value = "/" + UserAdminApi.API_VERSION)
@Tag(name = "UserQuotaController")
@ApiResponse(responseCode = "403", description = "The current user does not have right to ask these data")
public class UserQuotaController {
private final UserQuotaService userQuotaService;

public UserQuotaController(UserQuotaService userQuotaService) {
this.userQuotaService = userQuotaService;
}

@GetMapping(value = "/users/{sub}/quota/max")
@Operation(summary = "Get the user's quota")
@ApiResponse(responseCode = "200", description = "The user max quota")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Map<OperationType, Integer>> getUserProfileMaxQuota(@PathVariable("sub") String sub) {
Map<OperationType, Integer> userMaxQuota = userQuotaService.getUserMaxQuota(sub);
return ResponseEntity.ok().body(userMaxQuota);
}

@GetMapping(value = "/users/{sub}/quota/current")
@Operation(summary = "Get the user's current quota usage")
@ApiResponse(responseCode = "200", description = "The user current quota usage")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Map<OperationType, Integer>> getUserCurrentQuotaUsage(@PathVariable("sub") String sub) {
Map<OperationType, Integer> userCurrentQuotaUsage = userQuotaService.getUserCurrentQuotaUsage(sub);
return ResponseEntity.ok().body(userCurrentQuotaUsage);
}

@PostMapping(value = "/users/{sub}/quota/reset")
@Operation(summary = "Reset the user's current quota usage", description = "Access restricted to users of type: `admin`")
@ApiResponse(responseCode = "200", description = "The user current quota usage has been reseted")
public ResponseEntity<Void> resetUserCurrentQuotaUsage(@PathVariable("sub") String sub) {
userQuotaService.resetUserCurrentQuotaUsage(sub);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/users/{sub}/quota/{operation}/{operation_id}/start")
@Operation(summary = "Increase the user's current quota usage for a given operation")
@ApiResponse(responseCode = "200", description = "The user current quota usage has been updated")
public ResponseEntity<Void> startUserOperation(@PathVariable("sub") String sub,
@PathVariable("operation") OperationType operation,
@PathVariable("operation_id") UUID operationId) {
userQuotaService.startUserOperation(sub, operation, operationId);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/users/{sub}/quota/{operation}/{operation_id}/end")
@Operation(summary = "Decrease the user's current quota usage for a given operation")
@ApiResponse(responseCode = "200", description = "The user current quota usage has been updated")
public ResponseEntity<Void> endUserOperation(@PathVariable("sub") String sub,
@PathVariable("operation") OperationType operation,
@PathVariable("operation_id") UUID operationId) {
userQuotaService.endUserOperation(sub, operation, operationId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* 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.useradmin.server.dto;

/**
* @author Ghiles Abdellah {@literal <ghiles.abdellah at rte-france.com>}
*/
public enum OperationType {
CASES,
BUILD,
LOAD_FLOW,
SECURITY,
SENSITIVITY,
SHORT_CIRCUIT,
VOLTAGE_INIT,
PCC_MIN,
STATE_ESTIMATION,
BALANCE_ADJUSTEMENT,
DYNAMIC_SIMULATION,
DYNAMIC_SECURITY,
DYNAMIC_MARGIN,
}
37 changes: 16 additions & 21 deletions src/main/java/org/gridsuite/useradmin/server/dto/UserProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,7 @@
@Builder
public final class UserProfile {
public static final String DEFAULT_PROFILE_NAME = "default profile";
public static final String MAX_ALLOWED_CASES = "maxAllowedCases";
public static final String MAX_ALLOWED_BUILD = "maxAllowedBuilds";
public static final String MAX_ALLOWED_LOADFLOW = "maxAllowedLoadflow";
public static final String MAX_ALLOWED_SECURITY = "maxAllowedSecurity";
public static final String MAX_ALLOWED_SENSITIVITY = "maxAllowedSensitivity";
public static final String MAX_ALLOWED_SHORT_CIRCUIT = "maxAllowedShortCircuit";
public static final String MAX_ALLOWED_VOLTAGE_INIT = "maxAllowedVoltageInit";
public static final String MAX_ALLOWED_PCC_MIN = "maxAllowedPccMin";
public static final String MAX_ALLOWED_STATE_ESTIMATION = "maxAllowedStateEstimation";
public static final String MAX_ALLOWED_BALANCE_ADJUSTEMENT = "maxAllowedBalanceAdjustement";
public static final String MAX_ALLOWED_DYNAMIC_SIMULATION = "maxAllowedDynamicSimulation";
public static final String MAX_ALLOWED_DYNAMIC_SECURITY = "maxAllowedDynamicSecurity";
public static final String MAX_ALLOWED_DYNAMIC_MARGIN = "maxAllowedDynamicMargin";

private final UUID id;
private final String name;
private final UUID loadFlowParameterId;
Expand All @@ -43,10 +31,10 @@ public final class UserProfile {
private final UUID pccMinParameterId;
private final UUID voltageInitParameterId;
private final Boolean allLinksValid;
private final Map<String, Integer> maxAllowValuesMap;
private final UUID spreadsheetConfigCollectionId;
private final UUID networkVisualizationParameterId;
private final UUID workspaceId;
private final Map<OperationType, Integer> maxOperationQuota;

public UserProfile(
UUID id,
Expand All @@ -58,10 +46,10 @@ public UserProfile(
UUID pccMinParameterId,
UUID voltageInitParameterId,
Boolean allLinksValid,
Map<String, Integer> maxAllowValuesMap,
UUID spreadsheetConfigCollectionId,
UUID networkVisualizationParameterId,
UUID workspaceId
UUID workspaceId,
Map<OperationType, Integer> maxOperationQuota
) {
this.id = id;
this.name = name;
Expand All @@ -72,18 +60,25 @@ public UserProfile(
this.pccMinParameterId = pccMinParameterId;
this.voltageInitParameterId = voltageInitParameterId;
this.allLinksValid = allLinksValid;
this.maxAllowValuesMap = maxAllowValuesMap == null ? new HashMap<>() : new HashMap<>(maxAllowValuesMap);
this.spreadsheetConfigCollectionId = spreadsheetConfigCollectionId;
this.networkVisualizationParameterId = networkVisualizationParameterId;
this.workspaceId = workspaceId;
this.maxOperationQuota = maxOperationQuota == null ? new HashMap<>() : new HashMap<>(maxOperationQuota);
}

public static UserProfile createDefaultProfile(Map<OperationType, Integer> maxAllowValues) {
return UserProfile.builder()
.name(DEFAULT_PROFILE_NAME)
.maxOperationQuota(maxAllowValues)
.build();
}

public Map<String, Integer> getMaxAllowValuesMap() {
return Collections.unmodifiableMap(maxAllowValuesMap);
public Map<OperationType, Integer> getMaxOperationQuota() {
return Collections.unmodifiableMap(maxOperationQuota);
}

public static UserProfile createDefaultProfile(Map<String, Integer> maxAllowValues) {
return UserProfile.builder().name(DEFAULT_PROFILE_NAME).maxAllowValuesMap(maxAllowValues).build();
public Integer getMaxOperationQuota(OperationType operationType) {
return maxOperationQuota.get(operationType);
}

}
Loading
Loading