Browse Source

Merge pull request #3717 from YevhenBondarenko/feature/tenant-profile

[WIP]added maxCustomers, maxUsers, maxDashboards, maxRuleChains for Tenant…
pull/3722/head
Igor Kulikov 6 years ago
committed by GitHub
parent
commit
35a2107944
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java
  2. 23
      dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java
  3. 5
      dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java
  4. 7
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  5. 5
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java
  6. 13
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  7. 4
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java
  8. 16
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  9. 5
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java
  10. 7
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  11. 5
      dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
  12. 15
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  13. 4
      dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java
  14. 15
      dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java
  15. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java
  16. 1
      dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java
  17. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java
  18. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardRepository.java
  19. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java
  20. 26
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java
  21. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java
  22. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java
  23. 1
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java
  24. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java
  25. 1
      dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java
  26. 8
      dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java
  27. 18
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  28. 48
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
  29. 4
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
  30. 12
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java

@ -24,6 +24,10 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
private long maxDevices;
private long maxAssets;
private long maxCustomers;
private long maxUsers;
private long maxDashboards;
private long maxRuleChains;
private String transportTenantMsgRateLimit;
private String transportTenantTelemetryMsgRateLimit;

23
dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao;
import org.thingsboard.server.common.data.id.TenantId;
public interface TenantEntityDao {
Long countByTenantId(TenantId tenantId);
}

5
dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List;
import java.util.Optional;
@ -32,7 +33,7 @@ import java.util.UUID;
* The Interface AssetDao.
*
*/
public interface AssetDao extends Dao<Asset> {
public interface AssetDao extends Dao<Asset>, TenantEntityDao {
/**
* Find asset info by id.
@ -166,6 +167,4 @@ public interface AssetDao extends Dao<Asset> {
*/
ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId);
Long countAssetsByTenantId(TenantId tenantId);
}

7
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -330,12 +330,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxAssets = profileConfiguration.getMaxAssets();
if (maxAssets > 0) {
long currentAssetsCount = assetDao.countAssetsByTenantId(tenantId);
if (maxAssets >= currentAssetsCount) {
throw new DataValidationException("Can't create assets more then " + maxAssets);
}
}
validateNumberOfEntitiesPerTenant(tenantId, assetDao, maxAssets, EntityType.ASSET);
}
@Override

5
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java

