Commit ba1b000adbfc9253fd1fc3e984480a2dd7a60fb8

Authored by YevhenBondarenko
1 parent 627c0577

added maxCustomers, maxUsers, maxDashboards, maxRuleChains for TenantProfile

Showing 22 changed files with 180 additions and 3 deletions
... ... @@ -24,6 +24,10 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
24 24
25 25 private long maxDevices;
26 26 private long maxAssets;
  27 + private long maxCustomers;
  28 + private long maxUsers;
  29 + private long maxDashboards;
  30 + private long maxRuleChains;
27 31
28 32 private String transportTenantMsgRateLimit;
29 33 private String transportTenantTelemetryMsgRateLimit;
... ...
... ... @@ -332,7 +332,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
332 332 long maxAssets = profileConfiguration.getMaxAssets();
333 333 if (maxAssets > 0) {
334 334 long currentAssetsCount = assetDao.countAssetsByTenantId(tenantId);
335   - if (maxAssets >= currentAssetsCount) {
  335 + if (currentAssetsCount >= maxAssets) {
336 336 throw new DataValidationException("Can't create assets more then " + maxAssets);
337 337 }
338 338 }
... ...
... ... @@ -54,5 +54,7 @@ public interface CustomerDao extends Dao<Customer> {
54 54 * @return the optional customer object
55 55 */
56 56 Optional<Customer> findCustomersByTenantIdAndTitle(UUID tenantId, String title);
  57 +
  58 + Long countCustomersByTenantId(TenantId tenantId);
57 59
58 60 }
... ...
... ... @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
21 21 import lombok.extern.slf4j.Slf4j;
22 22 import org.apache.commons.lang3.StringUtils;
23 23 import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.context.annotation.Lazy;
24 25 import org.springframework.stereotype.Service;
25 26 import org.thingsboard.server.common.data.Customer;
26 27 import org.thingsboard.server.common.data.Tenant;
... ... @@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
28 29 import org.thingsboard.server.common.data.id.TenantId;
29 30 import org.thingsboard.server.common.data.page.PageData;
30 31 import org.thingsboard.server.common.data.page.PageLink;
  32 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
31 33 import org.thingsboard.server.dao.asset.AssetService;
32 34 import org.thingsboard.server.dao.dashboard.DashboardService;
33 35 import org.thingsboard.server.dao.device.DeviceService;
... ... @@ -38,6 +40,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
38 40 import org.thingsboard.server.dao.service.DataValidator;
39 41 import org.thingsboard.server.dao.service.PaginatedRemover;
40 42 import org.thingsboard.server.dao.service.Validator;
  43 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
41 44 import org.thingsboard.server.dao.tenant.TenantDao;
42 45 import org.thingsboard.server.dao.user.UserService;
43 46
... ... @@ -75,6 +78,10 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
75 78 @Autowired
76 79 private DashboardService dashboardService;
77 80
  81 + @Autowired
  82 + @Lazy
  83 + private TbTenantProfileCache tenantProfileCache;
  84 +
78 85 @Override
79 86 public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
80 87 log.trace("Executing findCustomerById [{}]", customerId);
... ... @@ -162,6 +169,15 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
162 169
163 170 @Override
164 171 protected void validateCreate(TenantId tenantId, Customer customer) {
  172 + DefaultTenantProfileConfiguration profileConfiguration =
  173 + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
  174 + long maxCustomers = profileConfiguration.getMaxCustomers();
  175 + if (maxCustomers > 0) {
  176 + long currentCustomersCount = customerDao.countCustomersByTenantId(tenantId);
  177 + if (currentCustomersCount >= maxCustomers) {
  178 + throw new DataValidationException("Can't create customers more then " + maxCustomers);
  179 + }
  180 + }
165 181 customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent(
166 182 c -> {
167 183 throw new DataValidationException("Customer with such title already exists!");
... ...
... ... @@ -32,4 +32,5 @@ public interface DashboardDao extends Dao<Dashboard> {
32 32 */
33 33 Dashboard save(TenantId tenantId, Dashboard dashboard);
34 34
  35 + Long countDashboardsByTenantId(TenantId tenantId);
35 36 }
... ...
... ... @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.apache.commons.lang3.StringUtils;
21 21 import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.context.annotation.Lazy;
22 23 import org.springframework.stereotype.Service;
23 24 import org.thingsboard.server.common.data.Customer;
24 25 import org.thingsboard.server.common.data.Dashboard;
... ... @@ -31,12 +32,14 @@ import org.thingsboard.server.common.data.page.PageData;
31 32 import org.thingsboard.server.common.data.page.PageLink;
32 33 import org.thingsboard.server.common.data.relation.EntityRelation;
33 34 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  35 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
34 36 import org.thingsboard.server.dao.customer.CustomerDao;
35 37 import org.thingsboard.server.dao.entity.AbstractEntityService;
36 38 import org.thingsboard.server.dao.exception.DataValidationException;
37 39 import org.thingsboard.server.dao.service.DataValidator;
38 40 import org.thingsboard.server.dao.service.PaginatedRemover;
39 41 import org.thingsboard.server.dao.service.Validator;
  42 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
40 43 import org.thingsboard.server.dao.tenant.TenantDao;
41 44
42 45 import java.util.concurrent.ExecutionException;
... ... @@ -61,6 +64,10 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
61 64 @Autowired
62 65 private CustomerDao customerDao;
63 66
  67 + @Autowired
  68 + @Lazy
  69 + private TbTenantProfileCache tenantProfileCache;
  70 +
64 71 @Override
65 72 public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) {
66 73 log.trace("Executing findDashboardById [{}]", dashboardId);
... ... @@ -215,6 +222,19 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
215 222 private DataValidator<Dashboard> dashboardValidator =
216 223 new DataValidator<Dashboard>() {
217 224 @Override
  225 + protected void validateCreate(TenantId tenantId, Dashboard data) {
  226 + DefaultTenantProfileConfiguration profileConfiguration =
  227 + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
  228 + long maxDashboards = profileConfiguration.getMaxDashboards();
  229 + if (maxDashboards > 0) {
  230 + long currentDashboardsCount = dashboardDao.countDashboardsByTenantId(tenantId);
  231 + if (currentDashboardsCount >= maxDashboards) {
  232 + throw new DataValidationException("Can't create dashboards more then " + maxDashboards);
  233 + }
  234 + }
  235 + }
  236 +
  237 + @Override
218 238 protected void validateDataImpl(TenantId tenantId, Dashboard dashboard) {
219 239 if (StringUtils.isEmpty(dashboard.getTitle())) {
220 240 throw new DataValidationException("Dashboard title should be specified!");
... ...
... ... @@ -532,7 +532,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
532 532 long maxDevices = profileConfiguration.getMaxDevices();
533 533 if (maxDevices > 0) {
534 534 long currentDevicesCount = deviceDao.countDevicesByTenantId(tenantId);
535   - if (maxDevices >= currentDevicesCount) {
  535 + if (currentDevicesCount >= maxDevices) {
536 536 throw new DataValidationException("Can't create devices more then " + maxDevices);
537 537 }
538 538 }
... ...
... ... @@ -24,6 +24,7 @@ import org.apache.commons.collections.CollectionUtils;
24 24 import org.apache.commons.lang3.StringUtils;
25 25 import org.hibernate.exception.ConstraintViolationException;
26 26 import org.springframework.beans.factory.annotation.Autowired;
  27 +import org.springframework.context.annotation.Lazy;
27 28 import org.springframework.stereotype.Service;
28 29 import org.thingsboard.server.common.data.BaseData;
29 30 import org.thingsboard.server.common.data.EntityType;
... ... @@ -44,11 +45,13 @@ import org.thingsboard.server.common.data.rule.RuleChainData;
44 45 import org.thingsboard.server.common.data.rule.RuleChainImportResult;
45 46 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
46 47 import org.thingsboard.server.common.data.rule.RuleNode;
  48 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
47 49 import org.thingsboard.server.dao.entity.AbstractEntityService;
48 50 import org.thingsboard.server.dao.exception.DataValidationException;
49 51 import org.thingsboard.server.dao.service.DataValidator;
50 52 import org.thingsboard.server.dao.service.PaginatedRemover;
51 53 import org.thingsboard.server.dao.service.Validator;
  54 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
52 55 import org.thingsboard.server.dao.tenant.TenantDao;
53 56
54 57 import java.util.ArrayList;
... ... @@ -81,6 +84,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
81 84 @Autowired
82 85 private TenantDao tenantDao;
83 86
  87 + @Autowired
  88 + @Lazy
  89 + private TbTenantProfileCache tenantProfileCache;
  90 +
84 91 @Override
85 92 public RuleChain saveRuleChain(RuleChain ruleChain) {
86 93 ruleChainValidator.validate(ruleChain, RuleChain::getTenantId);
... ... @@ -581,6 +588,19 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
581 588 private DataValidator<RuleChain> ruleChainValidator =
582 589 new DataValidator<RuleChain>() {
583 590 @Override
  591 + protected void validateCreate(TenantId tenantId, RuleChain data) {
  592 + DefaultTenantProfileConfiguration profileConfiguration =
  593 + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
  594 + long maxRuleChains = profileConfiguration.getMaxRuleChains();
  595 + if (maxRuleChains > 0) {
  596 + long currentRuleChainsCount = ruleChainDao.countRuleChainsByTenantId(tenantId);
  597 + if (currentRuleChainsCount >= maxRuleChains) {
  598 + throw new DataValidationException("Can't create rule chains more then " + maxRuleChains);
  599 + }
  600 + }
  601 + }
  602 +
  603 + @Override
584 604 protected void validateDataImpl(TenantId tenantId, RuleChain ruleChain) {
585 605 if (StringUtils.isEmpty(ruleChain.getName())) {
586 606 throw new DataValidationException("Rule chain name should be specified!.");
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.dao.rule;
17 17
  18 +import org.thingsboard.server.common.data.id.TenantId;
18 19 import org.thingsboard.server.common.data.page.PageData;
19 20 import org.thingsboard.server.common.data.page.PageLink;
20 21 import org.thingsboard.server.common.data.rule.RuleChain;
... ... @@ -36,4 +37,5 @@ public interface RuleChainDao extends Dao<RuleChain> {
36 37 */
37 38 PageData<RuleChain> findRuleChainsByTenantId(UUID tenantId, PageLink pageLink);
38 39
  40 + Long countRuleChainsByTenantId(TenantId tenantId);
39 41 }
... ...
... ... @@ -37,4 +37,5 @@ public interface CustomerRepository extends PagingAndSortingRepository<CustomerE
37 37
38 38 CustomerEntity findByTenantIdAndTitle(UUID tenantId, String title);
39 39
  40 + Long countByTenantId(UUID tenantId);
40 41 }
... ...
... ... @@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
19 19 import org.springframework.data.repository.CrudRepository;
20 20 import org.springframework.stereotype.Component;
21 21 import org.thingsboard.server.common.data.Customer;
  22 +import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.common.data.page.PageData;
23 24 import org.thingsboard.server.common.data.page.PageLink;
24 25 import org.thingsboard.server.dao.DaoUtil;
... ... @@ -62,4 +63,9 @@ public class JpaCustomerDao extends JpaAbstractSearchTextDao<CustomerEntity, Cus
62 63 Customer customer = DaoUtil.getData(customerRepository.findByTenantIdAndTitle(tenantId, title));
63 64 return Optional.ofNullable(customer);
64 65 }
  66 +
  67 + @Override
  68 + public Long countCustomersByTenantId(TenantId tenantId) {
  69 + return customerRepository.countByTenantId(tenantId.getId());
  70 + }
65 71 }
... ...
... ... @@ -24,4 +24,6 @@ import java.util.UUID;
24 24 * Created by Valerii Sosliuk on 5/6/2017.
25 25 */
26 26 public interface DashboardRepository extends CrudRepository<DashboardEntity, UUID> {
  27 +
  28 + Long countByTenantId(UUID tenantId);
27 29 }
... ...
... ... @@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
19 19 import org.springframework.data.repository.CrudRepository;
20 20 import org.springframework.stereotype.Component;
21 21 import org.thingsboard.server.common.data.Dashboard;
  22 +import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.dao.dashboard.DashboardDao;
23 24 import org.thingsboard.server.dao.model.sql.DashboardEntity;
24 25 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
... ... @@ -43,4 +44,9 @@ public class JpaDashboardDao extends JpaAbstractSearchTextDao<DashboardEntity, D
43 44 protected CrudRepository<DashboardEntity, UUID> getCrudRepository() {
44 45 return dashboardRepository;
45 46 }
  47 +
  48 + @Override
  49 + public Long countDashboardsByTenantId(TenantId tenantId) {
  50 + return dashboardRepository.countByTenantId(tenantId.getId());
  51 + }
46 52 }
... ...
... ... @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
19 19 import org.springframework.beans.factory.annotation.Autowired;
20 20 import org.springframework.data.repository.CrudRepository;
21 21 import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.common.data.page.PageData;
23 24 import org.thingsboard.server.common.data.page.PageLink;
24 25 import org.thingsboard.server.common.data.rule.RuleChain;
... ... @@ -56,4 +57,8 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
56 57 DaoUtil.toPageable(pageLink)));
57 58 }
58 59
  60 + @Override
  61 + public Long countRuleChainsByTenantId(TenantId tenantId) {
  62 + return ruleChainRepository.countByTenantId(tenantId.getId());
  63 + }
59 64 }
... ...
... ... @@ -32,4 +32,5 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
32 32 @Param("searchText") String searchText,
33 33 Pageable pageable);
34 34
  35 + Long countByTenantId(UUID tenantId);
35 36 }
... ...
... ... @@ -91,4 +91,9 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
91 91 DaoUtil.toPageable(pageLink)));
92 92
93 93 }
  94 +
  95 + @Override
  96 + public Long countUsersByTenantId(TenantId tenantId) {
  97 + return userRepository.countByTenantId(tenantId.getId());
  98 + }
