diff --git a/backend/core/src/main/java/org/opencdmp/commons/enums/UsageLimitTargetMetric.java b/backend/core/src/main/java/org/opencdmp/commons/enums/UsageLimitTargetMetric.java index 5e4aaddd1..4699559ff 100644 --- a/backend/core/src/main/java/org/opencdmp/commons/enums/UsageLimitTargetMetric.java +++ b/backend/core/src/main/java/org/opencdmp/commons/enums/UsageLimitTargetMetric.java @@ -21,7 +21,14 @@ public enum UsageLimitTargetMetric implements DatabaseEnum { FILE_TRANSFORMER_EXPORT_DESCRIPTIONS_EXECUTION_COUNT(TargetMetrics.FileTransformerExportDescriptionExecutionCount), FILE_TRANSFORMER_EXPORT_DESCRIPTIONS_EXECUTION_COUNT_FOR(TargetMetrics.FileTransformerExportDescriptionExecutionCountFor_), FILE_TRANSFORMER_IMPORT_PLAN_EXECUTION_COUNT(TargetMetrics.FileTransformerImportPlanExecutionCount), - FILE_TRANSFORMER_IMPORT_PLAN_EXECUTION_COUNT_FOR(TargetMetrics.FileTransformerImportPlanExecutionCountFor_); + FILE_TRANSFORMER_IMPORT_PLAN_EXECUTION_COUNT_FOR(TargetMetrics.FileTransformerImportPlanExecutionCountFor_), + EXPORT_PLAN_XML_EXECUTION_COUNT(TargetMetrics.ExportPlanXMLExecutionCount), + EXPORT_DESCRIPTION_XML_EXECUTION_COUNT(TargetMetrics.ExportDescriptionXMLExecutionCount), + EXPORT_BLUEPRINT_XML_EXECUTION_COUNT(TargetMetrics.ExportBlueprintXMLExecutionCount), + EXPORT_DESCRIPTION_TEMPLATE_XML_EXECUTION_COUNT(TargetMetrics.ExportDescriptionTemplateXMLExecutionCount), + IMPORT_PLAN_XML_EXECUTION_COUNT(TargetMetrics.ImportPlanXMLExecutionCount), + IMPORT_BLUEPRINT_XML_EXECUTION_COUNT(TargetMetrics.ImportBlueprintXMLExecutionCount), + IMPORT_DESCRIPTION_TEMPLATE_XML_EXECUTION_COUNT(TargetMetrics.ImportDescriptionTemplateXMLExecutionCount); private final String value; public static class TargetMetrics { @@ -41,6 +48,13 @@ public enum UsageLimitTargetMetric implements DatabaseEnum { public static final String FileTransformerExportDescriptionExecutionCountFor_ = "file_transformer_export_description_execution_count_for_"; public static final String FileTransformerImportPlanExecutionCount = "file_transformer_import_plan_execution_count"; public static final String FileTransformerImportPlanExecutionCountFor_ = "file_transformer_import_plan_execution_count_for_"; + public static final String ExportPlanXMLExecutionCount = "export_plan_xml_execution_count"; + public static final String ExportDescriptionXMLExecutionCount = "export_description_xml_execution_count"; + public static final String ExportBlueprintXMLExecutionCount = "export_blueprint_xml_execution_count"; + public static final String ExportDescriptionTemplateXMLExecutionCount = "export_description_template_xml_execution_count"; + public static final String ImportPlanXMLExecutionCount = "import_plan_xml_execution_count"; + public static final String ImportBlueprintXMLExecutionCount = "import_blueprint_xml_execution_count"; + public static final String ImportDescriptionTemplateXMLExecutionCount = "import_description_template_xml_execution_count"; } UsageLimitTargetMetric(String value) { diff --git a/backend/core/src/main/java/org/opencdmp/model/deleter/TenantUserDeleter.java b/backend/core/src/main/java/org/opencdmp/model/deleter/TenantUserDeleter.java index 209666bf4..8357c5f93 100644 --- a/backend/core/src/main/java/org/opencdmp/model/deleter/TenantUserDeleter.java +++ b/backend/core/src/main/java/org/opencdmp/model/deleter/TenantUserDeleter.java @@ -5,11 +5,13 @@ import gr.cite.tools.data.query.QueryFactory; import gr.cite.tools.logging.LoggerService; import gr.cite.tools.logging.MapLogEntry; import org.opencdmp.commons.enums.IsActive; +import org.opencdmp.commons.enums.UsageLimitTargetMetric; import org.opencdmp.data.TenantEntityManager; import org.opencdmp.data.TenantUserEntity; import org.opencdmp.event.EventBroker; import org.opencdmp.event.UserRemovedFromTenantEvent; import org.opencdmp.query.TenantUserQuery; +import org.opencdmp.service.accounting.AccountingService; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -30,15 +32,17 @@ public class TenantUserDeleter implements Deleter { private final TenantEntityManager entityManager; private final QueryFactory queryFactory; private final EventBroker eventBroker; + private final AccountingService accountingService; @Autowired public TenantUserDeleter( TenantEntityManager entityManager, - QueryFactory queryFactory, EventBroker eventBroker - ) { + QueryFactory queryFactory, EventBroker eventBroker, + AccountingService accountingService) { this.entityManager = entityManager; this.queryFactory = queryFactory; this.eventBroker = eventBroker; + this.accountingService = accountingService; } public void deleteAndSaveByIds(List ids) throws InvalidApplicationException { @@ -70,6 +74,7 @@ public class TenantUserDeleter implements Deleter { this.entityManager.merge(item); logger.trace("updated item"); this.eventBroker.emit(new UserRemovedFromTenantEvent(item.getUserId(), item.getTenantId())); + this.accountingService.decrease(UsageLimitTargetMetric.USER_COUNT.getValue()); } } } diff --git a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java index 7fffedc50..dcfc6bbd0 100644 --- a/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/description/DescriptionServiceImpl.java @@ -1184,6 +1184,7 @@ public class DescriptionServiceImpl implements DescriptionService { if (data == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, Description.class.getSimpleName()}, LocaleContextHolder.getLocale())); String xml = this.xmlHandlingService.toXml(this.exportXmlEntity(data.getId(), false)); + this.accountingService.increase(UsageLimitTargetMetric.EXPORT_DESCRIPTION_XML_EXECUTION_COUNT.getValue()); return this.responseUtilsService.buildResponseFileFromText(xml, data.getLabel() + ".xml"); } diff --git a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java index 7a57c6977..d69176492 100644 --- a/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/descriptiontemplate/DescriptionTemplateServiceImpl.java @@ -729,6 +729,7 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic persist.setHash(this.conventionService.hashValue(latestVersionDescriptionTemplate.getUpdatedAt())); this.validatorFactory.validator(NewVersionDescriptionTemplatePersist.NewVersionDescriptionTemplatePersistValidator.class).validateForce(persist); + this.accountingService.increase(UsageLimitTargetMetric.IMPORT_DESCRIPTION_TEMPLATE_XML_EXECUTION_COUNT.getValue()); return this.createNewVersion(persist, fields); } } @@ -902,6 +903,7 @@ public class DescriptionTemplateServiceImpl implements DescriptionTemplateServic if (data == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, DescriptionTemplate.class.getSimpleName()}, LocaleContextHolder.getLocale())); String xml = this.xmlHandlingService.toXml(this.exportXmlEntity(id, false)); + this.accountingService.increase(UsageLimitTargetMetric.EXPORT_DESCRIPTION_TEMPLATE_XML_EXECUTION_COUNT.getValue()); return this.responseUtilsService.buildResponseFileFromText(xml, data.getLabel() + ".xml"); } diff --git a/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java index a749f92cd..ad7bd6a79 100644 --- a/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/plan/PlanServiceImpl.java @@ -1635,6 +1635,7 @@ public class PlanServiceImpl implements PlanService { if (data == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, Plan.class.getSimpleName()}, LocaleContextHolder.getLocale())); String xml = this.xmlHandlingService.toXml(this.exportXmlEntity(data.getId(), false)); + this.accountingService.increase(UsageLimitTargetMetric.EXPORT_PLAN_XML_EXECUTION_COUNT.getValue()); return this.responseUtilsService.buildResponseFileFromText(xml, data.getLabel() + ".xml"); } @@ -1863,6 +1864,8 @@ public class PlanServiceImpl implements PlanService { } } + this.accountingService.increase(UsageLimitTargetMetric.IMPORT_PLAN_XML_EXECUTION_COUNT.getValue()); + return plan; } diff --git a/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java index fd7dbac23..646efd20e 100644 --- a/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/planblueprint/PlanBlueprintServiceImpl.java @@ -490,6 +490,7 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { if (data == null) throw new MyNotFoundException(this.messageSource.getMessage("General_ItemNotFound", new Object[]{id, PlanBlueprint.class.getSimpleName()}, LocaleContextHolder.getLocale())); String xml = this.xmlHandlingService.toXml(this.getExportXmlEntity(id, false)); + this.accountingService.increase(UsageLimitTargetMetric.EXPORT_BLUEPRINT_XML_EXECUTION_COUNT.getValue()); return this.responseUtilsService.buildResponseFileFromText(xml, data.getLabel() + ".xml"); } @@ -674,6 +675,7 @@ public class PlanBlueprintServiceImpl implements PlanBlueprintService { persist.setHash(this.conventionService.hashValue(latestVersionPlanBlueprint.getUpdatedAt())); this.validatorFactory.validator(NewVersionPlanBlueprintPersist.NewVersionPlanBlueprintPersistValidator.class).validateForce(persist); + this.accountingService.increase(UsageLimitTargetMetric.IMPORT_BLUEPRINT_XML_EXECUTION_COUNT.getValue()); return this.createNewVersion(persist, fields); } } diff --git a/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java index 062d131fd..acd148961 100644 --- a/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/tenant/TenantServiceImpl.java @@ -21,6 +21,7 @@ import org.opencdmp.authorization.AuthorizationFlags; import org.opencdmp.authorization.ClaimNames; import org.opencdmp.authorization.Permission; import org.opencdmp.commons.enums.IsActive; +import org.opencdmp.commons.enums.UsageLimitTargetMetric; import org.opencdmp.commons.scope.tenant.TenantScope; import org.opencdmp.convention.ConventionService; import org.opencdmp.data.*; @@ -38,7 +39,9 @@ import org.opencdmp.model.persist.TenantPersist; import org.opencdmp.query.TenantQuery; import org.opencdmp.query.UserCredentialQuery; import org.opencdmp.query.UserRoleQuery; +import org.opencdmp.service.accounting.AccountingService; import org.opencdmp.service.keycloak.KeycloakService; +import org.opencdmp.service.usagelimit.UsageLimitService; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; @@ -83,17 +86,19 @@ public class TenantServiceImpl implements TenantService { private final CurrentPrincipalResolver currentPrincipalResolver; private final ClaimExtractor claimExtractor; private final EventBroker eventBroker; + private final UsageLimitService usageLimitService; + private final AccountingService accountingService; @Autowired public TenantServiceImpl( - TenantEntityManager entityManager, - AuthorizationService authorizationService, - DeleterFactory deleterFactory, - BuilderFactory builderFactory, - ConventionService conventionService, - MessageSource messageSource, - ErrorThesaurusProperties errors, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, KeycloakService keycloakService, AuthorizationConfiguration authorizationConfiguration, TenantScope tenantScope, QueryFactory queryFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractor claimExtractor, EventBroker eventBroker) { + TenantEntityManager entityManager, + AuthorizationService authorizationService, + DeleterFactory deleterFactory, + BuilderFactory builderFactory, + ConventionService conventionService, + MessageSource messageSource, + ErrorThesaurusProperties errors, TenantTouchedIntegrationEventHandler tenantTouchedIntegrationEventHandler, TenantRemovalIntegrationEventHandler tenantRemovalIntegrationEventHandler, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, KeycloakService keycloakService, AuthorizationConfiguration authorizationConfiguration, TenantScope tenantScope, QueryFactory queryFactory, CurrentPrincipalResolver currentPrincipalResolver, ClaimExtractor claimExtractor, EventBroker eventBroker, UsageLimitService usageLimitService, AccountingService accountingService) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; @@ -111,6 +116,8 @@ public class TenantServiceImpl implements TenantService { this.currentPrincipalResolver = currentPrincipalResolver; this.claimExtractor = claimExtractor; this.eventBroker = eventBroker; + this.usageLimitService = usageLimitService; + this.accountingService = accountingService; } @Override @@ -177,6 +184,7 @@ public class TenantServiceImpl implements TenantService { List keycloakIdsToAddToTenantGroup = new ArrayList<>(); for (UUID userId : existingItems.stream().map(UserRoleEntity::getUserId).distinct().toList()) { + this.usageLimitService.checkIncrease(UsageLimitTargetMetric.USER_COUNT); TenantUserEntity tenantUserEntity = new TenantUserEntity(); tenantUserEntity.setId(UUID.randomUUID()); tenantUserEntity.setUserId(userId); @@ -186,7 +194,8 @@ public class TenantServiceImpl implements TenantService { tenantUserEntity.setUpdatedAt(Instant.now()); this.entityManager.persist(tenantUserEntity); this.eventBroker.emit(new UserAddedToTenantEvent(tenantUserEntity.getUserId(), tenantUserEntity.getTenantId())); - + this.accountingService.increase(UsageLimitTargetMetric.USER_COUNT.getValue()); + UserCredentialEntity userCredential = userCredentialEntities.stream().filter(x-> !this.conventionService.isNullOrEmpty(x.getExternalId()) && x.getUserId().equals(userId)).findFirst().orElse(null); if (userCredential == null) continue; UserRoleEntity item = new UserRoleEntity(); diff --git a/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java b/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java index b900245b2..1175ca252 100644 --- a/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java +++ b/backend/core/src/main/java/org/opencdmp/service/user/UserServiceImpl.java @@ -60,9 +60,11 @@ import org.opencdmp.model.referencetype.ReferenceType; import org.opencdmp.model.user.User; import org.opencdmp.model.usercredential.UserCredential; import org.opencdmp.query.*; +import org.opencdmp.service.accounting.AccountingService; import org.opencdmp.service.actionconfirmation.ActionConfirmationService; import org.opencdmp.service.elastic.ElasticService; import org.opencdmp.service.keycloak.KeycloakService; +import org.opencdmp.service.usagelimit.UsageLimitService; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; @@ -114,6 +116,8 @@ public class UserServiceImpl implements UserService { private final AuthorizationConfiguration authorizationConfiguration; private final TenantScope tenantScope; private final AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler; + private final UsageLimitService usageLimitService; + private final AccountingService accountingService; @Autowired public UserServiceImpl( TenantEntityManager entityManager, @@ -126,7 +130,7 @@ public class UserServiceImpl implements UserService { EventBroker eventBroker, JsonHandlingService jsonHandlingService, XmlHandlingService xmlHandlingService, QueryFactory queryFactory, - UserScope userScope, KeycloakService keycloakService, ActionConfirmationService actionConfirmationService, NotificationProperties notificationProperties, NotifyIntegrationEventHandler eventHandler, ValidatorFactory validatorFactory, ElasticService elasticService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, UserRemovalIntegrationEventHandler userRemovalIntegrationEventHandler, AuthorizationConfiguration authorizationConfiguration, TenantScope tenantScope, AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler) { + UserScope userScope, KeycloakService keycloakService, ActionConfirmationService actionConfirmationService, NotificationProperties notificationProperties, NotifyIntegrationEventHandler eventHandler, ValidatorFactory validatorFactory, ElasticService elasticService, UserTouchedIntegrationEventHandler userTouchedIntegrationEventHandler, UserRemovalIntegrationEventHandler userRemovalIntegrationEventHandler, AuthorizationConfiguration authorizationConfiguration, TenantScope tenantScope, AnnotationEntityTouchedIntegrationEventHandler annotationEntityTouchedIntegrationEventHandler, UsageLimitService usageLimitService, AccountingService accountingService) { this.entityManager = entityManager; this.authorizationService = authorizationService; this.deleterFactory = deleterFactory; @@ -150,6 +154,8 @@ public class UserServiceImpl implements UserService { this.authorizationConfiguration = authorizationConfiguration; this.tenantScope = tenantScope; this.annotationEntityTouchedIntegrationEventHandler = annotationEntityTouchedIntegrationEventHandler; + this.usageLimitService = usageLimitService; + this.accountingService = accountingService; } //region persist @@ -410,6 +416,7 @@ public class UserServiceImpl implements UserService { } if (!hasTenantUser && !model.getRoles().isEmpty() && !this.tenantScope.isDefaultTenant()){ + this.usageLimitService.checkIncrease(UsageLimitTargetMetric.USER_COUNT); TenantUserEntity tenantUserEntity = new TenantUserEntity(); tenantUserEntity.setId(UUID.randomUUID()); tenantUserEntity.setUserId(userId); @@ -420,6 +427,7 @@ public class UserServiceImpl implements UserService { this.entityManager.persist(tenantUserEntity); this.eventBroker.emit(new UserAddedToTenantEvent(tenantUserEntity.getUserId(), tenantUserEntity.getTenantId())); + this.accountingService.increase(UsageLimitTargetMetric.USER_COUNT.getValue()); } this.entityManager.flush(); @@ -768,9 +776,11 @@ public class UserServiceImpl implements UserService { tenantUsersToDelete.add(userTenantUser); } else { this.eventBroker.emit(new UserRemovedFromTenantEvent(userTenantUser.getUserId(), userTenantUser.getTenantId())); + this.accountingService.decrease(UsageLimitTargetMetric.USER_COUNT.getValue()); userTenantUser.setUserId(newUser.getId()); this.entityManager.merge(userTenantUser); this.eventBroker.emit(new UserAddedToTenantEvent(userTenantUser.getUserId(), userTenantUser.getTenantId())); + this.accountingService.increase(UsageLimitTargetMetric.USER_COUNT.getValue()); } } this.deleterFactory.deleter(TenantUserDeleter.class).delete(tenantUsersToDelete); @@ -1053,15 +1063,19 @@ public class UserServiceImpl implements UserService { if (userCredential == null) throw new MyApplicationException(); if (tenant != null){ - TenantUserEntity tenantUserEntity = new TenantUserEntity(); - tenantUserEntity.setId(UUID.randomUUID()); - tenantUserEntity.setUserId(userId); - tenantUserEntity.setIsActive(IsActive.Active); - tenantUserEntity.setTenantId(tenant.getId()); - tenantUserEntity.setCreatedAt(Instant.now()); - tenantUserEntity.setUpdatedAt(Instant.now()); - this.entityManager.persist(tenantUserEntity); - this.eventBroker.emit(new UserAddedToTenantEvent(tenantUserEntity.getUserId(), tenantUserEntity.getTenantId())); + boolean hasTenantUser = this.queryFactory.query(TenantUserQuery.class).tenantIds(tenant.getId()).isActive(IsActive.Active).userIds(userId).count() > 0; + if (!hasTenantUser) { + TenantUserEntity tenantUserEntity = new TenantUserEntity(); + tenantUserEntity.setId(UUID.randomUUID()); + tenantUserEntity.setUserId(userId); + tenantUserEntity.setIsActive(IsActive.Active); + tenantUserEntity.setTenantId(tenant.getId()); + tenantUserEntity.setCreatedAt(Instant.now()); + tenantUserEntity.setUpdatedAt(Instant.now()); + this.entityManager.persist(tenantUserEntity); + this.eventBroker.emit(new UserAddedToTenantEvent(tenantUserEntity.getUserId(), tenantUserEntity.getTenantId())); + this.accountingService.increase(UsageLimitTargetMetric.USER_COUNT.getValue()); + } }