@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.Optional;
import java.util.UUID;
@ -27,7 +28,7 @@ import java.util.UUID;
/**
* The Interface CustomerDao.
*/
public interface CustomerDao extends Dao<Customer> {
public interface CustomerDao extends Dao<Customer>, TenantEntityDao {
/**
* Save or update customer object
@ -54,5 +55,5 @@ public interface CustomerDao extends Dao<Customer> {
* @return the optional customer object
*/
Optional<Customer> findCustomersByTenantIdAndTitle(UUID tenantId, String title);
}

13
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java

@ -21,13 +21,16 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
@ -38,6 +41,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.dao.user.UserService;
@ -75,6 +79,10 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Autowired
private DashboardService dashboardService;
@Autowired
@Lazy
private TbTenantProfileCache tenantProfileCache;
@Override
public Customer findCustomerById(TenantId tenantId, CustomerId customerId) {
log.trace("Executing findCustomerById [{}]", customerId);
@ -162,6 +170,11 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Override
protected void validateCreate(TenantId tenantId, Customer customer) {
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxCustomers = profileConfiguration.getMaxCustomers();
validateNumberOfEntitiesPerTenant(tenantId, customerDao, maxCustomers, EntityType.CUSTOMER);
customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent(
c -> {
throw new DataValidationException("Customer with such title already exists!");

4
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java

@ -18,11 +18,12 @@ package org.thingsboard.server.dao.dashboard;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
/**
* The Interface DashboardDao.
*/
public interface DashboardDao extends Dao<Dashboard> {
public interface DashboardDao extends Dao<Dashboard>, TenantEntityDao {
/**
* Save or update dashboard object
@ -31,5 +32,4 @@ public interface DashboardDao extends Dao<Dashboard> {
* @return saved dashboard object
*/
Dashboard save(TenantId tenantId, Dashboard dashboard);
}

16
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -19,10 +19,12 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
@ -31,12 +33,14 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.concurrent.ExecutionException;
@ -61,6 +65,10 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Autowired
private CustomerDao customerDao;
@Autowired
@Lazy
private TbTenantProfileCache tenantProfileCache;
@Override
public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) {
log.trace("Executing findDashboardById [{}]", dashboardId);
@ -214,6 +222,14 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
private DataValidator<Dashboard> dashboardValidator =
new DataValidator<Dashboard>() {
@Override
protected void validateCreate(TenantId tenantId, Dashboard data) {
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxDashboards = profileConfiguration.getMaxDashboards();
validateNumberOfEntitiesPerTenant(tenantId, dashboardDao, maxDashboards, EntityType.DASHBOARD);
}
@Override
protected void validateDataImpl(TenantId tenantId, Dashboard dashboard) {
if (StringUtils.isEmpty(dashboard.getTitle())) {

5
dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.List;
import java.util.Optional;
@ -32,7 +33,7 @@ import java.util.UUID;
* The Interface DeviceDao.
*
*/
public interface DeviceDao extends Dao<Device> {
public interface DeviceDao extends Dao<Device>, TenantEntityDao {
/**
* Find device info by id.
@ -203,8 +204,6 @@ public interface DeviceDao extends Dao<Device> {
*/
ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id);
Long countDevicesByTenantId(TenantId tenantId);
Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId);
/**

7
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -530,12 +530,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxDevices = profileConfiguration.getMaxDevices();
if (maxDevices > 0) {
long currentDevicesCount = deviceDao.countDevicesByTenantId(tenantId);
if (maxDevices >= currentDevicesCount) {
throw new DataValidationException("Can't create devices more then " + maxDevices);
}
}
validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE);
}
@Override

5
dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java

@ -37,12 +37,11 @@ public abstract class AbstractEntityService {
protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {
if (t instanceof ConstraintViolationException) {
return Optional.of ((ConstraintViolationException) t);
return Optional.of((ConstraintViolationException) t);
} else if (t.getCause() instanceof ConstraintViolationException) {
return Optional.of ((ConstraintViolationException) (t.getCause()));
return Optional.of((ConstraintViolationException) (t.getCause()));
} else {
return Optional.empty();
}
}
}

15
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -24,6 +24,7 @@ import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType;
@ -44,11 +45,13 @@ import org.thingsboard.server.common.data.rule.RuleChainData;
import org.thingsboard.server.common.data.rule.RuleChainImportResult;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.ArrayList;
@ -81,6 +84,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Autowired
private TenantDao tenantDao;
@Autowired
@Lazy
private TbTenantProfileCache tenantProfileCache;
@Override
public RuleChain saveRuleChain(RuleChain ruleChain) {
ruleChainValidator.validate(ruleChain, RuleChain::getTenantId);
@ -580,6 +587,14 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
private DataValidator<RuleChain> ruleChainValidator =
new DataValidator<RuleChain>() {
@Override
protected void validateCreate(TenantId tenantId, RuleChain data) {
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxRuleChains = profileConfiguration.getMaxRuleChains();
validateNumberOfEntitiesPerTenant(tenantId, ruleChainDao, maxRuleChains, EntityType.RULE_CHAIN);
}
@Override
protected void validateDataImpl(TenantId tenantId, RuleChain ruleChain) {
if (StringUtils.isEmpty(ruleChain.getName())) {

4
dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java

@ -19,13 +19,14 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.UUID;
/**
* Created by igor on 3/12/18.
*/
public interface RuleChainDao extends Dao<RuleChain> {
public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao {
/**
* Find rule chains by tenantId and page link.
@ -35,5 +36,4 @@ public interface RuleChainDao extends Dao<RuleChain> {
* @return the list of rule chain objects
*/
PageData<RuleChain> findRuleChainsByTenantId(UUID tenantId, PageLink pageLink);
}

15
dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java

@ -18,7 +18,9 @@ package org.thingsboard.server.dao.service;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.TenantEntityDao;
import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.HashSet;
@ -79,6 +81,19 @@ public abstract class DataValidator<D extends BaseData<?>> {
return emailMatcher.matches();
}
protected void validateNumberOfEntitiesPerTenant(TenantId tenantId,
TenantEntityDao tenantEntityDao,
long maxEntities,
EntityType entityType) {
if (maxEntities > 0) {
long currentEntitiesCount = tenantEntityDao.countByTenantId(tenantId);
if (currentEntitiesCount >= maxEntities) {
throw new DataValidationException(String.format("Can't create more then %d %ss!",
maxEntities, entityType.name().toLowerCase().replaceAll("_", " ")));
}
}
}
protected static void validateJsonStructure(JsonNode expectedNode, JsonNode actualNode) {
Set<String> expectedFields = new HashSet<>();
Iterator<String> fieldsIterator = expectedNode.fieldNames();

3
dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java

@ -178,8 +178,7 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> im
}
@Override
public Long countAssetsByTenantId(TenantId tenantId) {
public Long countByTenantId(TenantId tenantId) {
return assetRepository.countByTenantId(tenantId.getId());
}
}

1
dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java

@ -37,4 +37,5 @@ public interface CustomerRepository extends PagingAndSortingRepository<CustomerE
CustomerEntity findByTenantIdAndTitle(UUID tenantId, String title);
Long countByTenantId(UUID tenantId);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java

@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
@ -62,4 +63,9 @@ public class JpaCustomerDao extends JpaAbstractSearchTextDao<CustomerEntity, Cus
Customer customer = DaoUtil.getData(customerRepository.findByTenantIdAndTitle(tenantId, title));
return Optional.ofNullable(customer);
}
@Override
public Long countByTenantId(TenantId tenantId) {
return customerRepository.countByTenantId(tenantId.getId());
}
}

2
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardRepository.java

@ -24,4 +24,6 @@ import java.util.UUID;
* Created by Valerii Sosliuk on 5/6/2017.
*/
public interface DashboardRepository extends CrudRepository<DashboardEntity, UUID> {
Long countByTenantId(UUID tenantId);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java

@ -19,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.dashboard.DashboardDao;
import org.thingsboard.server.dao.model.sql.DashboardEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
@ -43,4 +44,9 @@ public class JpaDashboardDao extends JpaAbstractSearchTextDao<DashboardEntity, D
protected CrudRepository<DashboardEntity, UUID> getCrudRepository() {
return dashboardRepository;
}
@Override
public Long countByTenantId(TenantId tenantId) {
return dashboardRepository.countByTenantId(tenantId.getId());
}
}

26
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java

@ -50,9 +50,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
"AND d.deviceProfileId = :profileId " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<DeviceEntity> findByTenantIdAndProfileId(@Param("tenantId") UUID tenantId,
@Param("profileId") UUID profileId,
@Param("searchText") String searchText,
Pageable pageable);
@Param("profileId") UUID profileId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
"FROM DeviceEntity d " +
@ -62,9 +62,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
"AND d.customerId = :customerId " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<DeviceInfoEntity> findDeviceInfosByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId,
@Param("customerId") UUID customerId,
@Param("searchText") String searchText,
Pageable pageable);
@Param("customerId") UUID customerId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId")
Page<DeviceEntity> findByTenantId(@Param("tenantId") UUID tenantId,
@ -102,9 +102,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
"AND d.type = :type " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
Page<DeviceInfoEntity> findDeviceInfosByTenantIdAndType(@Param("tenantId") UUID tenantId,
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
"FROM DeviceEntity d " +
@ -137,10 +137,10 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
"AND d.type = :type " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
Page<DeviceInfoEntity> findDeviceInfosByTenantIdAndCustomerIdAndType(@Param("tenantId") UUID tenantId,
@Param("customerId") UUID customerId,
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("customerId") UUID customerId,
@Param("type") String type,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
"FROM DeviceEntity d " +

2
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java

@ -220,7 +220,7 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
}
@Override
public Long countDevicesByTenantId(TenantId tenantId) {
public Long countByTenantId(TenantId tenantId) {
return deviceRepository.countByTenantId(tenantId.getId());
}

5
dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java

@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -56,4 +57,8 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
DaoUtil.toPageable(pageLink)));
}
@Override
public Long countByTenantId(TenantId tenantId) {
return ruleChainRepository.countByTenantId(tenantId.getId());
}
}

1
dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java

@ -32,4 +32,5 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
@Param("searchText") String searchText,
Pageable pageable);
Long countByTenantId(UUID tenantId);
}

5
dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java

@ -91,4 +91,9 @@ public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> imple
DaoUtil.toPageable(pageLink)));
}
@Override
public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId());
}
}