94 99 }
... ...
... ... @@ -47,4 +47,5 @@ public interface UserRepository extends PagingAndSortingRepository<UserEntity, U
47 47 @Param("searchText") String searchText,
48 48 Pageable pageable);
49 49
  50 + Long countByTenantId(UUID tenantId);
50 51 }
... ...
... ... @@ -68,5 +68,6 @@ public interface UserDao extends Dao<User> {
68 68 * @return the list of user entities
69 69 */
70 70 PageData<User> findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink);
71   -
  71 +
  72 + Long countUsersByTenantId(TenantId tenantId);
72 73 }
... ...
... ... @@ -24,6 +24,7 @@ import org.apache.commons.lang3.RandomStringUtils;
24 24 import org.apache.commons.lang3.StringUtils;
25 25 import org.springframework.beans.factory.annotation.Autowired;
26 26 import org.springframework.beans.factory.annotation.Value;
  27 +import org.springframework.context.annotation.Lazy;
27 28 import org.springframework.stereotype.Service;
28 29 import org.thingsboard.server.common.data.Customer;
29 30 import org.thingsboard.server.common.data.Tenant;
... ... @@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.page.PageData;
36 37 import org.thingsboard.server.common.data.page.PageLink;
37 38 import org.thingsboard.server.common.data.security.Authority;
38 39 import org.thingsboard.server.common.data.security.UserCredentials;
  40 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
