6161import org .slf4j .Logger ;
6262import org .slf4j .LoggerFactory ;
6363import org .springframework .beans .factory .annotation .Autowired ;
64+ import org .springframework .beans .factory .annotation .Value ;
6465import org .springframework .context .annotation .Lazy ;
6566import org .springframework .data .domain .Pageable ;
6667import org .springframework .data .domain .Sort ;
@@ -165,6 +166,9 @@ public enum ReportType {
165166
166167 private final StudyService self ;
167168
169+ @ Value ("${study.enable-operation-quotas}" )
170+ private Boolean shouldCheckOperationQuotas = true ;
171+
168172 @ Autowired
169173 public StudyService (
170174 StudyRepository studyRepository ,
@@ -1009,6 +1013,7 @@ private void handleLoadflowRequest(StudyEntity studyEntity, UUID nodeUuid, UUID
10091013 new LoadFlowService .ParametersInfos (lfParametersUuid , withRatioTapChangers , isSecurityNode ), lfReportUuid , userId );
10101014 rootNetworkNodeInfoService .updateLoadflowResultUuid (nodeUuid , rootNetworkUuid , result , withRatioTapChangers );
10111015
1016+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (LOAD_FLOW ), result );
10121017 notificationService .emitStudyChanged (studyEntity .getId (), nodeUuid , rootNetworkUuid , LOAD_FLOW .getUpdateStatusType ());
10131018 notificationService .emitElementUpdated (studyEntity .getId (), userId );
10141019 }
@@ -1324,7 +1329,10 @@ public UUID runSecurityAnalysis(@NonNull UUID studyUuid, @NonNull UUID nodeUuid,
13241329 StudyEntity study = getStudy (studyUuid );
13251330 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
13261331
1327- return handleSecurityAnalysisRequest (study , nodeUuid , rootNetworkUuid , userId );
1332+ UUID result = handleSecurityAnalysisRequest (study , nodeUuid , rootNetworkUuid , userId );
1333+
1334+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (SECURITY_ANALYSIS ), result );
1335+ return result ;
13281336 }
13291337
13301338 private UUID handleSecurityAnalysisRequest (StudyEntity study , UUID nodeUuid , UUID rootNetworkUuid , String userId ) {
@@ -1737,20 +1745,25 @@ public void handleBuildSuccess(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUu
17371745 }
17381746
17391747 private long getAllowedBuildNodesUpToQuota (@ NonNull UUID studyUuid , @ NonNull UUID rootNetworkUuid , @ NonNull String userId ) {
1740- return userAdminService .getUserMaxAllowedBuilds (userId ).map (maxBuilds -> {
1748+ Map <OperationType , Integer > userMaxQuotas = userAdminService .getUserMaxQuota (userId );
1749+
1750+ return Optional .ofNullable (userMaxQuotas .get (OperationType .BUILD .name ())).map (maxBuilds -> {
17411751 long nbBuiltNodes = networkModificationTreeService .countBuiltNodes (studyUuid , rootNetworkUuid );
17421752 return maxBuilds - nbBuiltNodes ;
17431753 }).orElse (Long .MAX_VALUE );
17441754 }
17451755
17461756 public void assertNoMaxBuilds (@ NonNull UUID studyUuid , @ NonNull UUID rootNetworkUuid , @ NonNull String userId ) {
1757+ Map <OperationType , Integer > userMaxQuotas = userAdminService .getUserMaxQuota (userId );
1758+
17471759 // check restrictions on node builds number
1748- userAdminService .getUserMaxAllowedBuilds (userId ).ifPresent (maxBuilds -> {
1760+ Integer maxBuilds = userMaxQuotas .get (OperationType .BUILD .name ());
1761+ if (maxBuilds != null ) {
17491762 long nbBuiltNodes = networkModificationTreeService .countBuiltNodes (studyUuid , rootNetworkUuid );
17501763 if (nbBuiltNodes >= maxBuilds ) {
17511764 throw new StudyException (MAX_NODE_BUILDS_EXCEEDED , "max allowed built nodes reached" , Map .of ("limit" , maxBuilds ));
17521765 }
1753- });
1766+ }
17541767 }
17551768
17561769 @ Transactional
@@ -2601,7 +2614,10 @@ public UUID runSensitivityAnalysis(@NonNull UUID studyUuid, @NonNull UUID nodeUu
26012614 StudyEntity study = getStudy (studyUuid );
26022615 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
26032616
2604- return handleSensitivityAnalysisRequest (study , nodeUuid , rootNetworkUuid , userId );
2617+ UUID result = handleSensitivityAnalysisRequest (study , nodeUuid , rootNetworkUuid , userId );
2618+
2619+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (SENSITIVITY_ANALYSIS ), result );
2620+ return result ;
26052621 }
26062622
26072623 private UUID handleSensitivityAnalysisRequest (StudyEntity study , UUID nodeUuid , UUID rootNetworkUuid , String userId ) {
@@ -2634,7 +2650,10 @@ public UUID runShortCircuit(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid,
26342650 StudyEntity studyEntity = getStudy (studyUuid );
26352651 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
26362652
2637- return handleShortCircuitRequest (studyEntity , nodeUuid , rootNetworkUuid , busId , debug , userId );
2653+ UUID result = handleShortCircuitRequest (studyEntity , nodeUuid , rootNetworkUuid , busId , debug , userId );
2654+
2655+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (SHORT_CIRCUIT ), result );
2656+ return result ;
26382657 }
26392658
26402659 private UUID handleShortCircuitRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , Optional <String > busId , boolean debug , String userId ) {
@@ -2661,7 +2680,10 @@ public UUID runVoltageInit(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid,
26612680 StudyEntity studyEntity = getStudy (studyUuid );
26622681 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
26632682
2664- return handleVoltageInitRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
2683+ UUID result = handleVoltageInitRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
2684+
2685+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (VOLTAGE_INITIALIZATION ), result );
2686+ return result ;
26652687 }
26662688
26672689 private UUID handleVoltageInitRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , boolean debug , String userId ) {
@@ -2949,7 +2971,10 @@ public UUID runDynamicSimulation(@NonNull UUID studyUuid, @NonNull UUID nodeUuid
29492971 StudyEntity studyEntity = getStudy (studyUuid );
29502972 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
29512973
2952- return handleDynamicSimulationRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
2974+ UUID result = handleDynamicSimulationRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
2975+
2976+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (DYNAMIC_SIMULATION ), result );
2977+ return result ;
29532978 }
29542979
29552980 private UUID handleDynamicSimulationRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , boolean debug , String userId ) {
@@ -3021,7 +3046,10 @@ public UUID runDynamicSecurityAnalysis(@NonNull UUID studyUuid, @NonNull UUID no
30213046 StudyEntity studyEntity = getStudy (studyUuid );
30223047 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
30233048
3024- return handleDynamicSecurityAnalysisRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
3049+ UUID result = handleDynamicSecurityAnalysisRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
3050+
3051+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (DYNAMIC_SECURITY_ANALYSIS ), result );
3052+ return result ;
30253053 }
30263054
30273055 private UUID handleDynamicSecurityAnalysisRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , boolean debug , String userId ) {
@@ -3100,7 +3128,10 @@ public UUID runDynamicMarginCalculation(@NonNull UUID studyUuid, @NonNull UUID n
31003128 StudyEntity studyEntity = getStudy (studyUuid );
31013129 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
31023130
3103- return handleDynamicMarginCalculationRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
3131+ UUID result = handleDynamicMarginCalculationRequest (studyEntity , nodeUuid , rootNetworkUuid , debug , userId );
3132+
3133+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (DYNAMIC_MARGIN_CALCULATION ), result );
3134+ return result ;
31043135 }
31053136
31063137 private UUID handleDynamicMarginCalculationRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , boolean debug , String userId ) {
@@ -3322,15 +3353,21 @@ public UUID runStateEstimation(@NonNull UUID studyUuid, @NonNull UUID nodeUuid,
33223353 StudyEntity studyEntity = getStudy (studyUuid );
33233354 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
33243355
3325- return handleStateEstimationRequest (studyEntity , nodeUuid , rootNetworkUuid , userId , debug );
3356+ UUID result = handleStateEstimationRequest (studyEntity , nodeUuid , rootNetworkUuid , userId , debug );
3357+
3358+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (STATE_ESTIMATION ), result );
3359+ return result ;
33263360 }
33273361
33283362 @ Transactional
33293363 public UUID runPccMin (@ NonNull UUID studyUuid , @ NonNull UUID nodeUuid , @ NonNull UUID rootNetworkUuid , String userId ) {
33303364 StudyEntity studyEntity = getStudy (studyUuid );
33313365 networkModificationTreeService .blockNode (rootNetworkUuid , nodeUuid );
33323366
3333- return handlePccMinRequest (studyEntity , nodeUuid , rootNetworkUuid , userId );
3367+ UUID result = handlePccMinRequest (studyEntity , nodeUuid , rootNetworkUuid , userId );
3368+
3369+ userAdminService .startOperationWithQuota (userId , OperationType .mapFromComputationType (PCC_MIN ), result );
3370+ return result ;
33343371 }
33353372
33363373 private UUID handleStateEstimationRequest (StudyEntity studyEntity , UUID nodeUuid , UUID rootNetworkUuid , String userId , boolean debug ) {
@@ -3734,4 +3771,26 @@ public void invalidateStudyRootNetwork(UUID studyUuid, UUID rootNetworkUuid, Str
37343771 rootNetworkService .updateRootNetworkIndexationStatus (studyUuid , rootNetworkUuid , RootNetworkIndexationStatus .NOT_INDEXED );
37353772 notificationService .emitRootNetworksUpdated (studyUuid );
37363773 }
3774+
3775+ public void assertOnQuotasAvailability (ComputationType computationType , String userId ) {
3776+ if (!shouldCheckOperationQuotas ) {
3777+ return ;
3778+ }
3779+
3780+ Map <OperationType , Integer > userMaxQuotas = userAdminService .getUserMaxQuota (userId );
3781+ Map <OperationType , Integer > userCurrentQuotas = userAdminService .getUserCurrentQuota (userId );
3782+ OperationType quotaType = OperationType .mapFromComputationType (computationType );
3783+
3784+ Integer maxComputation = userMaxQuotas .get (quotaType .name ());
3785+ Integer currentComputation = userCurrentQuotas .get (quotaType .name ());
3786+
3787+ if (maxComputation != null && currentComputation != null && currentComputation >= maxComputation ) {
3788+ throw new StudyException (MAX_OPERATION_TYPE_EXCEEDED , "Max number of " + computationType .name () + " already reached" ,
3789+ Map .of ("maxComputation" , maxComputation , "currentComputation" , currentComputation ));
3790+ }
3791+ }
3792+
3793+ public Boolean getOperationQuotaStatus () {
3794+ return shouldCheckOperationQuotas ;
3795+ }
37373796}
0 commit comments