1
dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java

@ -47,4 +47,5 @@ public interface UserRepository extends PagingAndSortingRepository<UserEntity, U
@Param("searchText") String searchText,
Pageable pageable);
Long countByTenantId(UUID tenantId);
}

8
dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java

@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao;
import java.util.UUID;
public interface UserDao extends Dao<User> {
public interface UserDao extends Dao<User>, TenantEntityDao {
/**
* Save or update user object
@ -49,7 +50,7 @@ public interface UserDao extends Dao<User> {
* @return the list of user entities
*/
PageData<User> findByTenantId(UUID tenantId, PageLink pageLink);
/**
* Find tenant admin users by tenantId and page link.
*
@ -58,7 +59,7 @@ public interface UserDao extends Dao<User> {
* @return the list of user entities
*/
PageData<User> findTenantAdmins(UUID tenantId, PageLink pageLink);
/**
* Find customer users by tenantId, customerId and page link.
*
@ -68,5 +69,4 @@ public interface UserDao extends Dao<User> {
* @return the list of user entities
*/
PageData<User> findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink);
}

18
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -24,8 +24,10 @@ import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
@ -36,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -43,6 +46,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.HashMap;
@ -84,6 +88,10 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
@Autowired
private CustomerDao customerDao;
@Autowired
@Lazy
private TbTenantProfileCache tenantProfileCache;
@Override
public User findUserByEmail(TenantId tenantId, String email) {
log.trace("Executing findUserByEmail [{}]", email);
@ -364,6 +372,16 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
private DataValidator<User> userValidator =
new DataValidator<User>() {
@Override
protected void validateCreate(TenantId tenantId, User user) {
if (!user.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
DefaultTenantProfileConfiguration profileConfiguration =
(DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
long maxUsers = profileConfiguration.getMaxUsers();
validateNumberOfEntitiesPerTenant(tenantId, userDao, maxUsers, EntityType.USER);
}
}
@Override
protected void validateDataImpl(TenantId requestTenantId, User user) {
if (StringUtils.isEmpty(user.getEmail())) {

48
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html

@ -40,6 +40,54 @@
{{ 'tenant-profile.maximum-assets-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-customers</mat-label>
<input matInput required min="0" step="1"
formControlName="maxCustomers"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxCustomers').hasError('required')">
{{ 'tenant-profile.maximum-customers-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxCustomers').hasError('min')">
{{ 'tenant-profile.maximum-customers-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-users</mat-label>
<input matInput required min="0" step="1"
formControlName="maxUsers"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxUsers').hasError('required')">
{{ 'tenant-profile.maximum-users-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxUsers').hasError('min')">
{{ 'tenant-profile.maximum-users-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-dashboards</mat-label>
<input matInput required min="0" step="1"
formControlName="maxDashboards"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxDashboards').hasError('required')">
{{ 'tenant-profile.maximum-dashboards-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxDashboards').hasError('min')">
{{ 'tenant-profile.maximum-dashboards-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.maximum-rule-chains</mat-label>
<input matInput required min="0" step="1"
formControlName="maxRuleChains"
type="number">
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxRuleChains').hasError('required')">
{{ 'tenant-profile.maximum-rule-chains-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('maxRuleChains').hasError('min')">
{{ 'tenant-profile.maximum-rule-chains-range' | translate}}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>tenant-profile.max-transport-messages</mat-label>
<input matInput required min="0" step="1"

4
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts

@ -55,6 +55,10 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
this.defaultTenantProfileConfigurationFormGroup = this.fb.group({
maxDevices: [null, [Validators.required, Validators.min(0)]],
maxAssets: [null, [Validators.required, Validators.min(0)]],
maxCustomers: [null, [Validators.required, Validators.min(0)]],
maxUsers: [null, [Validators.required, Validators.min(0)]],
maxDashboards: [null, [Validators.required, Validators.min(0)]],
maxRuleChains: [null, [Validators.required, Validators.min(0)]],
transportTenantMsgRateLimit: [null, []],
transportTenantTelemetryMsgRateLimit: [null, []],
transportTenantTelemetryDataPointsRateLimit: [null, []],

12
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1946,6 +1946,18 @@
"maximum-assets": "Maximum number of assets (0 - unlimited)",
"maximum-assets-required": "Maximum number of assets is required.",
"maximum-assets-range": "Maximum number of assets can't be negative",
"maximum-customers": "Maximum number of customers (0 - unlimited)",
"maximum-customers-required": "Maximum number of customers is required.",
"maximum-customers-range": "Maximum number of customers can't be negative",
"maximum-users": "Maximum number of users (0 - unlimited)",
"maximum-users-required": "Maximum number of users is required.",
"maximum-users-range": "Maximum number of users can't be negative",
"maximum-dashboards": "Maximum number of dashboards (0 - unlimited)",
"maximum-dashboards-required": "Maximum number of dashboards is required.",
"maximum-dashboards-range": "Maximum number of dashboards can't be negative",
"maximum-rule-chains": "Maximum number of rule chains (0 - unlimited)",
"maximum-rule-chains-required": "Maximum number of rule chains is required.",
"maximum-rule-chains-range": "Maximum number of rule chains can't be negative",
"transport-tenant-msg-rate-limit": "Transport tenant messages rate limit.",
"transport-tenant-telemetry-msg-rate-limit": "Transport tenant telemetry messages rate limit.",
"transport-tenant-telemetry-data-points-rate-limit": "Transport tenant telemetry data points rate limit.",

Loading…
Cancel
Save