39 41 import org.thingsboard.server.dao.customer.CustomerDao;
40 42 import org.thingsboard.server.dao.entity.AbstractEntityService;
41 43 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -43,6 +45,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
43 45 import org.thingsboard.server.dao.model.ModelConstants;
44 46 import org.thingsboard.server.dao.service.DataValidator;
45 47 import org.thingsboard.server.dao.service.PaginatedRemover;
  48 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
46 49 import org.thingsboard.server.dao.tenant.TenantDao;
47 50
48 51 import java.util.HashMap;
... ... @@ -84,6 +87,10 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
84 87 @Autowired
85 88 private CustomerDao customerDao;
86 89
  90 + @Autowired
  91 + @Lazy
  92 + private TbTenantProfileCache tenantProfileCache;
  93 +
87 94 @Override
88 95 public User findUserByEmail(TenantId tenantId, String email) {
89 96 log.trace("Executing findUserByEmail [{}]", email);
... ... @@ -365,6 +372,19 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
365 372 private DataValidator<User> userValidator =
366 373 new DataValidator<User>() {
367 374 @Override
  375 + protected void validateCreate(TenantId tenantId, User data) {
  376 + DefaultTenantProfileConfiguration profileConfiguration =
  377 + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
  378 + long maxUsers = profileConfiguration.getMaxUsers();
  379 + if (maxUsers > 0) {
  380 + long currentUsersCount = userDao.countUsersByTenantId(tenantId);
  381 + if (currentUsersCount >= maxUsers) {
  382 + throw new DataValidationException("Can't create users more then " + maxUsers);
  383 + }
  384 + }
  385 + }
  386 +
  387 + @Override
368 388 protected void validateDataImpl(TenantId requestTenantId, User user) {
369 389 if (StringUtils.isEmpty(user.getEmail())) {
370 390 throw new DataValidationException("User email should be specified!");
... ...
... ... @@ -41,6 +41,54 @@
41 41 </mat-error>
42 42 </mat-form-field>
43 43 <mat-form-field class="mat-block">
  44 + <mat-label translate>tenant-profile.maximum-customers</mat-label>
  45 + <input matInput required min="0" step="1"
  46 + formControlName="maxCustomers"
  47 + type="number">
  48 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxCustomers').hasError('required')">
  49 + {{ 'tenant-profile.maximum-customers-required' | translate}}
  50 + </mat-error>
  51 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxCustomers').hasError('min')">
  52 + {{ 'tenant-profile.maximum-customers-range' | translate}}
  53 + </mat-error>
  54 + </mat-form-field>
  55 + <mat-form-field class="mat-block">
  56 + <mat-label translate>tenant-profile.maximum-users</mat-label>
  57 + <input matInput required min="0" step="1"
  58 + formControlName="maxUsers"
  59 + type="number">
  60 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxUsers').hasError('required')">
  61 + {{ 'tenant-profile.maximum-users-required' | translate}}
  62 + </mat-error>
  63 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxUsers').hasError('min')">
  64 + {{ 'tenant-profile.maximum-users-range' | translate}}
  65 + </mat-error>
  66 + </mat-form-field>
  67 + <mat-form-field class="mat-block">
  68 + <mat-label translate>tenant-profile.maximum-dashboards</mat-label>
  69 + <input matInput required min="0" step="1"
  70 + formControlName="maxDashboards"
  71 + type="number">
  72 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxDashboards').hasError('required')">
  73 + {{ 'tenant-profile.maximum-dashboards-required' | translate}}
  74 + </mat-error>
  75 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxDashboards').hasError('min')">
  76 + {{ 'tenant-profile.maximum-dashboards-range' | translate}}
  77 + </mat-error>
  78 + </mat-form-field>
  79 + <mat-form-field class="mat-block">
  80 + <mat-label translate>tenant-profile.maximum-rule-chains</mat-label>
  81 + <input matInput required min="0" step="1"
  82 + formControlName="maxRuleChains"
  83 + type="number">
  84 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxRuleChains').hasError('required')">
  85 + {{ 'tenant-profile.maximum-rule-chains-required' | translate}}
  86 + </mat-error>
  87 + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxRuleChains').hasError('min')">
  88 + {{ 'tenant-profile.maximum-rule-chains-range' | translate}}
  89 + </mat-error>
  90 + </mat-form-field>
  91 + <mat-form-field class="mat-block">
44 92 <mat-label translate>tenant-profile.max-transport-messages</mat-label>
45 93 <input matInput required min="0" step="1"
46 94 formControlName="maxTransportMessages"
... ...
... ... @@ -55,6 +55,10 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
55 55 this.defaultTenantProfileConfigurationFormGroup = this.fb.group({
56 56 maxDevices: [null, [Validators.required, Validators.min(0)]],
57 57 maxAssets: [null, [Validators.required, Validators.min(0)]],
  58 + maxCustomers: [null, [Validators.required, Validators.min(0)]],
  59 + maxUsers: [null, [Validators.required, Validators.min(0)]],
  60 + maxDashboards: [null, [Validators.required, Validators.min(0)]],
  61 + maxRuleChains: [null, [Validators.required, Validators.min(0)]],
58 62 transportTenantMsgRateLimit: [null, []],
59 63 transportTenantTelemetryMsgRateLimit: [null, []],
60 64 transportTenantTelemetryDataPointsRateLimit: [null, []],
... ...
... ... @@ -1946,6 +1946,18 @@
1946 1946 "maximum-assets": "Maximum number of assets (0 - unlimited)",
1947 1947 "maximum-assets-required": "Maximum number of assets is required.",
1948 1948 "maximum-assets-range": "Maximum number of assets can't be negative",
  1949 + "maximum-customers": "Maximum number of customers (0 - unlimited)",
  1950 + "maximum-customers-required": "Maximum number of customers is required.",
  1951 + "maximum-customers-range": "Maximum number of customers can't be negative",
  1952 + "maximum-users": "Maximum number of users (0 - unlimited)",
  1953 + "maximum-users-required": "Maximum number of users is required.",
  1954 + "maximum-users-range": "Maximum number of users can't be negative",
  1955 + "maximum-dashboards": "Maximum number of dashboards (0 - unlimited)",
  1956 + "maximum-dashboards-required": "Maximum number of dashboards is required.",
  1957 + "maximum-dashboards-range": "Maximum number of dashboards can't be negative",
  1958 + "maximum-rule-chains": "Maximum number of rule chains (0 - unlimited)",
  1959 + "maximum-rule-chains-required": "Maximum number of rule chains is required.",
  1960 + "maximum-rule-chains-range": "Maximum number of rule chains can't be negative",
1949 1961 "transport-tenant-msg-rate-limit": "Transport tenant messages rate limit.",
1950 1962 "transport-tenant-telemetry-msg-rate-limit": "Transport tenant telemetry messages rate limit.",
1951 1963 "transport-tenant-telemetry-data-points-rate-limit": "Transport tenant telemetry data points rate limit.",
... ...