From 9531e891c85b662115f8abecf04d089f9383533d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 9 Nov 2020 17:49:05 +0200 Subject: [PATCH 01/37] added validation with maxDevices and maxAssets to deviceService and assetService --- .../server/actors/ActorSystemContext.java | 2 +- .../thingsboard/server/actors/app/AppActor.java | 3 +-- .../server/controller/BaseController.java | 3 +-- .../apiusage/DefaultTbApiUsageStateService.java | 2 +- .../queue/DefaultTbCoreConsumerService.java | 2 +- .../DefaultTbRuleEngineConsumerService.java | 2 +- .../queue/DefaultTenantRoutingInfoService.java | 3 +-- .../processing/AbstractConsumerService.java | 2 +- .../transport/DefaultTransportApiService.java | 2 +- .../server/dao/tenant}/TbTenantProfileCache.java | 2 +- .../thingsboard/server/dao/asset/AssetDao.java | 2 ++ .../server/dao/asset/BaseAssetService.java | 16 ++++++++++++++++ .../thingsboard/server/dao/device/DeviceDao.java | 2 ++ .../server/dao/device/DeviceServiceImpl.java | 16 ++++++++++++++++ .../server/dao/sql/asset/AssetRepository.java | 1 + .../server/dao/sql/asset/JpaAssetDao.java | 6 ++++++ .../server/dao/sql/device/DeviceRepository.java | 2 ++ .../server/dao/sql/device/JpaDeviceDao.java | 5 +++++ .../dao/tenant}/DefaultTbTenantProfileCache.java | 9 ++------- 19 files changed, 62 insertions(+), 20 deletions(-) rename {application/src/main/java/org/thingsboard/server/service/profile => common/dao-api/src/main/java/org/thingsboard/server/dao/tenant}/TbTenantProfileCache.java (95%) rename {application/src/main/java/org/thingsboard/server/service/profile => dao/src/main/java/org/thingsboard/server/dao/tenant}/DefaultTbTenantProfileCache.java (90%) diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 5a0e291ac2..52dbb38c9c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -73,7 +73,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.mail.MailExecutorService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index fea5558540..ba8654854c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.MsgType; @@ -41,7 +40,7 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; import java.util.HashSet; diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index b8fe956217..869cbea127 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; @@ -94,7 +93,7 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.AccessControlService; diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 0dcef2c88d..79f05fa897 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -55,7 +55,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.telemetry.InternalTelemetryService; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index ac7aea9f44..f56e08b10f 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -55,7 +55,7 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.processing.AbstractConsumerService; import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index ffb431ca37..aa3be47ef9 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -45,7 +45,7 @@ import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; import org.thingsboard.server.queue.util.TbRuleEngineComponent; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.processing.AbstractConsumerService; import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDecision; import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java index 4d5219fbfe..2bcf7e7e88 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTenantRoutingInfoService.java @@ -21,11 +21,10 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.discovery.TenantRoutingInfo; import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @Slf4j @Service diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index fd95f66346..0dfc9c5742 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -38,7 +38,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbPackCallback; import org.thingsboard.server.service.queue.TbPackProcessingContext; diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index ab566fb147..3e9e413ceb 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -71,7 +71,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; -import org.thingsboard.server.service.profile.TbTenantProfileCache; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.state.DeviceStateService; diff --git a/application/src/main/java/org/thingsboard/server/service/profile/TbTenantProfileCache.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TbTenantProfileCache.java similarity index 95% rename from application/src/main/java/org/thingsboard/server/service/profile/TbTenantProfileCache.java rename to common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TbTenantProfileCache.java index de69b5f51c..735e23e73a 100644 --- a/application/src/main/java/org/thingsboard/server/service/profile/TbTenantProfileCache.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TbTenantProfileCache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.profile; +package org.thingsboard.server.dao.tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.TenantId; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java index 00154ec602..1366df3ac2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java @@ -166,4 +166,6 @@ public interface AssetDao extends Dao { */ ListenableFuture> findTenantAssetTypesAsync(UUID tenantId); + Long countAssetsByTenantId(TenantId tenantId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index f0683ae5ae..923baa1df4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -26,6 +26,7 @@ import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Customer; @@ -44,12 +45,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.EntitySearchDirection; +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.entityview.EntityViewService; 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.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; @@ -90,6 +93,10 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @Autowired private CacheManager cacheManager; + @Autowired + @Lazy + private TbTenantProfileCache tenantProfileCache; + @Override public AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId) { log.trace("Executing findAssetInfoById [{}]", assetId); @@ -320,6 +327,15 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ @Override protected void validateCreate(TenantId tenantId, Asset asset) { + 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); + } + } } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 54ca245ee8..2f321ff499 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -203,6 +203,8 @@ public interface DeviceDao extends Dao { */ ListenableFuture findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); + Long countDevicesByTenantId(TenantId tenantId); + Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); /** diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index b0290e8eb1..9d3e161eb4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -27,6 +27,7 @@ import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -57,6 +58,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.dao.device.provision.ProvisionRequest; @@ -67,6 +69,7 @@ import org.thingsboard.server.dao.event.EventService; 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.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.dao.util.mapping.JacksonUtil; @@ -120,6 +123,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Autowired private EventService eventService; + @Autowired + @Lazy + private TbTenantProfileCache tenantProfileCache; + @Override public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { log.trace("Executing findDeviceInfoById [{}]", deviceId); @@ -520,6 +527,15 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override protected void validateCreate(TenantId tenantId, Device device) { + 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); + } + } } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java index 5e9d942720..a6e016c418 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java @@ -122,4 +122,5 @@ public interface AssetRepository extends PagingAndSortingRepository findTenantAssetTypes(@Param("tenantId") UUID tenantId); + Long countByTenantId(UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index 1e67802873..698183ea0a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -176,4 +176,10 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao im } return list; } + + @Override + public Long countAssetsByTenantId(TenantId tenantId) { + return assetRepository.countByTenantId(tenantId.getId()); + + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index b6ead2cdc3..9f3cc5b5a7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -168,4 +168,6 @@ public interface DeviceRepository extends PagingAndSortingRepository return deviceRepository.countByDeviceProfileId(deviceProfileId); } + @Override + public Long countDevicesByTenantId(TenantId tenantId) { + return deviceRepository.countByTenantId(tenantId.getId()); + } + private List convertTenantDeviceTypesToDto(UUID tenantId, List types) { List list = Collections.emptyList(); if (types != null && !types.isEmpty()) { diff --git a/application/src/main/java/org/thingsboard/server/service/profile/DefaultTbTenantProfileCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/DefaultTbTenantProfileCache.java similarity index 90% rename from application/src/main/java/org/thingsboard/server/service/profile/DefaultTbTenantProfileCache.java rename to dao/src/main/java/org/thingsboard/server/dao/tenant/DefaultTbTenantProfileCache.java index 42c09c104c..adf05e0f74 100644 --- a/application/src/main/java/org/thingsboard/server/service/profile/DefaultTbTenantProfileCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/DefaultTbTenantProfileCache.java @@ -13,20 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.profile; +package org.thingsboard.server.dao.tenant; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; -import org.thingsboard.server.dao.device.DeviceProfileService; -import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; From 92ba5907b0e8fb335e6562d636a3bcb627099f92 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 3 Nov 2020 16:51:41 +0200 Subject: [PATCH 02/37] Added validation for deviceName/attribute key contains only spaces situation --- .../thingsboard/server/controller/TelemetryController.java | 5 +++++ .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index af4eb0f08f..e8c4756a6f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -393,6 +393,11 @@ public class TelemetryController extends BaseController { if (attributes.isEmpty()) { return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST); } + for (AttributeKvEntry attributeKvEntry: attributes) { + if (attributeKvEntry.getKey().isEmpty() || attributeKvEntry.getKey().trim().length() == 0) { + return getImmediateDeferredResult("Key cannot be empty or contains only spaces", HttpStatus.BAD_REQUEST); + } + } SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> { tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index cb6d74cf10..8d29b9c447 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -388,7 +388,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (StringUtils.isEmpty(device.getType())) { throw new DataValidationException("Device type should be specified!"); } - if (StringUtils.isEmpty(device.getName())) { + if (StringUtils.isEmpty(device.getName()) || device.getName().trim().length() == 0) { throw new DataValidationException("Device name should be specified!"); } if (device.getTenantId() == null) { From 1daf5a44b5683a35b065f568e28498e414f95111 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 3 Nov 2020 17:33:57 +0200 Subject: [PATCH 03/37] alarm state improvements (added details to alarm from device profile details pattern) --- .../rule/engine/profile/AlarmState.java | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 6c771f0c86..3d29da6bd7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.profile; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.action.TbAlarmResult; @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.query.EntityKeyType; +import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.ServiceQueue; @@ -74,7 +76,7 @@ class AlarmState { public boolean createOrClearAlarms(TbContext ctx, T data, SnapshotUpdate update, BiFunction evalFunction) { boolean stateUpdate = false; - AlarmSeverity resultSeverity = null; + AlarmRuleState resultState = null; log.debug("[{}] processing update: {}", alarmDefinition.getId(), data); for (AlarmRuleState state : createRulesSortedBySeverityDesc) { if (!validateUpdate(update, state)) { @@ -84,15 +86,15 @@ class AlarmState { AlarmEvalResult evalResult = evalFunction.apply(state, data); stateUpdate |= state.checkUpdate(); if (AlarmEvalResult.TRUE.equals(evalResult)) { - resultSeverity = state.getSeverity(); + resultState = state; break; } else if (AlarmEvalResult.FALSE.equals(evalResult)) { state.clear(); stateUpdate |= state.checkUpdate(); } } - if (resultSeverity != null) { - TbAlarmResult result = calculateAlarmResult(ctx, resultSeverity); + if (resultState != null) { + TbAlarmResult result = calculateAlarmResult(ctx, resultState, data); if (result != null) { pushMsg(ctx, result); } @@ -187,7 +189,8 @@ class AlarmState { } } - private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmSeverity severity) { + private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState, T data) { + AlarmSeverity severity = ruleState.getSeverity(); if (currentAlarm != null) { // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). // Maybe we should fetch alarm every time? @@ -213,7 +216,7 @@ class AlarmState { currentAlarm.setSeverity(severity); currentAlarm.setStartTs(System.currentTimeMillis()); currentAlarm.setEndTs(currentAlarm.getStartTs()); - currentAlarm.setDetails(JacksonUtil.OBJECT_MAPPER.createObjectNode()); + currentAlarm.setDetails(createDetails(ruleState, (DataSnapshot) data)); currentAlarm.setOriginator(originator); currentAlarm.setTenantId(ctx.getTenantId()); currentAlarm.setPropagate(alarmDefinition.isPropagate()); @@ -226,6 +229,44 @@ class AlarmState { } } + private JsonNode createDetails(AlarmRuleState ruleState, DataSnapshot dataSnapshot) { + ObjectNode details = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + String alarmDetails = ruleState.getAlarmRule().getAlarmDetails(); + + if (alarmDetails != null) { + for (KeyFilter keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) { + EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey()); + alarmDetails = alarmDetails.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue)); + } + + details.put("data", alarmDetails); + } + + return details; + } + + private static String getValueAsString(EntityKeyValue entityKeyValue) { + Object result = null; + switch (entityKeyValue.getDataType()) { + case STRING: + result = entityKeyValue.getStrValue(); + break; + case JSON: + result = entityKeyValue.getJsonValue(); + break; + case LONG: + result = String.valueOf(entityKeyValue.getLngValue()); + break; + case DOUBLE: + result = String.valueOf(entityKeyValue.getDblValue()); + break; + case BOOLEAN: + result = String.valueOf(entityKeyValue.getBoolValue()); + break; + } + return String.valueOf(result); + } + public boolean processAlarmClear(TbContext ctx, Alarm alarmNf) { boolean updated = false; if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) { From 55b8ae92ea298a5eb2bddfe7c6b0d83a67a063de Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 4 Nov 2020 13:40:38 +0200 Subject: [PATCH 04/37] refactored --- .../org/thingsboard/rule/engine/profile/AlarmState.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 3d29da6bd7..8fe7bcb777 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -255,13 +255,13 @@ class AlarmState { result = entityKeyValue.getJsonValue(); break; case LONG: - result = String.valueOf(entityKeyValue.getLngValue()); + result = entityKeyValue.getLngValue(); break; case DOUBLE: - result = String.valueOf(entityKeyValue.getDblValue()); + result = entityKeyValue.getDblValue(); break; case BOOLEAN: - result = String.valueOf(entityKeyValue.getBoolValue()); + result = entityKeyValue.getBoolValue(); break; } return String.valueOf(result); From a2eea121bedf483e5a0a0db3e16fbb1891e96bcd Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 4 Nov 2020 18:14:18 +0200 Subject: [PATCH 05/37] AlarmState improvements --- .../org/thingsboard/rule/engine/profile/AlarmState.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 8fe7bcb777..c59dbb75ca 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -55,6 +55,7 @@ class AlarmState { private volatile boolean initialFetchDone; private volatile TbMsgMetaData lastMsgMetaData; private volatile String lastMsgQueueName; + private volatile DataSnapshot dataSnapshot; AlarmState(ProfileState deviceProfile, EntityId originator, DeviceProfileAlarm alarmDefinition, PersistedAlarmState alarmState) { this.deviceProfile = deviceProfile; @@ -94,7 +95,7 @@ class AlarmState { } } if (resultState != null) { - TbAlarmResult result = calculateAlarmResult(ctx, resultState, data); + TbAlarmResult result = calculateAlarmResult(ctx, resultState); if (result != null) { pushMsg(ctx, result); } @@ -189,7 +190,7 @@ class AlarmState { } } - private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState, T data) { + private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState) { AlarmSeverity severity = ruleState.getSeverity(); if (currentAlarm != null) { // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). @@ -216,7 +217,7 @@ class AlarmState { currentAlarm.setSeverity(severity); currentAlarm.setStartTs(System.currentTimeMillis()); currentAlarm.setEndTs(currentAlarm.getStartTs()); - currentAlarm.setDetails(createDetails(ruleState, (DataSnapshot) data)); + currentAlarm.setDetails(createDetails(ruleState)); currentAlarm.setOriginator(originator); currentAlarm.setTenantId(ctx.getTenantId()); currentAlarm.setPropagate(alarmDefinition.isPropagate()); @@ -229,7 +230,7 @@ class AlarmState { } } - private JsonNode createDetails(AlarmRuleState ruleState, DataSnapshot dataSnapshot) { + private JsonNode createDetails(AlarmRuleState ruleState) { ObjectNode details = JacksonUtil.OBJECT_MAPPER.createObjectNode(); String alarmDetails = ruleState.getAlarmRule().getAlarmDetails(); From 580c8aef51a355254ba14eff88974fee83e12f13 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Fri, 30 Oct 2020 14:28:30 +0200 Subject: [PATCH 06/37] Added handler for too long payload exception in MQTT transport --- .../server/transport/mqtt/MqttTransportHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 5d24f812eb..abb8f629f1 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -115,7 +115,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.trace("[{}] Processing msg: {}", sessionId, msg); try { if (msg instanceof MqttMessage) { - processMqttMsg(ctx, (MqttMessage) msg); + MqttMessage message = (MqttMessage) msg; + if (message.decoderResult().isSuccess()) { + processMqttMsg(ctx, message); + } else { + log.error("[{}] Message processing failed: {}", sessionId, message.decoderResult().cause().getMessage()); + ctx.close(); + } } else { ctx.close(); } From f6e9959ca5e215a61c5b8029c203dd166e1d5c9e Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 11 Nov 2020 12:22:00 +0200 Subject: [PATCH 07/37] Minor improvements --- .../DefaultSystemDataLoaderService.java | 3 --- .../usagestats/DefaultTbApiUsageClient.java | 4 +++- .../transport/mqtt/MqttTransportHandler.java | 6 +++-- .../DefaultTransportRateLimitService.java | 24 ++++++++++++++----- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index fd757ed6dd..6c7678f023 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -134,7 +134,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { TenantProfile isolatedTbCoreProfile = new TenantProfile(); isolatedTbCoreProfile.setDefault(false); isolatedTbCoreProfile.setName("Isolated TB Core"); - isolatedTbCoreProfile.setProfileData(new TenantProfileData()); isolatedTbCoreProfile.setDescription("Isolated TB Core tenant profile"); isolatedTbCoreProfile.setIsolatedTbCore(true); isolatedTbCoreProfile.setIsolatedTbRuleEngine(false); @@ -148,7 +147,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { TenantProfile isolatedTbRuleEngineProfile = new TenantProfile(); isolatedTbRuleEngineProfile.setDefault(false); isolatedTbRuleEngineProfile.setName("Isolated TB Rule Engine"); - isolatedTbRuleEngineProfile.setProfileData(new TenantProfileData()); isolatedTbRuleEngineProfile.setDescription("Isolated TB Rule Engine tenant profile"); isolatedTbRuleEngineProfile.setIsolatedTbCore(false); isolatedTbRuleEngineProfile.setIsolatedTbRuleEngine(true); @@ -163,7 +161,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { TenantProfile isolatedTbCoreAndTbRuleEngineProfile = new TenantProfile(); isolatedTbCoreAndTbRuleEngineProfile.setDefault(false); isolatedTbCoreAndTbRuleEngineProfile.setName("Isolated TB Core and TB Rule Engine"); - isolatedTbCoreAndTbRuleEngineProfile.setProfileData(new TenantProfileData()); isolatedTbCoreAndTbRuleEngineProfile.setDescription("Isolated TB Core and TB Rule Engine tenant profile"); isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbCore(true); isolatedTbCoreAndTbRuleEngineProfile.setIsolatedTbRuleEngine(true); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java index 0702322838..5c5b593d96 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageClient.java @@ -94,7 +94,9 @@ public class DefaultTbApiUsageClient implements TbApiUsageClient { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).newByTopic(msgProducer.getDefaultTopic()); msgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), builder.build()), null); })); - log.info("Report statistics for: {} tenants", report.size()); + if (!report.isEmpty()) { + log.info("Report statistics for: {} tenants", report.size()); + } } catch (Exception e) { log.warn("Failed to report statistics: ", e); } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 14712a7cb3..024e42f9ac 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -464,8 +464,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement String userName = msg.payload().userName(); log.info("[{}] Processing connect msg for client with user name: {}!", sessionId, userName); TransportProtos.ValidateBasicMqttCredRequestMsg.Builder request = TransportProtos.ValidateBasicMqttCredRequestMsg.newBuilder() - .setClientId(msg.payload().clientIdentifier()) - .setUserName(userName); + .setClientId(msg.payload().clientIdentifier()); + if (userName != null) { + request.setUserName(userName); + } String password = msg.payload().password(); if (password != null) { request.setPassword(password); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java index b6f160ad1e..6dc1db0fc2 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java @@ -21,6 +21,7 @@ import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; @@ -77,6 +78,7 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi @Override public void update(TenantProfileUpdateResult update) { + log.info("Received tenant profile update: {}", update.getProfile()); EntityTransportRateLimits tenantRateLimitPrototype = createRateLimits(update.getProfile(), true); EntityTransportRateLimits deviceRateLimitPrototype = createRateLimits(update.getProfile(), false); for (TenantId tenantId : update.getAffectedTenants()) { @@ -114,16 +116,26 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi tenantAllowed.put(tenantId, allowed); } - private void mergeLimits(T deviceId, EntityTransportRateLimits newRateLimits, - Function getFunction, - BiConsumer putFunction) { - EntityTransportRateLimits oldRateLimits = getFunction.apply(deviceId); + private void mergeLimits(T entityId, EntityTransportRateLimits newRateLimits, + Function getFunction, + BiConsumer putFunction) { + EntityTransportRateLimits oldRateLimits = getFunction.apply(entityId); if (oldRateLimits == null) { - putFunction.accept(deviceId, newRateLimits); + if (EntityType.TENANT.equals(entityId.getEntityType())) { + log.info("[{}] New rate limits: {}", entityId, newRateLimits); + } else { + log.debug("[{}] New rate limits: {}", entityId, newRateLimits); + } + putFunction.accept(entityId, newRateLimits); } else { EntityTransportRateLimits updated = merge(oldRateLimits, newRateLimits); if (updated != null) { - putFunction.accept(deviceId, updated); + if (EntityType.TENANT.equals(entityId.getEntityType())) { + log.info("[{}] Updated rate limits: {}", entityId, updated); + } else { + log.debug("[{}] Updated rate limits: {}", entityId, updated); + } + putFunction.accept(entityId, updated); } } } From f157d07c1f4e1550155159a383bc934964ba6f05 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 11 Nov 2020 12:45:14 +0200 Subject: [PATCH 08/37] Improvements --- .../apiusage/DefaultTbApiUsageStateService.java | 11 +++++++---- .../server/service/queue/DefaultTbClusterService.java | 1 + application/src/main/resources/thingsboard.yml | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 0dcef2c88d..d7b96c78be 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -221,6 +221,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @Override public void onTenantProfileUpdate(TenantProfileId tenantProfileId) { + log.info("[{}] On Tenant Profile Update", tenantProfileId); TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId); updateLock.lock(); try { @@ -236,6 +237,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @Override public void onTenantUpdate(TenantId tenantId) { + log.info("[{}] On Tenant Update", tenantId); TenantProfile tenantProfile = tenantProfileCache.get(tenantId); updateLock.lock(); try { @@ -248,16 +250,17 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { } } - private void updateTenantState(TenantApiUsageState state, TenantProfile tenantProfile) { + private void updateTenantState(TenantApiUsageState state, TenantProfile profile) { + log.info("[{}] On Tenant Update.", state.getTenantId()); TenantProfileData oldProfileData = state.getTenantProfileData(); - state.setTenantProfileId(tenantProfile.getId()); - state.setTenantProfileData(tenantProfile.getProfileData()); + state.setTenantProfileId(profile.getId()); + state.setTenantProfileData(profile.getProfileData()); Map result = state.checkStateUpdatedDueToThresholds(); if (!result.isEmpty()) { persistAndNotify(state, result); } updateProfileThresholds(state.getTenantId(), state.getApiUsageState().getId(), - oldProfileData.getConfiguration(), tenantProfile.getProfileData().getConfiguration()); + oldProfileData.getConfiguration(), profile.getProfileData().getConfiguration()); } private void updateProfileThresholds(TenantId tenantId, ApiUsageStateId id, diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 18f064b745..edd53c6727 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -274,6 +274,7 @@ public class DefaultTbClusterService implements TbClusterService { TbQueueProducer> toRuleEngineProducer = producerProvider.getRuleEngineNotificationsMsgProducer(); Set tbRuleEngineServices = new HashSet<>(partitionService.getAllServiceIds(ServiceType.TB_RULE_ENGINE)); if (msg.getEntityId().getEntityType().equals(EntityType.TENANT) + || msg.getEntityId().getEntityType().equals(EntityType.TENANT_PROFILE) || msg.getEntityId().getEntityType().equals(EntityType.DEVICE_PROFILE) || msg.getEntityId().getEntityType().equals(EntityType.API_USAGE_STATE)) { TbQueueProducer> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f0f4b9dd54..2766793acc 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -766,7 +766,6 @@ metrics: # Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,). percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" - management: endpoints: web: From ebf10b55c8cc1f3287ffb23baab3a255160a2f03 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 11 Nov 2020 12:59:22 +0200 Subject: [PATCH 09/37] api usage state alias improvements --- .../dao/sql/query/DefaultEntityQueryRepository.java | 2 +- .../server/dao/sql/query/EntityKeyMapping.java | 3 ++- .../dao/usagerecord/ApiUsageStateServiceImpl.java | 13 +++++++++++++ ui-ngx/src/app/shared/models/entity-type.models.ts | 9 ++++++++- ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 ++- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 380e166aa5..db61e6ab05 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -210,7 +210,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { entityTableMap.put(EntityType.CUSTOMER, "customer"); entityTableMap.put(EntityType.USER, "tb_user"); entityTableMap.put(EntityType.TENANT, "tenant"); - entityTableMap.put(EntityType.API_USAGE_STATE, "(select aus.id, aus.created_time, aus.tenant_id, '' as name, '' as additional_info from api_usage_state as aus)"); + entityTableMap.put(EntityType.API_USAGE_STATE, "api_usage_state"); } public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{ diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 525483f0a0..8d316aebcd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -79,7 +79,7 @@ public class EntityKeyMapping { public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE); public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - + public static final List apiUsageStateEntityFields = Collections.singletonList(CREATED_TIME); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); @@ -99,6 +99,7 @@ public class EntityKeyMapping { allowedEntityFieldMap.put(EntityType.RULE_NODE, new HashSet<>(commonEntityFields)); allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(widgetEntityFields)); allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(widgetEntityFields)); + allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, new HashSet<>(apiUsageStateEntityFields)); entityFieldColumnMap.put(CREATED_TIME, ModelConstants.CREATED_TIME_PROPERTY); entityFieldColumnMap.put(ENTITY_TYPE, ModelConstants.ENTITY_TYPE_PROPERTY); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index ed02bf7726..b525a71eaa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.usagerecord; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.ApiFeature; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.ApiUsageStateValue; @@ -27,6 +28,7 @@ import org.thingsboard.server.common.data.id.ApiUsageStateId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -84,6 +86,17 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId()); TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration(); List profileThresholds = new ArrayList<>(); + List apiUsageStates = new ArrayList<>(); + apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); + apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + new StringDataEntry(ApiFeature.DB.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); + apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + new StringDataEntry(ApiFeature.RE.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); + apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + new StringDataEntry(ApiFeature.JS.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); + tsService.save(tenantId, saved.getId(), apiUsageStates, 0L); + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { profileThresholds.add(new BasicTsKvEntry(saved.getCreatedTime(), new LongDataEntry(key.getApiLimitKey(), configuration.getProfileThreshold(key)))); } diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index c6a94ad8b5..e53c5fb10e 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -47,7 +47,8 @@ export enum EntityType { RULE_NODE = 'RULE_NODE', ENTITY_VIEW = 'ENTITY_VIEW', WIDGETS_BUNDLE = 'WIDGETS_BUNDLE', - WIDGET_TYPE = 'WIDGET_TYPE' + WIDGET_TYPE = 'WIDGET_TYPE', + API_USAGE_STATE = 'API_USAGE_STATE' } export enum AliasEntityType { @@ -238,6 +239,12 @@ export const entityTypeTranslations = new Map Date: Wed, 11 Nov 2020 13:03:22 +0200 Subject: [PATCH 10/37] refactored --- .../thingsboard/server/dao/sql/query/EntityKeyMapping.java | 5 +++-- .../server/dao/usagerecord/ApiUsageStateServiceImpl.java | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 8d316aebcd..7332de4b49 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -79,7 +79,8 @@ public class EntityKeyMapping { public static final List dashboardEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, TITLE); public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - public static final List apiUsageStateEntityFields = Collections.singletonList(CREATED_TIME); + + public static final Set apiUsageStateEntityFields = Collections.singleton(CREATED_TIME); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); @@ -99,7 +100,7 @@ public class EntityKeyMapping { allowedEntityFieldMap.put(EntityType.RULE_NODE, new HashSet<>(commonEntityFields)); allowedEntityFieldMap.put(EntityType.WIDGET_TYPE, new HashSet<>(widgetEntityFields)); allowedEntityFieldMap.put(EntityType.WIDGETS_BUNDLE, new HashSet<>(widgetEntityFields)); - allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, new HashSet<>(apiUsageStateEntityFields)); + allowedEntityFieldMap.put(EntityType.API_USAGE_STATE, apiUsageStateEntityFields); entityFieldColumnMap.put(CREATED_TIME, ModelConstants.CREATED_TIME_PROPERTY); entityFieldColumnMap.put(ENTITY_TYPE, ModelConstants.ENTITY_TYPE_PROPERTY); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index b525a71eaa..12b5b3c01a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -85,7 +85,6 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A Tenant tenant = tenantDao.findById(tenantId, tenantId.getId()); TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId()); TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration(); - List profileThresholds = new ArrayList<>(); List apiUsageStates = new ArrayList<>(); apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); @@ -97,6 +96,8 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A new StringDataEntry(ApiFeature.JS.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); tsService.save(tenantId, saved.getId(), apiUsageStates, 0L); + List profileThresholds = new ArrayList<>(); + for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { profileThresholds.add(new BasicTsKvEntry(saved.getCreatedTime(), new LongDataEntry(key.getApiLimitKey(), configuration.getProfileThreshold(key)))); } From 91aa144ae53f7598868e6b3f5c73985b6ecb32f9 Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Wed, 11 Nov 2020 15:13:59 +0200 Subject: [PATCH 11/37] Fix widget margin --- ui-ngx/src/app/core/services/dashboard-utils.service.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 0b21a3f9be..a825b51f72 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -422,6 +422,12 @@ export class DashboardUtilsService { widgetLayout.row = row; widgetLayout.col = 0; } + + widgetLayout.sizeX = Math.floor(widgetLayout.sizeX); + widgetLayout.sizeY = Math.floor(widgetLayout.sizeY); + widgetLayout.row = Math.floor(widgetLayout.row); + widgetLayout.col = Math.floor(widgetLayout.col); + layout.widgets[widget.id] = widgetLayout; } From 5de0059eb765631e7ac4862fe4c19bb4de75b98c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 11 Nov 2020 16:25:25 +0200 Subject: [PATCH 12/37] apiUsageState improvements --- .../server/dao/usagerecord/ApiUsageStateServiceImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index 12b5b3c01a..7836154c62 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -86,13 +86,13 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId()); TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration(); List apiUsageStates = new ArrayList<>(); - apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.TRANSPORT.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); - apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.DB.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); - apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.RE.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); - apiUsageStates.add(new BasicTsKvEntry(apiUsageState.getCreatedTime(), + apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.JS.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); tsService.save(tenantId, saved.getId(), apiUsageStates, 0L); From b02cbec0ee6b6bd2979b7f8b6e825642effa904d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 11 Nov 2020 16:41:07 +0200 Subject: [PATCH 13/37] Minor logging improvements --- .../service/queue/processing/AbstractConsumerService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index 0dfc9c5742..2d9ca3f042 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -153,6 +153,8 @@ public abstract class AbstractConsumerService Date: Wed, 11 Nov 2020 18:02:10 +0200 Subject: [PATCH 14/37] Improvements --- .../DefaultTbApiUsageStateService.java | 3 +-- .../transport/DefaultTransportApiService.java | 25 +++++++++++-------- docker/README.md | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index f5d65b8397..c7206712c3 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -237,7 +237,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @Override public void onTenantUpdate(TenantId tenantId) { - log.info("[{}] On Tenant Update", tenantId); + log.info("[{}] On Tenant Update.", tenantId); TenantProfile tenantProfile = tenantProfileCache.get(tenantId); updateLock.lock(); try { @@ -251,7 +251,6 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { } private void updateTenantState(TenantApiUsageState state, TenantProfile profile) { - log.info("[{}] On Tenant Update.", state.getTenantId()); TenantProfileData oldProfileData = state.getTenantProfileData(); state.setTenantProfileId(profile.getId()); state.setTenantProfileData(profile.getProfileData()); diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 3e9e413ceb..c7cbea8200 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -164,22 +164,25 @@ public class DefaultTransportApiService implements TransportApiService { } private ListenableFuture validateCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { - DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); - if (credentials != null) { - if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { - return getDeviceInfo(credentials.getDeviceId(), credentials); - } else if (credentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { - if (!checkMqttCredentials(mqtt, credentials)) { - credentials = null; + DeviceCredentials credentials = null; + if (mqtt.getUserName() != null) { + credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); + if (credentials != null) { + if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { + return getDeviceInfo(credentials.getDeviceId(), credentials); + } else if (credentials.getCredentialsType() == DeviceCredentialsType.MQTT_BASIC) { + if (!checkMqttCredentials(mqtt, credentials)) { + credentials = null; + } } } - } - if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); if (credentials == null) { - credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash("|", mqtt.getClientId(), mqtt.getUserName())); } } + if (credentials == null) { + credentials = checkMqttCredentials(mqtt, EncryptionUtil.getSha3Hash(mqtt.getClientId())); + } if (credentials != null) { return getDeviceInfo(credentials.getDeviceId(), credentials); } else { diff --git a/docker/README.md b/docker/README.md index a1051c039e..9664edc48e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -58,7 +58,7 @@ In case of any issues you can examine service logs for errors. For example to see ThingsBoard node logs execute the following command: ` -$ docker-compose logs -f tb-core1 tb-rule-engine1 +$ docker-compose logs -f tb-core1 tb-core2 tb-rule-engine1 tb-rule-engine2 tb-mqtt-transport1 tb-mqtt-transport2 ` Or use `docker-compose ps` to see the state of all the containers. From 2ccaa095cb5e255410641bcb11ee3e73b7d4e39e Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Thu, 24 Sep 2020 14:47:29 +0300 Subject: [PATCH 15/37] Fix marker move --- .../home/components/widget/lib/maps/leaflet-map.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5d6f39850e..14d296436d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -410,10 +410,16 @@ export default abstract class LeafletMap { } convertToCustomFormat(position: L.LatLng): object { - return { - [this.options.latKeyName]: position.lat % 90, - [this.options.lngKeyName]: position.lng % 180 - }; + if(position.lng > 180){ + position.lng = 180; + }else if(position.lng < -180){ + position.lng = -180; + }; + + return { + [this.options.latKeyName]: position.lat, + [this.options.lngKeyName]: position.lng + }; } convertToPolygonFormat(points: Array): Array { From a06c8354973e361c760fd90b293a7fad41d18a6a Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 28 Sep 2020 14:48:47 +0300 Subject: [PATCH 16/37] Fix marker move and marker point --- .../components/widget/lib/maps/leaflet-map.ts | 6 +++-- .../widget/lib/maps/providers/image-map.ts | 25 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 14d296436d..742451ec5e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -131,10 +131,13 @@ export default abstract class LeafletMap { tooltipAnchor: [16, -28], shadowSize: [41, 41] }); + const customLatLng = this.convertToCustomFormat(mousePositionOnMap); + mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; + mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; + const newMarker = L.marker(mousePositionOnMap, { icon }).addTo(this.map); this.addMarkers.push(newMarker); const datasourcesList = document.createElement('div'); - const customLatLng = this.convertToCustomFormat(mousePositionOnMap); const header = document.createElement('p'); header.appendChild(document.createTextNode('Select entity:')); header.setAttribute('style', 'font-size: 14px; margin: 8px 0'); @@ -415,7 +418,6 @@ export default abstract class LeafletMap { }else if(position.lng < -180){ position.lng = -180; }; - return { [this.options.latKeyName]: position.lat, [this.options.lngKeyName]: position.lng diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 1b20ddad01..2c967660e0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -258,10 +258,29 @@ export class ImageMap extends LeafletMap { } convertToCustomFormat(position: L.LatLng, width = this.width, height = this.height): object { - const point = this.latLngToPoint(position); + let point = this.latLngToPoint(position); + const customX = calculateNewPointCoordinate(point.x, width); + const customY = calculateNewPointCoordinate(point.y, height); + + if(customX === 0){ + point.x = 0; + } else if(customX === 1){ + point.x = width; + } + + if(customY === 0){ + point.y = 0; + } else if(customY === 1){ + point.y = height; + } + + const customLatLng = this.pointToLatLng(point.x,point.y) + return { - [this.options.xPosKeyName]: calculateNewPointCoordinate(point.x, width), - [this.options.yPosKeyName]: calculateNewPointCoordinate(point.y, height) + [this.options.xPosKeyName]: customX, + [this.options.yPosKeyName]: customY, + [this.options.latKeyName]:customLatLng.lat, + [this.options.lngKeyName]:customLatLng.lng }; } From 60de89015acf58d7efc9903d9713661c04f8afed Mon Sep 17 00:00:00 2001 From: Kalutka Zhenya Date: Mon, 28 Sep 2020 15:01:20 +0300 Subject: [PATCH 17/37] Refactoring --- .../modules/home/components/widget/lib/maps/leaflet-map.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 742451ec5e..f29ab38f03 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -132,8 +132,8 @@ export default abstract class LeafletMap { shadowSize: [41, 41] }); const customLatLng = this.convertToCustomFormat(mousePositionOnMap); - mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; - mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; + mousePositionOnMap.lat = customLatLng[this.options.latKeyName]; + mousePositionOnMap.lng = customLatLng[this.options.lngKeyName]; const newMarker = L.marker(mousePositionOnMap, { icon }).addTo(this.map); this.addMarkers.push(newMarker); From 724b6c5247c97e661b104985fbb5956c88fae0dc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 11 Nov 2020 18:03:33 +0200 Subject: [PATCH 18/37] Refactoring --- .../components/widget/lib/maps/leaflet-map.ts | 6 +++--- .../home/components/widget/lib/maps/markers.ts | 2 +- .../widget/lib/maps/providers/image-map.ts | 17 ++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index f29ab38f03..0f1f08799c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -413,11 +413,11 @@ export default abstract class LeafletMap { } convertToCustomFormat(position: L.LatLng): object { - if(position.lng > 180){ + if (position.lng > 180) { position.lng = 180; - }else if(position.lng < -180){ + } else if (position.lng < -180) { position.lng = -180; - }; + } return { [this.options.latKeyName]: position.lat, [this.options.lngKeyName]: position.lng diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index 4796956fa6..5f9e5e8362 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -94,7 +94,7 @@ export class Marker { } updateMarkerPosition(position: L.LatLng) { - if (!this.location.equals(position)) { + if (!this.leafletMarker.getLatLng().equals(position)) { this.location = position; this.leafletMarker.setLatLng(position); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 2c967660e0..825ace1227 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -258,29 +258,28 @@ export class ImageMap extends LeafletMap { } convertToCustomFormat(position: L.LatLng, width = this.width, height = this.height): object { - let point = this.latLngToPoint(position); + const point = this.latLngToPoint(position); const customX = calculateNewPointCoordinate(point.x, width); const customY = calculateNewPointCoordinate(point.y, height); - if(customX === 0){ + if (customX === 0) { point.x = 0; - } else if(customX === 1){ + } else if (customX === 1) { point.x = width; } - if(customY === 0){ + if (customY === 0) { point.y = 0; - } else if(customY === 1){ + } else if (customY === 1) { point.y = height; } - - const customLatLng = this.pointToLatLng(point.x,point.y) + const customLatLng = this.pointToLatLng(point.x, point.y); return { [this.options.xPosKeyName]: customX, [this.options.yPosKeyName]: customY, - [this.options.latKeyName]:customLatLng.lat, - [this.options.lngKeyName]:customLatLng.lng + [this.options.latKeyName]: customLatLng.lat, + [this.options.lngKeyName]: customLatLng.lng }; } From df21ce8043c03cf6131556abeeceae72534d48c4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 11 Nov 2020 19:02:01 +0200 Subject: [PATCH 19/37] Fix validate credentials method --- .../server/service/transport/DefaultTransportApiService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index c7cbea8200..5ceb9b3cd6 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -165,7 +165,7 @@ public class DefaultTransportApiService implements TransportApiService { private ListenableFuture validateCredentials(TransportProtos.ValidateBasicMqttCredRequestMsg mqtt) { DeviceCredentials credentials = null; - if (mqtt.getUserName() != null) { + if (!StringUtils.isEmpty(mqtt.getUserName())) { credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName()); if (credentials != null) { if (credentials.getCredentialsType() == DeviceCredentialsType.ACCESS_TOKEN) { From 671dfa7668a5b6279080030552b7367b9c2a17f6 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 11 Nov 2020 19:53:45 +0200 Subject: [PATCH 20/37] Add validator to unique MQTT device topic filter --- ...e-profile-transport-configuration.component.html | 3 +++ ...ice-profile-transport-configuration.component.ts | 13 +++++++++++-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html index 00ff4760ab..5b3f3d8abf 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html @@ -63,6 +63,9 @@ + + {{ 'device-profile.mqtt-device-topic-filters-unique' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts index 18dc1b2bf4..c36d685fec 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts @@ -51,7 +51,6 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control mqttTransportPayloadTypeTranslations = mqttTransportPayloadTypeTranslationMap; - mqttDeviceProfileTransportConfigurationFormGroup: FormGroup; private requiredValue: boolean; @@ -87,7 +86,7 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]], deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]], transportPayloadType: [MqttTransportPayloadType.JSON, Validators.required] - }) + }, {validator: this.uniqueDeviceTopicValidator}) }); this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { this.updateModel(); @@ -147,4 +146,14 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control return null; }; } + + private uniqueDeviceTopicValidator(control: FormGroup): { [key: string]: boolean } | null { + if (control.value) { + const formValue = control.value as MqttDeviceProfileTransportConfiguration; + if (formValue.deviceAttributesTopic === formValue.deviceTelemetryTopic) { + return {unique: true}; + } + } + return null; + } } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index f0d426be66..76799b73fd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -885,6 +885,7 @@ "no-device-profiles-found": "No device profiles found.", "create-new-device-profile": "Create a new one!", "mqtt-device-topic-filters": "MQTT device topic filters", + "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.", "mqtt-device-payload-type": "MQTT device payload", "mqtt-device-payload-type-json": "JSON", "mqtt-device-payload-type-proto": "Protobuf", From 0dd9450b92a04c230fb83c9b73fabfcfc2df76ee Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 12 Nov 2020 09:55:18 +0200 Subject: [PATCH 21/37] Fix for ApiStats security checks --- .../server/dao/sql/query/DefaultEntityQueryRepository.java | 5 ++++- .../thingsboard/server/dao/sql/query/EntityKeyMapping.java | 2 +- ui-ngx/src/app/core/http/entity.service.ts | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index db61e6ab05..8edb1917ba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -202,6 +202,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { " THEN (select additional_info from entity_view where id = entity_id)" + " END as additional_info"; + private static final String SELECT_API_USAGE_STATE = "(select aus.id, aus.created_time, aus.tenant_id, '13814000-1dd2-11b2-8080-808080808080'::uuid as customer_id, " + + "(select title from tenant where id = aus.tenant_id) as name from api_usage_state as aus)"; + static { entityTableMap.put(EntityType.ASSET, "asset"); entityTableMap.put(EntityType.DEVICE, "device"); @@ -210,7 +213,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { entityTableMap.put(EntityType.CUSTOMER, "customer"); entityTableMap.put(EntityType.USER, "tb_user"); entityTableMap.put(EntityType.TENANT, "tenant"); - entityTableMap.put(EntityType.API_USAGE_STATE, "api_usage_state"); + entityTableMap.put(EntityType.API_USAGE_STATE, SELECT_API_USAGE_STATE); } public static EntityType[] RELATION_QUERY_ENTITY_TYPES = new EntityType[]{ diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 7332de4b49..017306c47c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -80,7 +80,7 @@ public class EntityKeyMapping { public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, ADDITIONAL_INFO); public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO); - public static final Set apiUsageStateEntityFields = Collections.singleton(CREATED_TIME); + public static final Set apiUsageStateEntityFields = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME)); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE, ADDITIONAL_INFO)); diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index acd89e3c1b..9263838ffa 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -630,6 +630,9 @@ export class EntityService { case EntityType.DASHBOARD: entityFieldKeys.push(entityFields.title.keyName); break; + case EntityType.API_USAGE_STATE: + entityFieldKeys.push(entityFields.name.keyName); + break; } return query ? entityFieldKeys.filter((entityField) => entityField.toLowerCase().indexOf(query) === 0) : entityFieldKeys; } From 590f3a0a80ad7918b829545a83b39498afddd7be Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 12 Nov 2020 10:24:08 +0200 Subject: [PATCH 22/37] Improve tenant creation from OAuth mapper --- .../auth/oauth2/AbstractOAuth2ClientMapper.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java index f76521ac48..ea6e7d4f19 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/AbstractOAuth2ClientMapper.java @@ -35,14 +35,17 @@ import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo; import org.thingsboard.server.common.data.oauth2.OAuth2MapperConfig; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.oauth2.OAuth2User; +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.service.install.InstallScripts; +import org.thingsboard.server.service.queue.TbClusterService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.UserPrincipal; @@ -76,6 +79,12 @@ public abstract class AbstractOAuth2ClientMapper { @Autowired private InstallScripts installScripts; + @Autowired + protected TbTenantProfileCache tenantProfileCache; + + @Autowired + protected TbClusterService tbClusterService; + private final Lock userCreationLock = new ReentrantLock(); protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, OAuth2ClientRegistrationInfo clientRegistration) { @@ -162,6 +171,10 @@ public abstract class AbstractOAuth2ClientMapper { tenant.setTitle(tenantName); tenant = tenantService.saveTenant(tenant); installScripts.createDefaultRuleChains(tenant.getId()); + tenantProfileCache.evict(tenant.getId()); + tbClusterService.onTenantChange(tenant, null); + tbClusterService.onEntityStateChange(tenant.getId(), tenant.getId(), + ComponentLifecycleEvent.CREATED); } else { tenant = tenants.get(0); } From 31620008890eb6e8a474c63f8b09fd4e8c55adb9 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 12 Nov 2020 11:37:54 +0200 Subject: [PATCH 23/37] Use baseUrl from system security service for OAuth --- .../oauth2/Oauth2AuthenticationFailureHandler.java | 14 +++++++++++++- .../oauth2/Oauth2AuthenticationSuccessHandler.java | 10 ++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java index 984936874f..27a4962a0f 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationFailureHandler.java @@ -15,10 +15,15 @@ */ package org.thingsboard.server.service.security.auth.oauth2; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.utils.MiscUtils; import javax.servlet.ServletException; @@ -32,11 +37,18 @@ import java.nio.charset.StandardCharsets; @ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") public class Oauth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + private final SystemSecurityService systemSecurityService; + + @Autowired + public Oauth2AuthenticationFailureHandler(final SystemSecurityService systemSecurityService) { + this.systemSecurityService = systemSecurityService; + } + @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { - String baseUrl = MiscUtils.constructBaseUrl(request); + String baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request); getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" + URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8.toString())); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java index 8a65eadedc..2e2eeeee61 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/Oauth2AuthenticationSuccessHandler.java @@ -22,12 +22,16 @@ import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationInfo; import org.thingsboard.server.dao.oauth2.OAuth2Service; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.token.JwtToken; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; +import org.thingsboard.server.service.security.system.SystemSecurityService; import org.thingsboard.server.utils.MiscUtils; import javax.servlet.http.HttpServletRequest; @@ -45,25 +49,27 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS private final OAuth2ClientMapperProvider oauth2ClientMapperProvider; private final OAuth2Service oAuth2Service; private final OAuth2AuthorizedClientService oAuth2AuthorizedClientService; + private final SystemSecurityService systemSecurityService; @Autowired public Oauth2AuthenticationSuccessHandler(final JwtTokenFactory tokenFactory, final RefreshTokenRepository refreshTokenRepository, final OAuth2ClientMapperProvider oauth2ClientMapperProvider, final OAuth2Service oAuth2Service, - final OAuth2AuthorizedClientService oAuth2AuthorizedClientService) { + final OAuth2AuthorizedClientService oAuth2AuthorizedClientService, final SystemSecurityService systemSecurityService) { this.tokenFactory = tokenFactory; this.refreshTokenRepository = refreshTokenRepository; this.oauth2ClientMapperProvider = oauth2ClientMapperProvider; this.oAuth2Service = oAuth2Service; this.oAuth2AuthorizedClientService = oAuth2AuthorizedClientService; + this.systemSecurityService = systemSecurityService; } @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { - String baseUrl = MiscUtils.constructBaseUrl(request); + String baseUrl = this.systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request); try { OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication; From 7a13083851cc9afe40702d37f9a28982fb92602f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 12 Nov 2020 13:06:55 +0200 Subject: [PATCH 24/37] BaseUrl check --- .../security/system/DefaultSystemSecurityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index 4219dbc609..9bd22c88f5 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -202,16 +202,19 @@ public class DefaultSystemSecurityService implements SystemSecurityService { @Override public String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest) { - String baseUrl; + String baseUrl = null; AdminSettings generalSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "general"); JsonNode prohibitDifferentUrl = generalSettings.getJsonValue().get("prohibitDifferentUrl"); if (prohibitDifferentUrl != null && prohibitDifferentUrl.asBoolean()) { baseUrl = generalSettings.getJsonValue().get("baseUrl").asText(); - } else { + } + + if (StringUtils.isEmpty(baseUrl)) { baseUrl = MiscUtils.constructBaseUrl(httpServletRequest); } + return baseUrl; } From eece6418c36e99fa810f4527324519648e7fa24e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 12 Nov 2020 13:22:32 +0200 Subject: [PATCH 25/37] updated versions --- application/pom.xml | 4 --- pom.xml | 30 +++++++++++----------- rule-engine/rule-engine-components/pom.xml | 5 ++++ tools/pom.xml | 1 - 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 1730d7a5a5..1783d9f4c5 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -145,10 +145,6 @@ org.springframework.boot spring-boot-starter-websocket - - org.springframework.cloud - spring-cloud-starter-oauth2 - org.springframework.security spring-security-oauth2-client diff --git a/pom.xml b/pom.xml index 335e6c7eba..3495f83971 100755 --- a/pom.xml +++ b/pom.xml @@ -36,11 +36,10 @@ ${project.name} /var/log/${pkg.name} /usr/share/${pkg.name} - 2.2.6.RELEASE - 2.1.2.RELEASE - 5.2.6.RELEASE - 5.2.3.RELEASE - 2.2.4.RELEASE + 2.3.5.RELEASE + 5.3.1 + 5.4.1 + 2.4.1 3.1.0 0.7.0 2.2.0 @@ -51,15 +50,16 @@ 0.10 3.6.0 3.5.0.1 + 3.11.9 1.2.7 28.2-jre 2.6.1 3.4 2.5 1.4 - 2.10.2 - 2.10.2 - 2.10.2 + 2.11.3 + 2.11.3 + 2.11.3 2.2.6 1.0.2 2.6.2 @@ -72,7 +72,7 @@ 1.22.1 1.16.18 1.1.0 - 4.1.49.Final + 4.1.53.Final 1.5.0 4.8.0 2.19.1 @@ -96,7 +96,7 @@ 4.1.1 2.57 2.7.7 - 1.25 + 1.27 1.3.10 1.11.747 1.105.0 @@ -867,11 +867,6 @@ spring-boot-starter-security ${spring-boot.version} - - org.springframework.cloud - spring-cloud-starter-oauth2 - ${spring-oauth2.version} - org.springframework.security spring-security-oauth2-client @@ -1214,6 +1209,11 @@ ${cassandra-unit.version} test + + org.apache.cassandra + cassandra-all + ${cassandra-all.version} + junit junit diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 00d8101e5a..5bb14db250 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -120,6 +120,11 @@ org.locationtech.jts jts-core + + com.sun.mail + javax.mail + provided + junit junit diff --git a/tools/pom.xml b/tools/pom.xml index 91bf319b0e..10bfa3cc5b 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -54,7 +54,6 @@ org.apache.cassandra cassandra-all - 3.11.6 com.datastax.cassandra From 72a0126e23cd325fe95022911a5dcf592f7b99e1 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 12 Nov 2020 17:07:07 +0200 Subject: [PATCH 26/37] AlarmState improvements --- .../java/org/thingsboard/rule/engine/profile/AlarmState.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index c59dbb75ca..535294d94c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -67,6 +67,7 @@ class AlarmState { initCurrentAlarm(ctx); lastMsgMetaData = msg.getMetaData(); lastMsgQueueName = msg.getQueueName(); + this.dataSnapshot = data; return createOrClearAlarms(ctx, data, update, AlarmRuleState::eval); } @@ -190,7 +191,7 @@ class AlarmState { } } - private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState) { + private TbAlarmResult calculateAlarmResult(TbContext ctx, AlarmRuleState ruleState) { AlarmSeverity severity = ruleState.getSeverity(); if (currentAlarm != null) { // TODO: In some extremely rare cases, we might miss the event of alarm clear (If one use in-mem queue and restarted the server) or (if one manipulated the rule chain). @@ -230,7 +231,7 @@ class AlarmState { } } - private JsonNode createDetails(AlarmRuleState ruleState) { + private JsonNode createDetails(AlarmRuleState ruleState) { ObjectNode details = JacksonUtil.OBJECT_MAPPER.createObjectNode(); String alarmDetails = ruleState.getAlarmRule().getAlarmDetails(); From 5850fa0cd92ebf8e1deec1bd3875dd3378bae5f8 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 12 Nov 2020 18:58:07 +0200 Subject: [PATCH 27/37] updated jedis version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3495f83971..00968c525a 100755 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ 5.3.1 5.4.1 2.4.1 - 3.1.0 + 3.3.0 0.7.0 2.2.0 4.12 From cb41548b22bd11f64e3965cce5d9cec1108bacde Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 12 Nov 2020 19:32:45 +0200 Subject: [PATCH 28/37] Add cleanup of clear alarm state on non matching condition --- .../data/plugin/ComponentLifecycleEvent.java | 2 +- .../rule/engine/profile/AlarmState.java | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java index 1f242a0f88..87adc31713 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java @@ -21,5 +21,5 @@ import java.io.Serializable; * @author Andrew Shvayka */ public enum ComponentLifecycleEvent implements Serializable { - CREATED, STARTED, ACTIVATED, SUSPENDED, UPDATED, STOPPED, DELETED, ADDED_TO_ALLOW_LIST, ADDED_TO_DENY_LIST + CREATED, STARTED, ACTIVATED, SUSPENDED, UPDATED, STOPPED, DELETED } \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index c59dbb75ca..390a0d22d6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -90,8 +90,7 @@ class AlarmState { resultState = state; break; } else if (AlarmEvalResult.FALSE.equals(evalResult)) { - state.clear(); - stateUpdate |= state.checkUpdate(); + stateUpdate = clearAlarmState(stateUpdate, state); } } if (resultState != null) { @@ -99,6 +98,7 @@ class AlarmState { if (result != null) { pushMsg(ctx, result); } + stateUpdate = clearAlarmState(stateUpdate, clearState); } else if (currentAlarm != null && clearState != null) { if (!validateUpdate(update, clearState)) { log.debug("[{}] Update is not valid for current clear state", alarmDefinition.getId()); @@ -106,23 +106,26 @@ class AlarmState { } AlarmEvalResult evalResult = evalFunction.apply(clearState, data); if (AlarmEvalResult.TRUE.equals(evalResult)) { - clearState.clear(); - stateUpdate |= clearState.checkUpdate(); + stateUpdate = clearAlarmState(stateUpdate, clearState); for (AlarmRuleState state : createRulesSortedBySeverityDesc) { - state.clear(); - stateUpdate |= state.checkUpdate(); + stateUpdate = clearAlarmState(stateUpdate, state); } ctx.getAlarmService().clearAlarm(ctx.getTenantId(), currentAlarm.getId(), JacksonUtil.OBJECT_MAPPER.createObjectNode(), System.currentTimeMillis()); pushMsg(ctx, new TbAlarmResult(false, false, true, currentAlarm)); currentAlarm = null; } else if (AlarmEvalResult.FALSE.equals(evalResult)) { - clearState.clear(); - stateUpdate |= clearState.checkUpdate(); + stateUpdate = clearAlarmState(stateUpdate, clearState); } } return stateUpdate; } + public boolean clearAlarmState(boolean stateUpdate, AlarmRuleState state) { + state.clear(); + stateUpdate |= state.checkUpdate(); + return stateUpdate; + } + public boolean validateUpdate(SnapshotUpdate update, AlarmRuleState state) { if (update != null) { //Check that the update type and that keys match. @@ -273,8 +276,7 @@ class AlarmState { if (currentAlarm != null && currentAlarm.getId().equals(alarmNf.getId())) { currentAlarm = null; for (AlarmRuleState state : createRulesSortedBySeverityDesc) { - state.clear(); - updated |= state.checkUpdate(); + updated = clearAlarmState(updated, state); } } return updated; From 627c0577b08452308f925cecb3860e35292c649e Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 12 Nov 2020 19:44:49 +0200 Subject: [PATCH 29/37] Fix for ws reconnect issues --- .../service/subscription/DefaultTbLocalSubscriptionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java index 89233d2f4f..4e62628851 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java @@ -108,7 +108,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer * Since number of subscriptions is usually much less then number of devices that are pushing data. */ subscriptionsBySessionId.values().forEach(map -> map.values() - .forEach(sub -> pushSubscriptionToManagerService(sub, false))); + .forEach(sub -> pushSubscriptionToManagerService(sub, true))); } } From 57c14f1c93274f1f4013f3308363f5307a4dde7e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 10:17:46 +0200 Subject: [PATCH 30/37] changed spring version to 5.2.10.RELEASE --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 00968c525a..03b815635d 100755 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ /var/log/${pkg.name} /usr/share/${pkg.name} 2.3.5.RELEASE - 5.3.1 + 5.2.10.RELEASE 5.4.1 2.4.1 3.3.0 From ba1b000adbfc9253fd1fc3e984480a2dd7a60fb8 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 11:55:31 +0200 Subject: [PATCH 31/37] added maxCustomers, maxUsers, maxDashboards, maxRuleChains for TenantProfile --- .../DefaultTenantProfileConfiguration.java | 4 ++ .../server/dao/asset/BaseAssetService.java | 2 +- .../server/dao/customer/CustomerDao.java | 2 + .../dao/customer/CustomerServiceImpl.java | 16 +++++++ .../server/dao/dashboard/DashboardDao.java | 1 + .../dao/dashboard/DashboardServiceImpl.java | 20 ++++++++ .../server/dao/device/DeviceServiceImpl.java | 2 +- .../server/dao/rule/BaseRuleChainService.java | 20 ++++++++ .../server/dao/rule/RuleChainDao.java | 2 + .../dao/sql/customer/CustomerRepository.java | 1 + .../dao/sql/customer/JpaCustomerDao.java | 6 +++ .../sql/dashboard/DashboardRepository.java | 2 + .../dao/sql/dashboard/JpaDashboardDao.java | 6 +++ .../server/dao/sql/rule/JpaRuleChainDao.java | 5 ++ .../dao/sql/rule/RuleChainRepository.java | 1 + .../server/dao/sql/user/JpaUserDao.java | 5 ++ .../server/dao/sql/user/UserRepository.java | 1 + .../thingsboard/server/dao/user/UserDao.java | 3 +- .../server/dao/user/UserServiceImpl.java | 20 ++++++++ ...enant-profile-configuration.component.html | 48 +++++++++++++++++++ ...-tenant-profile-configuration.component.ts | 4 ++ .../assets/locale/locale.constant-en_US.json | 12 +++++ 22 files changed, 180 insertions(+), 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index 250f9c75a5..10df66ece5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/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; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index 923baa1df4..97cdb31f5d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -332,7 +332,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ long maxAssets = profileConfiguration.getMaxAssets(); if (maxAssets > 0) { long currentAssetsCount = assetDao.countAssetsByTenantId(tenantId); - if (maxAssets >= currentAssetsCount) { + if (currentAssetsCount >= maxAssets) { throw new DataValidationException("Can't create assets more then " + maxAssets); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java index 11fa5cb7cd..5ecfd2fe62 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java @@ -54,5 +54,7 @@ public interface CustomerDao extends Dao { * @return the optional customer object */ Optional findCustomersByTenantIdAndTitle(UUID tenantId, String title); + + Long countCustomersByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 14d591e7e8..b649200e23 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -21,6 +21,7 @@ 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.Tenant; @@ -28,6 +29,7 @@ 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 +40,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 +78,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 +169,15 @@ 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(); + if (maxCustomers > 0) { + long currentCustomersCount = customerDao.countCustomersByTenantId(tenantId); + if (currentCustomersCount >= maxCustomers) { + throw new DataValidationException("Can't create customers more then " + maxCustomers); + } + } customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent( c -> { throw new DataValidationException("Customer with such title already exists!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java index 0429c6d469..0c013b4d33 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java @@ -32,4 +32,5 @@ public interface DashboardDao extends Dao { */ Dashboard save(TenantId tenantId, Dashboard dashboard); + Long countDashboardsByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index 112f998cd4..f9ec7755d4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -19,6 +19,7 @@ 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; @@ -31,12 +32,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 +64,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 +221,19 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb private DataValidator dashboardValidator = new DataValidator() { + @Override + protected void validateCreate(TenantId tenantId, Dashboard data) { + DefaultTenantProfileConfiguration profileConfiguration = + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); + long maxDashboards = profileConfiguration.getMaxDashboards(); + if (maxDashboards > 0) { + long currentDashboardsCount = dashboardDao.countDashboardsByTenantId(tenantId); + if (currentDashboardsCount >= maxDashboards) { + throw new DataValidationException("Can't create dashboards more then " + maxDashboards); + } + } + } + @Override protected void validateDataImpl(TenantId tenantId, Dashboard dashboard) { if (StringUtils.isEmpty(dashboard.getTitle())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 24c597b4df..5728259ad7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -532,7 +532,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe long maxDevices = profileConfiguration.getMaxDevices(); if (maxDevices > 0) { long currentDevicesCount = deviceDao.countDevicesByTenantId(tenantId); - if (maxDevices >= currentDevicesCount) { + if (currentDevicesCount >= maxDevices) { throw new DataValidationException("Can't create devices more then " + maxDevices); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 5997839119..aaa5040f6e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/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,19 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC private DataValidator ruleChainValidator = new DataValidator() { + @Override + protected void validateCreate(TenantId tenantId, RuleChain data) { + DefaultTenantProfileConfiguration profileConfiguration = + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); + long maxRuleChains = profileConfiguration.getMaxRuleChains(); + if (maxRuleChains > 0) { + long currentRuleChainsCount = ruleChainDao.countRuleChainsByTenantId(tenantId); + if (currentRuleChainsCount >= maxRuleChains) { + throw new DataValidationException("Can't create rule chains more then " + maxRuleChains); + } + } + } + @Override protected void validateDataImpl(TenantId tenantId, RuleChain ruleChain) { if (StringUtils.isEmpty(ruleChain.getName())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index c3214425fe..9f792200fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.rule; +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; @@ -36,4 +37,5 @@ public interface RuleChainDao extends Dao { */ PageData findRuleChainsByTenantId(UUID tenantId, PageLink pageLink); + Long countRuleChainsByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java index bf2a845ec0..4b5a8e0791 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/CustomerRepository.java @@ -37,4 +37,5 @@ public interface CustomerRepository extends PagingAndSortingRepository { + + Long countByTenantId(UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java index 8d637f0cbe..a8cf3136ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardDao.java +++ b/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 getCrudRepository() { return dashboardRepository; } + + @Override + public Long countDashboardsByTenantId(TenantId tenantId) { + return dashboardRepository.countByTenantId(tenantId.getId()); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 57d1545a94..051d13f805 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/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 imple DaoUtil.toPageable(pageLink))); } + + @Override + public Long countUsersByTenantId(TenantId tenantId) { + return userRepository.countByTenantId(tenantId.getId()); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java index 1d512a7944..ceaf09ec59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java @@ -47,4 +47,5 @@ public interface UserRepository extends PagingAndSortingRepository { * @return the list of user entities */ PageData findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink); - + + Long countUsersByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 314684c3fe..acf9c7b1b0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -24,6 +24,7 @@ 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.Tenant; @@ -36,6 +37,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 +45,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 +87,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 +371,19 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private DataValidator userValidator = new DataValidator() { + @Override + protected void validateCreate(TenantId tenantId, User data) { + DefaultTenantProfileConfiguration profileConfiguration = + (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); + long maxUsers = profileConfiguration.getMaxUsers(); + if (maxUsers > 0) { + long currentUsersCount = userDao.countUsersByTenantId(tenantId); + if (currentUsersCount >= maxUsers) { + throw new DataValidationException("Can't create users more then " + maxUsers); + } + } + } + @Override protected void validateDataImpl(TenantId requestTenantId, User user) { if (StringUtils.isEmpty(user.getEmail())) { diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html index 12258ffd5f..ae9fd8ea9c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html +++ b/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}} + + tenant-profile.maximum-customers + + + {{ 'tenant-profile.maximum-customers-required' | translate}} + + + {{ 'tenant-profile.maximum-customers-range' | translate}} + + + + tenant-profile.maximum-users + + + {{ 'tenant-profile.maximum-users-required' | translate}} + + + {{ 'tenant-profile.maximum-users-range' | translate}} + + + + tenant-profile.maximum-dashboards + + + {{ 'tenant-profile.maximum-dashboards-required' | translate}} + + + {{ 'tenant-profile.maximum-dashboards-range' | translate}} + + + + tenant-profile.maximum-rule-chains + + + {{ 'tenant-profile.maximum-rule-chains-required' | translate}} + + + {{ 'tenant-profile.maximum-rule-chains-range' | translate}} + + tenant-profile.max-transport-messages Date: Fri, 13 Nov 2020 12:02:09 +0200 Subject: [PATCH 32/37] Add getEntityTimeseries method to Service Completion --- .../models/ace/service-completion.models.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts index f9b42f12f5..27a42680e5 100644 --- a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts +++ b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts @@ -56,6 +56,12 @@ export const customerHref = 'Attribute Data'; +export const timeseriesDataHref = 'Timeseries Data'; + +export const aggregationTypeHref = 'Aggregation Type'; + +export const dataSortOrderHref = 'Data Sort Order'; + export const userHref = 'User'; export const entityDataHref = 'Entity data'; @@ -1080,6 +1086,23 @@ export const serviceCompletions: TbEditorCompletions = { ], return: observableReturnTypeVariable('any') }, + getEntityTimeseries: { + description: 'Get entity timeseries', + meta: 'function', + args: [ + {name: 'entityId', type: entityIdHref, description: 'Id of the entity'}, + {name: 'keys', type: `Array<string>`, description: 'Array of the keys'}, + {name: 'startTs', type: 'number', description: 'Start time in milliseconds'}, + {name: 'endTs', type: 'number', description: 'End time in milliseconds'}, + {name: 'limit', type: 'number', description: 'Limit of values to receive for each key'}, + {name: 'agg', type: aggregationTypeHref, description: 'Aggregation type'}, + {name: 'interval', type: 'number', description: 'Aggregation interval'}, + {name: 'orderBy', type: dataSortOrderHref, description: 'Data order by time'}, + {name: 'useStrictDataTypes', type: 'boolean', description: 'If "false" all values will be returned as strings'}, + requestConfigArg + ], + return: observableReturnTypeVariable(timeseriesDataHref) + }, } }, entityService: { From 4eccf7f9165bf03b5905981c0a2bea60ed823b78 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 13:00:33 +0200 Subject: [PATCH 33/37] fix validateCreate from UserServiceImpl --- .../server/dao/user/UserServiceImpl.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index acf9c7b1b0..0f13cdf3c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -372,14 +372,16 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private DataValidator userValidator = new DataValidator() { @Override - protected void validateCreate(TenantId tenantId, User data) { - DefaultTenantProfileConfiguration profileConfiguration = - (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); - long maxUsers = profileConfiguration.getMaxUsers(); - if (maxUsers > 0) { - long currentUsersCount = userDao.countUsersByTenantId(tenantId); - if (currentUsersCount >= maxUsers) { - throw new DataValidationException("Can't create users more then " + maxUsers); + 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(); + if (maxUsers > 0) { + long currentUsersCount = userDao.countUsersByTenantId(tenantId); + if (currentUsersCount >= maxUsers) { + throw new DataValidationException("Can't create users more then " + maxUsers); + } } } } From 9f2bae98158e63dd1d3a61a31a0723b05fc63b6a Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 13 Nov 2020 13:29:23 +0200 Subject: [PATCH 34/37] Improvements to API usage statistics collection --- .../transport/service/DefaultTransportService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 4af723f3a0..9b2e3022a9 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -390,7 +390,8 @@ public class DefaultTransportService implements TransportService { metaData.putValue("deviceName", sessionInfo.getDeviceName()); metaData.putValue("deviceType", sessionInfo.getDeviceType()); metaData.putValue("notifyDevice", "false"); - sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST, new TransportTbQueueCallback(callback)); + sendToRuleEngine(tenantId, deviceId, sessionInfo, json, metaData, SessionMsgType.POST_ATTRIBUTES_REQUEST, + new TransportTbQueueCallback(new ApiStatsProxyCallback<>(tenantId, msg.getKvList().size(), callback))); } } @@ -399,7 +400,7 @@ public class DefaultTransportService implements TransportService { if (checkLimits(sessionInfo, msg, callback)) { reportActivityInternal(sessionInfo); sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) - .setGetAttributes(msg).build(), callback); + .setGetAttributes(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); } } @@ -409,7 +410,7 @@ public class DefaultTransportService implements TransportService { SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo); sessionMetaData.setSubscribedToAttributes(!msg.getUnsubscribe()); sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) - .setSubscribeToAttributes(msg).build(), callback); + .setSubscribeToAttributes(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); } } @@ -419,7 +420,7 @@ public class DefaultTransportService implements TransportService { SessionMetaData sessionMetaData = reportActivityInternal(sessionInfo); sessionMetaData.setSubscribedToRPC(!msg.getUnsubscribe()); sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) - .setSubscribeToRPC(msg).build(), callback); + .setSubscribeToRPC(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); } } @@ -428,7 +429,7 @@ public class DefaultTransportService implements TransportService { if (checkLimits(sessionInfo, msg, callback)) { reportActivityInternal(sessionInfo); sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo) - .setToDeviceRPCCallResponse(msg).build(), callback); + .setToDeviceRPCCallResponse(msg).build(), new ApiStatsProxyCallback<>(getTenantId(sessionInfo), 1, callback)); } } @@ -805,7 +806,7 @@ public class DefaultTransportService implements TransportService { @Override public void onFailure(Throwable t) { - callback.onError(t); + DefaultTransportService.this.transportCallbackExecutor.submit(() -> callback.onError(t)); } } From a1d9ce6e45a709104328cc4724590c872e18749c Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 15:32:49 +0200 Subject: [PATCH 35/37] created validateNumberOfEntitiesPerTenant --- .../server/dao/TenantEntityDao.java | 8 ++++++ .../server/dao/asset/AssetDao.java | 5 ++-- .../server/dao/asset/BaseAssetService.java | 7 +---- .../server/dao/customer/CustomerDao.java | 5 ++-- .../dao/customer/CustomerServiceImpl.java | 9 +++---- .../server/dao/dashboard/DashboardDao.java | 5 ++-- .../dao/dashboard/DashboardServiceImpl.java | 8 ++---- .../server/dao/device/DeviceDao.java | 5 ++-- .../server/dao/device/DeviceServiceImpl.java | 7 +---- .../dao/entity/AbstractEntityService.java | 5 ++-- .../server/dao/rule/BaseRuleChainService.java | 7 +---- .../server/dao/rule/RuleChainDao.java | 6 ++--- .../server/dao/service/DataValidator.java | 15 +++++++++++ .../server/dao/sql/asset/JpaAssetDao.java | 3 +-- .../dao/sql/customer/JpaCustomerDao.java | 2 +- .../dao/sql/dashboard/JpaDashboardDao.java | 2 +- .../dao/sql/device/DeviceRepository.java | 26 +++++++++---------- .../server/dao/sql/device/JpaDeviceDao.java | 2 +- .../server/dao/sql/rule/JpaRuleChainDao.java | 2 +- .../server/dao/sql/user/JpaUserDao.java | 2 +- .../thingsboard/server/dao/user/UserDao.java | 9 +++---- .../server/dao/user/UserServiceImpl.java | 8 ++---- 22 files changed, 68 insertions(+), 80 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java new file mode 100644 index 0000000000..0ac51a0dba --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java @@ -0,0 +1,8 @@ +package org.thingsboard.server.dao; + +import org.thingsboard.server.common.data.id.TenantId; + +public interface TenantEntityDao { + + Long countByTenantId(TenantId tenantId); +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java index 1366df3ac2..ae8bf5706c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java +++ b/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 { +public interface AssetDao extends Dao, TenantEntityDao { /** * Find asset info by id. @@ -166,6 +167,4 @@ public interface AssetDao extends Dao { */ ListenableFuture> findTenantAssetTypesAsync(UUID tenantId); - Long countAssetsByTenantId(TenantId tenantId); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index 97cdb31f5d..29eaad31fb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/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 (currentAssetsCount >= maxAssets) { - throw new DataValidationException("Can't create assets more then " + maxAssets); - } - } + validateNumberOfEntitiesPerTenant(tenantId, assetDao, maxAssets, EntityType.ASSET); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java index 5ecfd2fe62..98622c8b83 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerDao.java +++ b/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 { +public interface CustomerDao extends Dao, TenantEntityDao { /** * Save or update customer object @@ -55,6 +56,4 @@ public interface CustomerDao extends Dao { */ Optional findCustomersByTenantIdAndTitle(UUID tenantId, String title); - Long countCustomersByTenantId(TenantId tenantId); - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index b649200e23..d97b4e9c34 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -24,6 +24,7 @@ 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; @@ -172,12 +173,8 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); long maxCustomers = profileConfiguration.getMaxCustomers(); - if (maxCustomers > 0) { - long currentCustomersCount = customerDao.countCustomersByTenantId(tenantId); - if (currentCustomersCount >= maxCustomers) { - throw new DataValidationException("Can't create customers more then " + maxCustomers); - } - } + + validateNumberOfEntitiesPerTenant(tenantId, customerDao, maxCustomers, EntityType.CUSTOMER); customerDao.findCustomersByTenantIdAndTitle(customer.getTenantId().getId(), customer.getTitle()).ifPresent( c -> { throw new DataValidationException("Customer with such title already exists!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java index 0c013b4d33..0beb89ef06 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardDao.java +++ b/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 { +public interface DashboardDao extends Dao, TenantEntityDao { /** * Save or update dashboard object @@ -31,6 +32,4 @@ public interface DashboardDao extends Dao { * @return saved dashboard object */ Dashboard save(TenantId tenantId, Dashboard dashboard); - - Long countDashboardsByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index f9ec7755d4..55bf31e321 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -24,6 +24,7 @@ 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; @@ -226,12 +227,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); long maxDashboards = profileConfiguration.getMaxDashboards(); - if (maxDashboards > 0) { - long currentDashboardsCount = dashboardDao.countDashboardsByTenantId(tenantId); - if (currentDashboardsCount >= maxDashboards) { - throw new DataValidationException("Can't create dashboards more then " + maxDashboards); - } - } + validateNumberOfEntitiesPerTenant(tenantId, dashboardDao, maxDashboards, EntityType.DASHBOARD); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 2f321ff499..3e8f6445a2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/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 { +public interface DeviceDao extends Dao, TenantEntityDao { /** * Find device info by id. @@ -203,8 +204,6 @@ public interface DeviceDao extends Dao { */ ListenableFuture findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); - Long countDevicesByTenantId(TenantId tenantId); - Long countDevicesByDeviceProfileId(TenantId tenantId, UUID deviceProfileId); /** diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 5728259ad7..a919f86dfe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/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 (currentDevicesCount >= maxDevices) { - throw new DataValidationException("Can't create devices more then " + maxDevices); - } - } + validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index a0f03b2a32..42d02addcd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -37,12 +37,11 @@ public abstract class AbstractEntityService { protected Optional 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(); } } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index aaa5040f6e..263f01570e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -592,12 +592,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); long maxRuleChains = profileConfiguration.getMaxRuleChains(); - if (maxRuleChains > 0) { - long currentRuleChainsCount = ruleChainDao.countRuleChainsByTenantId(tenantId); - if (currentRuleChainsCount >= maxRuleChains) { - throw new DataValidationException("Can't create rule chains more then " + maxRuleChains); - } - } + validateNumberOfEntitiesPerTenant(tenantId, ruleChainDao, maxRuleChains, EntityType.RULE_CHAIN); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 9f792200fc..87ab9d26b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -15,18 +15,18 @@ */ package org.thingsboard.server.dao.rule; -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; 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 { +public interface RuleChainDao extends Dao, TenantEntityDao { /** * Find rule chains by tenantId and page link. @@ -36,6 +36,4 @@ public interface RuleChainDao extends Dao { * @return the list of rule chain objects */ PageData findRuleChainsByTenantId(UUID tenantId, PageLink pageLink); - - Long countRuleChainsByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index d78654164f..0bd0e7b030 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/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> { 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 expectedFields = new HashSet<>(); Iterator fieldsIterator = expectedNode.fieldNames(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index 698183ea0a..d2a5167b43 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -178,8 +178,7 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao im } @Override - public Long countAssetsByTenantId(TenantId tenantId) { + public Long countByTenantId(TenantId tenantId) { return assetRepository.countByTenantId(tenantId.getId()); - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java index 53c8b66038..fdfc12bf5a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/customer/JpaCustomerDao.java @@ -65,7 +65,7 @@ public class JpaCustomerDao extends JpaAbstractSearchTextDao 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 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 findByTenantId(@Param("tenantId") UUID tenantId, @@ -102,9 +102,9 @@ public interface DeviceRepository extends PagingAndSortingRepository 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 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 " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index fceefcadf9..7ce59bda0d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -220,7 +220,7 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao } @Override - public Long countDevicesByTenantId(TenantId tenantId) { + public Long countByTenantId(TenantId tenantId) { return deviceRepository.countByTenantId(tenantId.getId()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 051d13f805..3331f57e00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -58,7 +58,7 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao imple } @Override - public Long countUsersByTenantId(TenantId tenantId) { + public Long countByTenantId(TenantId tenantId) { return userRepository.countByTenantId(tenantId.getId()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java index c2b9e7ab6c..4cffadd595 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java +++ b/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 { +public interface UserDao extends Dao, TenantEntityDao { /** * Save or update user object @@ -49,7 +50,7 @@ public interface UserDao extends Dao { * @return the list of user entities */ PageData findByTenantId(UUID tenantId, PageLink pageLink); - + /** * Find tenant admin users by tenantId and page link. * @@ -58,7 +59,7 @@ public interface UserDao extends Dao { * @return the list of user entities */ PageData findTenantAdmins(UUID tenantId, PageLink pageLink); - + /** * Find customer users by tenantId, customerId and page link. * @@ -68,6 +69,4 @@ public interface UserDao extends Dao { * @return the list of user entities */ PageData findCustomerUsers(UUID tenantId, UUID customerId, PageLink pageLink); - - Long countUsersByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 0f13cdf3c6..a19ec57f48 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -27,6 +27,7 @@ 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; @@ -377,12 +378,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration(); long maxUsers = profileConfiguration.getMaxUsers(); - if (maxUsers > 0) { - long currentUsersCount = userDao.countUsersByTenantId(tenantId); - if (currentUsersCount >= maxUsers) { - throw new DataValidationException("Can't create users more then " + maxUsers); - } - } + validateNumberOfEntitiesPerTenant(tenantId, userDao, maxUsers, EntityType.USER); } } From 2df72b4ec130f472697032340c32b3cd21b80fef Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 15:51:28 +0200 Subject: [PATCH 36/37] license format --- .../thingsboard/server/dao/TenantEntityDao.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java index 0ac51a0dba..e47dd1e301 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/TenantEntityDao.java @@ -1,3 +1,18 @@ +/** + * 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; From 4b4e2b702e7edd93b7d7bf3fba1dec47dc5f53a8 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 13 Nov 2020 16:21:14 +0200 Subject: [PATCH 37/37] DefaultTenantProfileConfiguration improvements --- ui-ngx/src/app/shared/models/tenant.model.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index ad946efdb7..ce22c27fac 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -26,6 +26,10 @@ export enum TenantProfileType { export interface DefaultTenantProfileConfiguration { maxDevices: number; maxAssets: number; + maxCustomers: number; + maxUsers: number; + maxDashboards: number; + maxRuleChains: number; transportTenantMsgRateLimit?: string; transportTenantTelemetryMsgRateLimit?: string; @@ -56,6 +60,10 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan const defaultConfiguration: DefaultTenantProfileConfiguration = { maxDevices: 0, maxAssets: 0, + maxCustomers: 0, + maxUsers: 0, + maxDashboards: 0, + maxRuleChains: 0, maxTransportMessages: 0, maxTransportDataPoints: 0, maxREExecutions: 0,