From aff4f7bacb02b5e76dca98df11b0aa49394a0af1 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 10 Jun 2024 12:37:24 +0300 Subject: [PATCH 01/19] UI: Fixed colors for neon gauge --- .../home/components/widget/lib/canvas-digital-gauge.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts index 4a7e019a48..09dba7e9c5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts @@ -238,10 +238,10 @@ export class CanvasDigitalGauge extends BaseGauge { } if (options.neonGlowBrightness) { - options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString(); - options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString(); - options.neonColorValue = tinycolor(options.colorValue).brighten(options.neonGlowBrightness).toHexString(); - options.neonColorMinMax = tinycolor(options.colorMinMax).brighten(options.neonGlowBrightness).toHexString(); + options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toRgbString(); + options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toRgbString(); + options.neonColorValue = tinycolor(options.colorValue).brighten(options.neonGlowBrightness).toRgbString(); + options.neonColorMinMax = tinycolor(options.colorMinMax).brighten(options.neonGlowBrightness).toRgbString(); } return options; From 02dc49fd3a34e93f8110a2c8a34c92163e6d5186 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 10 Jun 2024 13:22:10 +0300 Subject: [PATCH 02/19] Fix tenant not found error for notification rules --- .../rule/cache/DefaultNotificationRulesCache.java | 11 +++++++++-- .../server/dao/tenant/TenantServiceImpl.java | 5 ++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java index bf2946313d..fdf795e34b 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.notification.rule.cache; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -29,7 +30,6 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.dao.notification.NotificationRuleService; -import jakarta.annotation.PostConstruct; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -71,7 +71,14 @@ public class DefaultNotificationRulesCache implements NotificationRulesCache { if (event.getEvent() == ComponentLifecycleEvent.DELETED) { lock.writeLock().lock(); // locking in case rules for tenant are fetched while evicting try { - evict(event.getTenantId()); + for (var triggerType : NotificationRuleTriggerType.values()) { + String key = key(event.getTenantId(), triggerType); + /* + * temporarily putting empty value because right after tenant deletion + * the rules are still in the db, we don't want them to be fetched + * */ + cache.put(key, Collections.emptyList()); + } } finally { lock.writeLock().unlock(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index b17cef53db..e86abdbb8b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -39,8 +39,6 @@ import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.mobile.MobileAppSettingsService; -import org.thingsboard.server.dao.notification.NotificationRequestService; -import org.thingsboard.server.dao.notification.NotificationRuleService; import org.thingsboard.server.dao.notification.NotificationSettingsService; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; @@ -168,8 +166,10 @@ public class TenantServiceImpl extends AbstractCachedEntityService Date: Mon, 10 Jun 2024 16:44:54 +0300 Subject: [PATCH 03/19] UI: fixed error on save relation qeury alias with empty relation filter, not option disabled if relation type is empty --- .../home/components/alias/entity-alias-dialog.component.ts | 2 +- .../home/components/relation/relation-filters.component.html | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts index 21d90e0c12..ac25981f6e 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts @@ -145,7 +145,7 @@ export class EntityAliasDialogComponent extends DialogComponent self.findIndex(v => v.relationType === value.relationType && isEqual(v.entityTypes, value.entityTypes)) === index && - (value.relationType || value.entityTypes.length) + (value.relationType || value.entityTypes?.length) ); } if (this.alias.filter.type) { diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index 055b5df22e..1d6fdb7ea1 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -27,7 +27,10 @@
- {{ 'relation.not' | translate}} + + {{ 'relation.not' | translate}} + Date: Mon, 10 Jun 2024 17:25:09 +0300 Subject: [PATCH 04/19] UI: set value of not option to false if relation type cleared --- .../relation/relation-filters.component.html | 5 +---- .../relation/relation-filters.component.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index 1d6fdb7ea1..6973a6a32d 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -27,10 +27,7 @@
- - {{ 'relation.not' | translate}} - + {{ 'relation.not' | translate }} { + if (value) { + formGroup.get('negate').enable({emitEvent: false}); + } else { + formGroup.get('negate').setValue(false, {emitEvent:false}); + formGroup.get('negate').disable({emitEvent: false}); + } + }); } return formGroup; } From 473681c343f61a0b10733571dde31db2f4a7229f Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 10 Jun 2024 17:59:35 +0300 Subject: [PATCH 05/19] Don't unassign deleted user alarms on tenant deletion --- .../server/dao/eventsourcing/ActionCause.java | 20 +++++++++++++++++++ .../dao/eventsourcing/DeleteEntityEvent.java | 4 +++- .../dao/housekeeper/CleanUpService.java | 3 ++- .../server/dao/user/UserServiceImpl.java | 11 ++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/eventsourcing/ActionCause.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/ActionCause.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/ActionCause.java new file mode 100644 index 0000000000..6b03173f31 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/ActionCause.java @@ -0,0 +1,20 @@ +/** + * Copyright © 2016-2024 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.eventsourcing; + +public enum ActionCause { + TENANT_DELETION +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java index fbae8541e3..016c0dc5ff 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java @@ -17,18 +17,20 @@ package org.thingsboard.server.dao.eventsourcing; import lombok.Builder; import lombok.Data; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @Builder @Data public class DeleteEntityEvent { + private final TenantId tenantId; private final EntityId entityId; private final T entity; private final String body; + private final ActionCause cause; @Builder.Default private final long ts = System.currentTimeMillis(); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/housekeeper/CleanUpService.java b/dao/src/main/java/org/thingsboard/server/dao/housekeeper/CleanUpService.java index d64e6ea536..27205a74c1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/housekeeper/CleanUpService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/housekeeper/CleanUpService.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.housekeeper.HousekeeperTask; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.housekeeper.HousekeeperClient; +import org.thingsboard.server.dao.eventsourcing.ActionCause; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.relation.RelationService; @@ -59,7 +60,7 @@ public class CleanUpService { if (!skippedEntities.contains(entityType)) { cleanUpRelatedData(tenantId, entityId); } - if (entityType == EntityType.USER) { + if (entityType == EntityType.USER && event.getCause() != ActionCause.TENANT_DELETION) { submitTask(HousekeeperTask.unassignAlarms((User) event.getEntity())); } } catch (Throwable e) { 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 61cd9f20dd..34602d81b3 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 @@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.settings.UserSettings; import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.entity.EntityCountService; +import org.thingsboard.server.dao.eventsourcing.ActionCause; import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; @@ -293,6 +294,10 @@ public class UserServiceImpl extends AbstractCachedEntityService Date: Tue, 11 Jun 2024 11:36:45 +0300 Subject: [PATCH 06/19] UI: removed negate option set to false on relation types clear of relation filters --- .../home/components/relation/relation-filters.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts index 5bbce12bec..66d188248a 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts @@ -135,7 +135,6 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa if (value) { formGroup.get('negate').enable({emitEvent: false}); } else { - formGroup.get('negate').setValue(false, {emitEvent:false}); formGroup.get('negate').disable({emitEvent: false}); } }); From 796bab6aa9b33939af2f818fb09dcc564124f523 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 11 Jun 2024 12:57:16 +0300 Subject: [PATCH 07/19] Fix sysadmin notification being sent with tenant mail sender --- .../service/notification/channels/EmailNotificationChannel.java | 2 +- .../service/notification/channels/SmsNotificationChannel.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/channels/EmailNotificationChannel.java b/application/src/main/java/org/thingsboard/server/service/notification/channels/EmailNotificationChannel.java index c7a3d83d8f..2f01e26424 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/channels/EmailNotificationChannel.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/channels/EmailNotificationChannel.java @@ -33,7 +33,7 @@ public class EmailNotificationChannel implements NotificationChannel Date: Tue, 11 Jun 2024 15:03:45 +0300 Subject: [PATCH 08/19] fixed request param arrays in swagger --- .../server/controller/AlarmController.java | 13 +++++++------ .../server/controller/AssetController.java | 3 ++- .../controller/ComponentDescriptorController.java | 3 ++- .../server/controller/DashboardController.java | 7 ++++--- .../server/controller/DeviceController.java | 3 ++- .../server/controller/EdgeController.java | 3 ++- .../server/controller/QueueStatsController.java | 3 ++- .../server/controller/TbResourceController.java | 3 ++- .../server/controller/WidgetTypeController.java | 5 +++-- 9 files changed, 26 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index e78313f6d8..535700335d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -350,11 +351,11 @@ public class AlarmController extends BaseController { @PathVariable(ENTITY_TYPE) String strEntityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable(ENTITY_ID) String strEntityId, - @Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"ANY", "ACTIVE", "CLEARED", "ACK", "UNACK"})) + @Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"ANY", "ACTIVE", "CLEARED", "ACK", "UNACK"}))) @RequestParam(required = false) String[] statusList, - @Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"})) + @Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"}))) @RequestParam(required = false) String[] severityList, - @Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION) + @Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam(required = false) String[] typeList, @Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION) @RequestParam(required = false) String assigneeId, @@ -412,11 +413,11 @@ public class AlarmController extends BaseController { @RequestMapping(value = "/v2/alarms", method = RequestMethod.GET) @ResponseBody public PageData getAllAlarmsV2( - @Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"ANY", "ACTIVE", "CLEARED", "ACK", "UNACK"})) + @Parameter(description = ALARM_QUERY_SEARCH_STATUS_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"ANY", "ACTIVE", "CLEARED", "ACK", "UNACK"}))) @RequestParam(required = false) String[] statusList, - @Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"})) + @Parameter(description = ALARM_QUERY_SEVERITY_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"CRITICAL", "MAJOR", "MINOR", "WARNING", "INDETERMINATE"}))) @RequestParam(required = false) String[] severityList, - @Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION) + @Parameter(description = ALARM_QUERY_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam(required = false) String[] typeList, @Parameter(description = ALARM_QUERY_ASSIGNEE_DESCRIPTION) @RequestParam(required = false) String assigneeId, diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index 8c03d34e8e..7b4621db28 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.google.common.util.concurrent.ListenableFuture; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -354,7 +355,7 @@ public class AssetController extends BaseController { @RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET) @ResponseBody public List getAssetsByIds( - @Parameter(description = "A list of assets ids, separated by comma ','") + @Parameter(description = "A list of assets ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam("assetIds") String[] strAssetIds) throws ThingsboardException, ExecutionException, InterruptedException { checkArrayParameter("assetIds", strAssetIds); SecurityUser user = getCurrentUser(); diff --git a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java index 58b9296379..eeb67d7ae8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -83,7 +84,7 @@ public class ComponentDescriptorController extends BaseController { @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) @ResponseBody public List getComponentDescriptorsByTypes( - @Parameter(description = "List of types of the Rule Nodes, (ENRICHMENT, FILTER, TRANSFORMATION, ACTION or EXTERNAL)", required = true) + @Parameter(description = "List of types of the Rule Nodes, (ENRICHMENT, FILTER, TRANSFORMATION, ACTION or EXTERNAL)", array = @ArraySchema(schema = @Schema(type = "string")), required = true) @RequestParam("componentTypes") String[] strComponentTypes, @Parameter(description = "Type of the Rule Chain", schema = @Schema(allowableValues = {"CORE", "EDGE"})) @RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 013575361d..37b5b8b3b1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -18,6 +18,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; @@ -249,7 +250,7 @@ public class DashboardController extends BaseController { public Dashboard updateDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids, or empty to remove all customers") + @Parameter(description = "JSON array with the list of customer ids, or empty to remove all customers", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestBody(required = false) String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); @@ -267,7 +268,7 @@ public class DashboardController extends BaseController { public Dashboard addDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids") + @Parameter(description = "JSON array with the list of customer ids", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); @@ -285,7 +286,7 @@ public class DashboardController extends BaseController { public Dashboard removeDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids") + @Parameter(description = "JSON array with the list of customer ids", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index fedbd48503..416991a996 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -488,7 +489,7 @@ public class DeviceController extends BaseController { @RequestMapping(value = "/devices", params = {"deviceIds"}, method = RequestMethod.GET) @ResponseBody public List getDevicesByIds( - @Parameter(description = "A list of devices ids, separated by comma ','") + @Parameter(description = "A list of devices ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam("deviceIds") String[] strDeviceIds) throws ThingsboardException, ExecutionException, InterruptedException { checkArrayParameter("deviceIds", strDeviceIds); SecurityUser user = getCurrentUser(); diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 3042b8f2a1..030cb902a6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.google.common.util.concurrent.ListenableFuture; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -426,7 +427,7 @@ public class EdgeController extends BaseController { @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) @ResponseBody public List getEdgesByIds( - @Parameter(description = "A list of edges ids, separated by comma ','", required = true) + @Parameter(description = "A list of edges ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true) @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException, ExecutionException, InterruptedException { checkArrayParameter("edgeIds", strEdgeIds); SecurityUser user = getCurrentUser(); diff --git a/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java b/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java index 912a1ca7b2..eee35ee973 100644 --- a/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java +++ b/application/src/main/java/org/thingsboard/server/controller/QueueStatsController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -89,7 +90,7 @@ public class QueueStatsController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @GetMapping(value = "/queueStats", params = {"queueStatsIds"}) public List getQueueStatsByIds( - @Parameter(description = "A list of queue stats ids, separated by comma ','", required = true) + @Parameter(description = "A list of queue stats ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string")), required = true) @RequestParam("queueStatsIds") String[] strQueueStatsIds) throws ThingsboardException { checkArrayParameter("queueStatsIds", strQueueStatsIds); List queueStatsIds = new ArrayList<>(); diff --git a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java index e646c34e4f..74bc087abf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TbResourceController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -272,7 +273,7 @@ public class TbResourceController extends BaseController { @RequestParam String sortOrder, @Parameter(description = SORT_PROPERTY_DESCRIPTION, schema = @Schema(allowableValues = {"id", "name"}, requiredMode = Schema.RequiredMode.REQUIRED)) @RequestParam String sortProperty, - @Parameter(description = "LwM2M Object ids.", required = true) + @Parameter(description = "LwM2M Object ids.", array = @ArraySchema(schema = @Schema(type = "string")), required = true) @RequestParam(required = false) String[] objectIds) throws ThingsboardException { return checkNotNull(tbResourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds)); } diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index f2e3f9192f..4c48dbd434 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -185,7 +186,7 @@ public class WidgetTypeController extends AutoCommitController { @RequestParam(required = false) Boolean fullSearch, @Parameter(description = DEPRECATED_FILTER_PARAM_DESCRIPTION, schema = @Schema(allowableValues = {"ALL", "ACTUAL", "DEPRECATED"})) @RequestParam(required = false) String deprecatedFilter, - @Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"timeseries", "latest", "control", "alarm", "static"})) + @Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"timeseries", "latest", "control", "alarm", "static"}))) @RequestParam(required = false) String[] widgetTypeList) throws ThingsboardException { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); List widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList(); @@ -331,7 +332,7 @@ public class WidgetTypeController extends AutoCommitController { @RequestParam(required = false) Boolean fullSearch, @Parameter(description = DEPRECATED_FILTER_PARAM_DESCRIPTION, schema = @Schema(allowableValues = {"ALL", "ACTUAL", "DEPRECATED"})) @RequestParam(required = false) String deprecatedFilter, - @Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, schema = @Schema(allowableValues = {"timeseries", "latest", "control", "alarm", "static"})) + @Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(allowableValues = {"timeseries", "latest", "control", "alarm", "static"}))) @RequestParam(required = false) String[] widgetTypeList) throws ThingsboardException { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); From bfe666398405efccf507488b0747b8731ce50af5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 11 Jun 2024 15:28:58 +0300 Subject: [PATCH 09/19] UI: Fixed translate typo in api-limit --- ui-ngx/src/app/shared/models/limited-api.models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/models/limited-api.models.ts b/ui-ngx/src/app/shared/models/limited-api.models.ts index 9046d8881f..946d816cfc 100644 --- a/ui-ngx/src/app/shared/models/limited-api.models.ts +++ b/ui-ngx/src/app/shared/models/limited-api.models.ts @@ -46,7 +46,7 @@ export const LimitedApiTranslationMap = new Map( [LimitedApi.TRANSPORT_MESSAGES_PER_TENANT, 'api-limit.transport-messages'], [LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE, 'api-limit.transport-messages-per-device'], [LimitedApi.TRANSPORT_MESSAGES_PER_GATEWAY, 'api-limit.transport-messages-per-gateway'], - [LimitedApi.TRANSPORT_MESSAGES_PER_GATEWAY_DEVICE, 'api-limit.transport-messages-per-gateway_device'], + [LimitedApi.TRANSPORT_MESSAGES_PER_GATEWAY_DEVICE, 'api-limit.transport-messages-per-gateway-device'], [LimitedApi.EDGE_EVENTS, 'api-limit.edge-events'], [LimitedApi.EDGE_EVENTS_PER_EDGE, 'api-limit.edge-events-per-edge'], [LimitedApi.EDGE_UPLINK_MESSAGES, 'api-limit.edge-uplink-messages'], From 03eabdc3dff081d4a006c02fa97f93f6f1169d33 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 11 Jun 2024 15:35:55 +0300 Subject: [PATCH 10/19] deleted redundant swagger schema --- .../thingsboard/server/controller/DashboardController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 37b5b8b3b1..f94c1131ed 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -250,7 +250,7 @@ public class DashboardController extends BaseController { public Dashboard updateDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids, or empty to remove all customers", array = @ArraySchema(schema = @Schema(type = "string"))) + @Parameter(description = "JSON array with the list of customer ids, or empty to remove all customers") @RequestBody(required = false) String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); @@ -268,7 +268,7 @@ public class DashboardController extends BaseController { public Dashboard addDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids", array = @ArraySchema(schema = @Schema(type = "string"))) + @Parameter(description = "JSON array with the list of customer ids") @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); @@ -286,7 +286,7 @@ public class DashboardController extends BaseController { public Dashboard removeDashboardCustomers( @Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, - @Parameter(description = "JSON array with the list of customer ids", array = @ArraySchema(schema = @Schema(type = "string"))) + @Parameter(description = "JSON array with the list of customer ids") @RequestBody String[] strCustomerIds) throws ThingsboardException { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); From 8b94a69a0903e4f0ffb15d49a170364a7059b491 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 11 Jun 2024 15:38:36 +0300 Subject: [PATCH 11/19] deleted redundant import --- .../org/thingsboard/server/controller/DashboardController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index f94c1131ed..013575361d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -18,7 +18,6 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; From bb532ba1ce06ebfd7000dd6928e878a1fd8275c0 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 11 Jun 2024 16:07:24 +0300 Subject: [PATCH 12/19] fixed swagger request params annotation --- .../server/controller/NotificationTargetController.java | 4 +++- .../server/controller/NotificationTemplateController.java | 4 +++- .../server/controller/TenantProfileController.java | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java index 8436e8fe35..7634819e39 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTargetController.java @@ -16,6 +16,8 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -156,7 +158,7 @@ public class NotificationTargetController extends BaseController { SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping(value = "/targets", params = {"ids"}) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - public List getNotificationTargetsByIds(@Parameter(description = "Comma-separated list of uuids representing targets ids", required = true) + public List getNotificationTargetsByIds(@Parameter(description = "Comma-separated list of uuids representing targets ids", array = @ArraySchema(schema = @Schema(type = "string")), required = true) @RequestParam("ids") UUID[] ids, @AuthenticationPrincipal SecurityUser user) { // PE: generic permission diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java index 6948218531..474a2816b1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationTemplateController.java @@ -16,6 +16,8 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; @@ -147,7 +149,7 @@ public class NotificationTemplateController extends BaseController { @RequestParam(required = false) String sortProperty, @Parameter(description = SORT_ORDER_DESCRIPTION) @RequestParam(required = false) String sortOrder, - @Parameter(description = "Comma-separated list of notification types to filter the templates") + @Parameter(description = "Comma-separated list of notification types to filter the templates", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam(required = false) NotificationType[] notificationTypes, @AuthenticationPrincipal SecurityUser user) throws ThingsboardException { // PE: generic permission diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 9c42683b00..62c1ecc93a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -251,7 +251,8 @@ public class TenantProfileController extends BaseController { @GetMapping(value = "/tenantProfiles", params = {"ids"}) @PreAuthorize("hasAuthority('SYS_ADMIN')") - public List getTenantProfilesByIds(@RequestParam("ids") UUID[] ids) { + public List getTenantProfilesByIds(@Parameter(description = "Comma-separated list of tenant profile ids") + @RequestParam("ids") UUID[] ids) { return tenantProfileService.findTenantProfilesByIds(TenantId.SYS_TENANT_ID, ids); } From 9d7994ef494b8fff7b8f560b18a67bc45a618d0c Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 11 Jun 2024 16:36:42 +0300 Subject: [PATCH 13/19] fixed swagger request params annotation --- .../thingsboard/server/controller/TenantProfileController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java index 62c1ecc93a..ad1ed7824a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -251,7 +252,7 @@ public class TenantProfileController extends BaseController { @GetMapping(value = "/tenantProfiles", params = {"ids"}) @PreAuthorize("hasAuthority('SYS_ADMIN')") - public List getTenantProfilesByIds(@Parameter(description = "Comma-separated list of tenant profile ids") + public List getTenantProfilesByIds(@Parameter(description = "Comma-separated list of tenant profile ids", array = @ArraySchema(schema = @Schema(type = "string"))) @RequestParam("ids") UUID[] ids) { return tenantProfileService.findTenantProfilesByIds(TenantId.SYS_TENANT_ID, ids); } From 70a418cfb2257e573f9792b6cc8065261c3b9bb9 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 11 Jun 2024 17:24:39 +0300 Subject: [PATCH 14/19] UI: Fixed notification template control not propagate new init value --- ...cation-template-configuration.component.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts index eac2dc5a7e..06dd8d030e 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts @@ -95,9 +95,10 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co branding: false }; - private propagateChange = (v: any) => { }; + private propagateChange = null; private readonly destroy$ = new Subject(); private expendedBlocks: NotificationDeliveryMethod[]; + private propagateChangePending = false; constructor(private fb: FormBuilder, private translate: TranslateService) { @@ -105,7 +106,7 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co this.templateConfigurationForm.valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value) => { - this.propagateChange(value); + this.updateModel(value); }); } @@ -129,6 +130,12 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co registerOnChange(fn: any): void { this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + Promise.resolve().then(() => { + this.templateConfigurationForm.updateValueAndValidity(); + }); + } } registerOnTouched(fn: any): void { @@ -164,6 +171,14 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co return this.expendedBlocks.includes(name); } + private updateModel(value: Partial) { + if (this.propagateChange) { + this.propagateChange(value); + } else { + this.propagateChangePending = true; + } + } + private updateExpandedForm() { this.expendedBlocks = []; Object.keys(this.templateConfigurationForm.controls).forEach((name: NotificationDeliveryMethod) => { From 8e54329453849cfdfe72cd4c5a1093f0a2967188 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 11 Jun 2024 19:07:36 +0300 Subject: [PATCH 15/19] fixed saveEntityTelemetryWithTTL method --- .../org/thingsboard/server/controller/TelemetryController.java | 2 +- 1 file changed, 1 insertion(+), 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 5f1de4e3e3..6833a7ddfb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -447,7 +447,7 @@ public class TelemetryController extends BaseController { public DeferredResult saveEntityTelemetryWithTTL( @Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType, @Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, - @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")AttributeScope scope, + @Parameter(description = TELEMETRY_SCOPE_DESCRIPTION, required = true, schema = @Schema(allowableValues = "ANY")) @PathVariable("scope")String scope, @Parameter(description = "A long value representing TTL (Time to Live) parameter.", required = true)@PathVariable("ttl")Long ttl, @io.swagger.v3.oas.annotations.parameters.RequestBody(description = TELEMETRY_JSON_REQUEST_DESCRIPTION, required = true)@RequestBody String requestBody) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); From 4aa4f0f3e520fee702966ad82023d93cf948870b Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 11 Jun 2024 19:27:46 +0300 Subject: [PATCH 16/19] fix_bug: lwm2m Bootstrap ShortServerId --- .../dao/service/validator/DeviceProfileDataValidator.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java index 0a8d78fb86..0d14dbe7ed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java @@ -330,9 +330,7 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator 65534)) { throw new DeviceCredentialsValidationException("LwM2M Server ShortServerId must not be less than 1 and more than 65534!"); } - if (serverConfig.isBootstrapServerIs() && !(serverConfig.getShortServerId() == null || serverConfig.getShortServerId() ==0)) { - throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must be null or '0'!"); - } + String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (!shortServerIds.add(serverConfig.getShortServerId())) { throw new DeviceCredentialsValidationException(server + " \"Short server Id\" value = " + serverConfig.getShortServerId() + ". This value must be a unique value for all servers!"); From d5f954d3df6dca19c10793cac55f5fc315829b19 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 12 Jun 2024 07:45:14 +0300 Subject: [PATCH 17/19] fix_bug: lwm2m Bootstrap ShortServerId must not be less than 0 and more than 65535! --- .../dao/service/validator/DeviceProfileDataValidator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java index 0d14dbe7ed..a26b419d9c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java @@ -331,6 +331,10 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator 65535)) { + throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must not be less than 0 and more than 65535!"); + } + String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; if (!shortServerIds.add(serverConfig.getShortServerId())) { throw new DeviceCredentialsValidationException(server + " \"Short server Id\" value = " + serverConfig.getShortServerId() + ". This value must be a unique value for all servers!"); From 242b0019a2d41f37301987541f3bd3c98bc23238 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 12 Jun 2024 08:41:22 +0300 Subject: [PATCH 18/19] fix_bug: lwm2m Bootstrap ShortServerId must not be less than 0 and more than 65535! -2 --- .../dao/service/validator/DeviceProfileDataValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java index a26b419d9c..3095de6bb9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java @@ -331,7 +331,7 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator 65535)) { + if (serverConfig.isBootstrapServerIs() && (serverConfig.getShortServerId() < 0 || serverConfig.getShortServerId() > 65535)) { throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must not be less than 0 and more than 65535!"); } From 8420de0cb467cc75d6d61a0a67cdd5e3e51fc26d Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 12 Jun 2024 12:53:17 +0300 Subject: [PATCH 19/19] fix_bug: lwm2m Bootstrap ShortServerId must not be less than 0 and more than 65535! add test --- .../validator/DeviceProfileDataValidator.java | 18 ++-- .../DeviceProfileDataValidatorTest.java | 88 +++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java index 3095de6bb9..2d2c7bf21c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java @@ -327,12 +327,20 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator 65534)) { - throw new DeviceCredentialsValidationException("LwM2M Server ShortServerId must not be less than 1 and more than 65534!"); - } - if (serverConfig.isBootstrapServerIs() && (serverConfig.getShortServerId() < 0 || serverConfig.getShortServerId() > 65535)) { - throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must not be less than 0 and more than 65535!"); + if (serverConfig.getShortServerId() != null) { + if (serverConfig.isBootstrapServerIs()){ + if(serverConfig.getShortServerId() < 0 || serverConfig.getShortServerId() > 65535){ + throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must be in range [0 - 65535]!"); + } + } else { + if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) { + throw new DeviceCredentialsValidationException("LwM2M Server ShortServerId must be in range [1 - 65534]!"); + } + } + } else { + String serverName = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; + throw new DeviceCredentialsValidationException(serverName + " ShortServerId must not be null!"); } String server = serverConfig.isBootstrapServerIs() ? "Bootstrap Server" : "LwM2M Server"; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java index ac0fa2cfe1..2da8a7ff45 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java @@ -20,11 +20,18 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.AbstractLwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential; +import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.NoSecLwM2MBootstrapServerCredential; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceDao; @@ -34,6 +41,8 @@ import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import static org.mockito.BDDMockito.willReturn; @@ -42,6 +51,34 @@ import static org.mockito.Mockito.verify; @SpringBootTest(classes = DeviceProfileDataValidator.class) class DeviceProfileDataValidatorTest { + private static final String OBSERVE_ATTRIBUTES_WITHOUT_PARAMS = + " {\n" + + " \"keyName\": {},\n" + + " \"observe\": [],\n" + + " \"attribute\": [],\n" + + " \"telemetry\": [],\n" + + " \"attributeLwm2m\": {}\n" + + " }"; + + public static final String CLIENT_LWM2M_SETTINGS = + " {\n" + + " \"edrxCycle\": null,\n" + + " \"powerMode\": \"DRX\",\n" + + " \"fwUpdateResource\": null,\n" + + " \"fwUpdateStrategy\": 1,\n" + + " \"psmActivityTimer\": null,\n" + + " \"swUpdateResource\": null,\n" + + " \"swUpdateStrategy\": 1,\n" + + " \"pagingTransmissionWindow\": null,\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + + " }"; + + private static final String host = "localhost"; + private static final String hostBs = "localhost"; + + private static final int port = 5685; + private static final int portBs = 5687; + @MockBean DeviceProfileDao deviceProfileDao; @MockBean @@ -79,5 +116,56 @@ class DeviceProfileDataValidatorTest { validator.validateDataImpl(tenantId, deviceProfile); verify(validator).validateString("Device profile name", deviceProfile.getName()); } + @Test + void testValidateDeviceProfile_Lwm2mBootstrap_ShortServerId_Ok() { + Integer shortServerId = 123; + Integer shortServerIdBs = 0; + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = + getTransportConfiguration(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, getBootstrapServerCredentialsNoSec(shortServerId, shortServerIdBs)); + DeviceProfile deviceProfile = getDeviceProfile(transportConfiguration); + + validator.validateDataImpl(tenantId, deviceProfile); + verify(validator).validateString("Device profile name", deviceProfile.getName()); + } + + private DeviceProfile getDeviceProfile(Lwm2mDeviceProfileTransportConfiguration transportConfiguration) { + DeviceProfile deviceProfile = new DeviceProfile(); + deviceProfile.setName("default"); + deviceProfile.setType(DeviceProfileType.DEFAULT); + deviceProfile.setTransportType(DeviceTransportType.LWM2M); + DeviceProfileData data = new DeviceProfileData(); + data.setTransportConfiguration(transportConfiguration); + deviceProfile.setProfileData(data); + deviceProfile.setTenantId(tenantId); + return deviceProfile; + } + + private Lwm2mDeviceProfileTransportConfiguration getTransportConfiguration(String observeAttr, List bootstrapServerCredentials) { + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); + TelemetryMappingConfiguration observeAttrConfiguration = JacksonUtil.fromString(observeAttr, TelemetryMappingConfiguration.class); + OtherConfiguration clientLwM2mSettings = JacksonUtil.fromString(CLIENT_LWM2M_SETTINGS, OtherConfiguration.class); + transportConfiguration.setBootstrapServerUpdateEnable(true); + transportConfiguration.setObserveAttr(observeAttrConfiguration); + transportConfiguration.setClientLwM2mSettings(clientLwM2mSettings); + transportConfiguration.setBootstrap(bootstrapServerCredentials); + return transportConfiguration; + } + + private List getBootstrapServerCredentialsNoSec(Integer shortServerId, Integer shortServerIdBs){ + List bootstrap = new ArrayList<>(); + bootstrap.add(getBootstrapServerCredentialNoSec(false, shortServerId, shortServerIdBs)); + bootstrap.add(getBootstrapServerCredentialNoSec(true, shortServerId, shortServerIdBs)); + return bootstrap; + } + + private AbstractLwM2MBootstrapServerCredential getBootstrapServerCredentialNoSec(boolean isBootstrap, Integer shortServerId, Integer shortServerIdBs) { + AbstractLwM2MBootstrapServerCredential bootstrapServerCredential = new NoSecLwM2MBootstrapServerCredential(); + bootstrapServerCredential.setServerPublicKey(""); + bootstrapServerCredential.setShortServerId(isBootstrap ? shortServerIdBs : shortServerId); + bootstrapServerCredential.setBootstrapServerIs(isBootstrap); + bootstrapServerCredential.setHost(isBootstrap ? hostBs : host); + bootstrapServerCredential.setPort(isBootstrap ? portBs : port); + return bootstrapServerCredential; + } }