Skip to content
Merged
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 @@ -37,6 +37,61 @@ public class UserAdminApplicationProps {
*/
private Integer defaultMaxAllowedBuilds;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedLoadflow()} if {@code null}.
*/
private Integer defaultMaxAllowedLoadflow;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedSecurity()} if {@code null}.
*/
private Integer defaultMaxAllowedSecurity;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedSensitivity()} if {@code null}.
*/
private Integer defaultMaxAllowedSensitivity;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedShortCircuit()} if {@code null}.
*/
private Integer defaultMaxAllowedShortCircuit;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedVoltageInit()} if {@code null}.
*/
private Integer defaultMaxAllowedVoltageInit;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedPccMin()} if {@code null}.
*/
private Integer defaultMaxAllowedPccMin;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedStateEstimation()} if {@code null}.
*/
private Integer defaultMaxAllowedStateEstimation;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedBalanceAdjustement()} if {@code null}.
*/
private Integer defaultMaxAllowedBalanceAdjustement;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedDynamicSimulation()} if {@code null}.
*/
private Integer defaultMaxAllowedDynamicSimulation;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedDynamicSecurity()} if {@code null}.
*/
private Integer defaultMaxAllowedDynamicSecurity;

/**
* Default value of {@link org.gridsuite.useradmin.server.dto.UserInfos#maxAllowedDynamicMargin()} if {@code null}.
*/
private Integer defaultMaxAllowedDynamicMargin;

/**
* Cron jobs expression in UTC.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,93 @@ public ResponseEntity<Integer> getUserProfileMaxAllowedBuilds(@PathVariable("sub
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")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedDynamicSecurity(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedDynamicSecurity(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")
@ApiResponse(responseCode = "404", description = "The user doesn't exist")
public ResponseEntity<Integer> getUserProfileMaxAllowedDynamicMargin(@PathVariable String sub) {
return ResponseEntity.ok().body(service.getUserProfileMaxAllowedDynamicMargin(sub));
}
Comment on lines +151 to +237

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

404 response is documented but unreachable on the new quota endpoints.

At Lines 151-237, each handler always returns ResponseEntity.ok(...), and the delegated service path falls back to defaults instead of signaling not found. The @ApiResponse(responseCode = "404") on these endpoints is therefore inconsistent with actual behavior. Align the contract by either removing 404 from docs or explicitly returning 404 for unknown users/profiles.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/org/gridsuite/useradmin/server/controller/UserAdminController.java`
around lines 151 - 237, The endpoints getUserProfileMaxAllowedLoadflows,
getUserProfileMaxAllowedSecurity, getUserProfileMaxAllowedSensitivity,
getUserProfileMaxAllowedShortCircuit, getUserProfileMaxAllowedVoltageInit,
getUserProfileMaxAllowedPccMin, getUserProfileMaxAllowedStateEstimation,
getUserProfileMaxAllowedBalanceAdjustement,
getUserProfileMaxAllowedDynamicSimulation,
getUserProfileMaxAllowedDynamicSecurity, and
getUserProfileMaxAllowedDynamicMargin all document 404 responses in their
ApiResponse annotations, but they always return ResponseEntity.ok() which means
they never actually return 404. Resolve this inconsistency by either removing
the 404 ApiResponse annotations from all these endpoints if the service never
returns not-found errors, or if the service can return null or throw an
exception for unknown users, modify these handlers to check the result and
return ResponseEntity.notFound().build() when appropriate.


}
22 changes: 22 additions & 0 deletions src/main/java/org/gridsuite/useradmin/server/dto/UserInfos.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ public record UserInfos(
Integer maxAllowedCases,
Integer numberCasesUsed,
Integer maxAllowedBuilds,
Integer maxAllowedLoadflow,
Integer maxAllowedSecurity,
Integer maxAllowedSensitivity,
Integer maxAllowedShortCircuit,
Integer maxAllowedVoltageInit,
Integer maxAllowedPccMin,
Integer maxAllowedStateEstimation,
Integer maxAllowedBalanceAdjustement,
Integer maxAllowedDynamicSimulation,
Integer maxAllowedDynamicSecurity,
Integer maxAllowedDynamicMargin,
Set<String> groups
) {
/**
Expand All @@ -39,6 +50,17 @@ public UserInfos withIdentity(UserIdentity identity) {
maxAllowedCases,
numberCasesUsed,
maxAllowedBuilds,
maxAllowedLoadflow,
maxAllowedSecurity,
maxAllowedSensitivity,
maxAllowedShortCircuit,
maxAllowedVoltageInit,
maxAllowedPccMin,
maxAllowedStateEstimation,
maxAllowedBalanceAdjustement,
maxAllowedDynamicSimulation,
maxAllowedDynamicSecurity,
maxAllowedDynamicMargin,
groups
);
}
Expand Down
110 changes: 76 additions & 34 deletions src/main/java/org/gridsuite/useradmin/server/dto/UserProfile.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,89 @@
/*
/**
* Copyright (c) 2024, 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;

import lombok.Builder;
import lombok.Getter;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public record UserProfile(
UUID id,
String name,
UUID loadFlowParameterId,
UUID securityAnalysisParameterId,
UUID sensitivityAnalysisParameterId,
UUID shortcircuitParameterId,
UUID pccMinParameterId,
UUID voltageInitParameterId,
Boolean allLinksValid,
Integer maxAllowedCases,
Integer maxAllowedBuilds,
UUID spreadsheetConfigCollectionId,
UUID networkVisualizationParameterId,
UUID workspaceId
) {
/**
* @author Etienne Lesot <etienne.lesot at rte-france.com>
*/
@Getter
@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;
private final UUID securityAnalysisParameterId;
private final UUID sensitivityAnalysisParameterId;
private final UUID shortcircuitParameterId;
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;

