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