From fc837f3f1bc3a9fc73c6a4775e6664e30c70bfd1 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 30 Apr 2021 12:50:40 +0300 Subject: [PATCH 01/29] UI: Rename LWM2M tab name --- .../lwm2m-device-profile-transport-configuration.component.html | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 5363d05d74..a29605a527 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -51,7 +51,7 @@ - +
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 57727fa40f..5a9d90ebb2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1227,7 +1227,6 @@ "required": " value is required.", "mode": "Security config mode", "pattern_hex_dec": "{ count, plural, 0 {must be hex decimal format} other {must be # characters} }", - "bootstrap-tab": "Bootstrap", "servers": "Servers", "short-id": "Short ID", "short-id-tip": "Short Server ID", From 89c1743fa0549034767a45ee740f8f53114f0ead Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 5 May 2021 18:27:39 +0300 Subject: [PATCH 02/29] Lwm2m: RPC finish --- .../DefaultLwM2MTransportMsgHandler.java | 34 +++++++++++++++++-- .../lwm2m/server/LwM2mTransportRequest.java | 17 ++++++++-- .../server/client/Lwm2mClientRpcRequest.java | 10 ++++++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index b9de7bcea2..a654abdad5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -104,6 +104,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @@ -455,9 +456,23 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwm2mClientRpcRequest.setValue(rpcRequest.get(lwm2mClientRpcRequest.valueKey).getAsString()); } if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) { - lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) + ConcurrentHashMap params = new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) .getAsJsonObject().toString(), new TypeToken>() { - }.getType())); + }.getType()); + if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) { + ConcurrentHashMap paramsResourceId = convertParamsToResourceId (params, sessionInfo); + if (paramsResourceId.size() > 0) { + lwm2mClientRpcRequest.setParams(paramsResourceId); + } + } + else { + lwm2mClientRpcRequest.setParams(params); + } + } + else if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonArray()) { + new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) + .getAsJsonObject().toString(), new TypeToken>() { + }.getType()); } lwm2mClientRpcRequest.setSessionInfo(sessionInfo); if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) { @@ -484,6 +499,21 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler return lwm2mClientRpcRequest; } + private ConcurrentHashMap convertParamsToResourceId (ConcurrentHashMap params, + SessionInfoProto sessionInfo) { + ConcurrentHashMap paramsIdVer = new ConcurrentHashMap<>(); + params.forEach((k, v) -> { + String targetIdVer = this.getPresentPathIntoProfile(sessionInfo, k); + if (targetIdVer != null ) { + LwM2mPath targetId = new LwM2mPath(convertPathFromIdVerToObjectId(targetIdVer)); + if (targetId.isResource()) { + paramsIdVer.put(String.valueOf(targetId.getResourceId()), v); + } + } + }); + return paramsIdVer; + } + public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { rpcRequest.setResponseCode(requestCode); if (LOG_LW2M_ERROR.equals(typeMsg)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index a187143974..0a5a545065 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -197,8 +197,18 @@ public class LwM2mTransportRequest { targetIdVer, params, this.config.getModelProvider(), this.converter); - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), - resultIds.getObjectInstanceId(), resources); + if (resources.size()>0) { + request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resources); + } + else { + Lwm2mClientRpcRequest rpcRequestClone = (Lwm2mClientRpcRequest) rpcRequest.clone(); + if (rpcRequestClone != null) { + String errorMsg = String.format("Path %s params is not valid", targetIdVer); + serviceImpl.sentRpcRequest(rpcRequestClone, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); + rpcRequest = null; + } + } } } else if (resultIds.getObjectId() >= 0) { request = new ObserveRequest(resultIds.getObjectId()); @@ -218,7 +228,8 @@ public class LwM2mTransportRequest { } catch (ClientSleepingException e) { DownlinkRequest finalRequest = request; long finalTimeoutInMs = timeoutInMs; - lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest)); + Lwm2mClientRpcRequest finalRpcRequest = rpcRequest; + lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest)); } catch (Exception e) { log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java index 4734b5dd8e..0f0bd34024 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java @@ -107,4 +107,14 @@ public class Lwm2mClientRpcRequest { .setRequestId(this.requestId) .build(); } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return null; + } } From d5b640d6021d4a3b57ae1b70cb1706084809a0af Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 6 May 2021 17:01:46 +0300 Subject: [PATCH 03/29] Add image fields for dashboard and device profile entities. Introduce getAllAlarms and getCustomerAlarms API --- .../main/data/upgrade/3.2.2/schema_update.sql | 4 ++ .../server/controller/AlarmController.java | 35 ++++++++++ .../DefaultAlarmSubscriptionService.java | 5 ++ .../BaseDeviceProfileControllerTest.java | 2 +- .../server/dao/alarm/AlarmService.java | 2 + .../server/common/data/DashboardInfo.java | 10 +++ .../server/common/data/DeviceProfile.java | 2 + .../server/common/data/DeviceProfileInfo.java | 6 +- .../server/dao/alarm/AlarmDao.java | 2 + .../server/dao/alarm/BaseAlarmService.java | 43 ++++++++----- .../server/dao/model/ModelConstants.java | 2 + .../server/dao/model/sql/DashboardEntity.java | 7 +- .../dao/model/sql/DashboardInfoEntity.java | 5 ++ .../dao/model/sql/DeviceProfileEntity.java | 5 ++ .../server/dao/sql/alarm/AlarmRepository.java | 64 +++++++++++++++++++ .../server/dao/sql/alarm/JpaAlarmDao.java | 41 +++++++++++- .../sql/device/DeviceProfileRepository.java | 8 +-- .../resources/sql/schema-entities-hsql.sql | 4 +- .../main/resources/sql/schema-entities.sql | 4 +- .../service/BaseDeviceProfileServiceTest.java | 2 +- .../engine/api/RuleEngineAlarmService.java | 2 + .../add-device-profile-dialog.component.html | 5 ++ .../add-device-profile-dialog.component.ts | 2 + .../profile/device-profile.component.html | 5 ++ .../profile/device-profile.component.ts | 2 + .../dashboard/dashboard-form.component.html | 5 ++ .../dashboard/dashboard-form.component.ts | 2 + .../components/image-input.component.html | 8 +-- .../src/app/shared/models/dashboard.models.ts | 1 + ui-ngx/src/app/shared/models/device.models.ts | 1 + .../assets/locale/locale.constant-en_US.json | 3 + 31 files changed, 257 insertions(+), 32 deletions(-) diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index af3fd418a8..4bb63f3b9f 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -78,7 +78,11 @@ CREATE TABLE IF NOT EXISTS firmware ( CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version) ); +ALTER TABLE dashboard + ADD COLUMN IF NOT EXISTS image varchar(1000000); + ALTER TABLE device_profile + ADD COLUMN IF NOT EXISTS image varchar(1000000), ADD COLUMN IF NOT EXISTS firmware_id uuid, ADD COLUMN IF NOT EXISTS software_id uuid; 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 9453bd46b7..6aec756f61 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -196,6 +196,41 @@ public class AlarmController extends BaseController { } } + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarms", method = RequestMethod.GET) + @ResponseBody + public PageData getAllAlarms( + @RequestParam(required = false) String searchStatus, + @RequestParam(required = false) String status, + @RequestParam int pageSize, + @RequestParam int page, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String sortProperty, + @RequestParam(required = false) String sortOrder, + @RequestParam(required = false) Long startTime, + @RequestParam(required = false) Long endTime, + @RequestParam(required = false) Boolean fetchOriginator + ) throws ThingsboardException { + accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, Operation.READ); + AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); + AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); + if (alarmSearchStatus != null && alarmStatus != null) { + throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); + + try { + if (getCurrentUser().isCustomerUser()) { + return checkNotNull(alarmService.findCustomerAlarms(getCurrentUser().getTenantId(), getCurrentUser().getCustomerId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); + } else { + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); + } + } catch (Exception e) { + throw handleException(e); + } + } + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java index c2ff292667..82700ff064 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java @@ -127,6 +127,11 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return alarmService.findAlarms(tenantId, query); } + @Override + public ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query) { + return alarmService.findCustomerAlarms(tenantId, customerId, query); + } + @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) { return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java index 310fb40215..95a878f9db 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java @@ -313,7 +313,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator); List deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), - deviceProfile.getName(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); + deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 5badd872df..2bca57b1b0 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -53,6 +53,8 @@ public interface AlarmService { ListenableFuture> findAlarms(TenantId tenantId, AlarmQuery query); + ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); + AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index 854c5ff64b..cbcd213377 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -30,6 +30,7 @@ public class DashboardInfo extends SearchTextBased implements HasNa private TenantId tenantId; @NoXss private String title; + private String image; @Valid private Set assignedCustomers; @@ -45,6 +46,7 @@ public class DashboardInfo extends SearchTextBased implements HasNa super(dashboardInfo); this.tenantId = dashboardInfo.getTenantId(); this.title = dashboardInfo.getTitle(); + this.image = dashboardInfo.getImage(); this.assignedCustomers = dashboardInfo.getAssignedCustomers(); } @@ -64,6 +66,14 @@ public class DashboardInfo extends SearchTextBased implements HasNa this.title = title; } + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + public Set getAssignedCustomers() { return assignedCustomers; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index daf7d77af0..8104f6bf80 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -43,6 +43,7 @@ public class DeviceProfile extends SearchTextBased implements H private String name; @NoXss private String description; + private String image; private boolean isDefault; private DeviceProfileType type; private DeviceTransportType transportType; @@ -74,6 +75,7 @@ public class DeviceProfile extends SearchTextBased implements H this.tenantId = deviceProfile.getTenantId(); this.name = deviceProfile.getName(); this.description = deviceProfile.getDescription(); + this.image = deviceProfile.getImage(); this.isDefault = deviceProfile.isDefault(); this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId(); this.defaultQueueName = deviceProfile.getDefaultQueueName(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index db83c58d13..c134934d66 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java @@ -30,21 +30,25 @@ import java.util.UUID; @ToString(callSuper = true) public class DeviceProfileInfo extends EntityInfo { + private final String image; private final DeviceProfileType type; private final DeviceTransportType transportType; @JsonCreator public DeviceProfileInfo(@JsonProperty("id") EntityId id, @JsonProperty("name") String name, + @JsonProperty("image") String image, @JsonProperty("type") DeviceProfileType type, @JsonProperty("transportType") DeviceTransportType transportType) { super(id, name); + this.image = image; this.type = type; this.transportType = transportType; } - public DeviceProfileInfo(UUID uuid, String name, DeviceProfileType type, DeviceTransportType transportType) { + public DeviceProfileInfo(UUID uuid, String name, String image, DeviceProfileType type, DeviceTransportType transportType) { super(EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE_PROFILE, uuid), name); + this.image = image; this.type = type; this.transportType = transportType; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java index ebbfae0f05..eb873db679 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java @@ -48,6 +48,8 @@ public interface AlarmDao extends Dao { PageData findAlarms(TenantId tenantId, AlarmQuery query); + PageData findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); + PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 9dff668f2e..472cbb588f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -292,25 +292,38 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ public ListenableFuture> findAlarms(TenantId tenantId, AlarmQuery query) { PageData alarms = alarmDao.findAlarms(tenantId, query); if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { - List> alarmFutures = new ArrayList<>(alarms.getData().size()); - for (AlarmInfo alarmInfo : alarms.getData()) { - alarmFutures.add(Futures.transform( - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { - if (originatorName == null) { - originatorName = "Deleted"; - } - alarmInfo.setOriginatorName(originatorName); - return alarmInfo; - }, MoreExecutors.directExecutor() - )); - } - return Futures.transform(Futures.successfulAsList(alarmFutures), - alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), - alarms.hasNext()), MoreExecutors.directExecutor()); + return fetchAlarmsOriginators(tenantId, alarms); } return Futures.immediateFuture(alarms); } + @Override + public ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query) { + PageData alarms = alarmDao.findCustomerAlarms(tenantId, customerId, query); + if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { + return fetchAlarmsOriginators(tenantId, alarms); + } + return Futures.immediateFuture(alarms); + } + + private ListenableFuture> fetchAlarmsOriginators(TenantId tenantId, PageData alarms) { + List> alarmFutures = new ArrayList<>(alarms.getData().size()); + for (AlarmInfo alarmInfo : alarms.getData()) { + alarmFutures.add(Futures.transform( + entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { + if (originatorName == null) { + originatorName = "Deleted"; + } + alarmInfo.setOriginatorName(originatorName); + return alarmInfo; + }, MoreExecutors.directExecutor() + )); + } + return Futures.transform(Futures.successfulAsList(alarmFutures), + alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), + alarms.hasNext()), MoreExecutors.directExecutor()); + } + @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index bc0afe630d..5b4ea874ee 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -170,6 +170,7 @@ public class ModelConstants { public static final String DEVICE_PROFILE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String DEVICE_PROFILE_NAME_PROPERTY = "name"; public static final String DEVICE_PROFILE_TYPE_PROPERTY = "type"; + public static final String DEVICE_PROFILE_IMAGE_PROPERTY = "image"; public static final String DEVICE_PROFILE_TRANSPORT_TYPE_PROPERTY = "transport_type"; public static final String DEVICE_PROFILE_PROVISION_TYPE_PROPERTY = "provision_type"; public static final String DEVICE_PROFILE_PROFILE_DATA_PROPERTY = "profile_data"; @@ -333,6 +334,7 @@ public class ModelConstants { public static final String DASHBOARD_COLUMN_FAMILY_NAME = "dashboard"; public static final String DASHBOARD_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String DASHBOARD_TITLE_PROPERTY = TITLE_PROPERTY; + public static final String DASHBOARD_IMAGE_PROPERTY = "image"; public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration"; public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java index e0780a5fc9..8e499858bc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java @@ -58,7 +58,10 @@ public final class DashboardEntity extends BaseSqlEntity implements S @Column(name = ModelConstants.DASHBOARD_TITLE_PROPERTY) private String title; - + + @Column(name = ModelConstants.DASHBOARD_IMAGE_PROPERTY) + private String image; + @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; @@ -82,6 +85,7 @@ public final class DashboardEntity extends BaseSqlEntity implements S this.tenantId = dashboard.getTenantId().getId(); } this.title = dashboard.getTitle(); + this.image = dashboard.getImage(); if (dashboard.getAssignedCustomers() != null) { try { this.assignedCustomers = objectMapper.writeValueAsString(dashboard.getAssignedCustomers()); @@ -110,6 +114,7 @@ public final class DashboardEntity extends BaseSqlEntity implements S dashboard.setTenantId(new TenantId(tenantId)); } dashboard.setTitle(title); + dashboard.setImage(image); if (!StringUtils.isEmpty(assignedCustomers)) { try { dashboard.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java index 47c7016aba..b3d7738843 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java @@ -54,6 +54,9 @@ public class DashboardInfoEntity extends BaseSqlEntity implements @Column(name = ModelConstants.DASHBOARD_TITLE_PROPERTY) private String title; + @Column(name = ModelConstants.DASHBOARD_IMAGE_PROPERTY) + private String image; + @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; @@ -73,6 +76,7 @@ public class DashboardInfoEntity extends BaseSqlEntity implements this.tenantId = dashboardInfo.getTenantId().getId(); } this.title = dashboardInfo.getTitle(); + this.image = dashboardInfo.getImage(); if (dashboardInfo.getAssignedCustomers() != null) { try { this.assignedCustomers = objectMapper.writeValueAsString(dashboardInfo.getAssignedCustomers()); @@ -104,6 +108,7 @@ public class DashboardInfoEntity extends BaseSqlEntity implements dashboardInfo.setTenantId(new TenantId(tenantId)); } dashboardInfo.setTitle(title); + dashboardInfo.setImage(image); if (!StringUtils.isEmpty(assignedCustomers)) { try { dashboardInfo.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index e4c32a44f0..f66153abbc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -60,6 +60,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.DEVICE_PROFILE_TYPE_PROPERTY) private DeviceProfileType type; + @Column(name = ModelConstants.DEVICE_PROFILE_IMAGE_PROPERTY) + private String image; + @Enumerated(EnumType.STRING) @Column(name = ModelConstants.DEVICE_PROFILE_TRANSPORT_TYPE_PROPERTY) private DeviceTransportType transportType; @@ -110,6 +113,7 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl this.setCreatedTime(deviceProfile.getCreatedTime()); this.name = deviceProfile.getName(); this.type = deviceProfile.getType(); + this.image = deviceProfile.getImage(); this.transportType = deviceProfile.getTransportType(); this.provisionType = deviceProfile.getProvisionType(); this.description = deviceProfile.getDescription(); @@ -151,6 +155,7 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl } deviceProfile.setName(name); deviceProfile.setType(type); + deviceProfile.setImage(image); deviceProfile.setTransportType(transportType); deviceProfile.setProvisionType(provisionType); deviceProfile.setDescription(description); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 446125e4fb..028eda1583 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -94,6 +94,70 @@ public interface AlarmRepository extends CrudRepository { @Param("searchText") String searchText, Pageable pageable); + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + + "WHERE a.tenantId = :tenantId " + + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ", + countQuery = "" + + "SELECT count(a) " + + "FROM AlarmEntity a " + + "WHERE a.tenantId = :tenantId " + + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ") + Page findAllAlarms(@Param("tenantId") UUID tenantId, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime, + @Param("alarmStatuses") Set alarmStatuses, + @Param("searchText") String searchText, + Pageable pageable); + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + + "WHERE a.tenantId = :tenantId " + + "AND (" + + "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + + "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + + "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + + "OR a.originatorId = :customerId" + + ") " + + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) " + , + countQuery = "" + + "SELECT count(a) " + + "FROM AlarmEntity a " + + "WHERE a.tenantId = :tenantId " + + "AND (" + + "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + + "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + + "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + + "OR a.originatorId = :customerId" + + ") " + + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%')) " + + " OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%'))) ") + Page findCustomerAlarms(@Param("tenantId") UUID tenantId, + @Param("customerId") UUID customerId, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime, + @Param("alarmStatuses") Set alarmStatuses, + @Param("searchText") String searchText, + Pageable pageable); + @Query(value = "SELECT a.severity FROM AlarmEntity a " + "LEFT JOIN RelationEntity re ON a.id = re.toId " + "AND re.relationTypeGroup = 'ALARM' " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java index bfca088c69..cf222413b0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java @@ -103,11 +103,46 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } else if (query.getStatus() != null) { statusSet = Collections.singleton(query.getStatus()); } + if (affectedEntity != null) { + return DaoUtil.toPageData( + alarmRepository.findAlarms( + tenantId.getId(), + affectedEntity.getId(), + affectedEntity.getEntityType().name(), + query.getPageLink().getStartTime(), + query.getPageLink().getEndTime(), + statusSet, + Objects.toString(query.getPageLink().getTextSearch(), ""), + DaoUtil.toPageable(query.getPageLink()) + ) + ); + } else { + return DaoUtil.toPageData( + alarmRepository.findAllAlarms( + tenantId.getId(), + query.getPageLink().getStartTime(), + query.getPageLink().getEndTime(), + statusSet, + Objects.toString(query.getPageLink().getTextSearch(), ""), + DaoUtil.toPageable(query.getPageLink()) + ) + ); + } + } + + @Override + public PageData findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query) { + log.trace("Try to find customer alarms by status [{}] and pageLink [{}]", query.getStatus(), query.getPageLink()); + Set statusSet = null; + if (query.getSearchStatus() != null) { + statusSet = query.getSearchStatus().getStatuses(); + } else if (query.getStatus() != null) { + statusSet = Collections.singleton(query.getStatus()); + } return DaoUtil.toPageData( - alarmRepository.findAlarms( + alarmRepository.findCustomerAlarms( tenantId.getId(), - affectedEntity.getId(), - affectedEntity.getEntityType().name(), + customerId.getId(), query.getPageLink().getStartTime(), query.getPageLink().getEndTime(), statusSet, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index c4d6db691b..33d1c3ece1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -28,7 +28,7 @@ import java.util.UUID; public interface DeviceProfileRepository extends PagingAndSortingRepository { - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.type, d.transportType) " + + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + "FROM DeviceProfileEntity d " + "WHERE d.id = :deviceProfileId") DeviceProfileInfo findDeviceProfileInfoById(@Param("deviceProfileId") UUID deviceProfileId); @@ -39,14 +39,14 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository findDeviceProfileInfos(@Param("tenantId") UUID tenantId, @Param("textSearch") String textSearch, Pageable pageable); - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.type, d.transportType) " + + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + "FROM DeviceProfileEntity d WHERE " + "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") Page findDeviceProfileInfos(@Param("tenantId") UUID tenantId, @@ -58,7 +58,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository deviceProfileInfos = deviceProfiles.stream() .map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), - deviceProfile.getName(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); + deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java index d6a0a3e576..7d3157588b 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java @@ -57,6 +57,8 @@ public interface RuleEngineAlarmService { ListenableFuture> findAlarms(TenantId tenantId, AlarmQuery query); + ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); + AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus); PageData findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataQuery query, Collection orderedEntityIds); diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index 23219f1074..fa9b03bcb3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -60,6 +60,11 @@ {{ 'device-profile.type-required' | translate }} + + device-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index 9ad7993857..1de74c9de5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -106,6 +106,7 @@ export class AddDeviceProfileDialogComponent extends { name: [data.deviceProfileName, [Validators.required]], type: [DeviceProfileType.DEFAULT, [Validators.required]], + image: [null, []], defaultRuleChainId: [null, []], defaultQueueName: ['', []], description: ['', []] @@ -183,6 +184,7 @@ export class AddDeviceProfileDialogComponent extends const deviceProfile: DeviceProfile = { name: this.deviceProfileDetailsFormGroup.get('name').value, type: this.deviceProfileDetailsFormGroup.get('type').value, + image: this.deviceProfileDetailsFormGroup.get('image').value, transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 5c21d65adc..cff6177955 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -86,6 +86,11 @@ {{ 'device-profile.type-required' | translate }} + + device-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index d8505a0a3b..1e8699210d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -103,6 +103,7 @@ export class DeviceProfileComponent extends EntityComponent { { name: [entity ? entity.name : '', [Validators.required]], type: [entity ? entity.type : null, [Validators.required]], + image: [entity ? entity.image : null], transportType: [entity ? entity.transportType : null, [Validators.required]], profileData: this.fb.group({ configuration: [entity && !this.isAdd ? entity.profileData?.configuration : {}, Validators.required], @@ -178,6 +179,7 @@ export class DeviceProfileComponent extends EntityComponent { }; this.entityForm.patchValue({name: entity.name}); this.entityForm.patchValue({type: entity.type}, {emitEvent: false}); + this.entityForm.patchValue({image: entity.image}, {emitEvent: false}); this.entityForm.patchValue({transportType: entity.transportType}, {emitEvent: false}); this.entityForm.patchValue({provisionType: entity.provisionType}, {emitEvent: false}); this.entityForm.patchValue({provisionDeviceKey: entity.provisionDeviceKey}, {emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html index 1fb8978f22..ca7512d7ec 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html @@ -105,6 +105,11 @@ {{ 'dashboard.title-required' | translate }} + +
dashboard.description diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts index 37030c57f1..70914e069d 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts @@ -80,6 +80,7 @@ export class DashboardFormComponent extends EntityComponent { return this.fb.group( { title: [entity ? entity.title : '', [Validators.required]], + image: [entity ? entity.image : null], configuration: this.fb.group( { description: [entity && entity.configuration ? entity.configuration.description : ''], @@ -92,6 +93,7 @@ export class DashboardFormComponent extends EntityComponent { updateForm(entity: Dashboard) { this.updateFields(entity); this.entityForm.patchValue({title: entity.title}); + this.entityForm.patchValue({image: entity.image}); this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); } diff --git a/ui-ngx/src/app/shared/components/image-input.component.html b/ui-ngx/src/app/shared/components/image-input.component.html index 4b7e4fe1d4..2fe8cc4102 100644 --- a/ui-ngx/src/app/shared/components/image-input.component.html +++ b/ui-ngx/src/app/shared/components/image-input.component.html @@ -21,10 +21,10 @@ [flowConfig]="{singleFile: true, allowDuplicateUploads: true}">
-
dashboard.no-image
+
{{ (disabled ? 'dashboard.empty-image' : 'dashboard.no-image') | translate }}
-
+
-
@@ -42,5 +42,5 @@
-
dashboard.maximum-upload-file-size
+
dashboard.maximum-upload-file-size
diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index 6a90101923..98a19d1b13 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -26,6 +26,7 @@ import { Filters } from '@shared/models/query/query.models'; export interface DashboardInfo extends BaseData { tenantId?: TenantId; title?: string; + image?: string; assignedCustomers?: Array; } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 683d9ddcc1..81fdb7a8fd 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -492,6 +492,7 @@ export interface DeviceProfile extends BaseData { description?: string; default?: boolean; type: DeviceProfileType; + image?: string; transportType: DeviceTransportType; provisionType: DeviceProvisionType; provisionDeviceKey?: string; 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 f664dc27a7..adfd8434a2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -666,6 +666,7 @@ "no-widgets": "No widgets configured", "add-widget": "Add new widget", "title": "Title", + "image": "Dashboard image", "select-widget-title": "Select widget", "select-widget-value": "{{title}}: select widget", "select-widget-subtitle": "List of available widget types", @@ -712,6 +713,7 @@ "background-image": "Background image", "background-size-mode": "Background size mode", "no-image": "No image selected", + "empty-image": "No image", "drop-image": "Drop an image or click to select a file to upload.", "maximum-upload-file-size": "Maximum upload file size: {{ size }}", "cannot-upload-file": "Cannot upload file", @@ -1028,6 +1030,7 @@ "type": "Profile type", "type-required": "Profile type is required.", "type-default": "Default", + "image": "Device profile image", "transport-type": "Transport type", "transport-type-required": "Transport type is required.", "transport-type-default": "Default", From df8c9cecaecda12a08372a4de59ffe8e3a2a3507 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 6 May 2021 20:14:34 +0300 Subject: [PATCH 04/29] Minor improvements --- ui-ngx/src/app/core/http/alarm.service.ts | 2 +- .../modules/home/components/alarm/alarm-table-config.ts | 2 +- ui-ngx/src/app/shared/models/alarm.models.ts | 7 +------ ui-ngx/src/app/shared/models/device.models.ts | 1 + 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/core/http/alarm.service.ts b/ui-ngx/src/app/core/http/alarm.service.ts index ab35c49b01..dc5771e31b 100644 --- a/ui-ngx/src/app/core/http/alarm.service.ts +++ b/ui-ngx/src/app/core/http/alarm.service.ts @@ -72,7 +72,7 @@ export class AlarmService { public getHighestAlarmSeverity(entityId: EntityId, alarmSearchStatus: AlarmSearchStatus, alarmStatus: AlarmStatus, config?: RequestConfig): Observable { - let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.entityType}`; + let url = `/api/alarm/highestSeverity/${entityId.entityType}/${entityId.id}`; if (alarmSearchStatus) { url += `?searchStatus=${alarmSearchStatus}`; } else if (alarmStatus) { diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index 743b49c286..2bff69a53e 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -108,7 +108,7 @@ export class AlarmTableConfig extends EntityTableConfig } fetchAlarms(pageLink: TimePageLink): Observable> { - const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true, null); + const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true); return this.alarmService.getAlarms(query); } diff --git a/ui-ngx/src/app/shared/models/alarm.models.ts b/ui-ngx/src/app/shared/models/alarm.models.ts index a76bf1b425..c79935f23d 100644 --- a/ui-ngx/src/app/shared/models/alarm.models.ts +++ b/ui-ngx/src/app/shared/models/alarm.models.ts @@ -201,17 +201,15 @@ export class AlarmQuery { searchStatus: AlarmSearchStatus; status: AlarmStatus; fetchOriginator: boolean; - offset: string; constructor(entityId: EntityId, pageLink: TimePageLink, searchStatus: AlarmSearchStatus, status: AlarmStatus, - fetchOriginator: boolean, offset: string) { + fetchOriginator: boolean) { this.affectedEntityId = entityId; this.pageLink = pageLink; this.searchStatus = searchStatus; this.status = status; this.fetchOriginator = fetchOriginator; - this.offset = offset; } public toQuery(): string { @@ -225,9 +223,6 @@ export class AlarmQuery { if (typeof this.fetchOriginator !== 'undefined' && this.fetchOriginator !== null) { query += `&fetchOriginator=${this.fetchOriginator}`; } - if (isString(this.offset) && this.offset.length) { - query += `&offset=${this.offset}`; - } return query; } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 81fdb7a8fd..5e5418fa4d 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -506,6 +506,7 @@ export interface DeviceProfile extends BaseData { export interface DeviceProfileInfo extends EntityInfoData { type: DeviceProfileType; transportType: DeviceTransportType; + image?: string; } export interface DefaultDeviceConfiguration { From 96878b6d1356c95a2c13ffbe32eb4fa08d30363a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 6 May 2021 20:36:02 +0300 Subject: [PATCH 05/29] Minor improvements --- .../java/org/thingsboard/server/controller/AlarmController.java | 1 - 1 file changed, 1 deletion(-) 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 6aec756f61..03883fc167 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -211,7 +211,6 @@ public class AlarmController extends BaseController { @RequestParam(required = false) Long endTime, @RequestParam(required = false) Boolean fetchOriginator ) throws ThingsboardException { - accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, Operation.READ); AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); if (alarmSearchStatus != null && alarmStatus != null) { From 0f150337397472a1b0deb117a7eeb649c9dbcfff Mon Sep 17 00:00:00 2001 From: nickAS21 <44275303+nickAS21@users.noreply.github.com> Date: Fri, 7 May 2021 16:05:48 +0300 Subject: [PATCH 06/29] Lwm2m: fix bug add new instance (#4554) * Lwm2m: fix bug add new instance * Lwm2m: add KeyName default with instanceId --- ...-profile-transport-configuration.component.ts | 16 ++++++++++++---- .../lwm2m-observe-attr-telemetry.component.ts | 5 +++-- .../device/lwm2m/lwm2m-profile-config.models.ts | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 60fb27a752..0a943ab5af 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts @@ -23,6 +23,7 @@ import { BINDING_MODE, BINDING_MODE_NAMES, getDefaultProfileConfig, + Instance, INSTANCES, KEY_NAME, Lwm2mProfileConfigModels, @@ -37,6 +38,7 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; import { deepClone, isDefinedAndNotNull, isEmpty, isUndefined } from '@core/utils'; import { JsonArray, JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point'; import { Direction } from '@shared/models/page/sort-order'; +import _ from 'lodash'; @Component({ selector: 'tb-profile-lwm2m-device-transport-configuration', @@ -230,24 +232,30 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro const isNotZeroInstanceId = (instance) => !instance.includes('/0/'); return attribute.some(isNotZeroInstanceId) || telemetry.some(isNotZeroInstanceId); } - private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => { const instancesPath = attribute.concat(telemetry) .filter(instance => !instance.includes('/0/')) .map(instance => instance.slice(1, instance.lastIndexOf('/'))) .sort(this.sortPath); - new Set(instancesPath).forEach(path => { const pathParameter = Array.from(path.split('/'), String); const objectLwM2M = clientObserveAttrTelemetry.find(x => x.keyId === pathParameter[0]); if (objectLwM2M) { - const instance = deepClone(objectLwM2M.instances[0]); - instance.id = +pathParameter[1]; + const instance = this.updateInInstanceKeyName (objectLwM2M.instances[0], +pathParameter[1]); objectLwM2M.instances.push(instance); } }); } + private updateInInstanceKeyName = (instance: Instance, instanceId: number): Instance => { + const instanceUpdate = deepClone(instance); + instanceUpdate.id = instanceId; + instanceUpdate.resources.forEach(resource => { + resource.keyName = _.camelCase(resource.name + instanceUpdate.id); + }) + return instanceUpdate; + } + private updateObserveAttrTelemetryObjects = (parameters: string[], objectLwM2MS: ObjectLwM2M[], nameParameter: string): void => { parameters.forEach(parameter => { diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts index 3d6b93b84c..530679113c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.ts @@ -45,6 +45,7 @@ import { Lwm2mObjectAddInstancesData, Lwm2mObjectAddInstancesDialogComponent } from '@home/components/profile/device/lwm2m/lwm2m-object-add-instances-dialog.component'; +import _ from 'lodash'; @Component({ selector: 'tb-profile-lwm2m-observe-attr-telemetry', @@ -261,7 +262,6 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor r.attribute = false; r.telemetry = false; r.observe = false; - r.keyName = {}; r.attributeLwm2m = {}; }); const valueOld = this.instancesToSetId(instancesArray); @@ -280,7 +280,8 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor private addInstancesNew = (idsAdd: Set, objectLwM2MFormGroup: FormGroup, instancesFormArray: FormArray, instanceNew: Instance): void => { idsAdd.forEach(x => { - this.pushInstance(instancesFormArray, x, instanceNew); + instanceNew.resources.forEach(resource => {resource.keyName = _.camelCase(resource.name + x);}); + this.pushInstance(instancesFormArray, x, deepClone(instanceNew as Instance)); }); (instancesFormArray.controls as FormGroup[]).sort((a, b) => a.value.id - b.value.id); } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index f6e58df903..acea41394a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -246,7 +246,7 @@ export interface ResourceLwM2M { observe: boolean; attribute: boolean; telemetry: boolean; - keyName: {}; + keyName: string; attributeLwm2m?: {}; } From 3094fb72400687f2d67ec0efeb58917814d12ad0 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 7 May 2021 16:05:54 +0300 Subject: [PATCH 07/29] Add customerId to alarm --- .../main/data/upgrade/3.2.2/schema_update.sql | 5 + .../update/DefaultDataUpdateService.java | 117 +++++++++++++-- .../install/update/PaginatedUpdater.java | 16 +++ .../server/dao/entity/EntityService.java | 2 + .../server/common/data/alarm/Alarm.java | 6 +- .../server/dao/alarm/BaseAlarmService.java | 2 + .../server/dao/entity/BaseEntityService.java | 46 ++++++ .../server/dao/model/ModelConstants.java | 1 + .../dao/model/sql/AbstractAlarmEntity.java | 12 ++ .../server/dao/model/sql/AlarmEntity.java | 5 + .../server/dao/rule/BaseRuleChainService.java | 136 +++++++----------- .../server/dao/rule/RuleChainDao.java | 9 ++ .../server/dao/sql/alarm/AlarmRepository.java | 16 +-- .../server/dao/sql/rule/JpaRuleChainDao.java | 6 + .../dao/sql/rule/RuleChainRepository.java | 3 + .../resources/sql/schema-entities-hsql.sql | 1 + .../main/resources/sql/schema-entities.sql | 1 + .../dashboard-page.component.html | 6 +- 18 files changed, 281 insertions(+), 109 deletions(-) diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index 4bb63f3b9f..4df24b4edf 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -90,6 +90,11 @@ ALTER TABLE device ADD COLUMN IF NOT EXISTS firmware_id uuid, ADD COLUMN IF NOT EXISTS software_id uuid; +ALTER TABLE alarm + ADD COLUMN IF NOT EXISTS customer_id uuid; + +DELETE FROM relation WHERE from_type = 'TENANT' AND relation_type_group = 'RULE_CHAIN'; + DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 3f93aef41a..b91c46417c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -27,6 +27,9 @@ import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; @@ -34,9 +37,13 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.alarm.AlarmDao; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -72,6 +79,15 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private TimeseriesService tsService; + @Autowired + private AlarmService alarmService; + + @Autowired + private EntityService entityService; + + @Autowired + private AlarmDao alarmDao; + @Override public void updateData(String fromVersion) throws Exception { switch (fromVersion) { @@ -90,14 +106,25 @@ public class DefaultDataUpdateService implements DataUpdateService { case "3.2.2": log.info("Updating data from version 3.2.2 to 3.3.0 ..."); tenantsDefaultEdgeRuleChainUpdater.updateEntities(null); + tenantsAlarmsCustomerUpdater.updateEntities(null); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } } - private PaginatedUpdater tenantsDefaultRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsDefaultRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants default rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -117,8 +144,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants default edge rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -138,8 +175,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsRootRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsRootRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants root rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -192,8 +239,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsEntityViewsUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsEntityViewsUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants entity views updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -261,4 +318,48 @@ public class DefaultDataUpdateService implements DataUpdateService { }, MoreExecutors.directExecutor()); } + private final PaginatedUpdater tenantsAlarmsCustomerUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants alarms customer updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } + + @Override + protected PageData findEntities(String region, PageLink pageLink) { + return tenantService.findTenants(pageLink); + } + + @Override + protected void updateEntity(Tenant tenant) { + updateTenantAlarmsCustomer(tenant.getId()); + } + }; + + private void updateTenantAlarmsCustomer(TenantId tenantId) { + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(100), null, null, false); + PageData alarms = alarmDao.findAlarms(tenantId, alarmQuery); + boolean hasNext = true; + while (hasNext) { + for (Alarm alarm : alarms.getData()) { + if (alarm.getCustomerId() == null && alarm.getOriginator() != null) { + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); + alarmDao.save(tenantId, alarm); + } + } + if (alarms.hasNext()) { + alarmQuery.setPageLink(alarmQuery.getPageLink().nextPageLink()); + alarms = alarmDao.findAlarms(tenantId, alarmQuery); + } else { + hasNext = false; + } + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java index e766bb0daa..4bfe744863 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java @@ -15,16 +15,20 @@ */ package org.thingsboard.server.service.install.update; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +@Slf4j public abstract class PaginatedUpdater> { private static final int DEFAULT_LIMIT = 100; + private int updated = 0; public void updateEntities(I id) { + updated = 0; PageLink pageLink = new PageLink(DEFAULT_LIMIT); boolean hasNext = true; while (hasNext) { @@ -32,13 +36,25 @@ public abstract class PaginatedUpdater DEFAULT_LIMIT || forceReportTotal()) { + log.info("{}: {} total entities updated.", getName(), updated); + } } } } + protected boolean forceReportTotal() { + return false; + } + + protected abstract String getName(); + protected abstract PageData findEntities(I id, PageLink pageLink); protected abstract void updateEntity(D entity); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index 09c05e3c0c..e6a9538e54 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -28,6 +28,8 @@ public interface EntityService { ListenableFuture fetchEntityNameAsync(TenantId tenantId, EntityId entityId); + CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + void deleteEntityRelations(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java index 32d0a516eb..54f7ab72f5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java @@ -21,9 +21,11 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -35,9 +37,10 @@ import java.util.List; @Data @Builder @AllArgsConstructor -public class Alarm extends BaseData implements HasName, HasTenantId { +public class Alarm extends BaseData implements HasName, HasTenantId, HasCustomerId { private TenantId tenantId; + private CustomerId customerId; private String type; private EntityId originator; private AlarmSeverity severity; @@ -62,6 +65,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { super(alarm.getId()); this.createdTime = alarm.getCreatedTime(); this.tenantId = alarm.getTenantId(); + this.customerId = alarm.getCustomerId(); this.type = alarm.getType(); this.originator = alarm.getOriginator(); this.severity = alarm.getSeverity(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 472cbb588f..b40993b76b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -110,6 +110,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getEndTs() == 0L) { alarm.setEndTs(alarm.getStartTs()); } + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator())); if (alarm.getId() == null) { Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get(); if (existing == null || existing.getStatus().isCleared()) { @@ -355,6 +356,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ existing.setStatus(alarm.getStatus()); existing.setSeverity(alarm.getSeverity()); existing.setDetails(alarm.getDetails()); + existing.setCustomerId(alarm.getCustomerId()); existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); List existingPropagateRelationTypes = existing.getPropagateRelationTypes(); List newRelationTypes = alarm.getPropagateRelationTypes(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 7e0218740a..73cebc0797 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; @@ -54,6 +55,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; /** @@ -175,6 +177,50 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return entityName; } + @Override + public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { + log.trace("Executing fetchEntityCustomerId [{}]", entityId); + HasCustomerId hasCustomerId = null; + switch (entityId.getEntityType()) { + case TENANT: + case RULE_CHAIN: + case RULE_NODE: + case DASHBOARD: + case WIDGETS_BUNDLE: + case WIDGET_TYPE: + case TENANT_PROFILE: + case DEVICE_PROFILE: + case API_USAGE_STATE: + case TB_RESOURCE: + case FIRMWARE: + break; + case CUSTOMER: + hasCustomerId = () -> new CustomerId(entityId.getId()); + break; + case USER: + hasCustomerId = userService.findUserById(tenantId, new UserId(entityId.getId())); + break; + case ASSET: + hasCustomerId = assetService.findAssetById(tenantId, new AssetId(entityId.getId())); + break; + case DEVICE: + hasCustomerId = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())); + break; + case ALARM: + try { + hasCustomerId = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId())).get(); + } catch (Exception e) {} + break; + case ENTITY_VIEW: + hasCustomerId = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())); + break; + case EDGE: + hasCustomerId = edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())); + break; + } + return hasCustomerId != null ? hasCustomerId.getCustomerId() : new CustomerId(NULL_UUID); + } + private static void validateEntityCountQuery(EntityCountQuery query) { if (query == null) { throw new IncorrectParameterException("Query must be specified."); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 5b4ea874ee..ee0d837ea0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -258,6 +258,7 @@ public class ModelConstants { */ public static final String ALARM_COLUMN_FAMILY_NAME = "alarm"; public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String ALARM_TYPE_PROPERTY = "type"; public static final String ALARM_DETAILS_PROPERTY = "details"; public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java index 297fa39e62..8ade2b78d5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseEntity; @@ -44,6 +45,7 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CLEAR_TS_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; @@ -64,6 +66,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity @Column(name = ALARM_TENANT_ID_PROPERTY) private UUID tenantId; + @Column(name = ALARM_CUSTOMER_ID_PROPERTY) + private UUID customerId; + @Column(name = ALARM_ORIGINATOR_ID_PROPERTY) private UUID originatorId; @@ -115,6 +120,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity if (alarm.getTenantId() != null) { this.tenantId = alarm.getTenantId().getId(); } + if (alarm.getCustomerId() != null) { + this.customerId = alarm.getCustomerId().getId(); + } this.type = alarm.getType(); this.originatorId = alarm.getOriginator().getId(); this.originatorType = alarm.getOriginator().getEntityType(); @@ -138,6 +146,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.setId(alarmEntity.getId()); this.setCreatedTime(alarmEntity.getCreatedTime()); this.tenantId = alarmEntity.getTenantId(); + this.customerId = alarmEntity.getCustomerId(); this.type = alarmEntity.getType(); this.originatorId = alarmEntity.getOriginatorId(); this.originatorType = alarmEntity.getOriginatorType(); @@ -159,6 +168,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity if (tenantId != null) { alarm.setTenantId(new TenantId(tenantId)); } + if (customerId != null) { + alarm.setCustomerId(new CustomerId(customerId)); + } alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); alarm.setType(type); alarm.setSeverity(severity); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java index 73b181a170..5848ffa572 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java @@ -19,6 +19,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Entity; @@ -37,6 +38,10 @@ public final class AlarmEntity extends AbstractAlarmEntity { super(); } + public AlarmEntity(AlarmInfo alarmInfo) { + super(alarmInfo); + } + public AlarmEntity(Alarm alarm) { super(alarm); } 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 786d86d8dd..b61e18e08a 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 @@ -100,12 +100,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Transactional public RuleChain saveRuleChain(RuleChain ruleChain) { ruleChainValidator.validate(ruleChain, RuleChain::getTenantId); - RuleChain savedRuleChain = ruleChainDao.save(ruleChain.getTenantId(), ruleChain); - if (ruleChain.isRoot() && ruleChain.getId() == null) { - createRelation(ruleChain.getTenantId(), new EntityRelation(savedRuleChain.getTenantId(), savedRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - } - return savedRuleChain; + return ruleChainDao.save(ruleChain.getTenantId(), ruleChain); } @Override @@ -114,29 +109,20 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId()); if (!ruleChain.isRoot()) { RuleChain previousRootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId()); - try { - if (previousRootRuleChain == null) { - setRootAndSave(tenantId, ruleChain); - return true; - } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) { - deleteRelation(tenantId, new EntityRelation(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - previousRootRuleChain.setRoot(false); - ruleChainDao.save(tenantId, previousRootRuleChain); - setRootAndSave(tenantId, ruleChain); - return true; - } - } catch (ExecutionException | InterruptedException e) { - log.warn("[{}] Failed to set root rule chain, ruleChainId: [{}]", ruleChainId); - throw new RuntimeException(e); + if (previousRootRuleChain == null) { + setRootAndSave(tenantId, ruleChain); + return true; + } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) { + previousRootRuleChain.setRoot(false); + ruleChainDao.save(tenantId, previousRootRuleChain); + setRootAndSave(tenantId, ruleChain); + return true; } } return false; } - private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) throws ExecutionException, InterruptedException { - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); + private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) { ruleChain.setRoot(true); ruleChainDao.save(tenantId, ruleChain); } @@ -179,41 +165,45 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC toDelete.add(existingNode); } } - for (RuleNode node : toAddOrUpdate) { - node.setRuleChainId(ruleChain.getId()); - RuleNode savedNode = ruleNodeDao.save(tenantId, node); - createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - int index = nodes.indexOf(node); - nodes.set(index, savedNode); - ruleNodeIndexMap.put(savedNode.getId(), index); + if (nodes != null) { + for (RuleNode node : toAddOrUpdate) { + node.setRuleChainId(ruleChain.getId()); + RuleNode savedNode = ruleNodeDao.save(tenantId, node); + createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); + int index = nodes.indexOf(node); + nodes.set(index, savedNode); + ruleNodeIndexMap.put(savedNode.getId(), index); + } } for (RuleNode node : toDelete) { deleteRuleNode(tenantId, node.getId()); } RuleNodeId firstRuleNodeId = null; - if (ruleChainMetaData.getFirstNodeIndex() != null) { - firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId(); - } - if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId)) - || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { - ruleChain.setFirstRuleNodeId(firstRuleNodeId); - ruleChainDao.save(tenantId, ruleChain); - } - if (ruleChainMetaData.getConnections() != null) { - for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) { - EntityId from = nodes.get(nodeConnection.getFromIndex()).getId(); - EntityId to = nodes.get(nodeConnection.getToIndex()).getId(); - String type = nodeConnection.getType(); - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE)); + if (nodes != null) { + if (ruleChainMetaData.getFirstNodeIndex() != null) { + firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId(); } - } - if (ruleChainMetaData.getRuleChainConnections() != null) { - for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) { - EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId(); - EntityId to = nodeToRuleChainConnection.getTargetRuleChainId(); - String type = nodeToRuleChainConnection.getType(); - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo())); + if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId)) + || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { + ruleChain.setFirstRuleNodeId(firstRuleNodeId); + ruleChainDao.save(tenantId, ruleChain); + } + if (ruleChainMetaData.getConnections() != null) { + for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) { + EntityId from = nodes.get(nodeConnection.getFromIndex()).getId(); + EntityId to = nodes.get(nodeConnection.getToIndex()).getId(); + String type = nodeConnection.getType(); + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE)); + } + } + if (ruleChainMetaData.getRuleChainConnections() != null) { + for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) { + EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId(); + EntityId to = nodeToRuleChainConnection.getTargetRuleChainId(); + String type = nodeToRuleChainConnection.getType(); + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo())); + } } } @@ -307,24 +297,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override public RuleChain getRootTenantRuleChain(TenantId tenantId) { - return getRootRuleChainByType(tenantId, RuleChainType.CORE); - } - - private RuleChain getRootRuleChainByType(TenantId tenantId, RuleChainType type) { Validator.validateId(tenantId, "Incorrect tenant id for search request."); - List relations = relationService.findByFrom(tenantId, tenantId, RelationTypeGroup.RULE_CHAIN); - if (relations != null && !relations.isEmpty()) { - for (EntityRelation relation : relations) { - RuleChainId ruleChainId = new RuleChainId(relation.getTo().getId()); - RuleChain ruleChainById = findRuleChainById(tenantId, ruleChainId); - if (type.equals(ruleChainById.getType())) { - return ruleChainById; - } - } - return null; - } else { - return null; - } + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.CORE); } @Override @@ -366,7 +340,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC boolean valid = true; EntityType toType = relation.getTo().getEntityType(); if (toType == EntityType.RULE_NODE || toType == EntityType.RULE_CHAIN) { - BaseData entity; + BaseData entity; if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { entity = ruleNodeDao.findById(tenantId, relation.getTo().getId()); } else { @@ -501,9 +475,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ObjectNode objNode = (ObjectNode) node; objNode.put("id", tenantId.getId().toString()); } else { - Iterator childIter = node.iterator(); - while (childIter.hasNext()) { - searchTenantIdRecursive(tenantId, childIter.next()); + for (JsonNode jsonNode : node) { + searchTenantIdRecursive(tenantId, jsonNode); } } } @@ -608,7 +581,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override public RuleChain getEdgeTemplateRootRuleChain(TenantId tenantId) { - return getRootRuleChainByType(tenantId, RuleChainType.EDGE); + Validator.validateId(tenantId, "Incorrect tenant id for search request."); + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.EDGE); } @Override @@ -618,13 +592,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (previousEdgeTemplateRootRuleChain == null || !previousEdgeTemplateRootRuleChain.getId().equals(ruleChain.getId())) { try { if (previousEdgeTemplateRootRuleChain != null) { - deleteRelation(tenantId, new EntityRelation(previousEdgeTemplateRootRuleChain.getTenantId(), previousEdgeTemplateRootRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); previousEdgeTemplateRootRuleChain.setRoot(false); ruleChainDao.save(tenantId, previousEdgeTemplateRootRuleChain); } - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); ruleChain.setRoot(true); ruleChainDao.save(tenantId, ruleChain); return true; @@ -699,8 +669,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ruleNodeDao.removeById(tenantId, entityId.getId()); } - private DataValidator ruleChainValidator = - new DataValidator() { + private final DataValidator ruleChainValidator = + new DataValidator<>() { @Override protected void validateCreate(TenantId tenantId, RuleChain data) { DefaultTenantProfileConfiguration profileConfiguration = @@ -739,8 +709,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } }; - private PaginatedRemover tenantRuleChainsRemover = - new PaginatedRemover() { + private final PaginatedRemover tenantRuleChainsRemover = + new PaginatedRemover<>() { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { 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 4baa3bd576..2aaaa934d7 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 @@ -50,6 +50,15 @@ public interface RuleChainDao extends Dao, TenantEntityDao { */ PageData findRuleChainsByTenantIdAndType(UUID tenantId, RuleChainType type, PageLink pageLink); + /** + * Find root rule chain by tenantId and type + * + * @param tenantId the tenantId + * @param type the type + * @return the rule chain object + */ + RuleChain findRootRuleChainByTenantIdAndType(UUID tenantId, RuleChainType type); + /** * Find rule chains by tenantId, edgeId and page link. * diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 028eda1583..b4c0ac09c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -120,13 +120,7 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + - "WHERE a.tenantId = :tenantId " + - "AND (" + - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + - "OR a.originatorId = :customerId" + - ") " + + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + @@ -137,13 +131,7 @@ public interface AlarmRepository extends CrudRepository { countQuery = "" + "SELECT count(a) " + "FROM AlarmEntity a " + - "WHERE a.tenantId = :tenantId " + - "AND (" + - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + - "OR a.originatorId = :customerId" + - ") " + + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + 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 760d9e7aeb..0dbe22571e 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 @@ -82,6 +82,12 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) { log.debug("Try to find rule chains by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 3c3c5ff3b4..1251234fa1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -50,5 +50,8 @@ public interface RuleChainRepository extends PagingAndSortingRepository