public UserProfile(

Check warning on line 51 in src/main/java/org/gridsuite/useradmin/server/dto/UserProfile.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Constructor has 13 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ8DPE2LKuyMrAPv9HEh&open=AZ8DPE2LKuyMrAPv9HEh&pullRequest=102
UUID id,
String name,
UUID loadFlowParameterId,
UUID securityAnalysisParameterId,
UUID sensitivityAnalysisParameterId,
UUID shortcircuitParameterId,
UUID pccMinParameterId,
UUID voltageInitParameterId,
Boolean allLinksValid,
Map<String, Integer> maxAllowValuesMap,
UUID spreadsheetConfigCollectionId,
UUID networkVisualizationParameterId,
UUID workspaceId
) {
this.id = id;
this.name = name;
this.loadFlowParameterId = loadFlowParameterId;
this.securityAnalysisParameterId = securityAnalysisParameterId;
this.sensitivityAnalysisParameterId = sensitivityAnalysisParameterId;
this.shortcircuitParameterId = shortcircuitParameterId;
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;

}

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

public static UserProfile createDefaultProfile(Integer maxAllowedCases, Integer maxAllowedBuilds) {
return new UserProfile(
null,
DEFAULT_PROFILE_NAME,
null,
null,
null,
null,
null,
null,
null,
maxAllowedCases,
maxAllowedBuilds,
null,
null,
null
);
public static UserProfile createDefaultProfile(Map<String, Integer> maxAllowValues) {
return UserProfile.builder().name(DEFAULT_PROFILE_NAME).maxAllowValuesMap(maxAllowValues).build();
Comment on lines +20 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

This breaks the existing /profiles JSON contract.

The DTO no longer exposes top-level maxAllowedCases / maxAllowedBuilds; callers now have to send and read maxAllowValuesMap instead. UserProfileTest was updated to post the new map shape, so existing clients of the current API version will break unless you keep backward-compatible aliases/accessors or version the endpoint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/gridsuite/useradmin/server/dto/UserProfile.java` around
lines 18 - 50, The UserProfile DTO change breaks the existing /profiles JSON
contract by exposing maxAllowValuesMap instead of the top-level maxAllowed*
fields. Update UserProfile so Jackson still serializes/deserializes the legacy
property names while keeping the internal map, using the UserProfile class and
createDefaultProfile builder path as the main locations to adjust. Preserve
backward compatibility with existing clients by adding aliases/accessors or
another compatibility layer rather than changing the payload shape outright.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,44 @@
@ManyToMany(mappedBy = "users")
private Set<GroupInfosEntity> groups;

private UserInfos toUserInfos(Integer maxAllowedCases,

Check warning on line 51 in src/main/java/org/gridsuite/useradmin/server/entity/UserInfosEntity.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Method has 14 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ7QkES_BRsh8bC5eZc0&open=AZ7QkES_BRsh8bC5eZc0&pullRequest=102
Integer numberCasesUsed,
Integer maxAllowedBuilds) {
Integer maxAllowedBuilds,
Integer maxAllowedLoadflow,
Integer maxAllowedSecurity,
Integer maxAllowedSensitivity,
Integer maxAllowedShortCircuit,
Integer maxAllowedVoltageInit,
Integer maxAllowedPccMin,
Integer maxAllowedStateEstimation,
Integer maxAllowedBalanceAdjustement,
Integer maxAllowedDynamicSimulation,
Integer maxAllowedDynamicSecurity,
Integer maxAllowedDynamicMargin
) {
String profileName = getProfile() == null ? null : getProfile().getName();
Set<String> groupNames = getGroups() == null ? null : getGroups().stream().map(GroupInfosEntity::getName).collect(Collectors.toSet());
return new UserInfos(getSub(), null, null, profileName, maxAllowedCases, numberCasesUsed, maxAllowedBuilds, groupNames);
return new UserInfos(getSub(), null, null, profileName, maxAllowedCases, numberCasesUsed, maxAllowedBuilds,
maxAllowedLoadflow, maxAllowedSecurity, maxAllowedSensitivity, maxAllowedShortCircuit, maxAllowedVoltageInit,
maxAllowedPccMin, maxAllowedStateEstimation, maxAllowedBalanceAdjustement, maxAllowedDynamicSimulation,
maxAllowedDynamicSecurity, maxAllowedDynamicMargin, groupNames);
}

public static UserInfos toDto(@Nullable final UserInfosEntity entity) {
return entity == null ? null : entity.toUserInfos(null, null, null);
return entity == null ? null : entity.toUserInfos(null, null, null,
null, null, null, null,
null, null, null, null,
null, null, null);
}

public static UserInfos toDtoWithDetail(@Nullable final UserInfosEntity entity, Integer maxAllowedCases, Integer numberCasesUsed, Integer maxAllowedBuilds) {
return entity == null ? null : entity.toUserInfos(maxAllowedCases, numberCasesUsed, maxAllowedBuilds);
public static UserInfos toDtoWithDetail(@Nullable final UserInfosEntity entity, Integer maxAllowedCases, Integer numberCasesUsed,

Check warning on line 81 in src/main/java/org/gridsuite/useradmin/server/entity/UserInfosEntity.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Method has 15 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Auser-admin-server&issues=AZ7QkES_BRsh8bC5eZc1&open=AZ7QkES_BRsh8bC5eZc1&pullRequest=102
Integer maxAllowedBuilds, Integer maxAllowedLoadflow, Integer maxAllowedSecurity,
Integer maxAllowedSensitivity, Integer maxAllowedShortCircuit, Integer maxAllowedVoltageInit,
Integer maxAllowedPccMin, Integer maxAllowedStateEstimation, Integer maxAllowedBalanceAdjustement,
Integer maxAllowedDynamicSimulation, Integer maxAllowedDynamicSecurity, Integer maxAllowedDynamicMargin) {
return entity == null ? null : entity.toUserInfos(maxAllowedCases, numberCasesUsed, maxAllowedBuilds,
maxAllowedLoadflow, maxAllowedSecurity, maxAllowedSensitivity, maxAllowedShortCircuit, maxAllowedVoltageInit,
maxAllowedPccMin, maxAllowedStateEstimation, maxAllowedBalanceAdjustement, maxAllowedDynamicSimulation,
maxAllowedDynamicSecurity, maxAllowedDynamicMargin);
}
}
Loading
Loading