From 0dcde6044392b8f6f22766a54d7999c80b4f8d96 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 30 Nov 2022 13:06:00 +0200 Subject: [PATCH 01/27] Added alarm assignment feature and tests for it --- .../main/data/upgrade/3.4.2/schema_update.sql | 27 +++++++ .../server/controller/AlarmController.java | 73 +++++++++++++++-- .../controller/ControllerConstants.java | 2 + .../install/ThingsboardInstallService.java | 4 + .../service/action/EntityActionService.java | 6 ++ .../entitiy/AbstractTbEntityService.java | 2 +- .../DefaultTbNotificationEntityService.java | 4 + .../entitiy/alarm/DefaultTbAlarmService.java | 29 +++++++ .../service/entitiy/alarm/TbAlarmService.java | 5 ++ .../install/SqlDatabaseUpgradeService.java | 12 +++ .../update/DefaultDataUpdateService.java | 2 +- .../DefaultAlarmSubscriptionService.java | 19 ++++- .../controller/BaseAlarmControllerTest.java | 79 +++++++++++++++++++ .../server/dao/alarm/AlarmService.java | 7 +- .../server/common/data/DataConstants.java | 2 + .../server/common/data/alarm/Alarm.java | 25 +++--- .../server/common/data/alarm/AlarmQuery.java | 2 + .../server/common/data/alarm/EntityAlarm.java | 2 + .../server/common/data/audit/ActionType.java | 2 + .../common/data/edge/EdgeEventActionType.java | 2 + .../server/dao/alarm/AlarmDao.java | 3 +- .../server/dao/alarm/BaseAlarmService.java | 44 ++++++++++- .../server/dao/audit/AuditLogServiceImpl.java | 2 + .../server/dao/model/ModelConstants.java | 3 + .../dao/model/sql/AbstractAlarmEntity.java | 21 +++++ .../dao/model/sql/EntityAlarmEntity.java | 11 +++ .../server/dao/sql/alarm/AlarmRepository.java | 15 +++- .../server/dao/sql/alarm/JpaAlarmDao.java | 20 ++++- .../resources/sql/schema-entities-idx.sql | 2 + .../main/resources/sql/schema-entities.sql | 3 + .../dao/service/BaseAlarmServiceTest.java | 12 +-- .../engine/api/RuleEngineAlarmService.java | 7 +- .../components/alarm/alarm-table-config.ts | 2 +- .../home/models/widget-component.models.ts | 5 +- ui-ngx/src/app/shared/models/alarm.models.ts | 17 +++- .../src/app/shared/models/audit-log.models.ts | 4 + .../assets/locale/locale.constant-en_US.json | 3 + 37 files changed, 442 insertions(+), 38 deletions(-) create mode 100644 application/src/main/data/upgrade/3.4.2/schema_update.sql diff --git a/application/src/main/data/upgrade/3.4.2/schema_update.sql b/application/src/main/data/upgrade/3.4.2/schema_update.sql new file mode 100644 index 0000000000..e47a6bf2f3 --- /dev/null +++ b/application/src/main/data/upgrade/3.4.2/schema_update.sql @@ -0,0 +1,27 @@ +-- +-- Copyright © 2016-2022 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. +-- + + +-- ALARM ASSIGN TO USER START + +ALTER TABLE alarm ADD COLUMN assign_ts BIGINT; +ALTER TABLE alarm ADD COLUMN assignee_id UUID; + +ALTER TABLE entity_alarm ADD COLUMN assignee_id UUID; + +CREATE INDEX IF NOT EXISTS idx_entity_alarm_assignee_id ON entity_alarm(assignee_id); + +-- ALARM ASSIGN TO USER END \ No newline at end of file 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 858a7ee3c4..cb1093c745 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -48,9 +49,13 @@ import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.util.UUID; + import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ALARM_INFO_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.ASSIGNEE_ID; +import static org.thingsboard.server.controller.ControllerConstants.ASSIGN_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE; @@ -79,6 +84,7 @@ public class AlarmController extends BaseController { private static final String ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES = "ANY, ACTIVE, CLEARED, ACK, UNACK"; private static final String ALARM_QUERY_STATUS_DESCRIPTION = "A string value representing one of the AlarmStatus enumeration value"; private static final String ALARM_QUERY_STATUS_ALLOWABLE_VALUES = "ACTIVE_UNACK, ACTIVE_ACK, CLEARED_UNACK, CLEARED_ACK"; + private static final String ALARM_QUERY_ASSIGNEE_DESCRIPTION = "A string value representing the assignee user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; private static final String ALARM_QUERY_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on of next alarm fields: type, severity or status"; private static final String ALARM_QUERY_START_TIME_DESCRIPTION = "The start timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; private static final String ALARM_QUERY_END_TIME_DESCRIPTION = "The end timestamp in milliseconds of the search time range over the Alarm class field: 'createdTime'."; @@ -179,6 +185,45 @@ public class AlarmController extends BaseController { tbAlarmService.clear(alarm, getCurrentUser()).get(); } + @ApiOperation(value = "Assign/Reassign Alarm (assignAlarm)", + notes = "Assign the Alarm. " + + "Once assigned, the 'assign_ts' field will be set to current timestamp and special rule chain event 'ALARM_ASSIGNED' " + + "(or ALARM_REASSIGNED in case of assigning already assigned alarm) will be generated. " + + "Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarm/{alarmId}/assign/{assigneeId}", method = RequestMethod.POST) + @ResponseStatus(value = HttpStatus.OK) + public void assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmId, + @ApiParam(value = ASSIGN_ID_PARAM_DESCRIPTION) + @PathVariable(ASSIGNEE_ID) String strAssigneeId + ) throws Exception { + checkParameter(ALARM_ID, strAlarmId); + checkParameter(ASSIGNEE_ID, strAssigneeId); + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); + // TODO Add special permissions for assignment + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); + tbAlarmService.assign(alarm, getCurrentUser(), assigneeId).get(); + } + + @ApiOperation(value = "Unassign Alarm (unassignAlarm)", + notes = "Unassign the Alarm. " + + "Once unassigned, the 'assign_ts' field will be set to current timestamp and special rule chain event 'ALARM_UNASSIGNED' will be generated. " + + "Referencing non-existing Alarm Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarm/{alarmId}/assign", method = RequestMethod.DELETE) + @ResponseStatus(value = HttpStatus.OK) + public void assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmId + ) throws Exception { + checkParameter(ALARM_ID, strAlarmId); + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); + // TODO Add special permissions for unassignment + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + tbAlarmService.unassign(alarm, getCurrentUser()).get(); + } + @ApiOperation(value = "Get Alarms (getAlarms)", notes = "Returns a page of alarms for the selected entity. Specifying both parameters 'searchStatus' and 'status' at the same time will cause an error. " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @@ -194,6 +239,8 @@ public class AlarmController extends BaseController { @RequestParam(required = false) String searchStatus, @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, + @ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION) + @RequestParam(required = false) String assigneeId, @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @@ -221,10 +268,14 @@ public class AlarmController extends BaseController { "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } checkEntityId(entityId, Operation.READ); + UserId assigneeUserId = null; + if (assigneeId != null) { + assigneeUserId = new UserId(UUID.fromString(assigneeId)); + } TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); try { - return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get()); } catch (Exception e) { throw handleException(e); } @@ -244,6 +295,8 @@ public class AlarmController extends BaseController { @RequestParam(required = false) String searchStatus, @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String status, + @ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION) + @RequestParam(required = false) String assigneeId, @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @@ -267,13 +320,17 @@ public class AlarmController extends BaseController { throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } + UserId assigneeUserId = null; + if (assigneeId != null) { + assigneeUserId = new UserId(UUID.fromString(assigneeId)); + } 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()); + return checkNotNull(alarmService.findCustomerAlarms(getCurrentUser().getTenantId(), getCurrentUser().getCustomerId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get()); } else { - return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(null, pageLink, alarmSearchStatus, alarmStatus, assigneeUserId, fetchOriginator)).get()); } } catch (Exception e) { throw handleException(e); @@ -295,7 +352,9 @@ public class AlarmController extends BaseController { @ApiParam(value = ALARM_QUERY_SEARCH_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_SEARCH_STATUS_ALLOWABLE_VALUES) @RequestParam(required = false) String searchStatus, @ApiParam(value = ALARM_QUERY_STATUS_DESCRIPTION, allowableValues = ALARM_QUERY_STATUS_ALLOWABLE_VALUES) - @RequestParam(required = false) String status + @RequestParam(required = false) String status, + @ApiParam(value = ALARM_QUERY_ASSIGNEE_DESCRIPTION) + @RequestParam(required = false) String assigneeId ) throws ThingsboardException { checkParameter("EntityId", strEntityId); checkParameter("EntityType", strEntityType); @@ -306,9 +365,13 @@ public class AlarmController extends BaseController { throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } + UserId assigneeUserId = null; + if (assigneeId != null) { + assigneeUserId = new UserId(UUID.fromString(assigneeId)); + } checkEntityId(entityId, Operation.READ); try { - return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus); + return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus, assigneeUserId); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index e00ccaa4bc..27d26164df 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -27,6 +27,7 @@ public class ControllerConstants { protected static final String EDGE_ID = "edgeId"; protected static final String RPC_ID = "rpcId"; protected static final String ENTITY_ID = "entityId"; + protected static final String ASSIGNEE_ID = "assigneeId"; protected static final String PAGE_DATA_PARAMETERS = "You can specify parameters to filter the results. " + "The result is wrapped with PageData object that allows you to iterate over result set using pagination. " + "See the 'Model' tab of the Response Class for more details. "; @@ -44,6 +45,7 @@ public class ControllerConstants { protected static final String USER_ID_PARAM_DESCRIPTION = "A string value representing the user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String ASSET_ID_PARAM_DESCRIPTION = "A string value representing the asset id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String ALARM_ID_PARAM_DESCRIPTION = "A string value representing the alarm id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String ASSIGN_ID_PARAM_DESCRIPTION = "A string value representing the user id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String ENTITY_ID_PARAM_DESCRIPTION = "A string value representing the entity id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String OTA_PACKAGE_ID_PARAM_DESCRIPTION = "A string value representing the ota package id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String ENTITY_TYPE_PARAM_DESCRIPTION = "A string value representing the entity type. For example, 'DEVICE'"; diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 9facea6dde..6b6104b0e2 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -236,6 +236,10 @@ public class ThingsboardInstallService { log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; + case "3.4.2": + log.info("Upgrading ThingsBoard from version 3.4.2 to 3.5 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.4.2"); + break; //TODO update CacheCleanupService on the next version upgrade diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 7057f903be..fc8b71947c 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -86,6 +86,12 @@ public class EntityActionService { case ALARM_CLEAR: msgType = DataConstants.ALARM_CLEAR; break; + case ALARM_ASSIGN: + msgType = DataConstants.ALARM_CLEAR; + break; + case ALARM_UNASSIGN: + msgType = DataConstants.ALARM_CLEAR; + break; case ALARM_DELETE: msgType = DataConstants.ALARM_DELETE; break; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java index 9f34c061fe..f4885c56cc 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java @@ -73,7 +73,7 @@ public abstract class AbstractTbEntityService { protected ListenableFuture removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { ListenableFuture> alarmsFuture = - alarmService.findAlarms(tenantId, new AlarmQuery(entityId, new TimePageLink(Integer.MAX_VALUE), null, null, false)); + alarmService.findAlarms(tenantId, new AlarmQuery(entityId, new TimePageLink(Integer.MAX_VALUE), null, null, null, false)); ListenableFuture> alarmIdsFuture = Futures.transform(alarmsFuture, page -> page.getData().stream().map(AlarmInfo::getId).collect(Collectors.toList()), dbExecutor); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 8f8531a5b4..94370d6ff2 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -306,6 +306,10 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS return EdgeEventActionType.ALARM_ACK; case ALARM_CLEAR: return EdgeEventActionType.ALARM_CLEAR; + case ALARM_ASSIGN: + return EdgeEventActionType.ALARM_ASSIGN; + case ALARM_UNASSIGN: + return EdgeEventActionType.ALARM_UNASSIGN; case DELETED: return EdgeEventActionType.DELETED; case RELATION_ADD_OR_UPDATE: diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 8157eff3e5..023e144bf0 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -75,6 +76,34 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb }, MoreExecutors.directExecutor()); } + @Override + public ListenableFuture assign(Alarm alarm, User user, UserId assigneeId) { + long assignTs = System.currentTimeMillis(); + ListenableFuture future = alarmSubscriptionService.assignAlarm(alarm.getTenantId(), alarm.getId(), assigneeId, assignTs); + return Futures.transform(future, result -> { + if (result != null && result) { + alarm.setAssignTs(assignTs); + alarm.setAssigneeId(assigneeId); + notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ASSIGN, user); + } + return null; + }, MoreExecutors.directExecutor()); + } + + @Override + public ListenableFuture unassign(Alarm alarm, User user) { + long assignTs = System.currentTimeMillis(); + ListenableFuture future = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), assignTs); + return Futures.transform(future, result -> { + if (result != null && result) { + alarm.setAssignTs(assignTs); + alarm.setAssigneeId(null); + notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_UNASSIGN, user); + } + return null; + }, MoreExecutors.directExecutor()); + } + @Override public Boolean delete(Alarm alarm, User user) { TenantId tenantId = alarm.getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 8cd8d0b49d..0cf2de5ba9 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.UserId; public interface TbAlarmService { @@ -28,5 +29,9 @@ public interface TbAlarmService { ListenableFuture clear(Alarm alarm, User user); + ListenableFuture assign(Alarm alarm, User user, UserId assigneeId); + + ListenableFuture unassign(Alarm alarm, User user); + Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 80665d544f..349400ecd1 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -677,6 +677,18 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.4.2": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.4.2", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + log.info("Updating schema settings..."); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004003;"); + log.info("Schema updated."); + } catch (Exception e) { + log.error("Failed updating schema!!!", e); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } 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 ee34bd7f23..a831a0af5e 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 @@ -555,7 +555,7 @@ public class DefaultDataUpdateService implements DataUpdateService { }; private void updateTenantAlarmsCustomer(TenantId tenantId, String name, AtomicLong processed) { - AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(1000), null, null, false); + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(1000), null, null, null, false); PageData alarms = alarmDao.findAlarms(tenantId, alarmQuery); boolean hasNext = true; while (hasNext) { 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 956dde8024..f7d121d9ff 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 @@ -34,6 +34,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -124,6 +125,20 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService return result; } + @Override + public ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) { + ListenableFuture result = alarmService.assignAlarm(tenantId, alarmId, assigneeId, assignTs); + Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor); + return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor); + } + + @Override + public ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) { + ListenableFuture result = alarmService.unassignAlarm(tenantId, alarmId, assignTs); + Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor); + return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor); + } + @Override public ListenableFuture findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId) { return alarmService.findAlarmByIdAsync(tenantId, alarmId); @@ -150,8 +165,8 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus) { - return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus); + public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, UserId assigneeUserId) { + return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus, assigneeUserId); } @Override diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java index 493b1818d9..05b6f15c61 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java @@ -347,6 +347,85 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest { .andExpect(statusReason(containsString(msgErrorPermission))); } + @Test + public void testAssignAlarm() throws Exception { + loginTenantAdmin(); + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + tenantAdminUserId.getId()).andExpect(status().isOk()); + Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(tenantAdminUserId, foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGN); + } + + @Test + public void testReassignAlarm() throws Exception { + loginTenantAdmin(); + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + tenantAdminUserId.getId()).andExpect(status().isOk()); + + Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(tenantAdminUserId, foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGN); + + logout(); + + loginCustomerUser(); + Mockito.reset(tbClusterService, auditLogService); + beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + customerUserId.getId()).andExpect(status().isOk()); + + foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(customerUserId, foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_ASSIGN); + } + + @Test + public void testUnassignAlarm() throws Exception { + loginTenantAdmin(); + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + tenantAdminUserId.getId()).andExpect(status().isOk()); + Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(tenantAdminUserId, foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGN); + + beforeAssignmentTs = System.currentTimeMillis(); + + doDelete("/api/alarm/" + alarm.getId() + "/assign").andExpect(status().isOk()); + foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGN); + } + @Test public void testFindAlarmsViaCustomerUser() throws Exception { loginCustomerUser(); 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 b8041aa3fc..81b4de263a 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 @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -48,6 +49,10 @@ public interface AlarmService { ListenableFuture clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); + ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); + + ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); + Alarm findAlarmById(TenantId tenantId, AlarmId alarmId); ListenableFuture findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId); @@ -59,7 +64,7 @@ public interface AlarmService { ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, - AlarmStatus alarmStatus); + AlarmStatus alarmStatus, UserId assigneeUserId); ListenableFuture findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index 69c36697d3..099a452712 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -73,6 +73,8 @@ public class DataConstants { public static final String TIMESERIES_DELETED = "TIMESERIES_DELETED"; public static final String ALARM_ACK = "ALARM_ACK"; public static final String ALARM_CLEAR = "ALARM_CLEAR"; + public static final String ALARM_ASSIGN = "ALARM_ASSIGN"; + public static final String ALARM_UNASSIGN = "ALARM_UNASSIGN"; public static final String ALARM_DELETE = "ALARM_DELETE"; public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT"; 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 f13c84bc82..8eaca6b567 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 @@ -30,6 +30,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.validation.Length; import java.util.List; @@ -58,23 +59,27 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha private AlarmSeverity severity; @ApiModelProperty(position = 9, required = true, value = "Alarm status", example = "CLEARED_UNACK") private AlarmStatus status; - @ApiModelProperty(position = 10, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565") + @ApiModelProperty(position = 10, value = "Alarm assignee user id") + private UserId assigneeId; + @ApiModelProperty(position = 11, value = "Timestamp of the alarm start time, in milliseconds", example = "1634058704565") private long startTs; - @ApiModelProperty(position = 11, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522") + @ApiModelProperty(position = 12, value = "Timestamp of the alarm end time(last time update), in milliseconds", example = "1634111163522") private long endTs; - @ApiModelProperty(position = 12, value = "Timestamp of the alarm acknowledgement, in milliseconds", example = "1634115221948") + @ApiModelProperty(position = 13, value = "Timestamp of the alarm acknowledgement, in milliseconds", example = "1634115221948") private long ackTs; - @ApiModelProperty(position = 13, value = "Timestamp of the alarm clearing, in milliseconds", example = "1634114528465") + @ApiModelProperty(position = 14, value = "Timestamp of the alarm clearing, in milliseconds", example = "1634114528465") private long clearTs; - @ApiModelProperty(position = 14, value = "JSON object with alarm details") + @ApiModelProperty(position = 15, value = "Timestamp of the alarm assigning0, in milliseconds", example = "1634115928465") + private long assignTs; + @ApiModelProperty(position = 16, value = "JSON object with alarm details") private transient JsonNode details; - @ApiModelProperty(position = 15, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true") + @ApiModelProperty(position = 17, value = "Propagation flag to specify if alarm should be propagated to parent entities of alarm originator", example = "true") private boolean propagate; - @ApiModelProperty(position = 16, value = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true") + @ApiModelProperty(position = 18, value = "Propagation flag to specify if alarm should be propagated to the owner (tenant or customer) of alarm originator", example = "true") private boolean propagateToOwner; - @ApiModelProperty(position = 17, value = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true") + @ApiModelProperty(position = 19, value = "Propagation flag to specify if alarm should be propagated to the tenant entity", example = "true") private boolean propagateToTenant; - @ApiModelProperty(position = 18, value = "JSON array of relation types that should be used for propagation. " + + @ApiModelProperty(position = 20, value = "JSON array of relation types that should be used for propagation. " + "By default, 'propagateRelationTypes' array is empty which means that the alarm will be propagated based on any relation type to parent entities. " + "This parameter should be used only in case when 'propagate' parameter is set to true, otherwise, 'propagateRelationTypes' array will be ignored.") private List propagateRelationTypes; @@ -96,10 +101,12 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha this.originator = alarm.getOriginator(); this.severity = alarm.getSeverity(); this.status = alarm.getStatus(); + this.assigneeId = alarm.getAssigneeId(); this.startTs = alarm.getStartTs(); this.endTs = alarm.getEndTs(); this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); + this.assignTs = alarm.getAssignTs(); this.details = alarm.getDetails(); this.propagate = alarm.isPropagate(); this.propagateToOwner = alarm.isPropagateToOwner(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java index 25bfefd4b2..945442dc9b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmQuery.java @@ -19,6 +19,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.TimePageLink; /** @@ -33,6 +34,7 @@ public class AlarmQuery { private TimePageLink pageLink; private AlarmSearchStatus searchStatus; private AlarmStatus status; + private UserId assigneeId; private Boolean fetchOriginator; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java index e7606d852b..b75adf7ebb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/EntityAlarm.java @@ -23,6 +23,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; @Data @NoArgsConstructor @@ -35,6 +36,7 @@ public class EntityAlarm implements HasTenantId { private String alarmType; private CustomerId customerId; + private UserId assigneeId; private AlarmId alarmId; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java index 41f6f30dbe..4b666fa425 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java @@ -40,6 +40,8 @@ public enum ActionType { ALARM_ACK(false), ALARM_CLEAR(false), ALARM_DELETE(false), + ALARM_ASSIGN(false), + ALARM_UNASSIGN(false), LOGIN(false), LOGOUT(false), LOCKOUT(false), diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventActionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventActionType.java index bba8767fca..79a689f2e6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventActionType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventActionType.java @@ -31,6 +31,8 @@ public enum EdgeEventActionType { RPC_CALL, ALARM_ACK, ALARM_CLEAR, + ALARM_ASSIGN, + ALARM_UNASSIGN, ASSIGNED_TO_EDGE, UNASSIGNED_FROM_EDGE, CREDENTIALS_REQUEST, 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 87788d1b2b..11c3e47599 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 @@ -26,6 +26,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.AlarmData; @@ -58,7 +59,7 @@ public interface AlarmDao extends Dao { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status); + Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status, UserId assigneeUserId); PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); 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 e6012602f1..3abefb780b 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 @@ -39,6 +39,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -261,6 +262,42 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ }); } + @Override + public ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) { + return getAndUpdateAsync(tenantId, alarmId, new Function() { + @Nullable + @Override + public AlarmOperationResult apply(@Nullable Alarm alarm) { + if (alarm == null || assigneeId.equals(alarm.getAssigneeId())) { + return new AlarmOperationResult(alarm, false); + } else { + alarm.setAssigneeId(assigneeId); + alarm.setAssignTs(assignTime); + alarm = alarmDao.save(alarm.getTenantId(), alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + } + } + }); + } + + @Override + public ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTime) { + return getAndUpdateAsync(tenantId, alarmId, new Function() { + @Nullable + @Override + public AlarmOperationResult apply(@Nullable Alarm alarm) { + if (alarm == null || alarm.getAssigneeId() == null) { + return new AlarmOperationResult(alarm, false); + } else { + alarm.setAssigneeId(null); + alarm.setAssignTs(assignTime); + alarm = alarmDao.save(alarm.getTenantId(), alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + } + } + }); + } + @Override public Alarm findAlarmById(TenantId tenantId, AlarmId alarmId) { log.trace("Executing findAlarmById [{}]", alarmId); @@ -328,7 +365,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, - AlarmStatus alarmStatus) { + AlarmStatus alarmStatus, UserId assigneeUserId) { Set statusList = null; if (alarmSearchStatus != null) { statusList = alarmSearchStatus.getStatuses(); @@ -336,7 +373,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ statusList = Collections.singleton(alarmStatus); } - Set alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList); + Set alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList, assigneeUserId); return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } @@ -390,7 +427,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) { - EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), alarm.getId()); + // TODO Add ability to automatically assign created alarm to some user + EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), null,alarm.getId()); try { alarmDao.createEntityAlarmRecord(entityAlarm); } catch (Exception e) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index 8bb862bea5..8a08abcf3b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -165,6 +165,8 @@ public class AuditLogServiceImpl implements AuditLogService { case UPDATED: case ALARM_ACK: case ALARM_CLEAR: + case ALARM_ASSIGN: + case ALARM_UNASSIGN: case RELATIONS_DELETED: case ASSIGNED_TO_TENANT: if (entity != null) { 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 e24bde91fb..c64dea0c40 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 @@ -41,6 +41,7 @@ public class ModelConstants { public static final String USER_ID_PROPERTY = "user_id"; public static final String TENANT_ID_PROPERTY = "tenant_id"; public static final String CUSTOMER_ID_PROPERTY = "customer_id"; + public static final String ASSIGNEE_ID_PROPERTY = "assignee_id"; public static final String DEVICE_ID_PROPERTY = "device_id"; public static final String TITLE_PROPERTY = "title"; public static final String ALIAS_PROPERTY = "alias"; @@ -286,10 +287,12 @@ public class ModelConstants { public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type"; public static final String ALARM_SEVERITY_PROPERTY = "severity"; public static final String ALARM_STATUS_PROPERTY = "status"; + public static final String ALARM_ASSIGNEE_ID_PROPERTY = "assignee_id"; public static final String ALARM_START_TS_PROPERTY = "start_ts"; public static final String ALARM_END_TS_PROPERTY = "end_ts"; public static final String ALARM_ACK_TS_PROPERTY = "ack_ts"; public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts"; + public static final String ALARM_ASSIGN_TS_PROPERTY = "assign_ts"; public static final String ALARM_PROPAGATE_PROPERTY = "propagate"; public static final String ALARM_PROPAGATE_TO_OWNER_PROPERTY = "propagate_to_owner"; public static final String ALARM_PROPAGATE_TO_TENANT_PROPERTY = "propagate_to_tenant"; 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 56adfae6de..c01b145174 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 @@ -20,6 +20,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.springframework.data.annotation.Id; import org.springframework.util.CollectionUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; @@ -30,6 +31,7 @@ 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.common.data.id.UserId; import org.thingsboard.server.dao.model.BaseEntity; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; @@ -44,6 +46,8 @@ import java.util.Collections; 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_ASSIGNEE_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ASSIGN_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; @@ -88,6 +92,10 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity @Column(name = ALARM_STATUS_PROPERTY) private AlarmStatus status; + @Type(type="pg-uuid") + @Column(name = ALARM_ASSIGNEE_ID_PROPERTY) + private UUID assigneeId; + @Column(name = ALARM_START_TS_PROPERTY) private Long startTs; @@ -100,6 +108,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity @Column(name = ALARM_CLEAR_TS_PROPERTY) private Long clearTs; + @Column(name = ALARM_ASSIGN_TS_PROPERTY) + private Long assignTs; + @Type(type = "json") @Column(name = ModelConstants.ASSET_ADDITIONAL_INFO_PROPERTY) private JsonNode details; @@ -137,6 +148,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.type = alarm.getType(); this.severity = alarm.getSeverity(); this.status = alarm.getStatus(); + if (alarm.getAssigneeId() != null) { + this.assigneeId = alarm.getAssigneeId().getId(); + } this.propagate = alarm.isPropagate(); this.propagateToOwner = alarm.isPropagateToOwner(); this.propagateToTenant = alarm.isPropagateToTenant(); @@ -144,6 +158,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.endTs = alarm.getEndTs(); this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); + this.assignTs = alarm.getAssignTs(); this.details = alarm.getDetails(); if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); @@ -163,6 +178,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.type = alarmEntity.getType(); this.severity = alarmEntity.getSeverity(); this.status = alarmEntity.getStatus(); + this.assigneeId = alarmEntity.getAssigneeId(); this.propagate = alarmEntity.getPropagate(); this.propagateToOwner = alarmEntity.getPropagateToOwner(); this.propagateToTenant = alarmEntity.getPropagateToTenant(); @@ -170,6 +186,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.endTs = alarmEntity.getEndTs(); this.ackTs = alarmEntity.getAckTs(); this.clearTs = alarmEntity.getClearTs(); + this.assignTs = alarmEntity.getAssignTs(); this.details = alarmEntity.getDetails(); this.propagateRelationTypes = alarmEntity.getPropagateRelationTypes(); } @@ -187,6 +204,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity alarm.setType(type); alarm.setSeverity(severity); alarm.setStatus(status); + if (assigneeId != null) { + alarm.setAssigneeId(new UserId(assigneeId)); + } alarm.setPropagate(propagate); alarm.setPropagateToOwner(propagateToOwner); alarm.setPropagateToTenant(propagateToTenant); @@ -194,6 +214,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity alarm.setEndTs(endTs); alarm.setAckTs(ackTs); alarm.setClearTs(clearTs); + alarm.setAssignTs(assignTs); alarm.setDetails(details); if (!StringUtils.isEmpty(propagateRelationTypes)) { alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java index 1f1a40b25a..434a4662fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java @@ -21,6 +21,7 @@ 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.common.data.id.UserId; import org.thingsboard.server.dao.model.ToData; import javax.persistence.Column; @@ -30,6 +31,7 @@ import javax.persistence.IdClass; import javax.persistence.Table; import java.util.UUID; +import static org.thingsboard.server.dao.model.ModelConstants.ASSIGNEE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.CREATED_TIME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ALARM_COLUMN_FAMILY_NAME; @@ -66,6 +68,9 @@ public final class EntityAlarmEntity implements ToData { @Column(name = CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") private UUID customerId; + @Column(name = ASSIGNEE_ID_PROPERTY, columnDefinition = "uuid") + private UUID assigneeId; + public EntityAlarmEntity() { super(); } @@ -80,6 +85,9 @@ public final class EntityAlarmEntity implements ToData { if (entityAlarm.getCustomerId() != null) { customerId = entityAlarm.getCustomerId().getId(); } + if (entityAlarm.getAssigneeId() != null) { + assigneeId = entityAlarm.getAssigneeId().getId(); + } } @Override @@ -93,6 +101,9 @@ public final class EntityAlarmEntity implements ToData { if (customerId != null) { result.setCustomerId(new CustomerId(customerId)); } + if (assigneeId != null) { + result.setAssigneeId(new UserId(assigneeId)); + } return result; } 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 beadcddf31..24bfe88656 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 @@ -48,6 +48,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -63,6 +64,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -72,6 +74,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, + @Param("assigneeId") UUID assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -80,6 +83,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ", @@ -90,6 +94,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -97,6 +102,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, + @Param("assigneeId") UUID assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -105,6 +111,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -116,6 +123,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -124,6 +132,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, + @Param("assigneeId") UUID assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -133,11 +142,13 @@ public interface AlarmRepository extends JpaRepository { "AND ea.tenantId = :tenantId " + "AND ea.entityId = :affectedEntityId " + "AND ea.entityType = :affectedEntityType " + - "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses))") + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))") Set findAlarmSeverities(@Param("tenantId") UUID tenantId, @Param("affectedEntityId") UUID affectedEntityId, @Param("affectedEntityType") String affectedEntityType, - @Param("alarmStatuses") Set alarmStatuses); + @Param("alarmStatuses") Set alarmStatuses, + @Param("assigneeId") UUID assigneeId); @Query("SELECT a.id FROM AlarmEntity a WHERE a.tenantId = :tenantId AND a.createdTime < :time AND a.endTs < :time") Page findAlarmsIdsByEndTsBeforeAndTenantId(@Param("time") Long time, @Param("tenantId") UUID tenantId, Pageable pageable); 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 407f7658fe..b862f1c7e7 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 @@ -32,6 +32,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.AlarmData; @@ -112,6 +113,10 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } else if (query.getStatus() != null) { statusSet = Collections.singleton(query.getStatus()); } + UUID assigneeId = null; + if (query.getAssigneeId() != null) { + assigneeId = query.getAssigneeId().getId(); + } if (affectedEntity != null) { return DaoUtil.toPageData( alarmRepository.findAlarms( @@ -121,6 +126,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A query.getPageLink().getStartTime(), query.getPageLink().getEndTime(), statusSet, + assigneeId, Objects.toString(query.getPageLink().getTextSearch(), ""), DaoUtil.toPageable(query.getPageLink()) ) @@ -132,6 +138,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A query.getPageLink().getStartTime(), query.getPageLink().getEndTime(), statusSet, + assigneeId, Objects.toString(query.getPageLink().getTextSearch(), ""), DaoUtil.toPageable(query.getPageLink()) ) @@ -148,6 +155,10 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } else if (query.getStatus() != null) { statusSet = Collections.singleton(query.getStatus()); } + UUID assigneeId = null; + if (query.getAssigneeId() != null) { + assigneeId = query.getAssigneeId().getId(); + } return DaoUtil.toPageData( alarmRepository.findCustomerAlarms( tenantId.getId(), @@ -155,6 +166,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A query.getPageLink().getStartTime(), query.getPageLink().getEndTime(), statusSet, + assigneeId, Objects.toString(query.getPageLink().getTextSearch(), ""), DaoUtil.toPageable(query.getPageLink()) ) @@ -167,8 +179,12 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } @Override - public Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set statuses) { - return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), entityId.getEntityType().name(), statuses); + public Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set statuses, UserId assigneeUserId) { + UUID assigneeId = null; + if (assigneeUserId != null) { + assigneeId = assigneeUserId.getId(); + } + return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), entityId.getEntityType().name(), statuses, assigneeId); } @Override diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index e7586b17a8..2e1a830eb0 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -28,6 +28,8 @@ CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_ CREATE INDEX IF NOT EXISTS idx_entity_alarm_alarm_id ON entity_alarm(alarm_id); +CREATE INDEX IF NOT EXISTS idx_entity_alarm_assignee_id ON entity_alarm(assignee_id); + CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 73039274a6..5ceb03288f 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -52,7 +52,9 @@ CREATE TABLE IF NOT EXISTS alarm ( propagate boolean, severity varchar(255), start_ts bigint, + assign_ts bigint, status varchar(255), + assignee_id uuid, tenant_id uuid, customer_id uuid, propagate_relation_types varchar, @@ -69,6 +71,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, + assignee_id uuid, CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index f56936f87e..ba22a57110 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -425,7 +425,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { customerDevice = deviceService.saveDevice(customerDevice); // no one alarms was created - Assert.assertNull(alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null)); + Assert.assertNull(alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null, null)); Alarm alarm1 = Alarm.builder() .tenantId(tenantId) @@ -459,11 +459,11 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .build(); alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarm(); - Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.UNACK, null)); - Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null)); - Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_UNACK)); - Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.ACTIVE, null)); - Assert.assertEquals(AlarmSeverity.MINOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_ACK)); + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.UNACK, null, null)); + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null, null)); + Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_UNACK, null)); + Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.ACTIVE, null, null)); + Assert.assertEquals(AlarmSeverity.MINOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, AlarmStatus.CLEARED_ACK, null)); } @Test 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 21bab255f2..e41c7ad5d5 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 @@ -27,6 +27,7 @@ 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; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -49,6 +50,10 @@ public interface RuleEngineAlarmService { ListenableFuture clearAlarmForResult(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); + ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); + + ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); + ListenableFuture findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId); Alarm findAlarmById(TenantId tenantId, AlarmId alarmId); @@ -61,7 +66,7 @@ public interface RuleEngineAlarmService { ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); - AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus); + AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, UserId assigneeId); PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); } 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 6cc51857e7..ba70a43c14 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 @@ -116,7 +116,7 @@ export class AlarmTableConfig extends EntityTableConfig } fetchAlarms(pageLink: TimePageLink): Observable> { - const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true); + const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, null, true); return this.alarmService.getAlarms(query); } diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 813b3b6927..7a7a81e302 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -89,6 +89,7 @@ import { TbPopoverComponent } from '@shared/components/popover.component'; import { EntityId } from '@shared/models/id/entity-id'; import { AlarmQuery, AlarmSearchStatus, AlarmStatus} from '@app/shared/models/alarm.models'; import { TelemetrySubscriber } from '@app/shared/public-api'; +import { UserId } from '@shared/models/id/user-id'; export interface IWidgetAction { name: string; @@ -414,8 +415,8 @@ export class WidgetContext { return new TimePageLink(pageSize, page, textSearch, sortOrder, startTime, endTime); } - alarmQuery(entityId: EntityId, pageLink: TimePageLink, searchStatus: AlarmSearchStatus, status: AlarmStatus, fetchOriginator: boolean) { - return new AlarmQuery(entityId, pageLink, searchStatus, status, fetchOriginator); + alarmQuery(entityId: EntityId, pageLink: TimePageLink, searchStatus: AlarmSearchStatus, status: AlarmStatus, assigneeId: UserId, fetchOriginator: boolean) { + return new AlarmQuery(entityId, pageLink, searchStatus, status, assigneeId, fetchOriginator); } } diff --git a/ui-ngx/src/app/shared/models/alarm.models.ts b/ui-ngx/src/app/shared/models/alarm.models.ts index fd2e200090..8059a1f585 100644 --- a/ui-ngx/src/app/shared/models/alarm.models.ts +++ b/ui-ngx/src/app/shared/models/alarm.models.ts @@ -23,6 +23,7 @@ import { NULL_UUID } from '@shared/models/id/has-uuid'; import { EntityType } from '@shared/models/entity-type.models'; import { CustomerId } from '@shared/models/id/customer-id'; import { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models'; +import { UserId } from "@shared/models/id/user-id"; export enum AlarmSeverity { CRITICAL = 'CRITICAL', @@ -89,6 +90,7 @@ export const alarmSeverityColors = new Map( export interface Alarm extends BaseData { tenantId: TenantId; customerId: CustomerId; + assigneeId: UserId; type: string; originator: EntityId; severity: AlarmSeverity; @@ -97,6 +99,7 @@ export interface Alarm extends BaseData { endTs: number; ackTs: number; clearTs: number; + assignTs: number; propagate: boolean; details?: any; } @@ -115,11 +118,13 @@ export const simulatedAlarm: AlarmInfo = { id: new AlarmId(NULL_UUID), tenantId: new TenantId(NULL_UUID), customerId: new CustomerId(NULL_UUID), + assigneeId: new UserId(NULL_UUID), createdTime: new Date().getTime(), startTs: new Date().getTime(), endTs: 0, ackTs: 0, clearTs: 0, + assignTs: 0, originatorName: 'Simulated', originator: { entityType: EntityType.DEVICE, @@ -172,6 +177,12 @@ export const alarmFields: {[fieldName: string]: AlarmField} = { name: 'alarm.clear-time', time: true }, + assignTime: { + keyName: 'assignTime', + value: 'assignTs', + name: 'alarm.assign-time', + time: true + }, originator: { keyName: 'originator', value: 'originatorName', @@ -205,15 +216,17 @@ export class AlarmQuery { pageLink: TimePageLink; searchStatus: AlarmSearchStatus; status: AlarmStatus; + assigneeId: UserId; fetchOriginator: boolean; constructor(entityId: EntityId, pageLink: TimePageLink, searchStatus: AlarmSearchStatus, status: AlarmStatus, - fetchOriginator: boolean) { + assigneeId: UserId, fetchOriginator: boolean) { this.affectedEntityId = entityId; this.pageLink = pageLink; this.searchStatus = searchStatus; this.status = status; + this.assigneeId = assigneeId; this.fetchOriginator = fetchOriginator; } @@ -224,6 +237,8 @@ export class AlarmQuery { query += `&searchStatus=${this.searchStatus}`; } else if (this.status) { query += `&status=${this.status}`; + } else if (this.assigneeId) { + query += `&assigneeId=${this.assigneeId.id}`; } if (typeof this.fetchOriginator !== 'undefined' && this.fetchOriginator !== null) { query += `&fetchOriginator=${this.fetchOriginator}`; diff --git a/ui-ngx/src/app/shared/models/audit-log.models.ts b/ui-ngx/src/app/shared/models/audit-log.models.ts index 056c6aa569..fd9ca82275 100644 --- a/ui-ngx/src/app/shared/models/audit-log.models.ts +++ b/ui-ngx/src/app/shared/models/audit-log.models.ts @@ -47,6 +47,8 @@ export enum ActionType { RELATIONS_DELETED = 'RELATIONS_DELETED', ALARM_ACK = 'ALARM_ACK', ALARM_CLEAR = 'ALARM_CLEAR', + ALARM_ASSIGN = 'ALARM_ASSIGN', + ALARM_UNASSIGN = 'ALARM_UNASSIGN', LOGIN = 'LOGIN', LOGOUT = 'LOGOUT', LOCKOUT = 'LOCKOUT', @@ -85,6 +87,8 @@ export const actionTypeTranslations = new Map( [ActionType.RELATIONS_DELETED, 'audit-log.type-relations-delete'], [ActionType.ALARM_ACK, 'audit-log.type-alarm-ack'], [ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'], + [ActionType.ALARM_ASSIGN, 'audit-log.type-alarm-assign'], + [ActionType.ALARM_UNASSIGN, 'audit-log.type-alarm-unassign'], [ActionType.LOGIN, 'audit-log.type-login'], [ActionType.LOGOUT, 'audit-log.type-logout'], [ActionType.LOCKOUT, 'audit-log.type-lockout'], 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 3df8a15e52..269e2e0f67 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -440,6 +440,7 @@ "end-time": "End time", "ack-time": "Acknowledged time", "clear-time": "Cleared time", + "assign-time": "Assign time", "alarm-severity-list": "Alarm severity list", "any-severity": "Any severity", "severity-critical": "Critical", @@ -727,6 +728,8 @@ "type-relations-delete": "All relation deleted", "type-alarm-ack": "Acknowledged", "type-alarm-clear": "Cleared", + "type-alarm-assign": "Assigned", + "type-alarm-unassign": "Unassigned", "type-login": "Login", "type-logout": "Logout", "type-lockout": "Lockout", From 6f5a116beda8846c17096b683828d14b36690884 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 30 Nov 2022 14:28:50 +0200 Subject: [PATCH 02/27] Added methods to REST client --- .../main/java/org/thingsboard/rest/client/RestClient.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index ec1ead3e6b..5f3cf943c0 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -414,6 +414,14 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/clear", null, alarmId.getId()); } + public void assignAlarm(AlarmId alarmId, UserId userId) { + restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/assign/{userId}", null, alarmId.getId(), userId.getId()); + } + + public void unassignAlarm(AlarmId alarmId) { + restTemplate.delete(baseURL + "/api/alarm/{alarmId}/assign", alarmId.getId()); + } + public PageData getAlarms(EntityId entityId, AlarmSearchStatus searchStatus, AlarmStatus status, TimePageLink pageLink, Boolean fetchOriginator) { String urlSecondPart = "/api/alarm/{entityType}/{entityId}?fetchOriginator={fetchOriginator}"; Map params = new HashMap<>(); From 229b2973ccf88dc5ff525dfac4adcf7563d43c88 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 5 Dec 2022 15:17:31 +0200 Subject: [PATCH 03/27] Added ability to check permissions for different user than the currect one --- .../server/controller/AlarmController.java | 12 +- .../server/controller/BaseController.java | 183 +++++++++++++----- 2 files changed, 140 insertions(+), 55 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 cb1093c745..fd91abed3a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; +import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -201,9 +202,15 @@ public class AlarmController extends BaseController { checkParameter(ALARM_ID, strAlarmId); checkParameter(ASSIGNEE_ID, strAssigneeId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - // TODO Add special permissions for assignment - Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + if (!getCurrentUser().getId().equals(assigneeId)) { + try { + checkEntityId(alarm.getOriginator(), Operation.WRITE, new SecurityUser(assigneeId)); + } catch (Exception e) { + throw new ThingsboardException("Assignee user doesn't have permission for alarm originator", ThingsboardErrorCode.PERMISSION_DENIED); + } + } tbAlarmService.assign(alarm, getCurrentUser(), assigneeId).get(); } @@ -219,7 +226,6 @@ public class AlarmController extends BaseController { ) throws Exception { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - // TODO Add special permissions for unassignment Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); tbAlarmService.unassign(alarm, getCurrentUser()).get(); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index ffc3fcf3cd..957b6348a7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -449,11 +449,15 @@ public abstract class BaseController { } Tenant checkTenantId(TenantId tenantId, Operation operation) throws ThingsboardException { + return checkTenantId(tenantId, operation, getCurrentUser()); + } + + Tenant checkTenantId(TenantId tenantId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Tenant tenant = tenantService.findTenantById(tenantId); checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant); + accessControlService.checkPermission(securityUser, Resource.TENANT, operation, tenantId, tenant); return tenant; } catch (Exception e) { throw handleException(e, false); @@ -473,11 +477,15 @@ public abstract class BaseController { } TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation) throws ThingsboardException { + return checkTenantProfileId(tenantProfileId, operation, getCurrentUser()); + } + + TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId); TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId); checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation); + accessControlService.checkPermission(securityUser, Resource.TENANT_PROFILE, operation); return tenantProfile; } catch (Exception e) { throw handleException(e, false); @@ -489,11 +497,15 @@ public abstract class BaseController { } Customer checkCustomerId(CustomerId customerId, Operation operation) throws ThingsboardException { + return checkCustomerId(customerId, operation, getCurrentUser()); + } + + Customer checkCustomerId(CustomerId customerId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(customerId, "Incorrect customerId " + customerId); Customer customer = customerService.findCustomerById(getTenantId(), customerId); checkNotNull(customer, "Customer with id [" + customerId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customerId, customer); + accessControlService.checkPermission(securityUser, Resource.CUSTOMER, operation, customerId, customer); return customer; } catch (Exception e) { throw handleException(e, false); @@ -501,11 +513,15 @@ public abstract class BaseController { } User checkUserId(UserId userId, Operation operation) throws ThingsboardException { + return checkUserId(userId, operation, getCurrentUser()); + } + + User checkUserId(UserId userId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(userId, "Incorrect userId " + userId); - User user = userService.findUserById(getCurrentUser().getTenantId(), userId); + User user = userService.findUserById(securityUser.getTenantId(), userId); checkNotNull(user, "User with id [" + userId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, userId, user); + accessControlService.checkPermission(securityUser, Resource.USER, operation, userId, user); return user; } catch (Exception e) { throw handleException(e, false); @@ -522,6 +538,10 @@ public abstract class BaseController { } protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException { + checkEntityId(entityId, operation, getCurrentUser()); + } + + protected void checkEntityId(EntityId entityId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { if (entityId == null) { throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); @@ -529,61 +549,61 @@ public abstract class BaseController { validateId(entityId.getId(), "Incorrect entityId " + entityId); switch (entityId.getEntityType()) { case ALARM: - checkAlarmId(new AlarmId(entityId.getId()), operation); + checkAlarmId(new AlarmId(entityId.getId()), operation, securityUser); return; case DEVICE: - checkDeviceId(new DeviceId(entityId.getId()), operation); + checkDeviceId(new DeviceId(entityId.getId()), operation, securityUser); return; case DEVICE_PROFILE: - checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation); + checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation, securityUser); return; case CUSTOMER: - checkCustomerId(new CustomerId(entityId.getId()), operation); + checkCustomerId(new CustomerId(entityId.getId()), operation, securityUser); return; case TENANT: - checkTenantId(TenantId.fromUUID(entityId.getId()), operation); + checkTenantId(TenantId.fromUUID(entityId.getId()), operation, securityUser); return; case TENANT_PROFILE: - checkTenantProfileId(new TenantProfileId(entityId.getId()), operation); + checkTenantProfileId(new TenantProfileId(entityId.getId()), operation, securityUser); return; case RULE_CHAIN: - checkRuleChain(new RuleChainId(entityId.getId()), operation); + checkRuleChain(new RuleChainId(entityId.getId()), operation, securityUser); return; case RULE_NODE: - checkRuleNode(new RuleNodeId(entityId.getId()), operation); + checkRuleNode(new RuleNodeId(entityId.getId()), operation, securityUser); return; case ASSET: - checkAssetId(new AssetId(entityId.getId()), operation); + checkAssetId(new AssetId(entityId.getId()), operation, securityUser); return; case ASSET_PROFILE: - checkAssetProfileId(new AssetProfileId(entityId.getId()), operation); + checkAssetProfileId(new AssetProfileId(entityId.getId()), operation, securityUser); return; case DASHBOARD: - checkDashboardId(new DashboardId(entityId.getId()), operation); + checkDashboardId(new DashboardId(entityId.getId()), operation, securityUser); return; case USER: - checkUserId(new UserId(entityId.getId()), operation); + checkUserId(new UserId(entityId.getId()), operation, securityUser); return; case ENTITY_VIEW: - checkEntityViewId(new EntityViewId(entityId.getId()), operation); + checkEntityViewId(new EntityViewId(entityId.getId()), operation, securityUser); return; case EDGE: - checkEdgeId(new EdgeId(entityId.getId()), operation); + checkEdgeId(new EdgeId(entityId.getId()), operation, securityUser); return; case WIDGETS_BUNDLE: - checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation); + checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation, securityUser); return; case WIDGET_TYPE: - checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation); + checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation, securityUser); return; case TB_RESOURCE: - checkResourceId(new TbResourceId(entityId.getId()), operation); + checkResourceId(new TbResourceId(entityId.getId()), operation, securityUser); return; case OTA_PACKAGE: - checkOtaPackageId(new OtaPackageId(entityId.getId()), operation); + checkOtaPackageId(new OtaPackageId(entityId.getId()), operation, securityUser); return; case QUEUE: - checkQueueId(new QueueId(entityId.getId()), operation); + checkQueueId(new QueueId(entityId.getId()), operation, securityUser); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); @@ -592,13 +612,16 @@ public abstract class BaseController { throw handleException(e, false); } } - Device checkDeviceId(DeviceId deviceId, Operation operation) throws ThingsboardException { + return checkDeviceId(deviceId, operation, getCurrentUser()); + } + + Device checkDeviceId(DeviceId deviceId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(deviceId, "Incorrect deviceId " + deviceId); - Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId); + Device device = deviceService.findDeviceById(securityUser.getTenantId(), deviceId); checkNotNull(device, "Device with id [" + deviceId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device); + accessControlService.checkPermission(securityUser, Resource.DEVICE, operation, deviceId, device); return device; } catch (Exception e) { throw handleException(e, false); @@ -618,11 +641,15 @@ public abstract class BaseController { } DeviceProfile checkDeviceProfileId(DeviceProfileId deviceProfileId, Operation operation) throws ThingsboardException { + return checkDeviceProfileId(deviceProfileId, operation, getCurrentUser()); + } + + DeviceProfile checkDeviceProfileId(DeviceProfileId deviceProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(deviceProfileId, "Incorrect deviceProfileId " + deviceProfileId); - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(getCurrentUser().getTenantId(), deviceProfileId); + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(securityUser.getTenantId(), deviceProfileId); checkNotNull(deviceProfile, "Device profile with id [" + deviceProfileId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile); + accessControlService.checkPermission(securityUser, Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile); return deviceProfile; } catch (Exception e) { throw handleException(e, false); @@ -630,11 +657,15 @@ public abstract class BaseController { } protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation) throws ThingsboardException { + return checkEntityViewId(entityViewId, operation, getCurrentUser()); + } + + protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); - EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId); + EntityView entityView = entityViewService.findEntityViewById(securityUser.getTenantId(), entityViewId); checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView); + accessControlService.checkPermission(securityUser, Resource.ENTITY_VIEW, operation, entityViewId, entityView); return entityView; } catch (Exception e) { throw handleException(e, false); @@ -654,11 +685,15 @@ public abstract class BaseController { } Asset checkAssetId(AssetId assetId, Operation operation) throws ThingsboardException { + return checkAssetId(assetId, operation, getCurrentUser()); + } + + Asset checkAssetId(AssetId assetId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(assetId, "Incorrect assetId " + assetId); - Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId); + Asset asset = assetService.findAssetById(securityUser.getTenantId(), assetId); checkNotNull(asset, "Asset with id [" + assetId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset); + accessControlService.checkPermission(securityUser, Resource.ASSET, operation, assetId, asset); return asset; } catch (Exception e) { throw handleException(e, false); @@ -678,11 +713,15 @@ public abstract class BaseController { } AssetProfile checkAssetProfileId(AssetProfileId assetProfileId, Operation operation) throws ThingsboardException { + return checkAssetProfileId(assetProfileId, operation, getCurrentUser()); + } + + AssetProfile checkAssetProfileId(AssetProfileId assetProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(assetProfileId, "Incorrect assetProfileId " + assetProfileId); - AssetProfile assetProfile = assetProfileService.findAssetProfileById(getCurrentUser().getTenantId(), assetProfileId); + AssetProfile assetProfile = assetProfileService.findAssetProfileById(securityUser.getTenantId(), assetProfileId); checkNotNull(assetProfile, "Asset profile with id [" + assetProfileId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.ASSET_PROFILE, operation, assetProfileId, assetProfile); + accessControlService.checkPermission(securityUser, Resource.ASSET_PROFILE, operation, assetProfileId, assetProfile); return assetProfile; } catch (Exception e) { throw handleException(e, false); @@ -690,11 +729,15 @@ public abstract class BaseController { } Alarm checkAlarmId(AlarmId alarmId, Operation operation) throws ThingsboardException { + return checkAlarmId(alarmId, operation, getCurrentUser()); + } + + Alarm checkAlarmId(AlarmId alarmId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(alarmId, "Incorrect alarmId " + alarmId); - Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get(); + Alarm alarm = alarmService.findAlarmByIdAsync(securityUser.getTenantId(), alarmId).get(); checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarm); + accessControlService.checkPermission(securityUser, Resource.ALARM, operation, alarmId, alarm); return alarm; } catch (Exception e) { throw handleException(e, false); @@ -714,11 +757,15 @@ public abstract class BaseController { } WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation) throws ThingsboardException { + return checkWidgetsBundleId(widgetsBundleId, operation, getCurrentUser()); + } + + WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); - WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId); + WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(securityUser.getTenantId(), widgetsBundleId); checkNotNull(widgetsBundle, "Widgets bundle with id [" + widgetsBundleId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle); + accessControlService.checkPermission(securityUser, Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle); return widgetsBundle; } catch (Exception e) { throw handleException(e, false); @@ -726,11 +773,15 @@ public abstract class BaseController { } WidgetTypeDetails checkWidgetTypeId(WidgetTypeId widgetTypeId, Operation operation) throws ThingsboardException { + return checkWidgetTypeId(widgetTypeId, operation, getCurrentUser()); + } + + WidgetTypeDetails checkWidgetTypeId(WidgetTypeId widgetTypeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); - WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(getCurrentUser().getTenantId(), widgetTypeId); + WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(securityUser.getTenantId(), widgetTypeId); checkNotNull(widgetTypeDetails, "Widget type with id [" + widgetTypeId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails); + accessControlService.checkPermission(securityUser, Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails); return widgetTypeDetails; } catch (Exception e) { throw handleException(e, false); @@ -738,11 +789,15 @@ public abstract class BaseController { } Dashboard checkDashboardId(DashboardId dashboardId, Operation operation) throws ThingsboardException { + return checkDashboardId(dashboardId, operation, getCurrentUser()); + } + + Dashboard checkDashboardId(DashboardId dashboardId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(dashboardId, "Incorrect dashboardId " + dashboardId); - Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId); + Dashboard dashboard = dashboardService.findDashboardById(securityUser.getTenantId(), dashboardId); checkNotNull(dashboard, "Dashboard with id [" + dashboardId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboard); + accessControlService.checkPermission(securityUser, Resource.DASHBOARD, operation, dashboardId, dashboard); return dashboard; } catch (Exception e) { throw handleException(e, false); @@ -750,11 +805,15 @@ public abstract class BaseController { } Edge checkEdgeId(EdgeId edgeId, Operation operation) throws ThingsboardException { + return checkEdgeId(edgeId, operation, getCurrentUser()); + } + + Edge checkEdgeId(EdgeId edgeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(edgeId, "Incorrect edgeId " + edgeId); Edge edge = edgeService.findEdgeById(getTenantId(), edgeId); checkNotNull(edge, "Edge with id [" + edgeId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); + accessControlService.checkPermission(securityUser, Resource.EDGE, operation, edgeId, edge); return edge; } catch (Exception e) { throw handleException(e, false); @@ -813,14 +872,22 @@ public abstract class BaseController { } protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation) throws ThingsboardException { + return checkRuleChain(ruleChainId, operation, getCurrentUser()); + } + + protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(ruleChainId, "Incorrect ruleChainId " + ruleChainId); - RuleChain ruleChain = ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId); + RuleChain ruleChain = ruleChainService.findRuleChainById(securityUser.getTenantId(), ruleChainId); checkNotNull(ruleChain, "Rule chain with id [" + ruleChainId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, ruleChainId, ruleChain); + accessControlService.checkPermission(securityUser, Resource.RULE_CHAIN, operation, ruleChainId, ruleChain); return ruleChain; } protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException { + return checkRuleNode(ruleNodeId, operation, getCurrentUser()); + } + + protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId); RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId); checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found"); @@ -829,11 +896,15 @@ public abstract class BaseController { } TbResource checkResourceId(TbResourceId resourceId, Operation operation) throws ThingsboardException { + return checkResourceId(resourceId, operation, getCurrentUser()); + } + + TbResource checkResourceId(TbResourceId resourceId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(resourceId, "Incorrect resourceId " + resourceId); - TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId); + TbResource resource = resourceService.findResourceById(securityUser.getTenantId(), resourceId); checkNotNull(resource, "Resource with id [" + resourceId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource); + accessControlService.checkPermission(securityUser, Resource.TB_RESOURCE, operation, resourceId, resource); return resource; } catch (Exception e) { throw handleException(e, false); @@ -853,11 +924,15 @@ public abstract class BaseController { } OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation) throws ThingsboardException { + return checkOtaPackageId(otaPackageId, operation, getCurrentUser()); + } + + OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId); - OtaPackage otaPackage = otaPackageService.findOtaPackageById(getCurrentUser().getTenantId(), otaPackageId); + OtaPackage otaPackage = otaPackageService.findOtaPackageById(securityUser.getTenantId(), otaPackageId); checkNotNull(otaPackage, "OTA package with id [" + otaPackageId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage); + accessControlService.checkPermission(securityUser, Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage); return otaPackage; } catch (Exception e) { throw handleException(e, false); @@ -889,10 +964,14 @@ public abstract class BaseController { } protected Queue checkQueueId(QueueId queueId, Operation operation) throws ThingsboardException { + return checkQueueId(queueId, operation, getCurrentUser()); + } + + protected Queue checkQueueId(QueueId queueId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(queueId, "Incorrect queueId " + queueId); - Queue queue = queueService.findQueueById(getCurrentUser().getTenantId(), queueId); + Queue queue = queueService.findQueueById(securityUser.getTenantId(), queueId); checkNotNull(queue); - accessControlService.checkPermission(getCurrentUser(), Resource.QUEUE, operation, queueId, queue); + accessControlService.checkPermission(securityUser, Resource.QUEUE, operation, queueId, queue); TenantId tenantId = getTenantId(); if (queue.getTenantId().isNullUid() && !tenantId.isNullUid()) { TenantProfile tenantProfile = tenantProfileCache.get(tenantId); From ac83e379ab26a3d715afc3a52396724ba6b2ca01 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 6 Dec 2022 15:33:21 +0200 Subject: [PATCH 04/27] Updated upgrade script --- application/src/main/data/upgrade/3.4.2/schema_update.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/data/upgrade/3.4.2/schema_update.sql b/application/src/main/data/upgrade/3.4.2/schema_update.sql index e47a6bf2f3..de7cd5b8b1 100644 --- a/application/src/main/data/upgrade/3.4.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.2/schema_update.sql @@ -17,10 +17,10 @@ -- ALARM ASSIGN TO USER START -ALTER TABLE alarm ADD COLUMN assign_ts BIGINT; -ALTER TABLE alarm ADD COLUMN assignee_id UUID; +ALTER TABLE alarm ADD COLUMN IF NOT EXISTS assign_ts BIGINT; +ALTER TABLE alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; -ALTER TABLE entity_alarm ADD COLUMN assignee_id UUID; +ALTER TABLE entity_alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; CREATE INDEX IF NOT EXISTS idx_entity_alarm_assignee_id ON entity_alarm(assignee_id); From 08e356a4152aef41c895c3fb0206ab3707a48d0c Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 12 Dec 2022 13:00:22 +0200 Subject: [PATCH 05/27] Updated alarm assignment to send websocket update on assign, added originator label to alarm info --- .../queue/DefaultTbCoreConsumerService.java | 4 +- .../DefaultSubscriptionManagerService.java | 15 ++- .../SubscriptionManagerService.java | 3 +- .../subscription/TbAlarmDataSubCtx.java | 3 +- .../subscription/TbSubscriptionUtils.java | 4 +- .../DefaultAlarmSubscriptionService.java | 8 +- .../sub/AlarmSubscriptionUpdate.java | 12 +- common/cluster-api/src/main/proto/queue.proto | 2 + .../server/dao/alarm/AlarmAdditionalInfo.java | 32 +++++ .../dao/alarm/AlarmOperationResult.java | 14 +- .../server/common/data/alarm/AlarmInfo.java | 50 +++++-- .../server/common/data/query/AlarmData.java | 10 +- .../server/dao/alarm/BaseAlarmService.java | 123 +++++++++++++++++- .../server/dao/model/ModelConstants.java | 4 + .../server/dao/model/sql/AlarmInfoEntity.java | 14 +- .../dao/sql/query/AlarmDataAdapter.java | 24 +++- .../query/DefaultAlarmQueryRepository.java | 16 ++- .../alarm/alarm-details-dialog.component.ts | 25 ++++ ui-ngx/src/app/shared/models/alarm.models.ts | 26 ++++ .../assets/locale/locale.constant-en_US.json | 4 + 20 files changed, 351 insertions(+), 42 deletions(-) create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 931acf908c..c2acd77953 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -26,6 +26,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rpc.RpcError; @@ -502,7 +503,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService { if (TbSubscriptionType.ALARMS.equals(s.getType())) { @@ -303,6 +304,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene }, s -> alarm.getCreatedTime() >= s.getTs(), s -> alarm, + alarmInfo, false ); callback.onSuccess(); @@ -320,6 +322,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene }, s -> alarm.getCreatedTime() >= s.getTs(), s -> alarm, + null, true ); callback.onSuccess(); @@ -414,18 +417,19 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene private void onLocalAlarmSubUpdate(EntityId entityId, Function castFunction, Predicate filterFunction, - Function processFunction, boolean deleted) { + Function processFunction, AlarmInfo alarmInfo, + boolean deleted) { Set entitySubscriptions = subscriptionsByEntityId.get(entityId); if (entitySubscriptions != null) { entitySubscriptions.stream().map(castFunction).filter(Objects::nonNull).filter(filterFunction).forEach(s -> { Alarm alarm = processFunction.apply(s); if (alarm != null) { if (serviceId.equals(s.getServiceId())) { - AlarmSubscriptionUpdate update = new AlarmSubscriptionUpdate(s.getSubscriptionId(), alarm, deleted); + AlarmSubscriptionUpdate update = new AlarmSubscriptionUpdate(s.getSubscriptionId(), alarm, alarmInfo, deleted); localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); - toCoreNotificationsProducer.send(tpi, toProto(s, alarm, deleted), null); + toCoreNotificationsProducer.send(tpi, toProto(s, alarm, alarmInfo, deleted), null); } } }); @@ -562,12 +566,13 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene return new TbProtoQueueMsg<>(subscription.getEntityId().getId(), toCoreMsg); } - private TbProtoQueueMsg toProto(TbSubscription subscription, Alarm alarm, boolean deleted) { + private TbProtoQueueMsg toProto(TbSubscription subscription, Alarm alarm, AlarmInfo alarmInfo, boolean deleted) { TbAlarmSubscriptionUpdateProto.Builder builder = TbAlarmSubscriptionUpdateProto.newBuilder(); builder.setSessionId(subscription.getSessionId()); builder.setSubscriptionId(subscription.getSubscriptionId()); builder.setAlarm(JacksonUtil.toString(alarm)); + builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); builder.setDeleted(deleted); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg( diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java index 15aab86327..747a73ebe1 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.subscription; import org.springframework.context.ApplicationListener; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; @@ -42,7 +43,7 @@ public interface SubscriptionManagerService extends ApplicationListener keys, TbCallback callback); - void onAlarmUpdate(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback); + void onAlarmUpdate(TenantId tenantId, EntityId entityId, Alarm alarm, AlarmInfo alarmInfo, TbCallback callback); void onAlarmDeleted(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index 5804002c77..7afc82c03b 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -20,6 +20,7 @@ import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EntityId; @@ -219,7 +220,7 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { boolean matchesFilter = filter(alarm); if (onCurrentPage) { if (matchesFilter) { - AlarmData updated = new AlarmData(alarm, current.getOriginatorName(), current.getEntityId()); + AlarmData updated = new AlarmData(alarm, subscriptionUpdate.getAlarmInfo(), current.getEntityId()); updated.getLatest().putAll(current.getLatest()); alarmsMap.put(alarmId, updated); sendWsMsg(new AlarmDataUpdate(cmdId, null, Collections.singletonList(updated), maxEntitiesPerAlarmSubscription, data.getTotalElements())); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index f8359a21ee..91583e1194 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.subscription; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; @@ -190,7 +191,8 @@ public class TbSubscriptionUtils { return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), SubscriptionErrorCode.forCode(proto.getErrorCode()), proto.getErrorMsg()); } else { Alarm alarm = JacksonUtil.fromString(proto.getAlarm(), Alarm.class); - return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), alarm); + AlarmInfo alarmInfo = JacksonUtil.fromString(proto.getAlarmInfo(), AlarmInfo.class); + return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), alarm, alarmInfo); } } 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 f7d121d9ff..634c90880a 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 @@ -187,7 +187,13 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { if (subscriptionManagerService.isPresent()) { - subscriptionManagerService.get().onAlarmUpdate(tenantId, entityId, alarm, TbCallback.EMPTY); + AlarmInfo alarmInfo = new AlarmInfo(alarm); + alarmInfo.setOriginatorName(result.getAlarmAdditionalInfo().getOriginatorName()); + alarmInfo.setOriginatorLabel(result.getAlarmAdditionalInfo().getOriginatorName()); + alarmInfo.setAssigneeFirstName(result.getAlarmAdditionalInfo().getFirstName()); + alarmInfo.setAssigneeLastName(result.getAlarmAdditionalInfo().getLastName()); + alarmInfo.setAssigneeEmail(result.getAlarmAdditionalInfo().getEmail()); + subscriptionManagerService.get().onAlarmUpdate(tenantId, entityId, alarm, alarmInfo, TbCallback.EMPTY); } else { log.warn("Possible misconfiguration because subscriptionManagerService is null!"); } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java index 3f4bc9ce1e..10b750c5c7 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.telemetry.sub; import lombok.Getter; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.query.AlarmData; @@ -38,16 +39,19 @@ public class AlarmSubscriptionUpdate { @Getter private Alarm alarm; @Getter + private AlarmInfo alarmInfo; + @Getter private boolean alarmDeleted; - public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm) { - this(subscriptionId, alarm, false); + public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm, AlarmInfo alarmInfo) { + this(subscriptionId, alarm, alarmInfo, false); } - public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm, boolean alarmDeleted) { + public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm, AlarmInfo alarmInfo, boolean alarmDeleted) { super(); this.subscriptionId = subscriptionId; this.alarm = alarm; + this.alarmInfo = alarmInfo; this.alarmDeleted = alarmDeleted; } @@ -65,6 +69,6 @@ public class AlarmSubscriptionUpdate { @Override public String toString() { return "AlarmUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + ", alarm=" - + alarm + "]"; + + alarm + ", alarmInfo=" + alarmInfo + "]"; } } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 5a28d42546..4ef017715d 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -562,6 +562,7 @@ message TbAlarmSubscriptionUpdateProto { string errorMsg = 4; string alarm = 5; bool deleted = 6; + string alarmInfo = 7; } message TbAttributeUpdateProto { @@ -581,6 +582,7 @@ message TbAlarmUpdateProto { int64 tenantIdMSB = 4; int64 tenantIdLSB = 5; string alarm = 6; + string alarmInfo = 7; } message TbAlarmDeleteProto { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java new file mode 100644 index 0000000000..a726ca599a --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2022 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.alarm; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +@AllArgsConstructor +public class AlarmAdditionalInfo { + private final String originatorName; + private final String originatorLabel; + + private final String firstName; + private final String lastName; + private final String email; +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java index 4940c74191..c8d2c0aad9 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java @@ -28,19 +28,25 @@ public class AlarmOperationResult { private final boolean successful; private final boolean created; private final List propagatedEntitiesList; + private final AlarmAdditionalInfo alarmAdditionalInfo; public AlarmOperationResult(Alarm alarm, boolean successful) { - this(alarm, successful, Collections.emptyList()); + this(alarm, successful, Collections.emptyList(), new AlarmAdditionalInfo(null, null, null, null, null)); } - public AlarmOperationResult(Alarm alarm, boolean successful, List propagatedEntitiesList) { - this(alarm, successful, false, propagatedEntitiesList); + public AlarmOperationResult(Alarm alarm, boolean successful, AlarmAdditionalInfo alarmAdditionalInfo) { + this(alarm, successful, Collections.emptyList(), alarmAdditionalInfo); } - public AlarmOperationResult(Alarm alarm, boolean successful, boolean created, List propagatedEntitiesList) { + public AlarmOperationResult(Alarm alarm, boolean successful, List propagatedEntitiesList, AlarmAdditionalInfo alarmAdditionalInfo) { + this(alarm, successful, false, propagatedEntitiesList, alarmAdditionalInfo); + } + + public AlarmOperationResult(Alarm alarm, boolean successful, boolean created, List propagatedEntitiesList, AlarmAdditionalInfo alarmAdditionalInfo) { this.alarm = alarm; this.successful = successful; this.created = created; this.propagatedEntitiesList = propagatedEntitiesList; + this.alarmAdditionalInfo = alarmAdditionalInfo; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java index 54537276bd..9b55324800 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java @@ -17,15 +17,42 @@ package org.thingsboard.server.common.data.alarm; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import org.thingsboard.server.common.data.User; + +import java.util.Objects; @ApiModel public class AlarmInfo extends Alarm { private static final long serialVersionUID = 2807343093519543363L; + @Getter + @Setter @ApiModelProperty(position = 19, value = "Alarm originator name", example = "Thermostat") private String originatorName; + @Getter + @Setter + @ApiModelProperty(position = 20, value = "Alarm originator label", example = "Thermostat label") + private String originatorLabel; + + @Getter + @Setter + @ApiModelProperty(position = 21, value = "Alarm assignee first name") + private String assigneeFirstName; + + @Getter + @Setter + @ApiModelProperty(position = 22, value = "Alarm assignee last name") + private String assigneeLastName; + + @Getter + @Setter + @ApiModelProperty(position = 23, value = "Alarm assignee email") + private String assigneeEmail; + public AlarmInfo() { super(); } @@ -34,17 +61,13 @@ public class AlarmInfo extends Alarm { super(alarm); } - public AlarmInfo(Alarm alarm, String originatorName) { + public AlarmInfo(Alarm alarm, AlarmInfo alarmInfo) { super(alarm); - this.originatorName = originatorName; - } - - public String getOriginatorName() { - return originatorName; - } - - public void setOriginatorName(String originatorName) { - this.originatorName = originatorName; + originatorName = alarmInfo.originatorName; + originatorLabel = alarmInfo.originatorLabel; + assigneeFirstName = alarmInfo.assigneeFirstName; + assigneeLastName = alarmInfo.assigneeLastName; + assigneeEmail = alarmInfo.assigneeEmail; } @Override @@ -55,8 +78,11 @@ public class AlarmInfo extends Alarm { AlarmInfo alarmInfo = (AlarmInfo) o; - return originatorName != null ? originatorName.equals(alarmInfo.originatorName) : alarmInfo.originatorName == null; - + return (Objects.equals(originatorName, alarmInfo.originatorName)) && + (Objects.equals(originatorLabel, alarmInfo.originatorLabel)) && + (Objects.equals(assigneeFirstName, alarmInfo.assigneeFirstName)) && + (Objects.equals(assigneeLastName, alarmInfo.assigneeLastName)) && + (Objects.equals(assigneeEmail, alarmInfo.assigneeEmail)); } @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java index c288fec13e..cae512af18 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java @@ -31,8 +31,14 @@ public class AlarmData extends AlarmInfo { @Getter private final Map> latest; - public AlarmData(Alarm alarm, String originatorName, EntityId entityId) { - super(alarm, originatorName); + public AlarmData(Alarm alarm, AlarmInfo alarmInfo, EntityId entityId) { + super(alarm, alarmInfo); + this.entityId = entityId; + this.latest = new HashMap<>(); + } + + public AlarmData(Alarm alarm, EntityId entityId) { + super(alarm); this.entityId = entityId; this.latest = new HashMap<>(); } 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 3abefb780b..1ccac7a19b 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 @@ -27,6 +27,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -34,10 +40,15 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.EntityAlarm; +import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; @@ -47,9 +58,16 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.dashboard.DashboardService; +import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.user.UserService; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -81,6 +99,27 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Autowired private EntityService entityService; + @Autowired + private UserService userService; + + @Autowired + private TenantService tenantService; + + @Autowired + private CustomerService customerService; + + @Autowired + private DashboardService dashboardService; + + @Autowired + private AssetService assetService; + + @Autowired + private DeviceService deviceService; + + @Autowired + private EntityViewService entityViewService; + @Autowired private DataValidator alarmDataValidator; @@ -151,7 +190,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm == null) { return new AlarmOperationResult(alarm, false); } - AlarmOperationResult result = new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); + AlarmOperationResult result = new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); deleteEntityRelations(tenantId, alarm.getId()); alarmDao.removeById(tenantId, alarm.getUuidId()); return result; @@ -161,7 +201,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ log.debug("New Alarm : {}", alarm); Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); List propagatedEntitiesList = createEntityAlarmRecords(saved); - return new AlarmOperationResult(saved, true, true, propagatedEntitiesList); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(alarm.getTenantId(), alarm); + return new AlarmOperationResult(saved, true, true, propagatedEntitiesList, alarmAdditionalInfo); } private List createEntityAlarmRecords(Alarm alarm) throws InterruptedException, ExecutionException { @@ -216,7 +257,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } else { propagatedEntitiesList = new ArrayList<>(getPropagationEntityIds(result)); } - return new AlarmOperationResult(result, true, propagatedEntitiesList); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(newAlarm.getTenantId(), newAlarm); + return new AlarmOperationResult(result, true, propagatedEntitiesList, alarmAdditionalInfo); } @Override @@ -233,7 +275,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setStatus(newStatus); alarm.setAckTs(ackTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); } } }); @@ -256,7 +299,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setDetails(details); } alarm = alarmDao.save(alarm.getTenantId(), alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); } } }); @@ -274,7 +318,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setAssigneeId(assigneeId); alarm.setAssignTs(assignTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); } } }); @@ -292,7 +337,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setAssigneeId(null); alarm.setAssignTs(assignTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm))); + AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); + return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); } } }); @@ -396,10 +442,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getAckTs() > existing.getAckTs()) { existing.setAckTs(alarm.getAckTs()); } + if (alarm.getAssignTs() > existing.getAssignTs()) { + existing.setAssignTs(alarm.getAssignTs()); + } existing.setStatus(alarm.getStatus()); existing.setSeverity(alarm.getSeverity()); existing.setDetails(alarm.getDetails()); existing.setCustomerId(alarm.getCustomerId()); + existing.setAssigneeId(alarm.getAssigneeId()); existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); existing.setPropagateToOwner(existing.isPropagateToOwner() || alarm.isPropagateToOwner()); existing.setPropagateToTenant(existing.isPropagateToTenant() || alarm.isPropagateToTenant()); @@ -447,4 +497,63 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ Alarm entity = alarmDao.findAlarmById(tenantId, alarmId.getId()); return function.apply(entity); } + + private AlarmAdditionalInfo getAlarmAdditionalInfo(TenantId tenantId, Alarm alarm) { + AlarmAdditionalInfo.AlarmAdditionalInfoBuilder builder = AlarmAdditionalInfo.builder(); + + addAlarmOriginatorNameAndLabel(tenantId, alarm.getOriginator(), builder); + + if (alarm.getAssigneeId() != null) { + User assignedUser = userService.findUserById(tenantId, alarm.getAssigneeId()); + builder.firstName(assignedUser.getFirstName()); + builder.lastName(assignedUser.getLastName()); + builder.email(assignedUser.getEmail()); + } + return builder.build(); + } + + private void addAlarmOriginatorNameAndLabel(TenantId tenantId, EntityId originatorId, AlarmAdditionalInfo.AlarmAdditionalInfoBuilder builder) { + String originatorName = "Unknown"; + String originatorLabel = "Unknown"; + switch(originatorId.getEntityType()) { + case TENANT: + Tenant tenantOriginator = tenantService.findTenantById((TenantId) originatorId); + originatorName = tenantOriginator.getTitle(); + originatorLabel = tenantOriginator.getEmail(); + break; + case CUSTOMER: + Customer customerOriginator = customerService.findCustomerById(tenantId, (CustomerId) originatorId); + originatorName = customerOriginator.getTitle(); + originatorLabel = customerOriginator.getEmail(); + break; + case USER: + User userOriginator = userService.findUserById(tenantId, (UserId) originatorId); + originatorName = userOriginator.getEmail(); + originatorLabel = userOriginator.getName(); + break; + case DASHBOARD: + Dashboard dashboardOriginator = dashboardService.findDashboardById(tenantId, (DashboardId) originatorId); + originatorName = dashboardOriginator.getTitle(); + originatorLabel = dashboardOriginator.getName(); + break; + case ASSET: + Asset assetOriginator = assetService.findAssetById(tenantId, (AssetId) originatorId); + originatorName = assetOriginator.getName(); + originatorLabel = assetOriginator.getLabel(); + break; + case DEVICE: + Device deviceOriginator = deviceService.findDeviceById(tenantId, (DeviceId) originatorId); + originatorName = deviceOriginator.getName(); + originatorLabel = deviceOriginator.getLabel(); + break; + case ENTITY_VIEW: + EntityView entityViewOriginator = entityViewService.findEntityViewById(tenantId, (EntityViewId) originatorId); + originatorName = entityViewOriginator.getName(); + originatorLabel = entityViewOriginator.getType(); // TODO Should we use something else? + break; + } + + builder.originatorName(originatorName); + builder.originatorLabel(originatorLabel); + } } 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 c64dea0c40..da2ffc7c89 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 @@ -284,10 +284,14 @@ public class ModelConstants { public static final String ALARM_DETAILS_PROPERTY = "details"; public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; public static final String ALARM_ORIGINATOR_NAME_PROPERTY = "originator_name"; + public static final String ALARM_ORIGINATOR_LABEL_PROPERTY = "originator_label"; public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type"; public static final String ALARM_SEVERITY_PROPERTY = "severity"; public static final String ALARM_STATUS_PROPERTY = "status"; public static final String ALARM_ASSIGNEE_ID_PROPERTY = "assignee_id"; + public static final String ALARM_ASSIGNEE_FIRST_NAME_PROPERTY = "assignee_first_name"; + public static final String ALARM_ASSIGNEE_LAST_NAME_PROPERTY = "assignee_last_name"; + public static final String ALARM_ASSIGNEE_EMAIL_PROPERTY = "assignee_email"; public static final String ALARM_START_TS_PROPERTY = "start_ts"; public static final String ALARM_END_TS_PROPERTY = "end_ts"; public static final String ALARM_ACK_TS_PROPERTY = "ack_ts"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java index cef7c47a73..aada0c7c17 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java @@ -24,6 +24,11 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; public class AlarmInfoEntity extends AbstractAlarmEntity { private String originatorName; + private String originatorLabel; + + private String assigneeFirstName; + private String assigneeLastName; + private String assigneeEmail; public AlarmInfoEntity() { super(); @@ -35,6 +40,13 @@ public class AlarmInfoEntity extends AbstractAlarmEntity { @Override public AlarmInfo toData() { - return new AlarmInfo(super.toAlarm(), this.originatorName); + AlarmInfo alarmInfo = new AlarmInfo(super.toAlarm()); + alarmInfo.setOriginatorName(originatorName); + alarmInfo.setOriginatorLabel(originatorLabel); + + alarmInfo.setAssigneeFirstName(assigneeFirstName); + alarmInfo.setAssigneeLastName(assigneeLastName); + alarmInfo.setAssigneeEmail(assigneeEmail); + return alarmInfo; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java index ff156eb51c..e7ea6a1b66 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.EntityDataPageLink; @@ -68,6 +69,7 @@ public class AlarmDataAdapter { alarm.setCreatedTime((long) row.get(ModelConstants.CREATED_TIME_PROPERTY)); alarm.setAckTs((long) row.get(ModelConstants.ALARM_ACK_TS_PROPERTY)); alarm.setClearTs((long) row.get(ModelConstants.ALARM_CLEAR_TS_PROPERTY)); + alarm.setAssignTs((long) row.get(ModelConstants.ALARM_ASSIGN_TS_PROPERTY)); alarm.setStartTs((long) row.get(ModelConstants.ALARM_START_TS_PROPERTY)); alarm.setEndTs((long) row.get(ModelConstants.ALARM_END_TS_PROPERTY)); Object additionalInfo = row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY); @@ -81,6 +83,16 @@ public class AlarmDataAdapter { EntityType originatorType = EntityType.values()[(int) row.get(ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY)]; UUID originatorId = (UUID) row.get(ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); + Object assigneeIdObj = row.get(ModelConstants.ASSIGNEE_ID_PROPERTY); + String assigneeFirstName = null; + String assigneeLastName = null; + String assigneeEmail = null; + if (assigneeIdObj != null) { + alarm.setAssigneeId(new UserId((UUID) row.get(ModelConstants.ALARM_ASSIGNEE_ID_PROPERTY))); + assigneeFirstName = row.get(ModelConstants.ALARM_ASSIGNEE_FIRST_NAME_PROPERTY).toString(); + assigneeLastName = row.get(ModelConstants.ALARM_ASSIGNEE_LAST_NAME_PROPERTY).toString(); + assigneeEmail = row.get(ModelConstants.ALARM_ASSIGNEE_EMAIL_PROPERTY).toString(); + } alarm.setPropagate((boolean) row.get(ModelConstants.ALARM_PROPAGATE_PROPERTY)); alarm.setPropagateToOwner((boolean) row.get(ModelConstants.ALARM_PROPAGATE_TO_OWNER_PROPERTY)); alarm.setPropagateToTenant((boolean) row.get(ModelConstants.ALARM_PROPAGATE_TO_TENANT_PROPERTY)); @@ -105,7 +117,17 @@ public class AlarmDataAdapter { EntityId entityId = entityIdMap.get(entityUuid); Object originatorNameObj = row.get(ModelConstants.ALARM_ORIGINATOR_NAME_PROPERTY); String originatorName = originatorNameObj != null ? originatorNameObj.toString() : null; - return new AlarmData(alarm, originatorName, entityId); + Object originatorLabelObj = row.get(ModelConstants.ALARM_ORIGINATOR_LABEL_PROPERTY); + String originatorLabel = originatorLabelObj != null ? originatorLabelObj.toString() : null; + + AlarmData alarmData = new AlarmData(alarm, entityId); + alarmData.setOriginatorName(originatorName); + alarmData.setOriginatorLabel(originatorLabel); + alarmData.setAssigneeFirstName(assigneeFirstName); + alarmData.setAssigneeLastName(assigneeLastName); + alarmData.setAssigneeEmail(assigneeEmail); + + return alarmData; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index d91a8c5fc4..d3b8137f8b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -57,6 +57,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { alarmFieldColumnMap.put("ackTime", ModelConstants.ALARM_ACK_TS_PROPERTY); alarmFieldColumnMap.put("clearTs", ModelConstants.ALARM_CLEAR_TS_PROPERTY); alarmFieldColumnMap.put("clearTime", ModelConstants.ALARM_CLEAR_TS_PROPERTY); + alarmFieldColumnMap.put("assignTime", ModelConstants.ALARM_ASSIGN_TS_PROPERTY); alarmFieldColumnMap.put("details", ModelConstants.ADDITIONAL_INFO_PROPERTY); alarmFieldColumnMap.put("endTs", ModelConstants.ALARM_END_TS_PROPERTY); alarmFieldColumnMap.put("endTime", ModelConstants.ALARM_END_TS_PROPERTY); @@ -67,7 +68,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { alarmFieldColumnMap.put("severity", ModelConstants.ALARM_SEVERITY_PROPERTY); alarmFieldColumnMap.put("originatorId", ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); alarmFieldColumnMap.put("originatorType", ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY); + alarmFieldColumnMap.put("assigneeId", ModelConstants.ALARM_ASSIGNEE_ID_PROPERTY); alarmFieldColumnMap.put("originator", "originator_name"); + alarmFieldColumnMap.put("originatorLabel", ModelConstants.ALARM_ORIGINATOR_LABEL_PROPERTY); + alarmFieldColumnMap.put("assigneeFirstName", ModelConstants.ALARM_ASSIGNEE_FIRST_NAME_PROPERTY); + alarmFieldColumnMap.put("assigneeLastName", ModelConstants.ALARM_ASSIGNEE_LAST_NAME_PROPERTY); + alarmFieldColumnMap.put("assigneeEmail", ModelConstants.ALARM_ASSIGNEE_EMAIL_PROPERTY); } private static final String SELECT_ORIGINATOR_NAME = " COALESCE(CASE" + @@ -87,10 +93,15 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " THEN (select name from entity_view where id = a.originator_id)" + " END, 'Deleted') as originator_name"; + private static final String SELECT_ASSIGNEE_INFO = " tbu.first_name as assignee_first_name," + + " tbu.last_name as assignee_last_name," + + " tbu.email as assignee_email"; + private static final String FIELDS_SELECTION = "select a.id as id," + " a.created_time as created_time," + " a.ack_ts as ack_ts," + " a.clear_ts as clear_ts," + + " a.assign_ts as assign_ts," + " a.additional_info as additional_info," + " a.end_ts as end_ts," + " a.originator_id as originator_id," + @@ -104,9 +115,11 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.tenant_id as tenant_id, " + " a.customer_id as customer_id, " + " a.propagate_relation_types as propagate_relation_types, " + - " a.type as type," + SELECT_ORIGINATOR_NAME + ", "; + " a.type as type," + SELECT_ORIGINATOR_NAME + ", " + + SELECT_ASSIGNEE_INFO + ", "; private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id"; + private static final String LEFT_JOIN_TB_USERS = "left join tb_user tbu on a.assignee_id = tbu.id"; protected final NamedParameterJdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; @@ -139,6 +152,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { } else { selectPart.append(" a.originator_id as entity_id "); } + fromPart.append(LEFT_JOIN_TB_USERS); EntityDataSortOrder sortOrder = pageLink.getSortOrder(); String textSearchQuery = buildTextSearchQuery(ctx, query.getAlarmFields(), pageLink.getTextSearch()); if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts index be3aff8c50..f8c257e641 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts @@ -84,10 +84,15 @@ export class AlarmDetailsDialogComponent extends DialogComponent { export interface AlarmInfo extends Alarm { originatorName: string; + assigneeFirstName: string; + assigneeLastName: string; + assigneeEmail: string; } export interface AlarmDataInfo extends AlarmInfo { @@ -126,6 +129,9 @@ export const simulatedAlarm: AlarmInfo = { clearTs: 0, assignTs: 0, originatorName: 'Simulated', + assigneeFirstName: "", + assigneeLastName: "", + assigneeEmail: "test@example.com", originator: { entityType: EntityType.DEVICE, id: '1' @@ -207,6 +213,26 @@ export const alarmFields: {[fieldName: string]: AlarmField} = { keyName: 'status', value: 'status', name: 'alarm.status' + }, + assigneeId: { + keyName: 'assigneeId', + value: 'assigneeId.id', + name: 'alarm.assignee-id' + }, + assigneeFirstName: { + keyName: 'assigneeFirstName', + value: 'assigneeFirstName', + name: 'alarm.assignee-first-name' + }, + assigneeLastName: { + keyName: 'assigneeLastName', + value: 'assigneeLastName', + name: 'alarm.assignee-last-name' + }, + assigneeEmail: { + keyName: 'assigneeEmail', + value: 'assigneeEmail', + name: 'alarm.assignee-email' } }; 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 269e2e0f67..d191442427 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -433,6 +433,10 @@ "severity": "Severity", "originator": "Originator", "originator-type": "Originator type", + "assignee-id": "Assignee id", + "assignee-first-name": "Assignee first name", + "assignee-last-name": "Assignee last name", + "assignee-email": "Assignee email", "details": "Details", "status": "Status", "alarm-details": "Alarm details", From f29d1b0effe02a8ce9639b03f845f9bea63f7b88 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 13 Dec 2022 13:39:09 +0200 Subject: [PATCH 06/27] Added HasLabel, HasEmail, HasTitle interfaces to get correctly label in entityService, refactoring for alarms processing. The main point is swithing from Alarm entity to AlarmInfo --- .../queue/DefaultTbCoreConsumerService.java | 3 +- .../DefaultSubscriptionManagerService.java | 27 ++-- .../SubscriptionManagerService.java | 5 +- .../subscription/TbAlarmDataSubCtx.java | 10 +- .../subscription/TbSubscriptionUtils.java | 11 +- .../DefaultAlarmSubscriptionService.java | 24 ++- .../sub/AlarmSubscriptionUpdate.java | 13 +- .../service/ttl/AlarmsCleanUpService.java | 5 +- common/cluster-api/src/main/proto/queue.proto | 8 +- .../dao/alarm/AlarmOperationResult.java | 19 ++- .../server/dao/entity/EntityService.java | 4 + .../server/common/data/ContactBased.java | 2 +- .../server/common/data/Customer.java | 2 +- .../server/common/data/DashboardInfo.java | 2 +- .../server/common/data/Device.java | 2 +- .../server/common/data/EntityType.java | 22 ++- .../server/common/data/HasEmail.java} | 16 +- .../server/common/data/HasLabel.java | 22 +++ .../server/common/data/HasTitle.java | 22 +++ .../server/common/data/OtaPackageInfo.java | 2 +- .../server/common/data/Tenant.java | 2 +- .../server/common/data/alarm/AlarmInfo.java | 15 +- .../server/common/data/asset/Asset.java | 3 +- .../server/common/data/edge/Edge.java | 3 +- .../server/common/data/query/AlarmData.java | 4 +- .../common/data/widget/BaseWidgetType.java | 3 +- .../common/data/widget/WidgetsBundle.java | 3 +- .../server/dao/alarm/BaseAlarmService.java | 139 ++++-------------- .../server/dao/entity/BaseEntityService.java | 26 ++++ .../query/DefaultAlarmQueryRepository.java | 37 ++++- .../dao/service/BaseAlarmServiceTest.java | 30 ++-- .../rule/engine/profile/AlarmState.java | 2 +- 32 files changed, 260 insertions(+), 228 deletions(-) rename common/{dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java => data/src/main/java/org/thingsboard/server/common/data/HasEmail.java} (62%) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasLabel.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasTitle.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index c2acd77953..c106090508 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -503,14 +503,13 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService { if (TbSubscriptionType.ALARMS.equals(s.getType())) { @@ -302,16 +302,15 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene return null; } }, - s -> alarm.getCreatedTime() >= s.getTs(), - s -> alarm, - alarmInfo, + s -> alarmInfo.getCreatedTime() >= s.getTs(), + s -> alarmInfo, false ); callback.onSuccess(); } @Override - public void onAlarmDeleted(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback) { + public void onAlarmDeleted(TenantId tenantId, EntityId entityId, AlarmInfo alarmInfo, TbCallback callback) { onLocalAlarmSubUpdate(entityId, s -> { if (TbSubscriptionType.ALARMS.equals(s.getType())) { @@ -320,9 +319,8 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene return null; } }, - s -> alarm.getCreatedTime() >= s.getTs(), - s -> alarm, - null, + s -> alarmInfo.getCreatedTime() >= s.getTs(), + s -> alarmInfo, true ); callback.onSuccess(); @@ -417,19 +415,19 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene private void onLocalAlarmSubUpdate(EntityId entityId, Function castFunction, Predicate filterFunction, - Function processFunction, AlarmInfo alarmInfo, + Function processFunction, boolean deleted) { Set entitySubscriptions = subscriptionsByEntityId.get(entityId); if (entitySubscriptions != null) { entitySubscriptions.stream().map(castFunction).filter(Objects::nonNull).filter(filterFunction).forEach(s -> { - Alarm alarm = processFunction.apply(s); - if (alarm != null) { + AlarmInfo alarmInfo = processFunction.apply(s); + if (alarmInfo != null) { if (serviceId.equals(s.getServiceId())) { - AlarmSubscriptionUpdate update = new AlarmSubscriptionUpdate(s.getSubscriptionId(), alarm, alarmInfo, deleted); + AlarmSubscriptionUpdate update = new AlarmSubscriptionUpdate(s.getSubscriptionId(), alarmInfo, deleted); localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY); } else { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId()); - toCoreNotificationsProducer.send(tpi, toProto(s, alarm, alarmInfo, deleted), null); + toCoreNotificationsProducer.send(tpi, toProto(s, alarmInfo, deleted), null); } } }); @@ -566,12 +564,11 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene return new TbProtoQueueMsg<>(subscription.getEntityId().getId(), toCoreMsg); } - private TbProtoQueueMsg toProto(TbSubscription subscription, Alarm alarm, AlarmInfo alarmInfo, boolean deleted) { + private TbProtoQueueMsg toProto(TbSubscription subscription, AlarmInfo alarmInfo, boolean deleted) { TbAlarmSubscriptionUpdateProto.Builder builder = TbAlarmSubscriptionUpdateProto.newBuilder(); builder.setSessionId(subscription.getSessionId()); builder.setSubscriptionId(subscription.getSubscriptionId()); - builder.setAlarm(JacksonUtil.toString(alarm)); builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); builder.setDeleted(deleted); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java index 747a73ebe1..63c8c9aa6e 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/SubscriptionManagerService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.subscription; import org.springframework.context.ApplicationListener; -import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -43,9 +42,9 @@ public interface SubscriptionManagerService extends ApplicationListener keys, TbCallback callback); - void onAlarmUpdate(TenantId tenantId, EntityId entityId, Alarm alarm, AlarmInfo alarmInfo, TbCallback callback); + void onAlarmUpdate(TenantId tenantId, EntityId entityId, AlarmInfo alarmInfo, TbCallback callback); - void onAlarmDeleted(TenantId tenantId, EntityId entityId, Alarm alarm, TbCallback callback); + void onAlarmDeleted(TenantId tenantId, EntityId entityId, AlarmInfo alarmInfo, TbCallback callback); } diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index 7afc82c03b..706cbcb8ad 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -63,10 +63,8 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { private final AlarmService alarmService; @Getter - @Setter private final LinkedHashMap entitiesMap; @Getter - @Setter private final HashMap alarmsMap; private final int maxEntitiesPerAlarmSubscription; @@ -207,8 +205,8 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { } private void sendWsMsg(String sessionId, AlarmSubscriptionUpdate subscriptionUpdate) { - Alarm alarm = subscriptionUpdate.getAlarm(); - AlarmId alarmId = alarm.getId(); + AlarmInfo alarmInfo = subscriptionUpdate.getAlarmInfo(); + AlarmId alarmId = alarmInfo.getId(); if (subscriptionUpdate.isAlarmDeleted()) { Alarm deleted = alarmsMap.remove(alarmId); if (deleted != null) { @@ -217,10 +215,10 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { } else { AlarmData current = alarmsMap.get(alarmId); boolean onCurrentPage = current != null; - boolean matchesFilter = filter(alarm); + boolean matchesFilter = filter(alarmInfo); if (onCurrentPage) { if (matchesFilter) { - AlarmData updated = new AlarmData(alarm, subscriptionUpdate.getAlarmInfo(), current.getEntityId()); + AlarmData updated = new AlarmData(alarmInfo, current.getEntityId()); updated.getLatest().putAll(current.getLatest()); alarmsMap.put(alarmId, updated); sendWsMsg(new AlarmDataUpdate(cmdId, null, Collections.singletonList(updated), maxEntitiesPerAlarmSubscription, data.getTotalElements())); diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index 91583e1194..7972f6f833 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -190,9 +190,8 @@ public class TbSubscriptionUtils { if (proto.getErrorCode() > 0) { return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), SubscriptionErrorCode.forCode(proto.getErrorCode()), proto.getErrorMsg()); } else { - Alarm alarm = JacksonUtil.fromString(proto.getAlarm(), Alarm.class); AlarmInfo alarmInfo = JacksonUtil.fromString(proto.getAlarmInfo(), AlarmInfo.class); - return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), alarm, alarmInfo); + return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), alarmInfo); } } @@ -318,27 +317,27 @@ public class TbSubscriptionUtils { return entry; } - public static ToCoreMsg toAlarmUpdateProto(TenantId tenantId, EntityId entityId, Alarm alarm) { + public static ToCoreMsg toAlarmUpdateProto(TenantId tenantId, EntityId entityId, AlarmInfo alarmInfo) { TbAlarmUpdateProto.Builder builder = TbAlarmUpdateProto.newBuilder(); builder.setEntityType(entityId.getEntityType().name()); builder.setEntityIdMSB(entityId.getId().getMostSignificantBits()); builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); - builder.setAlarm(JacksonUtil.toString(alarm)); + builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); msgBuilder.setAlarmUpdate(builder); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); } - public static ToCoreMsg toAlarmDeletedProto(TenantId tenantId, EntityId entityId, Alarm alarm) { + public static ToCoreMsg toAlarmDeletedProto(TenantId tenantId, EntityId entityId, AlarmInfo alarmInfo) { TbAlarmDeleteProto.Builder builder = TbAlarmDeleteProto.newBuilder(); builder.setEntityType(entityId.getEntityType().name()); builder.setEntityIdMSB(entityId.getId().getMostSignificantBits()); builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); - builder.setAlarm(JacksonUtil.toString(alarm)); + builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); msgBuilder.setAlarmDelete(builder); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); 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 634c90880a..9ab3858730 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 @@ -95,7 +95,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService if (result.isCreated()) { apiUsageClient.report(alarm.getTenantId(), null, ApiUsageRecordKey.CREATED_ALARMS_COUNT); } - return result.getAlarm(); + return result.getAlarmInfo(); } @Override @@ -181,24 +181,18 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService private void onAlarmUpdated(AlarmOperationResult result) { wsCallBackExecutor.submit(() -> { - Alarm alarm = result.getAlarm(); - TenantId tenantId = result.getAlarm().getTenantId(); + AlarmInfo alarmInfo = result.getAlarmInfo(); + TenantId tenantId = alarmInfo.getTenantId(); for (EntityId entityId : result.getPropagatedEntitiesList()) { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { if (subscriptionManagerService.isPresent()) { - AlarmInfo alarmInfo = new AlarmInfo(alarm); - alarmInfo.setOriginatorName(result.getAlarmAdditionalInfo().getOriginatorName()); - alarmInfo.setOriginatorLabel(result.getAlarmAdditionalInfo().getOriginatorName()); - alarmInfo.setAssigneeFirstName(result.getAlarmAdditionalInfo().getFirstName()); - alarmInfo.setAssigneeLastName(result.getAlarmAdditionalInfo().getLastName()); - alarmInfo.setAssigneeEmail(result.getAlarmAdditionalInfo().getEmail()); - subscriptionManagerService.get().onAlarmUpdate(tenantId, entityId, alarm, alarmInfo, TbCallback.EMPTY); + subscriptionManagerService.get().onAlarmUpdate(tenantId, entityId, alarmInfo, TbCallback.EMPTY); } else { log.warn("Possible misconfiguration because subscriptionManagerService is null!"); } } else { - TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarm); + TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toAlarmUpdateProto(tenantId, entityId, alarmInfo); clusterService.pushMsgToCore(tpi, entityId.getId(), toCoreMsg, null); } } @@ -207,18 +201,18 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService private void onAlarmDeleted(AlarmOperationResult result) { wsCallBackExecutor.submit(() -> { - Alarm alarm = result.getAlarm(); - TenantId tenantId = result.getAlarm().getTenantId(); + AlarmInfo alarmInfo = result.getAlarmInfo(); + TenantId tenantId = alarmInfo.getTenantId(); for (EntityId entityId : result.getPropagatedEntitiesList()) { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId); if (currentPartitions.contains(tpi)) { if (subscriptionManagerService.isPresent()) { - subscriptionManagerService.get().onAlarmDeleted(tenantId, entityId, alarm, TbCallback.EMPTY); + subscriptionManagerService.get().onAlarmDeleted(tenantId, entityId, alarmInfo, TbCallback.EMPTY); } else { log.warn("Possible misconfiguration because subscriptionManagerService is null!"); } } else { - TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarm); + TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toAlarmDeletedProto(tenantId, entityId, alarmInfo); clusterService.pushMsgToCore(tpi, entityId.getId(), toCoreMsg, null); } } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java index 10b750c5c7..47eb7c69bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java @@ -37,20 +37,17 @@ public class AlarmSubscriptionUpdate { @Getter private String errorMsg; @Getter - private Alarm alarm; - @Getter private AlarmInfo alarmInfo; @Getter private boolean alarmDeleted; - public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm, AlarmInfo alarmInfo) { - this(subscriptionId, alarm, alarmInfo, false); + public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarmInfo) { + this(subscriptionId, alarmInfo, false); } - public AlarmSubscriptionUpdate(int subscriptionId, Alarm alarm, AlarmInfo alarmInfo, boolean alarmDeleted) { + public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarmInfo, boolean alarmDeleted) { super(); this.subscriptionId = subscriptionId; - this.alarm = alarm; this.alarmInfo = alarmInfo; this.alarmDeleted = alarmDeleted; } @@ -68,7 +65,7 @@ public class AlarmSubscriptionUpdate { @Override public String toString() { - return "AlarmUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + ", alarm=" - + alarm + ", alarmInfo=" + alarmInfo + "]"; + return "AlarmUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + + ", alarmInfo=" + alarmInfo + "]"; } } diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java index e178055706..cd6fbb7eb5 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.TenantId; @@ -83,8 +84,8 @@ public class AlarmsCleanUpService { PageData toRemove = alarmDao.findAlarmsIdsByEndTsBeforeAndTenantId(expirationTime, tenantId, removalBatchRequest); toRemove.getData().forEach(alarmId -> { relationService.deleteEntityRelations(tenantId, alarmId); - Alarm alarm = alarmService.deleteAlarm(tenantId, alarmId).getAlarm(); - entityActionService.pushEntityActionToRuleEngine(alarm.getOriginator(), alarm, tenantId, null, ActionType.ALARM_DELETE, null); + AlarmInfo alarmInfo = alarmService.deleteAlarm(tenantId, alarmId).getAlarmInfo(); + entityActionService.pushEntityActionToRuleEngine(alarmInfo.getOriginator(), alarmInfo, tenantId, null, ActionType.ALARM_DELETE, null); }); totalRemoved += toRemove.getTotalElements(); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 4ef017715d..301c395a18 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -560,9 +560,8 @@ message TbAlarmSubscriptionUpdateProto { int32 subscriptionId = 2; int32 errorCode = 3; string errorMsg = 4; - string alarm = 5; + string alarmInfo = 5; bool deleted = 6; - string alarmInfo = 7; } message TbAttributeUpdateProto { @@ -581,8 +580,7 @@ message TbAlarmUpdateProto { int64 entityIdLSB = 3; int64 tenantIdMSB = 4; int64 tenantIdLSB = 5; - string alarm = 6; - string alarmInfo = 7; + string alarmInfo = 6; } message TbAlarmDeleteProto { @@ -591,7 +589,7 @@ message TbAlarmDeleteProto { int64 entityIdLSB = 3; int64 tenantIdMSB = 4; int64 tenantIdLSB = 5; - string alarm = 6; + string alarmInfo = 6; } message TbAttributeDeleteProto { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java index c8d2c0aad9..10fac5de08 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; import lombok.Data; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.id.EntityId; import java.util.Collections; @@ -24,29 +25,27 @@ import java.util.List; @Data public class AlarmOperationResult { - private final Alarm alarm; private final boolean successful; private final boolean created; private final List propagatedEntitiesList; - private final AlarmAdditionalInfo alarmAdditionalInfo; + private final AlarmInfo alarmInfo; public AlarmOperationResult(Alarm alarm, boolean successful) { - this(alarm, successful, Collections.emptyList(), new AlarmAdditionalInfo(null, null, null, null, null)); + this(new AlarmInfo(alarm, null, null, null, null, null), successful, Collections.emptyList()); } - public AlarmOperationResult(Alarm alarm, boolean successful, AlarmAdditionalInfo alarmAdditionalInfo) { - this(alarm, successful, Collections.emptyList(), alarmAdditionalInfo); + public AlarmOperationResult(AlarmInfo alarmInfo, boolean successful) { + this(alarmInfo, successful, Collections.emptyList()); } - public AlarmOperationResult(Alarm alarm, boolean successful, List propagatedEntitiesList, AlarmAdditionalInfo alarmAdditionalInfo) { - this(alarm, successful, false, propagatedEntitiesList, alarmAdditionalInfo); + public AlarmOperationResult(AlarmInfo alarmInfo, boolean successful, List propagatedEntitiesList) { + this(alarmInfo, successful, false, propagatedEntitiesList); } - public AlarmOperationResult(Alarm alarm, boolean successful, boolean created, List propagatedEntitiesList, AlarmAdditionalInfo alarmAdditionalInfo) { - this.alarm = alarm; + public AlarmOperationResult(AlarmInfo alarmInfo, boolean successful, boolean created, List propagatedEntitiesList) { + this.alarmInfo = alarmInfo; this.successful = successful; this.created = created; this.propagatedEntitiesList = propagatedEntitiesList; - this.alarmAdditionalInfo = alarmAdditionalInfo; } } 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 986da96d46..e819420e9d 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 @@ -24,10 +24,14 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.Optional; + public interface EntityService { ListenableFuture fetchEntityNameAsync(TenantId tenantId, EntityId entityId); + Optional fetchEntityLabel(TenantId tenantId, EntityId entityId); + CustomerId fetchEntityCustomerId(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/ContactBased.java b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java index 5ff7b874b3..9e17b72a5b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ContactBased.java @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) -public abstract class ContactBased extends SearchTextBasedWithAdditionalInfo implements HasName { +public abstract class ContactBased extends SearchTextBasedWithAdditionalInfo implements HasEmail { private static final long serialVersionUID = 5047448057830660988L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index bdd06606a6..9a2a409bcd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) -public class Customer extends ContactBased implements HasTenantId, ExportableEntity { +public class Customer extends ContactBased implements HasTenantId, ExportableEntity, HasTitle { private static final long serialVersionUID = -1599722990298929275L; 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 1895b41639..9f25272433 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 @@ -31,7 +31,7 @@ import java.util.Objects; import java.util.Set; @ApiModel -public class DashboardInfo extends SearchTextBased implements HasName, HasTenantId { +public class DashboardInfo extends SearchTextBased implements HasName, HasTenantId, HasTitle { private TenantId tenantId; @NoXss diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 4a6589d72c..02f56a4e90 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -40,7 +40,7 @@ import java.util.Optional; @ApiModel @EqualsAndHashCode(callSuper = true) @Slf4j -public class Device extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId, HasOtaPackage, ExportableEntity { +public class Device extends SearchTextBasedWithAdditionalInfo implements HasLabel, HasTenantId, HasCustomerId, HasOtaPackage, ExportableEntity { private static final long serialVersionUID = 2807343040519543363L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 0798647903..74e03a50d6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -19,5 +19,25 @@ package org.thingsboard.server.common.data; * @author Andrew Shvayka */ public enum EntityType { - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, ASSET_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE, RPC, QUEUE; + TENANT, + CUSTOMER, + USER, + DASHBOARD, + ASSET, + DEVICE, + ALARM, + RULE_CHAIN, + RULE_NODE, + ENTITY_VIEW, + WIDGETS_BUNDLE, + WIDGET_TYPE, + TENANT_PROFILE, + DEVICE_PROFILE, + ASSET_PROFILE, + API_USAGE_STATE, + TB_RESOURCE, + OTA_PACKAGE, + EDGE, + RPC, + QUEUE } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasEmail.java similarity index 62% rename from common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java rename to common/data/src/main/java/org/thingsboard/server/common/data/HasEmail.java index a726ca599a..7f413075f8 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmAdditionalInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasEmail.java @@ -13,20 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.alarm; +package org.thingsboard.server.common.data; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; +public interface HasEmail extends HasName { -@Builder -@Getter -@AllArgsConstructor -public class AlarmAdditionalInfo { - private final String originatorName; - private final String originatorLabel; + String getEmail(); - private final String firstName; - private final String lastName; - private final String email; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasLabel.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasLabel.java new file mode 100644 index 0000000000..d9c3c9b98c --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasLabel.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2022 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.common.data; + +public interface HasLabel extends HasName { + + String getLabel(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasTitle.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasTitle.java new file mode 100644 index 0000000000..886cef5fb1 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasTitle.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2022 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.common.data; + +public interface HasTitle { + + String getTitle(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java index b31d0a6bc0..b1e8c9eb65 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; @Slf4j @Data @EqualsAndHashCode(callSuper = true) -public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId { +public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasTitle { private static final long serialVersionUID = 3168391583570815419L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index 8d5a9fe3fc..68ad28eece 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @EqualsAndHashCode(callSuper = true) -public class Tenant extends ContactBased implements HasTenantId { +public class Tenant extends ContactBased implements HasTenantId, HasTitle { private static final long serialVersionUID = 8057243243859922101L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java index 9b55324800..878edb856e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java @@ -61,6 +61,15 @@ public class AlarmInfo extends Alarm { super(alarm); } + public AlarmInfo(Alarm alarm, String originatorName, String originatorLabel, String assigneeFirstName, String assigneeLastName, String assigneeEmail) { + super(alarm); + this.originatorName = originatorName; + this.originatorLabel = originatorLabel; + this.assigneeFirstName = assigneeFirstName; + this.assigneeLastName = assigneeLastName; + this.assigneeEmail = assigneeEmail; + } + public AlarmInfo(Alarm alarm, AlarmInfo alarmInfo) { super(alarm); originatorName = alarmInfo.originatorName; @@ -88,7 +97,11 @@ public class AlarmInfo extends Alarm { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (originatorName != null ? originatorName.hashCode() : 0); + result = 31 * result + (originatorName != null ? originatorName.hashCode() : 0) + + (originatorLabel != null ? originatorLabel.hashCode() : 0) + + (assigneeFirstName != null ? assigneeFirstName.hashCode() : 0) + + (assigneeLastName != null ? assigneeLastName.hashCode() : 0) + + (assigneeEmail != null ? assigneeEmail.hashCode() : 0); return result; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index e8eeaf75e9..46de963b66 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -23,6 +23,7 @@ import lombok.Getter; import lombok.Setter; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasCustomerId; +import org.thingsboard.server.common.data.HasLabel; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; @@ -37,7 +38,7 @@ import java.util.Optional; @ApiModel @EqualsAndHashCode(callSuper = true) -public class Asset extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId, ExportableEntity { +public class Asset extends SearchTextBasedWithAdditionalInfo implements HasLabel, HasTenantId, HasCustomerId, ExportableEntity { private static final long serialVersionUID = 2807343040519543363L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java index 58c23d0877..7ad50a90cf 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java @@ -21,6 +21,7 @@ import lombok.EqualsAndHashCode; import lombok.Setter; import lombok.ToString; import org.thingsboard.server.common.data.HasCustomerId; +import org.thingsboard.server.common.data.HasLabel; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; @@ -35,7 +36,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @EqualsAndHashCode(callSuper = true) @ToString @Setter -public class Edge extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId { +public class Edge extends SearchTextBasedWithAdditionalInfo implements HasLabel, HasTenantId, HasCustomerId { private static final long serialVersionUID = 4934987555236873728L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java index cae512af18..e7f22f2044 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmData.java @@ -31,8 +31,8 @@ public class AlarmData extends AlarmInfo { @Getter private final Map> latest; - public AlarmData(Alarm alarm, AlarmInfo alarmInfo, EntityId entityId) { - super(alarm, alarmInfo); + public AlarmData(AlarmInfo alarmInfo, EntityId entityId) { + super(alarmInfo); this.entityId = entityId; this.latest = new HashMap<>(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java index be5014a4cd..c165e3443a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/BaseWidgetType.java @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.widget; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; @@ -25,7 +26,7 @@ import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; @Data -public class BaseWidgetType extends BaseData implements HasTenantId { +public class BaseWidgetType extends BaseData implements HasName, HasTenantId { private static final long serialVersionUID = 8388684344603660756L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java index eca19f0db5..d862e67da1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java @@ -25,6 +25,7 @@ import lombok.Setter; import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.HasTitle; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; @@ -33,7 +34,7 @@ import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @EqualsAndHashCode(callSuper = true) -public class WidgetsBundle extends SearchTextBased implements HasName, HasTenantId, ExportableEntity { +public class WidgetsBundle extends SearchTextBased implements HasName, HasTenantId, ExportableEntity, HasTitle { private static final long serialVersionUID = -7627368878362410489L; 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 1ccac7a19b..4fc5075fb3 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 @@ -27,11 +27,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; @@ -40,15 +35,10 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.EntityAlarm; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.AlarmId; -import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DashboardId; -import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; @@ -58,15 +48,9 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.customer.CustomerService; -import org.thingsboard.server.dao.dashboard.DashboardService; -import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; -import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; import javax.annotation.Nullable; @@ -102,24 +86,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Autowired private UserService userService; - @Autowired - private TenantService tenantService; - - @Autowired - private CustomerService customerService; - - @Autowired - private DashboardService dashboardService; - - @Autowired - private AssetService assetService; - - @Autowired - private DeviceService deviceService; - - @Autowired - private EntityViewService entityViewService; - @Autowired private DataValidator alarmDataValidator; @@ -190,8 +156,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm == null) { return new AlarmOperationResult(alarm, false); } - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); - AlarmOperationResult result = new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(tenantId, alarm); + AlarmOperationResult result = new AlarmOperationResult(alarmInfo, true, new ArrayList<>(getPropagationEntityIds(alarm))); deleteEntityRelations(tenantId, alarm.getId()); alarmDao.removeById(tenantId, alarm.getUuidId()); return result; @@ -201,8 +167,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ log.debug("New Alarm : {}", alarm); Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); List propagatedEntitiesList = createEntityAlarmRecords(saved); - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(alarm.getTenantId(), alarm); - return new AlarmOperationResult(saved, true, true, propagatedEntitiesList, alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(alarm.getTenantId(), alarm); + return new AlarmOperationResult(alarmInfo, true, true, propagatedEntitiesList); } private List createEntityAlarmRecords(Alarm alarm) throws InterruptedException, ExecutionException { @@ -257,8 +223,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } else { propagatedEntitiesList = new ArrayList<>(getPropagationEntityIds(result)); } - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(newAlarm.getTenantId(), newAlarm); - return new AlarmOperationResult(result, true, propagatedEntitiesList, alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(newAlarm.getTenantId(), newAlarm); + return new AlarmOperationResult(alarmInfo, true, propagatedEntitiesList); } @Override @@ -275,8 +241,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setStatus(newStatus); alarm.setAckTs(ackTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(tenantId, alarm); + return new AlarmOperationResult(alarmInfo, true, new ArrayList<>(getPropagationEntityIds(alarm))); } } }); @@ -299,8 +265,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setDetails(details); } alarm = alarmDao.save(alarm.getTenantId(), alarm); - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(tenantId, alarm); + return new AlarmOperationResult(alarmInfo, true, new ArrayList<>(getPropagationEntityIds(alarm))); } } }); @@ -318,8 +284,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setAssigneeId(assigneeId); alarm.setAssignTs(assignTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(tenantId, alarm); + return new AlarmOperationResult(alarmInfo, true, new ArrayList<>(getPropagationEntityIds(alarm))); } } }); @@ -337,8 +303,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ alarm.setAssigneeId(null); alarm.setAssignTs(assignTime); alarm = alarmDao.save(alarm.getTenantId(), alarm); - AlarmAdditionalInfo alarmAdditionalInfo = getAlarmAdditionalInfo(tenantId, alarm); - return new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)), alarmAdditionalInfo); + AlarmInfo alarmInfo = getAlarmInfo(tenantId, alarm); + return new AlarmOperationResult(alarmInfo, true, new ArrayList<>(getPropagationEntityIds(alarm))); } } }); @@ -362,15 +328,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ public ListenableFuture findAlarmInfoByIdAsync(TenantId tenantId, AlarmId alarmId) { log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId); validateId(alarmId, "Incorrect alarmId " + alarmId); - return Futures.transformAsync(alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()), - a -> { - AlarmInfo alarmInfo = new AlarmInfo(a); - return Futures.transform( - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { - alarmInfo.setOriginatorName(originatorName); - return alarmInfo; - }, MoreExecutors.directExecutor()); - }, MoreExecutors.directExecutor()); + return Futures.transform(alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()), + a -> getAlarmInfo(tenantId, a), MoreExecutors.directExecutor()); } @Override @@ -478,7 +437,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) { // TODO Add ability to automatically assign created alarm to some user - EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), null,alarm.getId()); + EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), null, alarm.getId()); try { alarmDao.createEntityAlarmRecord(entityAlarm); } catch (Exception e) { @@ -498,62 +457,22 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ return function.apply(entity); } - private AlarmAdditionalInfo getAlarmAdditionalInfo(TenantId tenantId, Alarm alarm) { - AlarmAdditionalInfo.AlarmAdditionalInfoBuilder builder = AlarmAdditionalInfo.builder(); + private AlarmInfo getAlarmInfo(TenantId tenantId, Alarm alarm) { + String originatorName = null; + String originatorLabel = null; + String assigneeFirstName = null; + String assigneeLastName = null; + String assigneeEmail = null; - addAlarmOriginatorNameAndLabel(tenantId, alarm.getOriginator(), builder); + originatorName = entityService.fetchEntityName(tenantId, alarm.getOriginator()); + originatorLabel = entityService.fetchEntityLabel(tenantId, alarm.getOriginator()); if (alarm.getAssigneeId() != null) { User assignedUser = userService.findUserById(tenantId, alarm.getAssigneeId()); - builder.firstName(assignedUser.getFirstName()); - builder.lastName(assignedUser.getLastName()); - builder.email(assignedUser.getEmail()); + assigneeFirstName = assignedUser.getFirstName(); + assigneeLastName = assignedUser.getLastName(); + assigneeEmail = assignedUser.getEmail(); } - return builder.build(); - } - - private void addAlarmOriginatorNameAndLabel(TenantId tenantId, EntityId originatorId, AlarmAdditionalInfo.AlarmAdditionalInfoBuilder builder) { - String originatorName = "Unknown"; - String originatorLabel = "Unknown"; - switch(originatorId.getEntityType()) { - case TENANT: - Tenant tenantOriginator = tenantService.findTenantById((TenantId) originatorId); - originatorName = tenantOriginator.getTitle(); - originatorLabel = tenantOriginator.getEmail(); - break; - case CUSTOMER: - Customer customerOriginator = customerService.findCustomerById(tenantId, (CustomerId) originatorId); - originatorName = customerOriginator.getTitle(); - originatorLabel = customerOriginator.getEmail(); - break; - case USER: - User userOriginator = userService.findUserById(tenantId, (UserId) originatorId); - originatorName = userOriginator.getEmail(); - originatorLabel = userOriginator.getName(); - break; - case DASHBOARD: - Dashboard dashboardOriginator = dashboardService.findDashboardById(tenantId, (DashboardId) originatorId); - originatorName = dashboardOriginator.getTitle(); - originatorLabel = dashboardOriginator.getName(); - break; - case ASSET: - Asset assetOriginator = assetService.findAssetById(tenantId, (AssetId) originatorId); - originatorName = assetOriginator.getName(); - originatorLabel = assetOriginator.getLabel(); - break; - case DEVICE: - Device deviceOriginator = deviceService.findDeviceById(tenantId, (DeviceId) originatorId); - originatorName = deviceOriginator.getName(); - originatorLabel = deviceOriginator.getLabel(); - break; - case ENTITY_VIEW: - EntityView entityViewOriginator = entityViewService.findEntityViewById(tenantId, (EntityViewId) originatorId); - originatorName = entityViewOriginator.getName(); - originatorLabel = entityViewOriginator.getType(); // TODO Should we use something else? - break; - } - - builder.originatorName(originatorName); - builder.originatorLabel(originatorLabel); + return new AlarmInfo(alarm, originatorName, originatorLabel, assigneeFirstName, assigneeLastName, assigneeEmail); } } 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 49cea353fb..0f74f13fd9 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 @@ -24,7 +24,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.thingsboard.server.common.data.HasCustomerId; +import org.thingsboard.server.common.data.HasEmail; +import org.thingsboard.server.common.data.HasLabel; import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.HasTitle; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; @@ -33,6 +36,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TbResourceId; @@ -58,6 +62,8 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; +import java.util.Optional; + import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -175,6 +181,26 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return entityName; } + @Override + public Optional fetchEntityLabel(TenantId tenantId, EntityId entityId) { + return Optional.empty(); + HasId entity = fetchEntity(tenantId, entityId); + String entityLabel = null; + if (entity instanceof HasTitle) { + entityLabel = ((HasTitle) entity).getTitle(); + } + if (entity instanceof HasLabel && entityLabel == null) { + entityLabel = ((HasLabel) entity).getLabel(); + } + if (entity instanceof HasEmail && entityLabel == null) { + entityLabel = ((HasEmail) entity).getEmail(); + } + if (entity instanceof HasName && entityLabel == null) { + entityLabel = ((HasName) entity).getName(); + } + return Optional.ofNullable(entityLabel); + } + @Override public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchEntityCustomerId [{}]", entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index d3b8137f8b..0e0bf23f45 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -69,7 +69,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { alarmFieldColumnMap.put("originatorId", ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); alarmFieldColumnMap.put("originatorType", ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY); alarmFieldColumnMap.put("assigneeId", ModelConstants.ALARM_ASSIGNEE_ID_PROPERTY); - alarmFieldColumnMap.put("originator", "originator_name"); + alarmFieldColumnMap.put("originator", ModelConstants.ALARM_ORIGINATOR_NAME_PROPERTY); alarmFieldColumnMap.put("originatorLabel", ModelConstants.ALARM_ORIGINATOR_LABEL_PROPERTY); alarmFieldColumnMap.put("assigneeFirstName", ModelConstants.ALARM_ASSIGNEE_FIRST_NAME_PROPERTY); alarmFieldColumnMap.put("assigneeLastName", ModelConstants.ALARM_ASSIGNEE_LAST_NAME_PROPERTY); @@ -91,7 +91,36 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " THEN (select name from device where id = a.originator_id)" + " WHEN a.originator_type = " + EntityType.ENTITY_VIEW.ordinal() + " THEN (select name from entity_view where id = a.originator_id)" + - " END, 'Deleted') as originator_name"; + " WHEN a.originator_type = " + EntityType.DEVICE_PROFILE.ordinal() + + " THEN (select name from device_profile where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.ASSET_PROFILE.ordinal() + + " THEN (select name from asset_profile where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.EDGE.ordinal() + + " THEN (select name from edge where id = a.originator_id)" + + " END, 'Deleted') as " + ModelConstants.ALARM_ORIGINATOR_NAME_PROPERTY; + + private static final String SELECT_ORIGINATOR_LABEL = " COALESCE(CASE" + + " WHEN a.originator_type = " + EntityType.TENANT.ordinal() + + " THEN (select title from tenant where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.CUSTOMER.ordinal() + + " THEN (select COALESCE(title, email) from customer where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.USER.ordinal() + + " THEN (select email from tb_user where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.DASHBOARD.ordinal() + + " THEN (select title from dashboard where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.ASSET.ordinal() + + " THEN (select COALESCE(label, name) from asset where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.DEVICE.ordinal() + + " THEN (select COALESCE(label, name) from device where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.ENTITY_VIEW.ordinal() + + " THEN (select name from entity_view where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.DEVICE_PROFILE.ordinal() + + " THEN (select name from device_profile where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.ASSET_PROFILE.ordinal() + + " THEN (select name from asset_profile where id = a.originator_id)" + + " WHEN a.originator_type = " + EntityType.EDGE.ordinal() + + " THEN (select COALESCE(label, name) from edge where id = a.originator_id)" + + " END, 'Deleted') as " + ModelConstants.ALARM_ORIGINATOR_LABEL_PROPERTY; private static final String SELECT_ASSIGNEE_INFO = " tbu.first_name as assignee_first_name," + " tbu.last_name as assignee_last_name," + @@ -115,7 +144,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.tenant_id as tenant_id, " + " a.customer_id as customer_id, " + " a.propagate_relation_types as propagate_relation_types, " + - " a.type as type," + SELECT_ORIGINATOR_NAME + ", " + + " a.type as type," + + SELECT_ORIGINATOR_NAME + ", " + + SELECT_ORIGINATOR_LABEL + ", " + SELECT_ASSIGNEE_INFO + ", "; private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id"; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index ba22a57110..0d0503275d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -89,7 +89,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarm(); + Alarm created = result.getAlarmInfo(); Assert.assertNotNull(created); Assert.assertNotNull(created.getId()); @@ -128,7 +128,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarm(); + Alarm created = result.getAlarmInfo(); // Check child relation PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -153,7 +153,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { created.setPropagate(true); result = alarmService.createOrUpdateAlarm(created); - created = result.getAlarm(); + created = result.getAlarmInfo(); // Check child relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -242,7 +242,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarm(); + tenantAlarm = result.getAlarmInfo(); Alarm deviceAlarm = Alarm.builder().tenantId(tenantId) .originator(customerDevice.getId()) @@ -251,7 +251,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(deviceAlarm); - deviceAlarm = result.getAlarm(); + deviceAlarm = result.getAlarmInfo(); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -318,7 +318,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarm(); + tenantAlarm = result.getAlarmInfo(); Alarm customerAlarm = Alarm.builder().tenantId(tenantId) .originator(tenantDevice.getId()) @@ -327,7 +327,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(customerAlarm); - customerAlarm = result.getAlarm(); + customerAlarm = result.getAlarmInfo(); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -368,7 +368,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarm(); + tenantAlarm = result.getAlarmInfo(); Alarm customerAlarm = Alarm.builder().tenantId(tenantId) .originator(device.getId()) @@ -378,7 +378,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(customerAlarm); - customerAlarm = result.getAlarm(); + customerAlarm = result.getAlarmInfo(); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -435,7 +435,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .status(AlarmStatus.ACTIVE_UNACK) .startTs(System.currentTimeMillis()) .build(); - alarm1 = alarmService.createOrUpdateAlarm(alarm1).getAlarm(); + alarm1 = alarmService.createOrUpdateAlarm(alarm1).getAlarmInfo(); alarmService.clearAlarm(tenantId, alarm1.getId(), null, System.currentTimeMillis()).get(); Alarm alarm2 = Alarm.builder() @@ -446,7 +446,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .status(AlarmStatus.ACTIVE_ACK) .startTs(System.currentTimeMillis()) .build(); - alarm2 = alarmService.createOrUpdateAlarm(alarm2).getAlarm(); + alarm2 = alarmService.createOrUpdateAlarm(alarm2).getAlarmInfo(); alarmService.clearAlarm(tenantId, alarm2.getId(), null, System.currentTimeMillis()).get(); Alarm alarm3 = Alarm.builder() @@ -457,7 +457,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .status(AlarmStatus.ACTIVE_ACK) .startTs(System.currentTimeMillis()) .build(); - alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarm(); + alarm3 = alarmService.createOrUpdateAlarm(alarm3).getAlarmInfo(); Assert.assertEquals(AlarmSeverity.MAJOR, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), AlarmSearchStatus.UNACK, null, null)); Assert.assertEquals(AlarmSeverity.CRITICAL, alarmService.findHighestAlarmSeverity(tenantId, customerDevice.getId(), null, null, null)); @@ -487,7 +487,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarm(); + Alarm created = result.getAlarmInfo(); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -530,7 +530,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { // Check child relation created.setPropagate(true); result = alarmService.createOrUpdateAlarm(created); - created = result.getAlarm(); + created = result.getAlarmInfo(); // Check child relation pageLink.setPage(0); @@ -645,7 +645,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarm(); + Alarm created = result.getAlarmInfo(); PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() .affectedEntityId(childId) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 1f90b4e6c1..bbda497b46 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -132,7 +132,7 @@ class AlarmState { ); DonAsynchron.withCallback(alarmClearOperationResult, result -> { - pushMsg(ctx, msg, new TbAlarmResult(false, false, true, result.getAlarm()), clearState); + pushMsg(ctx, msg, new TbAlarmResult(false, false, true, result.getAlarmInfo()), clearState); }, throwable -> { throw new RuntimeException(throwable); From 022aee36d0015b88a492637ed9b66e16b3008df2 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Thu, 29 Dec 2022 20:49:58 +0200 Subject: [PATCH 07/27] Merge with develop/3.5 --- .../install/update/DefaultDataUpdateService.java | 2 +- .../thingsboard/server/dao/entity/EntityService.java | 2 +- .../server/dao/alarm/BaseAlarmService.java | 6 +++--- .../server/dao/entity/BaseEntityService.java | 12 ++++-------- .../server/dao/model/sql/AbstractAlarmEntity.java | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) 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 fae6eed91a..a831a0af5e 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 @@ -561,7 +561,7 @@ public class DefaultDataUpdateService implements DataUpdateService { while (hasNext) { for (Alarm alarm : alarms.getData()) { if (alarm.getCustomerId() == null && alarm.getOriginator() != null) { - alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()).get()); + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); alarmDao.save(tenantId, alarm); } if (processed.incrementAndGet() % 1000 == 0) { 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 59b9d8101f..0ad828acee 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 @@ -31,7 +31,7 @@ public interface EntityService { Optional fetchEntityLabel(TenantId tenantId, EntityId entityId); - Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); 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 a2ddf79367..3412e79085 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 @@ -122,7 +122,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getEndTs() == 0L) { alarm.setEndTs(alarm.getStartTs()); } - alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator()).get()); + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator())); if (alarm.getId() == null) { Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()); if (existing == null || existing.getStatus().isCleared()) { @@ -172,7 +172,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ log.debug("New Alarm : {}", alarm); Alarm saved = alarmDao.save(alarm.getTenantId(), alarm); List propagatedEntitiesList = createEntityAlarmRecords(saved); - AlarmInfo alarmInfo = getAlarmInfo(alarm.getTenantId(), alarm); + AlarmInfo alarmInfo = getAlarmInfo(alarm.getTenantId(), saved); return new AlarmOperationResult(alarmInfo, true, true, propagatedEntitiesList); } @@ -463,7 +463,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ String assigneeLastName = null; String assigneeEmail = null; - originatorName = entityService.fetchEntityName(tenantId, alarm.getOriginator()).orElse("Deleted"); + originatorName = entityService.fetchEntityName(tenantId, alarm.getOriginator()).orElse(null); originatorLabel = entityService.fetchEntityLabel(tenantId, alarm.getOriginator()).orElse(null); if (alarm.getAssigneeId() != null) { 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 b0c90315b4..34175edb5a 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 @@ -96,7 +96,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe public Optional fetchEntityLabel(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchEntityLabel [{}]", entityId); EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); - Optional> entityOpt = entityDaoService.fetchEntity(tenantId, entityId); + Optional> entityOpt = entityDaoService.findEntity(tenantId, entityId); String entityLabel = null; if (entityOpt.isPresent()) { HasId entity = entityOpt.get(); @@ -117,7 +117,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe } @Override - public Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { + public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchEntityCustomerId [{}]", entityId); EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); Optional> hasIdOpt = entityDaoService.findEntity(tenantId, entityId); @@ -125,14 +125,10 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe HasId hasId = hasIdOpt.get(); if (hasId instanceof HasCustomerId) { HasCustomerId hasCustomerId = (HasCustomerId) hasId; - CustomerId customerId = hasCustomerId.getCustomerId(); - if (customerId == null) { - customerId = NULL_CUSTOMER_ID; - } - return Optional.of(customerId); + return hasCustomerId.getCustomerId(); } } - return Optional.of(NULL_CUSTOMER_ID); + return null; } private static void validateEntityCountQuery(EntityCountQuery query) { 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 c01b145174..64006d0630 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 @@ -163,7 +163,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); } else { - this.propagateRelationTypes = null; + this.propagateRelationTypes = ""; } } From a812a88db1fd5a6e42c81e6be3a5ad0cbe5e5eb1 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Fri, 30 Dec 2022 12:51:45 +0200 Subject: [PATCH 08/27] Refactoring to keep EntityService --- .../install/update/DefaultDataUpdateService.java | 2 +- .../thingsboard/server/dao/entity/EntityService.java | 2 +- .../thingsboard/server/dao/alarm/BaseAlarmService.java | 2 +- .../server/dao/entity/BaseEntityService.java | 10 +++++++--- 4 files changed, 10 insertions(+), 6 deletions(-) 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 a831a0af5e..fae6eed91a 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 @@ -561,7 +561,7 @@ public class DefaultDataUpdateService implements DataUpdateService { while (hasNext) { for (Alarm alarm : alarms.getData()) { if (alarm.getCustomerId() == null && alarm.getOriginator() != null) { - alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()).get()); alarmDao.save(tenantId, alarm); } if (processed.incrementAndGet() % 1000 == 0) { 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 0ad828acee..59b9d8101f 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 @@ -31,7 +31,7 @@ public interface EntityService { Optional fetchEntityLabel(TenantId tenantId, EntityId entityId); - CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); 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 3412e79085..819c2b79b5 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 @@ -122,7 +122,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getEndTs() == 0L) { alarm.setEndTs(alarm.getStartTs()); } - alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator())); + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator()).orElse(null)); if (alarm.getId() == null) { Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()); if (existing == null || existing.getStatus().isCleared()) { 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 34175edb5a..de3810d102 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 @@ -117,7 +117,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe } @Override - public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { + public Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchEntityCustomerId [{}]", entityId); EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); Optional> hasIdOpt = entityDaoService.findEntity(tenantId, entityId); @@ -125,10 +125,14 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe HasId hasId = hasIdOpt.get(); if (hasId instanceof HasCustomerId) { HasCustomerId hasCustomerId = (HasCustomerId) hasId; - return hasCustomerId.getCustomerId(); + CustomerId customerId = hasCustomerId.getCustomerId(); + if (customerId == null) { + customerId = NULL_CUSTOMER_ID; + } + return Optional.of(customerId); } } - return null; + return Optional.of(NULL_CUSTOMER_ID); } private static void validateEntityCountQuery(EntityCountQuery query) { From 5df42a591a629753bec6528d03f52cf22478e14b Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 4 Jan 2023 08:27:42 +0200 Subject: [PATCH 09/27] Updated tests for alarms to compare correctly returned value --- .../server/dao/alarm/BaseAlarmService.java | 2 +- .../query/DefaultAlarmQueryRepository.java | 6 +-- .../dao/service/BaseAlarmServiceTest.java | 50 +++++++++---------- 3 files changed, 29 insertions(+), 29 deletions(-) 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 819c2b79b5..a94cca8a81 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 @@ -463,7 +463,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ String assigneeLastName = null; String assigneeEmail = null; - originatorName = entityService.fetchEntityName(tenantId, alarm.getOriginator()).orElse(null); + originatorName = entityService.fetchEntityName(tenantId, alarm.getOriginator()).orElse("Deleted"); originatorLabel = entityService.fetchEntityLabel(tenantId, alarm.getOriginator()).orElse(null); if (alarm.getAssigneeId() != null) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index 0e0bf23f45..71af76ce5d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -144,13 +144,13 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.tenant_id as tenant_id, " + " a.customer_id as customer_id, " + " a.propagate_relation_types as propagate_relation_types, " + - " a.type as type," + + " a.type as type, " + SELECT_ORIGINATOR_NAME + ", " + SELECT_ORIGINATOR_LABEL + ", " + SELECT_ASSIGNEE_INFO + ", "; - private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id"; - private static final String LEFT_JOIN_TB_USERS = "left join tb_user tbu on a.assignee_id = tbu.id"; + private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id "; + private static final String LEFT_JOIN_TB_USERS = "left join tb_user tbu on a.assignee_id = tbu.id "; protected final NamedParameterJdbcTemplate jdbcTemplate; private final TransactionTemplate transactionTemplate; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index 0d0503275d..695940ece8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -89,7 +89,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarmInfo(); + Alarm created = new Alarm(result.getAlarmInfo()); Assert.assertNotNull(created); Assert.assertNotNull(created.getId()); @@ -128,7 +128,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarmInfo(); + Alarm created = new Alarm(result.getAlarmInfo()); // Check child relation PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -139,7 +139,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); // Check parent relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -153,7 +153,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { created.setPropagate(true); result = alarmService.createOrUpdateAlarm(created); - created = result.getAlarmInfo(); + created = new Alarm(result.getAlarmInfo()); // Check child relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -164,7 +164,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); // Check parent relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -175,7 +175,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); alarmService.ackAlarm(tenantId, created.getId(), System.currentTimeMillis()).get(); created = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get(); @@ -188,7 +188,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); // Check not existing relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -211,7 +211,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); } @Test @@ -242,7 +242,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarmInfo(); + tenantAlarm = new Alarm(result.getAlarmInfo()); Alarm deviceAlarm = Alarm.builder().tenantId(tenantId) .originator(customerDevice.getId()) @@ -251,7 +251,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(deviceAlarm); - deviceAlarm = result.getAlarmInfo(); + deviceAlarm = new Alarm(result.getAlarmInfo()); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -279,7 +279,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(tenantAlarm, alarms.getData().get(0)); + Assert.assertEquals(tenantAlarm, new Alarm(alarms.getData().get(0))); } @Test @@ -318,7 +318,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarmInfo(); + tenantAlarm = new Alarm(result.getAlarmInfo()); Alarm customerAlarm = Alarm.builder().tenantId(tenantId) .originator(tenantDevice.getId()) @@ -327,7 +327,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(customerAlarm); - customerAlarm = result.getAlarmInfo(); + customerAlarm = new Alarm(result.getAlarmInfo()); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -368,7 +368,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(tenantAlarm); - tenantAlarm = result.getAlarmInfo(); + tenantAlarm = new Alarm(result.getAlarmInfo()); Alarm customerAlarm = Alarm.builder().tenantId(tenantId) .originator(device.getId()) @@ -378,7 +378,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(ts).build(); result = alarmService.createOrUpdateAlarm(customerAlarm); - customerAlarm = result.getAlarmInfo(); + customerAlarm = new Alarm(result.getAlarmInfo()); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -487,7 +487,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarmInfo(); + Alarm created = new Alarm(result.getAlarmInfo()); AlarmDataPageLink pageLink = new AlarmDataPageLink(); pageLink.setPage(0); @@ -504,7 +504,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); pageLink.setPage(0); pageLink.setPageSize(10); @@ -530,7 +530,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { // Check child relation created.setPropagate(true); result = alarmService.createOrUpdateAlarm(created); - created = result.getAlarmInfo(); + created = new Alarm(result.getAlarmInfo()); // Check child relation pageLink.setPage(0); @@ -546,7 +546,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); // Check parent relation pageLink.setPage(0); @@ -562,7 +562,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId)); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); PageData alarmsInfoData = alarmService.findAlarms(tenantId, AlarmQuery.builder() .affectedEntityId(childId) @@ -607,7 +607,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(parentId)); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); alarmService.ackAlarm(tenantId, created.getId(), System.currentTimeMillis()).get(); created = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get(); @@ -625,7 +625,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, toQuery(pageLink), Collections.singletonList(childId)); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); } @Test @@ -645,7 +645,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { .startTs(ts).build(); AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); - Alarm created = result.getAlarmInfo(); + Alarm created = new Alarm(result.getAlarmInfo()); PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() .affectedEntityId(childId) @@ -655,7 +655,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); // Check parent relation alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() @@ -666,7 +666,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { ).build()).get(); Assert.assertNotNull(alarms.getData()); Assert.assertEquals(1, alarms.getData().size()); - Assert.assertEquals(created, alarms.getData().get(0)); + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); Assert.assertTrue("Alarm was not deleted when expected", alarmService.deleteAlarm(tenantId, created.getId()).isSuccessful()); From 91b30f3ce7a09503263404bfa0543e871a832c6a Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 4 Jan 2023 11:14:06 +0200 Subject: [PATCH 10/27] Updated upgrade script --- .../main/data/upgrade/{3.4.2 => 3.4.3}/schema_update.sql | 0 .../server/service/install/SqlDatabaseUpgradeService.java | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename application/src/main/data/upgrade/{3.4.2 => 3.4.3}/schema_update.sql (100%) diff --git a/application/src/main/data/upgrade/3.4.2/schema_update.sql b/application/src/main/data/upgrade/3.4.3/schema_update.sql similarity index 100% rename from application/src/main/data/upgrade/3.4.2/schema_update.sql rename to application/src/main/data/upgrade/3.4.3/schema_update.sql diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 349400ecd1..f76178455b 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -677,13 +677,13 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; - case "3.4.2": + case "3.4.3": try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { log.info("Updating schema ..."); - schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.4.2", SCHEMA_UPDATE_SQL); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.4.3", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); log.info("Updating schema settings..."); - conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004003;"); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3004004;"); log.info("Schema updated."); } catch (Exception e) { log.error("Failed updating schema!!!", e); From 5677d61f4fe3651ba6e6fe54858b0fface746844 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 4 Jan 2023 12:50:43 +0200 Subject: [PATCH 11/27] Added returning alarm instead of alarmInfo for controllers and alarmState service --- .../service/telemetry/DefaultAlarmSubscriptionService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9ab3858730..d6aa9cba26 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 @@ -95,7 +95,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService if (result.isCreated()) { apiUsageClient.report(alarm.getTenantId(), null, ApiUsageRecordKey.CREATED_ALARMS_COUNT); } - return result.getAlarmInfo(); + return new Alarm(result.getAlarmInfo()); } @Override From 5700fe630d7c89d3d1c900af7ce4b7180c88306c Mon Sep 17 00:00:00 2001 From: zbeacon Date: Thu, 5 Jan 2023 11:35:46 +0200 Subject: [PATCH 12/27] Updated security check and tests --- .../server/controller/AlarmController.java | 15 ++++--- .../server/controller/AbstractWebTest.java | 4 +- .../controller/BaseAlarmControllerTest.java | 45 +++++++++++++++++++ 3 files changed, 57 insertions(+), 7 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 fd91abed3a..26e61a495a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -47,6 +48,7 @@ import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.security.model.SecurityUser; +import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; @@ -204,12 +206,13 @@ public class AlarmController extends BaseController { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); - if (!getCurrentUser().getId().equals(assigneeId)) { - try { - checkEntityId(alarm.getOriginator(), Operation.WRITE, new SecurityUser(assigneeId)); - } catch (Exception e) { - throw new ThingsboardException("Assignee user doesn't have permission for alarm originator", ThingsboardErrorCode.PERMISSION_DENIED); - } + User assigneeUser = userService.findUserById(getTenantId(), assigneeId); + + SecurityUser assigneeSecurityUser = new SecurityUser(assigneeUser, false, null); + try { + checkEntityId(alarm.getOriginator(), Operation.WRITE, assigneeSecurityUser); + } catch (Exception e) { + throw new ThingsboardException("Assignee user doesn't have permission for alarm originator", ThingsboardErrorCode.PERMISSION_DENIED); } tbAlarmService.assign(alarm, getCurrentUser(), assigneeId).get(); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index 9ea269918e..e94a0646d9 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -154,6 +154,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected TenantId differentTenantId; protected CustomerId differentCustomerId; protected UserId customerUserId; + protected UserId differentCustomerUserId; @SuppressWarnings("rawtypes") private HttpMessageConverter mappingJackson2HttpMessageConverter; @@ -324,7 +325,8 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { differentCustomerUser.setCustomerId(savedDifferentCustomer.getId()); differentCustomerUser.setEmail(DIFFERENT_CUSTOMER_USER_EMAIL); - createUserAndLogin(differentCustomerUser, DIFFERENT_CUSTOMER_USER_PASSWORD); + differentCustomerUser = createUserAndLogin(differentCustomerUser, DIFFERENT_CUSTOMER_USER_PASSWORD); + differentCustomerUserId = differentCustomerUser.getId(); } } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java index 05b6f15c61..cc793d8984 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.ResultActions; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; @@ -364,6 +365,18 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest { tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGN); } + @Test + public void testAssignAlarmViaDifferentTenant() throws Exception { + loginTenantAdmin(); + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + + loginDifferentTenant(); + + Mockito.reset(tbClusterService, auditLogService); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + tenantAdminUserId.getId()).andExpect(status().isForbidden()); + } + @Test public void testReassignAlarm() throws Exception { loginTenantAdmin(); @@ -426,6 +439,38 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest { tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGN); } + @Test + public void testUnassignTenantAlarmViaCustomer() throws Exception { + loginTenantAdmin(); + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + tenantAdminUserId.getId()).andExpect(status().isOk()); + Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(tenantAdminUserId, foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGN); + + logout(); + loginCustomerUser(); + + Mockito.reset(tbClusterService, auditLogService); + beforeAssignmentTs = System.currentTimeMillis(); + + doDelete("/api/alarm/" + alarm.getId() + "/assign").andExpect(status().isOk()); + foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_UNASSIGN); + } + @Test public void testFindAlarmsViaCustomerUser() throws Exception { loginCustomerUser(); From a657f9fcea5174161b13fdc4d37c44e4203bfb50 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Fri, 6 Jan 2023 12:24:34 +0200 Subject: [PATCH 13/27] Added getting assinment info to findAlarms methods --- .../server/dao/alarm/BaseAlarmService.java | 5 +- .../server/dao/model/sql/AlarmInfoEntity.java | 6 +- .../server/dao/sql/alarm/AlarmRepository.java | 12 +++- .../dao/service/BaseAlarmServiceTest.java | 58 +++++++++++++++++-- 4 files changed, 71 insertions(+), 10 deletions(-) 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 a94cca8a81..b0f904e71b 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 @@ -27,8 +27,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -360,6 +360,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ for (AlarmInfo alarmInfo : alarms.getData()) { alarmInfo.setOriginatorName( entityService.fetchEntityName(tenantId, alarmInfo.getOriginator()).orElse("Deleted")); + alarmInfo.setOriginatorLabel( + entityService.fetchEntityLabel(tenantId, alarmInfo.getOriginator()).orElse(null)); alarmFutures.add(Futures.immediateFuture(alarmInfo)); } return Futures.transform(Futures.successfulAsList(alarmFutures), @@ -435,7 +437,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) { - // TODO Add ability to automatically assign created alarm to some user EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), null, alarm.getId()); try { alarmDao.createEntityAlarmRecord(entityAlarm); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java index aada0c7c17..2e28c1407a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmInfoEntity.java @@ -34,8 +34,12 @@ public class AlarmInfoEntity extends AbstractAlarmEntity { super(); } - public AlarmInfoEntity(AlarmEntity alarmEntity) { + public AlarmInfoEntity(AlarmEntity alarmEntity, String assigneeFirstName, + String assigneeLastName, String assigneeEmail) { super(alarmEntity); + this.assigneeFirstName = assigneeFirstName; + this.assigneeLastName = assigneeLastName; + this.assigneeEmail = assigneeEmail; } @Override 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 24bfe88656..4fc8237661 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 @@ -39,8 +39,10 @@ public interface AlarmRepository extends JpaRepository { @Param("alarmType") String alarmType, Pageable pageable); - @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + + "FROM AlarmEntity a " + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + + "LEFT JOIN UserEntity tbu ON ea.assigneeId = tbu.id " + "WHERE a.tenantId = :tenantId " + "AND ea.tenantId = :tenantId " + "AND ea.entityId = :affectedEntityId " + @@ -78,7 +80,9 @@ public interface AlarmRepository extends JpaRepository { @Param("searchText") String searchText, Pageable pageable); - @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + + "FROM AlarmEntity a " + + "LEFT JOIN UserEntity tbu ON a.assigneeId = tbu.id " + "WHERE a.tenantId = :tenantId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + @@ -106,7 +110,9 @@ public interface AlarmRepository extends JpaRepository { @Param("searchText") String searchText, Pageable pageable); - @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + + "FROM AlarmEntity a " + + "LEFT JOIN UserEntity tbu ON a.assigneeId = tbu.id " + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index 695940ece8..cff9b81721 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -20,9 +20,11 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -31,7 +33,6 @@ import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.SortOrder; @@ -45,8 +46,8 @@ import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.alarm.AlarmOperationResult; -import org.thingsboard.common.util.JacksonUtil; import java.util.Arrays; import java.util.Collections; @@ -56,6 +57,11 @@ import java.util.concurrent.ExecutionException; public abstract class BaseAlarmServiceTest extends AbstractServiceTest { public static final String TEST_ALARM = "TEST_ALARM"; + + private static final String TEST_TENANT_EMAIL = "testtenant@thingsboard.org"; + private static final String TEST_TENANT_FIRST_NAME = "testtenantfirstname"; + private static final String TEST_TENANT_LAST_NAME = "testtenantlastname"; + private TenantId tenantId; @Before @@ -214,6 +220,50 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); } + @Test + public void testFindAssignedAlarm() throws ExecutionException, InterruptedException { + + AssetId parentId = new AssetId(Uuids.timeBased()); + AssetId childId = new AssetId(Uuids.timeBased()); + + EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); + + Assert.assertTrue(relationService.saveRelationAsync(tenantId, relation).get()); + + long ts = System.currentTimeMillis(); + Alarm alarm = Alarm.builder().tenantId(tenantId).originator(childId) + .type(TEST_ALARM) + .propagate(false) + .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) + .startTs(ts).build(); + + AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm); + Alarm created = new Alarm(result.getAlarmInfo()); + + User tenantUser = new User(); + tenantUser.setTenantId(tenantId); + tenantUser.setAuthority(Authority.TENANT_ADMIN); + tenantUser.setEmail(TEST_TENANT_EMAIL); + tenantUser.setFirstName(TEST_TENANT_FIRST_NAME); + tenantUser.setLastName(TEST_TENANT_LAST_NAME); + tenantUser = userService.saveUser(tenantUser); + + Assert.assertNotNull(tenantUser); + + AlarmOperationResult assignmentResult = alarmService.assignAlarm(tenantId, created.getId(), tenantUser.getId(), ts).get(); + created = assignmentResult.getAlarmInfo(); + + PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() + .assigneeId(tenantUser.getId()) + .fetchOriginator(true) + .pageLink(new TimePageLink(1, 0, "", + new SortOrder("createdTime", SortOrder.Direction.DESC), 0L, System.currentTimeMillis()) + ).build()).get(); + Assert.assertNotNull(alarms.getData()); + Assert.assertEquals(1, alarms.getData().size()); + Assert.assertEquals(created, alarms.getData().get(0)); + } + @Test public void testFindCustomerAlarm() throws ExecutionException, InterruptedException { Customer customer = new Customer(); @@ -402,11 +452,11 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertEquals(customerAlarm, customerAlarms.getData().get(0)); } - private AlarmDataQuery toQuery(AlarmDataPageLink pageLink){ + private AlarmDataQuery toQuery(AlarmDataPageLink pageLink) { return toQuery(pageLink, Collections.emptyList()); } - private AlarmDataQuery toQuery(AlarmDataPageLink pageLink, List alarmFields){ + private AlarmDataQuery toQuery(AlarmDataPageLink pageLink, List alarmFields) { return new AlarmDataQuery(new DeviceTypeFilter(), pageLink, null, null, null, alarmFields); } From c99316976a2d376e1aa056fc1c4eb323a4b1cacd Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 11 Jan 2023 13:20:20 +0200 Subject: [PATCH 14/27] Updated queries due to particle review --- .../main/data/upgrade/3.4.3/schema_update.sql | 2 -- .../server/dao/sql/alarm/AlarmRepository.java | 19 ++++++++++--------- .../server/dao/sql/alarm/JpaAlarmDao.java | 2 ++ .../resources/sql/schema-entities-idx.sql | 2 -- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/application/src/main/data/upgrade/3.4.3/schema_update.sql b/application/src/main/data/upgrade/3.4.3/schema_update.sql index de7cd5b8b1..ca57a80487 100644 --- a/application/src/main/data/upgrade/3.4.3/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.3/schema_update.sql @@ -22,6 +22,4 @@ ALTER TABLE alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; ALTER TABLE entity_alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; -CREATE INDEX IF NOT EXISTS idx_entity_alarm_assignee_id ON entity_alarm(assignee_id); - -- ALARM ASSIGN TO USER END \ No newline at end of file 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 4fc8237661..5a4d93d7ae 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 @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.sql.alarm; +import org.hibernate.type.UUIDCharType; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -42,7 +43,7 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + "FROM AlarmEntity a " + "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " + - "LEFT JOIN UserEntity tbu ON ea.assigneeId = tbu.id " + + "LEFT JOIN UserEntity tbu ON tbu.id = a.assigneeId " + "WHERE a.tenantId = :tenantId " + "AND ea.tenantId = :tenantId " + "AND ea.entityId = :affectedEntityId " + @@ -50,7 +51,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -66,7 +67,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -82,12 +83,12 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + "FROM AlarmEntity a " + - "LEFT JOIN UserEntity tbu ON a.assigneeId = tbu.id " + + "LEFT JOIN UserEntity tbu ON tbu.id = a.assigneeId " + "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ", @@ -98,7 +99,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -112,12 +113,12 @@ public interface AlarmRepository extends JpaRepository { @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a, tbu.firstName, tbu.lastName, tbu.email) " + "FROM AlarmEntity a " + - "LEFT JOIN UserEntity tbu ON a.assigneeId = tbu.id " + + "LEFT JOIN UserEntity tbu ON tbu.id = a.assigneeId " + "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)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -129,7 +130,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))" + + "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") 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 b862f1c7e7..954258a388 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 @@ -17,6 +17,8 @@ package org.thingsboard.server.dao.sql.alarm; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.hibernate.dialect.Dialect; +import org.hibernate.type.UUIDCharType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index d07650e657..e4c766e81d 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -28,8 +28,6 @@ CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_ CREATE INDEX IF NOT EXISTS idx_entity_alarm_alarm_id ON entity_alarm(alarm_id); -CREATE INDEX IF NOT EXISTS idx_entity_alarm_assignee_id ON entity_alarm(assignee_id); - CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id); CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id); From 37bc889f11fd89325d29d1bcb31de87f181316ab Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 11 Jan 2023 14:51:57 +0200 Subject: [PATCH 15/27] Updated queries --- .../server/dao/sql/alarm/AlarmRepository.java | 21 +++++++++---------- .../server/dao/sql/alarm/JpaAlarmDao.java | 8 +++---- 2 files changed, 14 insertions(+), 15 deletions(-) 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 5a4d93d7ae..7320451cd5 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 @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.sql.alarm; -import org.hibernate.type.UUIDCharType; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -51,7 +50,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -67,7 +66,7 @@ public interface AlarmRepository extends JpaRepository { "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -77,7 +76,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, - @Param("assigneeId") UUID assigneeId, + @Param("assigneeId") String assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -88,7 +87,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ", @@ -99,7 +98,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -107,7 +106,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, - @Param("assigneeId") UUID assigneeId, + @Param("assigneeId") String assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -118,7 +117,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " @@ -130,7 +129,7 @@ public interface AlarmRepository extends JpaRepository { "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 (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId)) " + + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId)) " + "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " + " OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) ") @@ -139,7 +138,7 @@ public interface AlarmRepository extends JpaRepository { @Param("startTime") Long startTime, @Param("endTime") Long endTime, @Param("alarmStatuses") Set alarmStatuses, - @Param("assigneeId") UUID assigneeId, + @Param("assigneeId") String assigneeId, @Param("searchText") String searchText, Pageable pageable); @@ -150,7 +149,7 @@ public interface AlarmRepository extends JpaRepository { "AND ea.entityId = :affectedEntityId " + "AND ea.entityType = :affectedEntityType " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + - "AND (cast(:assigneeId as org.hibernate.type.UUIDCharType) IS NULL OR a.assigneeId = (:assigneeId))") + "AND (:assigneeId IS NULL OR a.assigneeId = uuid(:assigneeId))") Set findAlarmSeverities(@Param("tenantId") UUID tenantId, @Param("affectedEntityId") UUID affectedEntityId, @Param("affectedEntityType") String affectedEntityType, 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 954258a388..fae28ac916 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 @@ -115,9 +115,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } else if (query.getStatus() != null) { statusSet = Collections.singleton(query.getStatus()); } - UUID assigneeId = null; + String assigneeId = null; if (query.getAssigneeId() != null) { - assigneeId = query.getAssigneeId().getId(); + assigneeId = query.getAssigneeId().toString(); } if (affectedEntity != null) { return DaoUtil.toPageData( @@ -157,9 +157,9 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } else if (query.getStatus() != null) { statusSet = Collections.singleton(query.getStatus()); } - UUID assigneeId = null; + String assigneeId = null; if (query.getAssigneeId() != null) { - assigneeId = query.getAssigneeId().getId(); + assigneeId = query.getAssigneeId().toString(); } return DaoUtil.toPageData( alarmRepository.findCustomerAlarms( From f9e1077bca23d40233932da29d385b5182483755 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Thu, 12 Jan 2023 10:03:04 +0200 Subject: [PATCH 16/27] Updated findSeverity method --- .../org/thingsboard/server/controller/AlarmController.java | 6 +----- .../service/telemetry/DefaultAlarmSubscriptionService.java | 4 ++-- .../java/org/thingsboard/server/dao/alarm/AlarmService.java | 2 +- .../java/org/thingsboard/server/dao/alarm/AlarmDao.java | 2 +- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 4 ++-- .../thingsboard/server/dao/sql/alarm/AlarmRepository.java | 2 +- .../org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java | 6 +----- .../thingsboard/rule/engine/api/RuleEngineAlarmService.java | 2 +- 8 files changed, 10 insertions(+), 18 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 26e61a495a..03a7f20c8c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -374,13 +374,9 @@ public class AlarmController extends BaseController { throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } - UserId assigneeUserId = null; - if (assigneeId != null) { - assigneeUserId = new UserId(UUID.fromString(assigneeId)); - } checkEntityId(entityId, Operation.READ); try { - return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus, assigneeUserId); + return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus, assigneeId); } catch (Exception e) { throw handleException(e); } 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 d6aa9cba26..dd4b9b6c55 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 @@ -165,8 +165,8 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, UserId assigneeUserId) { - return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus, assigneeUserId); + public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, String assigneeId) { + return alarmService.findHighestAlarmSeverity(tenantId, entityId, alarmSearchStatus, alarmStatus, assigneeId); } @Override 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 a6a61d01c5..848d6dd5b1 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 @@ -65,7 +65,7 @@ public interface AlarmService extends EntityDaoService { ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, - AlarmStatus alarmStatus, UserId assigneeUserId); + AlarmStatus alarmStatus, String assigneeId); ListenableFuture findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); 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 11c3e47599..f4bc66d4e4 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 @@ -59,7 +59,7 @@ public interface AlarmDao extends Dao { PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); - Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status, UserId assigneeUserId); + Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set status, String assigneeId); PageData findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink); 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 b0f904e71b..e1b38a0dd5 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 @@ -371,7 +371,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Override public AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, - AlarmStatus alarmStatus, UserId assigneeUserId) { + AlarmStatus alarmStatus, String assigneeId) { Set statusList = null; if (alarmSearchStatus != null) { statusList = alarmSearchStatus.getStatuses(); @@ -379,7 +379,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ statusList = Collections.singleton(alarmStatus); } - Set alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList, assigneeUserId); + Set alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList, assigneeId); return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null); } 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 7320451cd5..6b28577851 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 @@ -154,7 +154,7 @@ public interface AlarmRepository extends JpaRepository { @Param("affectedEntityId") UUID affectedEntityId, @Param("affectedEntityType") String affectedEntityType, @Param("alarmStatuses") Set alarmStatuses, - @Param("assigneeId") UUID assigneeId); + @Param("assigneeId") String assigneeId); @Query("SELECT a.id FROM AlarmEntity a WHERE a.tenantId = :tenantId AND a.createdTime < :time AND a.endTs < :time") Page findAlarmsIdsByEndTsBeforeAndTenantId(@Param("time") Long time, @Param("tenantId") UUID tenantId, Pageable pageable); 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 fae28ac916..64857269f7 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 @@ -181,11 +181,7 @@ public class JpaAlarmDao extends JpaAbstractDao implements A } @Override - public Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set statuses, UserId assigneeUserId) { - UUID assigneeId = null; - if (assigneeUserId != null) { - assigneeId = assigneeUserId.getId(); - } + public Set findAlarmSeverities(TenantId tenantId, EntityId entityId, Set statuses, String assigneeId) { return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), entityId.getEntityType().name(), statuses, assigneeId); } 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 e41c7ad5d5..3afaf677d8 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 @@ -66,7 +66,7 @@ public interface RuleEngineAlarmService { ListenableFuture> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query); - AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, UserId assigneeId); + AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, AlarmStatus alarmStatus, String assigneeId); PageData findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection orderedEntityIds); } From 1af6648ce9c26e4437543298dd7210515dba6f96 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 16 Jan 2023 10:01:05 +0200 Subject: [PATCH 17/27] Merge with develop/3.5 --- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 6790c6912b..0ff440d079 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 @@ -229,10 +229,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } else { propagatedEntitiesList = new ArrayList<>(getPropagationEntityIds(result)); } - // TODO oldAlarmSeverity AlarmInfo alarmInfo = getAlarmInfo(newAlarm.getTenantId(), newAlarm); - return new AlarmOperationResult(alarmInfo, true, propagatedEntitiesList); - return new AlarmOperationResult(result, true, false, oldAlarmSeverity, propagatedEntitiesList); + return new AlarmOperationResult(alarmInfo, true, false, oldAlarmSeverity, propagatedEntitiesList); } @Override From 24215f2bce33785e6ae32ba3a4fd8e988aea324e Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 16 Jan 2023 10:15:41 +0200 Subject: [PATCH 18/27] Added constructor for alarmOperationResult --- .../org/thingsboard/server/dao/alarm/AlarmOperationResult.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java index b47aba3d88..28fad9adc5 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmOperationResult.java @@ -51,5 +51,6 @@ public class AlarmOperationResult { this.successful = successful; this.created = created; this.propagatedEntitiesList = propagatedEntitiesList; + this.oldSeverity = null; } } From 8517a01570d3088a436f627bc6fc8b0845c75785 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 16 Jan 2023 11:00:41 +0200 Subject: [PATCH 19/27] Alarm info update --- .../service/telemetry/DefaultAlarmSubscriptionService.java | 4 ++-- .../server/dao/service/BaseAlarmCommentServiceTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 c23f9a1272..9fab55218a 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 @@ -99,11 +99,11 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService if (result.isSuccessful()) { onAlarmUpdated(result); AlarmSeverity oldSeverity = result.getOldSeverity(); - if (oldSeverity != null && !oldSeverity.equals(result.getAlarm().getSeverity())) { + if (oldSeverity != null && !oldSeverity.equals(result.getAlarmInfo().getSeverity())) { AlarmComment alarmComment = AlarmComment.builder() .alarmId(alarm.getId()) .type(AlarmCommentType.SYSTEM) - .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm severity was updated from %s to %s", oldSeverity, result.getAlarm().getSeverity()))) + .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm severity was updated from %s to %s", oldSeverity, result.getAlarmInfo().getSeverity()))) .build(); alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java index 914c360d86..7ade09a2c3 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java @@ -60,7 +60,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { .type(TEST_ALARM) .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) .startTs(System.currentTimeMillis()).build(); - alarm = alarmService.createOrUpdateAlarm(alarm).getAlarm(); + alarm = new Alarm(alarmService.createOrUpdateAlarm(alarm).getAlarmInfo()); user = new User(); user.setAuthority(Authority.TENANT_ADMIN); From 6d8252de15d60c29770bb88cef605cb2d07ba8e6 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Mon, 16 Jan 2023 13:19:55 +0200 Subject: [PATCH 20/27] Removed reduntant case in installation service --- .../thingsboard/server/install/ThingsboardInstallService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 715e59f390..61cdcd1bbf 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -240,10 +240,6 @@ public class ThingsboardInstallService { log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); break; - case "3.4.2": - log.info("Upgrading ThingsBoard from version 3.4.2 to 3.5 ..."); - databaseEntitiesUpgradeService.upgradeDatabase("3.4.2"); - break; //TODO update CacheCleanupService on the next version upgrade From 44dcda3bc5aa9b3a80238b032a55cde5744dff56 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 17 Jan 2023 08:15:00 +0200 Subject: [PATCH 21/27] Changes, accroding to comments --- .../main/data/upgrade/3.4.3/schema_update.sql | 2 -- .../server/controller/AlarmController.java | 8 ++--- .../service/action/EntityActionService.java | 4 +-- .../entitiy/alarm/DefaultTbAlarmService.java | 29 ++++++------------- .../service/entitiy/alarm/TbAlarmService.java | 4 +-- .../queue/DefaultTbCoreConsumerService.java | 4 +-- .../subscription/TbSubscriptionUtils.java | 6 ++-- .../DefaultAlarmSubscriptionService.java | 24 ++++++++++----- common/cluster-api/src/main/proto/queue.proto | 6 ++-- .../server/dao/alarm/AlarmService.java | 4 +-- .../server/dao/alarm/BaseAlarmService.java | 8 ++--- .../dao/model/sql/EntityAlarmEntity.java | 9 ------ .../main/resources/sql/schema-entities.sql | 1 - .../engine/api/RuleEngineAlarmService.java | 4 +-- 14 files changed, 49 insertions(+), 64 deletions(-) diff --git a/application/src/main/data/upgrade/3.4.3/schema_update.sql b/application/src/main/data/upgrade/3.4.3/schema_update.sql index 117f8f5fa3..234f9eeeeb 100644 --- a/application/src/main/data/upgrade/3.4.3/schema_update.sql +++ b/application/src/main/data/upgrade/3.4.3/schema_update.sql @@ -20,8 +20,6 @@ ALTER TABLE alarm ADD COLUMN IF NOT EXISTS assign_ts BIGINT; ALTER TABLE alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; -ALTER TABLE entity_alarm ADD COLUMN IF NOT EXISTS assignee_id UUID; - -- ALARM ASSIGN TO USER END CREATE TABLE IF NOT EXISTS alarm_comment ( 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 03a7f20c8c..cf55311016 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -196,7 +196,7 @@ public class AlarmController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/assign/{assigneeId}", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) - public void assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + public Alarm assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ASSIGN_ID_PARAM_DESCRIPTION) @PathVariable(ASSIGNEE_ID) String strAssigneeId @@ -214,7 +214,7 @@ public class AlarmController extends BaseController { } catch (Exception e) { throw new ThingsboardException("Assignee user doesn't have permission for alarm originator", ThingsboardErrorCode.PERMISSION_DENIED); } - tbAlarmService.assign(alarm, getCurrentUser(), assigneeId).get(); + return tbAlarmService.assign(alarm, getCurrentUser(), assigneeId); } @ApiOperation(value = "Unassign Alarm (unassignAlarm)", @@ -224,13 +224,13 @@ public class AlarmController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/assign", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) - public void assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + public Alarm assignAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId ) throws Exception { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); - tbAlarmService.unassign(alarm, getCurrentUser()).get(); + return tbAlarmService.unassign(alarm, getCurrentUser()); } @ApiOperation(value = "Get Alarms (getAlarms)", diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index fc8b71947c..fab8622d8c 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -87,10 +87,10 @@ public class EntityActionService { msgType = DataConstants.ALARM_CLEAR; break; case ALARM_ASSIGN: - msgType = DataConstants.ALARM_CLEAR; + msgType = DataConstants.ALARM_ASSIGN; break; case ALARM_UNASSIGN: - msgType = DataConstants.ALARM_CLEAR; + msgType = DataConstants.ALARM_UNASSIGN; break; case ALARM_DELETE: msgType = DataConstants.ALARM_DELETE; diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 368253c075..28c4a4aa09 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.dao.alarm.AlarmOperationResult; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; @@ -95,31 +96,19 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public ListenableFuture assign(Alarm alarm, User user, UserId assigneeId) { + public Alarm assign(Alarm alarm, User user, UserId assigneeId) { long assignTs = System.currentTimeMillis(); - ListenableFuture future = alarmSubscriptionService.assignAlarm(alarm.getTenantId(), alarm.getId(), assigneeId, assignTs); - return Futures.transform(future, result -> { - if (result != null && result) { - alarm.setAssignTs(assignTs); - alarm.setAssigneeId(assigneeId); - notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ASSIGN, user); - } - return null; - }, MoreExecutors.directExecutor()); + Alarm assignedAlarm = alarmSubscriptionService.assignAlarm(alarm.getTenantId(), alarm.getId(), assigneeId, assignTs); + notificationEntityService.notifyCreateOrUpdateAlarm(assignedAlarm, ActionType.ALARM_ASSIGN, user); + return assignedAlarm; } @Override - public ListenableFuture unassign(Alarm alarm, User user) { + public Alarm unassign(Alarm alarm, User user) { long assignTs = System.currentTimeMillis(); - ListenableFuture future = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), assignTs); - return Futures.transform(future, result -> { - if (result != null && result) { - alarm.setAssignTs(assignTs); - alarm.setAssigneeId(null); - notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_UNASSIGN, user); - } - return null; - }, MoreExecutors.directExecutor()); + Alarm unassignedAlarm = alarmSubscriptionService.unassignAlarm(alarm.getTenantId(), alarm.getId(), assignTs); + notificationEntityService.notifyCreateOrUpdateAlarm(unassignedAlarm, ActionType.ALARM_UNASSIGN, user); + return unassignedAlarm; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 0cf2de5ba9..66b733783c 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -29,9 +29,9 @@ public interface TbAlarmService { ListenableFuture clear(Alarm alarm, User user); - ListenableFuture assign(Alarm alarm, User user, UserId assigneeId); + Alarm assign(Alarm alarm, User user, UserId assigneeId); - ListenableFuture unassign(Alarm alarm, User user); + Alarm unassign(Alarm alarm, User user); Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index c106090508..3fcf3a8b29 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -503,13 +503,13 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService 0) { return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), SubscriptionErrorCode.forCode(proto.getErrorCode()), proto.getErrorMsg()); } else { - AlarmInfo alarmInfo = JacksonUtil.fromString(proto.getAlarmInfo(), AlarmInfo.class); + AlarmInfo alarmInfo = JacksonUtil.fromString(proto.getAlarm(), AlarmInfo.class); return new AlarmSubscriptionUpdate(proto.getSubscriptionId(), alarmInfo); } } @@ -324,7 +324,7 @@ public class TbSubscriptionUtils { builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); - builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); + builder.setAlarm(JacksonUtil.toString(alarmInfo)); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); msgBuilder.setAlarmUpdate(builder); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); @@ -337,7 +337,7 @@ public class TbSubscriptionUtils { builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); - builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); + builder.setAlarm(JacksonUtil.toString(alarmInfo)); SubscriptionMgrMsgProto.Builder msgBuilder = SubscriptionMgrMsgProto.newBuilder(); msgBuilder.setAlarmDelete(builder); return ToCoreMsg.newBuilder().setToSubscriptionMgrMsg(msgBuilder.build()).build(); 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 9fab55218a..2b28c382ed 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 @@ -142,17 +142,25 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) { - ListenableFuture result = alarmService.assignAlarm(tenantId, alarmId, assigneeId, assignTs); - Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor); - return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor); + public Alarm assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) { + AlarmOperationResult result = alarmService.assignAlarm(tenantId, alarmId, assigneeId, assignTs); + if (result.isSuccessful()) { + onAlarmUpdated(result); + } else { + log.warn("Failed to assign alarm!"); + } + return result.getAlarmInfo(); } @Override - public ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) { - ListenableFuture result = alarmService.unassignAlarm(tenantId, alarmId, assignTs); - Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor); - return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor); + public Alarm unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) { + AlarmOperationResult result = alarmService.unassignAlarm(tenantId, alarmId, assignTs); + if (result.isSuccessful()) { + onAlarmUpdated(result); + } else { + log.warn("Failed to unassign alarm!"); + } + return result.getAlarmInfo(); } @Override diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 301c395a18..5a28d42546 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -560,7 +560,7 @@ message TbAlarmSubscriptionUpdateProto { int32 subscriptionId = 2; int32 errorCode = 3; string errorMsg = 4; - string alarmInfo = 5; + string alarm = 5; bool deleted = 6; } @@ -580,7 +580,7 @@ message TbAlarmUpdateProto { int64 entityIdLSB = 3; int64 tenantIdMSB = 4; int64 tenantIdLSB = 5; - string alarmInfo = 6; + string alarm = 6; } message TbAlarmDeleteProto { @@ -589,7 +589,7 @@ message TbAlarmDeleteProto { int64 entityIdLSB = 3; int64 tenantIdMSB = 4; int64 tenantIdLSB = 5; - string alarmInfo = 6; + string alarm = 6; } message TbAttributeDeleteProto { 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 d2bc6fcd47..077a3a8b97 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 @@ -50,9 +50,9 @@ public interface AlarmService extends EntityDaoService { ListenableFuture clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); - ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); + AlarmOperationResult assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); - ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); + AlarmOperationResult unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); Alarm findAlarmById(TenantId tenantId, AlarmId alarmId); 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 0ff440d079..82385f776f 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 @@ -279,8 +279,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } @Override - public ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) { - return getAndUpdateAsync(tenantId, alarmId, new Function() { + public AlarmOperationResult assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) { + return getAndUpdate(tenantId, alarmId, new Function<>() { @Nullable @Override public AlarmOperationResult apply(@Nullable Alarm alarm) { @@ -298,8 +298,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } @Override - public ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTime) { - return getAndUpdateAsync(tenantId, alarmId, new Function() { + public AlarmOperationResult unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTime) { + return getAndUpdate(tenantId, alarmId, new Function<>() { @Nullable @Override public AlarmOperationResult apply(@Nullable Alarm alarm) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java index 434a4662fc..d02f5f0778 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityAlarmEntity.java @@ -68,9 +68,6 @@ public final class EntityAlarmEntity implements ToData { @Column(name = CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") private UUID customerId; - @Column(name = ASSIGNEE_ID_PROPERTY, columnDefinition = "uuid") - private UUID assigneeId; - public EntityAlarmEntity() { super(); } @@ -85,9 +82,6 @@ public final class EntityAlarmEntity implements ToData { if (entityAlarm.getCustomerId() != null) { customerId = entityAlarm.getCustomerId().getId(); } - if (entityAlarm.getAssigneeId() != null) { - assigneeId = entityAlarm.getAssigneeId().getId(); - } } @Override @@ -101,9 +95,6 @@ public final class EntityAlarmEntity implements ToData { if (customerId != null) { result.setCustomerId(new CustomerId(customerId)); } - if (assigneeId != null) { - result.setAssigneeId(new UserId(assigneeId)); - } return result; } diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 2a7e0df528..1e0b50cc29 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -81,7 +81,6 @@ CREATE TABLE IF NOT EXISTS entity_alarm ( alarm_type varchar(255) NOT NULL, customer_id uuid, alarm_id uuid, - assignee_id uuid, CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id), CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ); 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 3afaf677d8..053cc03eed 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 @@ -50,9 +50,9 @@ public interface RuleEngineAlarmService { ListenableFuture clearAlarmForResult(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); - ListenableFuture assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); + Alarm assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); - ListenableFuture unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); + Alarm unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); ListenableFuture findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId); From 334455e6837b656436c49cae094fdec6d7608e39 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 17 Jan 2023 09:03:00 +0200 Subject: [PATCH 22/27] Fix for build after changes --- .../service/subscription/DefaultSubscriptionManagerService.java | 2 +- .../thingsboard/server/dao/service/BaseAlarmServiceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 87c3ec60c3..67ac32ee73 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -569,7 +569,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene builder.setSessionId(subscription.getSessionId()); builder.setSubscriptionId(subscription.getSubscriptionId()); - builder.setAlarmInfo(JacksonUtil.toString(alarmInfo)); + builder.setAlarm(JacksonUtil.toString(alarmInfo)); builder.setDeleted(deleted); ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setToLocalSubscriptionServiceMsg( diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index cff9b81721..c920d66a5d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -250,7 +250,7 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { Assert.assertNotNull(tenantUser); - AlarmOperationResult assignmentResult = alarmService.assignAlarm(tenantId, created.getId(), tenantUser.getId(), ts).get(); + AlarmOperationResult assignmentResult = alarmService.assignAlarm(tenantId, created.getId(), tenantUser.getId(), ts); created = assignmentResult.getAlarmInfo(); PageData alarms = alarmService.findAlarms(tenantId, AlarmQuery.builder() From 6b03a9a24860641d054084c0172b1ef2d091b723 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 17 Jan 2023 11:06:15 +0200 Subject: [PATCH 23/27] Removed redundant check --- .../server/controller/AlarmController.java | 13 +- .../server/controller/BaseController.java | 182 +++++------------- 2 files changed, 56 insertions(+), 139 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 cf55311016..40fa35b8b6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -204,15 +204,12 @@ public class AlarmController extends BaseController { checkParameter(ALARM_ID, strAlarmId); checkParameter(ASSIGNEE_ID, strAssigneeId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); - User assigneeUser = userService.findUserById(getTenantId(), assigneeId); - - SecurityUser assigneeSecurityUser = new SecurityUser(assigneeUser, false, null); - try { - checkEntityId(alarm.getOriginator(), Operation.WRITE, assigneeSecurityUser); - } catch (Exception e) { - throw new ThingsboardException("Assignee user doesn't have permission for alarm originator", ThingsboardErrorCode.PERMISSION_DENIED); + UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); + User user = userService.findUserById(getCurrentUser().getTenantId(), assigneeId); + checkNotNull(user, "User with id [" + strAssigneeId + "] is not found"); + if (!getTenantId().equals(user.getTenantId())) { + throw new ThingsboardException("User with id [" + strAssigneeId + "] is not found", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } return tbAlarmService.assign(alarm, getCurrentUser(), assigneeId); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index faf9fa39be..5c82e7cc40 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -458,15 +458,11 @@ public abstract class BaseController { } Tenant checkTenantId(TenantId tenantId, Operation operation) throws ThingsboardException { - return checkTenantId(tenantId, operation, getCurrentUser()); - } - - Tenant checkTenantId(TenantId tenantId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Tenant tenant = tenantService.findTenantById(tenantId); checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.TENANT, operation, tenantId, tenant); + accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant); return tenant; } catch (Exception e) { throw handleException(e, false); @@ -486,15 +482,11 @@ public abstract class BaseController { } TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation) throws ThingsboardException { - return checkTenantProfileId(tenantProfileId, operation, getCurrentUser()); - } - - TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId); TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId); checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.TENANT_PROFILE, operation); + accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation); return tenantProfile; } catch (Exception e) { throw handleException(e, false); @@ -506,15 +498,11 @@ public abstract class BaseController { } Customer checkCustomerId(CustomerId customerId, Operation operation) throws ThingsboardException { - return checkCustomerId(customerId, operation, getCurrentUser()); - } - - Customer checkCustomerId(CustomerId customerId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(customerId, "Incorrect customerId " + customerId); Customer customer = customerService.findCustomerById(getTenantId(), customerId); checkNotNull(customer, "Customer with id [" + customerId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.CUSTOMER, operation, customerId, customer); + accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customerId, customer); return customer; } catch (Exception e) { throw handleException(e, false); @@ -522,15 +510,11 @@ public abstract class BaseController { } User checkUserId(UserId userId, Operation operation) throws ThingsboardException { - return checkUserId(userId, operation, getCurrentUser()); - } - - User checkUserId(UserId userId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(userId, "Incorrect userId " + userId); - User user = userService.findUserById(securityUser.getTenantId(), userId); + User user = userService.findUserById(getCurrentUser().getTenantId(), userId); checkNotNull(user, "User with id [" + userId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.USER, operation, userId, user); + accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, userId, user); return user; } catch (Exception e) { throw handleException(e, false); @@ -547,10 +531,6 @@ public abstract class BaseController { } protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException { - checkEntityId(entityId, operation, getCurrentUser()); - } - - protected void checkEntityId(EntityId entityId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { if (entityId == null) { throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); @@ -558,61 +538,61 @@ public abstract class BaseController { validateId(entityId.getId(), "Incorrect entityId " + entityId); switch (entityId.getEntityType()) { case ALARM: - checkAlarmId(new AlarmId(entityId.getId()), operation, securityUser); + checkAlarmId(new AlarmId(entityId.getId()), operation); return; case DEVICE: - checkDeviceId(new DeviceId(entityId.getId()), operation, securityUser); + checkDeviceId(new DeviceId(entityId.getId()), operation); return; case DEVICE_PROFILE: - checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation, securityUser); + checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation); return; case CUSTOMER: - checkCustomerId(new CustomerId(entityId.getId()), operation, securityUser); + checkCustomerId(new CustomerId(entityId.getId()), operation); return; case TENANT: - checkTenantId(TenantId.fromUUID(entityId.getId()), operation, securityUser); + checkTenantId(TenantId.fromUUID(entityId.getId()), operation); return; case TENANT_PROFILE: - checkTenantProfileId(new TenantProfileId(entityId.getId()), operation, securityUser); + checkTenantProfileId(new TenantProfileId(entityId.getId()), operation); return; case RULE_CHAIN: - checkRuleChain(new RuleChainId(entityId.getId()), operation, securityUser); + checkRuleChain(new RuleChainId(entityId.getId()), operation); return; case RULE_NODE: - checkRuleNode(new RuleNodeId(entityId.getId()), operation, securityUser); + checkRuleNode(new RuleNodeId(entityId.getId()), operation); return; case ASSET: - checkAssetId(new AssetId(entityId.getId()), operation, securityUser); + checkAssetId(new AssetId(entityId.getId()), operation); return; case ASSET_PROFILE: - checkAssetProfileId(new AssetProfileId(entityId.getId()), operation, securityUser); + checkAssetProfileId(new AssetProfileId(entityId.getId()), operation); return; case DASHBOARD: - checkDashboardId(new DashboardId(entityId.getId()), operation, securityUser); + checkDashboardId(new DashboardId(entityId.getId()), operation); return; case USER: - checkUserId(new UserId(entityId.getId()), operation, securityUser); + checkUserId(new UserId(entityId.getId()), operation); return; case ENTITY_VIEW: - checkEntityViewId(new EntityViewId(entityId.getId()), operation, securityUser); + checkEntityViewId(new EntityViewId(entityId.getId()), operation); return; case EDGE: - checkEdgeId(new EdgeId(entityId.getId()), operation, securityUser); + checkEdgeId(new EdgeId(entityId.getId()), operation); return; case WIDGETS_BUNDLE: - checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation, securityUser); + checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation); return; case WIDGET_TYPE: - checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation, securityUser); + checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation); return; case TB_RESOURCE: - checkResourceId(new TbResourceId(entityId.getId()), operation, securityUser); + checkResourceId(new TbResourceId(entityId.getId()), operation); return; case OTA_PACKAGE: - checkOtaPackageId(new OtaPackageId(entityId.getId()), operation, securityUser); + checkOtaPackageId(new OtaPackageId(entityId.getId()), operation); return; case QUEUE: - checkQueueId(new QueueId(entityId.getId()), operation, securityUser); + checkQueueId(new QueueId(entityId.getId()), operation); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); @@ -622,15 +602,11 @@ public abstract class BaseController { } } Device checkDeviceId(DeviceId deviceId, Operation operation) throws ThingsboardException { - return checkDeviceId(deviceId, operation, getCurrentUser()); - } - - Device checkDeviceId(DeviceId deviceId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(deviceId, "Incorrect deviceId " + deviceId); - Device device = deviceService.findDeviceById(securityUser.getTenantId(), deviceId); + Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId); checkNotNull(device, "Device with id [" + deviceId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.DEVICE, operation, deviceId, device); + accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device); return device; } catch (Exception e) { throw handleException(e, false); @@ -650,15 +626,11 @@ public abstract class BaseController { } DeviceProfile checkDeviceProfileId(DeviceProfileId deviceProfileId, Operation operation) throws ThingsboardException { - return checkDeviceProfileId(deviceProfileId, operation, getCurrentUser()); - } - - DeviceProfile checkDeviceProfileId(DeviceProfileId deviceProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(deviceProfileId, "Incorrect deviceProfileId " + deviceProfileId); - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(securityUser.getTenantId(), deviceProfileId); + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(getCurrentUser().getTenantId(), deviceProfileId); checkNotNull(deviceProfile, "Device profile with id [" + deviceProfileId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile); + accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile); return deviceProfile; } catch (Exception e) { throw handleException(e, false); @@ -666,15 +638,11 @@ public abstract class BaseController { } protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation) throws ThingsboardException { - return checkEntityViewId(entityViewId, operation, getCurrentUser()); - } - - protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); - EntityView entityView = entityViewService.findEntityViewById(securityUser.getTenantId(), entityViewId); + EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId); checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.ENTITY_VIEW, operation, entityViewId, entityView); + accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView); return entityView; } catch (Exception e) { throw handleException(e, false); @@ -694,15 +662,11 @@ public abstract class BaseController { } Asset checkAssetId(AssetId assetId, Operation operation) throws ThingsboardException { - return checkAssetId(assetId, operation, getCurrentUser()); - } - - Asset checkAssetId(AssetId assetId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(assetId, "Incorrect assetId " + assetId); - Asset asset = assetService.findAssetById(securityUser.getTenantId(), assetId); + Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId); checkNotNull(asset, "Asset with id [" + assetId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.ASSET, operation, assetId, asset); + accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset); return asset; } catch (Exception e) { throw handleException(e, false); @@ -722,15 +686,11 @@ public abstract class BaseController { } AssetProfile checkAssetProfileId(AssetProfileId assetProfileId, Operation operation) throws ThingsboardException { - return checkAssetProfileId(assetProfileId, operation, getCurrentUser()); - } - - AssetProfile checkAssetProfileId(AssetProfileId assetProfileId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(assetProfileId, "Incorrect assetProfileId " + assetProfileId); - AssetProfile assetProfile = assetProfileService.findAssetProfileById(securityUser.getTenantId(), assetProfileId); + AssetProfile assetProfile = assetProfileService.findAssetProfileById(getCurrentUser().getTenantId(), assetProfileId); checkNotNull(assetProfile, "Asset profile with id [" + assetProfileId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.ASSET_PROFILE, operation, assetProfileId, assetProfile); + accessControlService.checkPermission(getCurrentUser(), Resource.ASSET_PROFILE, operation, assetProfileId, assetProfile); return assetProfile; } catch (Exception e) { throw handleException(e, false); @@ -738,15 +698,11 @@ public abstract class BaseController { } Alarm checkAlarmId(AlarmId alarmId, Operation operation) throws ThingsboardException { - return checkAlarmId(alarmId, operation, getCurrentUser()); - } - - Alarm checkAlarmId(AlarmId alarmId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(alarmId, "Incorrect alarmId " + alarmId); - Alarm alarm = alarmService.findAlarmByIdAsync(securityUser.getTenantId(), alarmId).get(); + Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get(); checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.ALARM, operation, alarmId, alarm); + accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarm); return alarm; } catch (Exception e) { throw handleException(e, false); @@ -780,15 +736,11 @@ public abstract class BaseController { } WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation) throws ThingsboardException { - return checkWidgetsBundleId(widgetsBundleId, operation, getCurrentUser()); - } - - WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); - WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(securityUser.getTenantId(), widgetsBundleId); + WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId); checkNotNull(widgetsBundle, "Widgets bundle with id [" + widgetsBundleId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle); + accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle); return widgetsBundle; } catch (Exception e) { throw handleException(e, false); @@ -796,15 +748,11 @@ public abstract class BaseController { } WidgetTypeDetails checkWidgetTypeId(WidgetTypeId widgetTypeId, Operation operation) throws ThingsboardException { - return checkWidgetTypeId(widgetTypeId, operation, getCurrentUser()); - } - - WidgetTypeDetails checkWidgetTypeId(WidgetTypeId widgetTypeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); - WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(securityUser.getTenantId(), widgetTypeId); + WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(getCurrentUser().getTenantId(), widgetTypeId); checkNotNull(widgetTypeDetails, "Widget type with id [" + widgetTypeId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails); + accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails); return widgetTypeDetails; } catch (Exception e) { throw handleException(e, false); @@ -812,15 +760,11 @@ public abstract class BaseController { } Dashboard checkDashboardId(DashboardId dashboardId, Operation operation) throws ThingsboardException { - return checkDashboardId(dashboardId, operation, getCurrentUser()); - } - - Dashboard checkDashboardId(DashboardId dashboardId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(dashboardId, "Incorrect dashboardId " + dashboardId); - Dashboard dashboard = dashboardService.findDashboardById(securityUser.getTenantId(), dashboardId); + Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId); checkNotNull(dashboard, "Dashboard with id [" + dashboardId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.DASHBOARD, operation, dashboardId, dashboard); + accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboard); return dashboard; } catch (Exception e) { throw handleException(e, false); @@ -828,15 +772,11 @@ public abstract class BaseController { } Edge checkEdgeId(EdgeId edgeId, Operation operation) throws ThingsboardException { - return checkEdgeId(edgeId, operation, getCurrentUser()); - } - - Edge checkEdgeId(EdgeId edgeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(edgeId, "Incorrect edgeId " + edgeId); Edge edge = edgeService.findEdgeById(getTenantId(), edgeId); checkNotNull(edge, "Edge with id [" + edgeId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.EDGE, operation, edgeId, edge); + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); return edge; } catch (Exception e) { throw handleException(e, false); @@ -895,22 +835,14 @@ public abstract class BaseController { } protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation) throws ThingsboardException { - return checkRuleChain(ruleChainId, operation, getCurrentUser()); - } - - protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(ruleChainId, "Incorrect ruleChainId " + ruleChainId); - RuleChain ruleChain = ruleChainService.findRuleChainById(securityUser.getTenantId(), ruleChainId); + RuleChain ruleChain = ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId); checkNotNull(ruleChain, "Rule chain with id [" + ruleChainId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.RULE_CHAIN, operation, ruleChainId, ruleChain); + accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, ruleChainId, ruleChain); return ruleChain; } protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException { - return checkRuleNode(ruleNodeId, operation, getCurrentUser()); - } - - protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId); RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId); checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found"); @@ -919,15 +851,11 @@ public abstract class BaseController { } TbResource checkResourceId(TbResourceId resourceId, Operation operation) throws ThingsboardException { - return checkResourceId(resourceId, operation, getCurrentUser()); - } - - TbResource checkResourceId(TbResourceId resourceId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(resourceId, "Incorrect resourceId " + resourceId); - TbResource resource = resourceService.findResourceById(securityUser.getTenantId(), resourceId); + TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId); checkNotNull(resource, "Resource with id [" + resourceId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.TB_RESOURCE, operation, resourceId, resource); + accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource); return resource; } catch (Exception e) { throw handleException(e, false); @@ -947,15 +875,11 @@ public abstract class BaseController { } OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation) throws ThingsboardException { - return checkOtaPackageId(otaPackageId, operation, getCurrentUser()); - } - - OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation, SecurityUser securityUser) throws ThingsboardException { try { validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId); - OtaPackage otaPackage = otaPackageService.findOtaPackageById(securityUser.getTenantId(), otaPackageId); + OtaPackage otaPackage = otaPackageService.findOtaPackageById(getCurrentUser().getTenantId(), otaPackageId); checkNotNull(otaPackage, "OTA package with id [" + otaPackageId + "] is not found"); - accessControlService.checkPermission(securityUser, Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage); + accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage); return otaPackage; } catch (Exception e) { throw handleException(e, false); @@ -987,14 +911,10 @@ public abstract class BaseController { } protected Queue checkQueueId(QueueId queueId, Operation operation) throws ThingsboardException { - return checkQueueId(queueId, operation, getCurrentUser()); - } - - protected Queue checkQueueId(QueueId queueId, Operation operation, SecurityUser securityUser) throws ThingsboardException { validateId(queueId, "Incorrect queueId " + queueId); - Queue queue = queueService.findQueueById(securityUser.getTenantId(), queueId); + Queue queue = queueService.findQueueById(getCurrentUser().getTenantId(), queueId); checkNotNull(queue); - accessControlService.checkPermission(securityUser, Resource.QUEUE, operation, queueId, queue); + accessControlService.checkPermission(getCurrentUser(), Resource.QUEUE, operation, queueId, queue); TenantId tenantId = getTenantId(); if (queue.getTenantId().isNullUid() && !tenantId.isNullUid()) { TenantProfile tenantProfile = tenantProfileCache.get(tenantId); From 58f94460ccb579d5d2c10d1dcf36468b11f91b67 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 18 Jan 2023 08:51:37 +0200 Subject: [PATCH 24/27] Changes due to commits --- .../server/controller/AlarmController.java | 6 +----- .../service/subscription/TbAlarmDataSubCtx.java | 2 +- .../telemetry/sub/AlarmSubscriptionUpdate.java | 13 +++++++------ ui-ngx/src/app/shared/models/alarm.models.ts | 7 +++++++ ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 5 files changed, 17 insertions(+), 12 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 40fa35b8b6..15b5daa6ae 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -206,11 +206,7 @@ public class AlarmController extends BaseController { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); UserId assigneeId = new UserId(UUID.fromString(strAssigneeId)); - User user = userService.findUserById(getCurrentUser().getTenantId(), assigneeId); - checkNotNull(user, "User with id [" + strAssigneeId + "] is not found"); - if (!getTenantId().equals(user.getTenantId())) { - throw new ThingsboardException("User with id [" + strAssigneeId + "] is not found", ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } + checkUserId(assigneeId, Operation.READ); return tbAlarmService.assign(alarm, getCurrentUser(), assigneeId); } diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java index d807eb766b..1a339ffcb6 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java @@ -211,7 +211,7 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx { } private void sendWsMsg(String sessionId, AlarmSubscriptionUpdate subscriptionUpdate) { - AlarmInfo alarmInfo = subscriptionUpdate.getAlarmInfo(); + AlarmInfo alarmInfo = subscriptionUpdate.getAlarm(); AlarmId alarmId = alarmInfo.getId(); if (subscriptionUpdate.isAlarmDeleted()) { Alarm deleted = alarmsMap.remove(alarmId); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java index 47eb7c69bf..a7dc3fe867 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java @@ -37,18 +37,18 @@ public class AlarmSubscriptionUpdate { @Getter private String errorMsg; @Getter - private AlarmInfo alarmInfo; + private AlarmInfo alarm; @Getter private boolean alarmDeleted; - public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarmInfo) { - this(subscriptionId, alarmInfo, false); + public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarm) { + this(subscriptionId, alarm, false); } - public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarmInfo, boolean alarmDeleted) { + public AlarmSubscriptionUpdate(int subscriptionId, AlarmInfo alarm, boolean alarmDeleted) { super(); this.subscriptionId = subscriptionId; - this.alarmInfo = alarmInfo; + this.alarm = alarm; this.alarmDeleted = alarmDeleted; } @@ -66,6 +66,7 @@ public class AlarmSubscriptionUpdate { @Override public String toString() { return "AlarmUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + - ", alarmInfo=" + alarmInfo + "]"; + ", alarm=" + alarm + "]"; } } +// TODO imbeacon Alarm instead of alarm info \ No newline at end of file diff --git a/ui-ngx/src/app/shared/models/alarm.models.ts b/ui-ngx/src/app/shared/models/alarm.models.ts index 3d801b91b1..c991764d3f 100644 --- a/ui-ngx/src/app/shared/models/alarm.models.ts +++ b/ui-ngx/src/app/shared/models/alarm.models.ts @@ -106,6 +106,7 @@ export interface Alarm extends BaseData { export interface AlarmInfo extends Alarm { originatorName: string; + originatorLabel: string; assigneeFirstName: string; assigneeLastName: string; assigneeEmail: string; @@ -129,6 +130,7 @@ export const simulatedAlarm: AlarmInfo = { clearTs: 0, assignTs: 0, originatorName: 'Simulated', + originatorLabel: 'Simulated', assigneeFirstName: "", assigneeLastName: "", assigneeEmail: "test@example.com", @@ -194,6 +196,11 @@ export const alarmFields: {[fieldName: string]: AlarmField} = { value: 'originatorName', name: 'alarm.originator' }, + originatorLabel: { + keyName: 'originatorLabel', + value: 'originatorLabel', + name: 'alarm.originator-label' + }, originatorType: { keyName: 'originatorType', value: 'originator.entityType', 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 298e789cf5..5c5a6a9c96 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -433,6 +433,7 @@ "type": "Type", "severity": "Severity", "originator": "Originator", + "originator-label": "Originator label", "originator-type": "Originator type", "assignee-id": "Assignee id", "assignee-first-name": "Assignee first name", From 26a9f101097e5d970b11f20751e83a5a5591c47a Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 31 Jan 2023 18:41:41 +0200 Subject: [PATCH 25/27] Updated alarm websocket subscriptions --- .../DefaultSubscriptionManagerService.java | 2 +- .../DefaultAlarmSubscriptionService.java | 8 ++++---- .../telemetry/sub/AlarmSubscriptionUpdate.java | 3 +-- .../alarm/DefaultTbAlarmServiceTest.java | 2 +- .../server/common/data/alarm/AlarmInfo.java | 18 +++++++++--------- .../engine/api/RuleEngineAlarmService.java | 6 +++--- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 67ac32ee73..421f22c1b6 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -302,7 +302,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene return null; } }, - s -> alarmInfo.getCreatedTime() >= s.getTs(), + s -> alarmInfo.getCreatedTime() >= s.getTs() || alarmInfo.getAssignTs() >= s.getTs(), s -> alarmInfo, false ); 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 2b28c382ed..c3ffb59cad 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 @@ -94,7 +94,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public Alarm createOrUpdateAlarm(Alarm alarm) { + public AlarmInfo createOrUpdateAlarm(Alarm alarm) { AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm, apiUsageStateService.getApiUsageState(alarm.getTenantId()).isAlarmCreationEnabled()); if (result.isSuccessful()) { onAlarmUpdated(result); @@ -111,7 +111,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService if (result.isCreated()) { apiUsageClient.report(alarm.getTenantId(), null, ApiUsageRecordKey.CREATED_ALARMS_COUNT); } - return new Alarm(result.getAlarmInfo()); + return result.getAlarmInfo(); } @Override @@ -142,7 +142,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public Alarm assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) { + public AlarmInfo assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) { AlarmOperationResult result = alarmService.assignAlarm(tenantId, alarmId, assigneeId, assignTs); if (result.isSuccessful()) { onAlarmUpdated(result); @@ -153,7 +153,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService } @Override - public Alarm unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) { + public AlarmInfo unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) { AlarmOperationResult result = alarmService.unassignAlarm(tenantId, alarmId, assignTs); if (result.isSuccessful()) { onAlarmUpdated(result); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java index a7dc3fe867..e8de05ee2f 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/sub/AlarmSubscriptionUpdate.java @@ -68,5 +68,4 @@ public class AlarmSubscriptionUpdate { return "AlarmUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + ", alarm=" + alarm + "]"; } -} -// TODO imbeacon Alarm instead of alarm info \ No newline at end of file +} \ No newline at end of file diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index bea64f12af..dd8567cf43 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -82,7 +82,7 @@ public class DefaultTbAlarmServiceTest { @Test public void testSave() throws ThingsboardException { var alarm = new Alarm(); - when(alarmSubscriptionService.createOrUpdateAlarm(alarm)).thenReturn(alarm); + when((Alarm) alarmSubscriptionService.createOrUpdateAlarm(alarm)).thenReturn(alarm); service.save(alarm, new User()); verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java index 878edb856e..1c14da7f9f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java @@ -61,6 +61,15 @@ public class AlarmInfo extends Alarm { super(alarm); } + public AlarmInfo(AlarmInfo alarmInfo) { + super(alarmInfo); + this.originatorName = alarmInfo.originatorName; + this.originatorLabel = alarmInfo.originatorLabel; + this.assigneeFirstName = alarmInfo.assigneeFirstName; + this.assigneeLastName = alarmInfo.assigneeLastName; + this.assigneeEmail = alarmInfo.assigneeEmail; + } + public AlarmInfo(Alarm alarm, String originatorName, String originatorLabel, String assigneeFirstName, String assigneeLastName, String assigneeEmail) { super(alarm); this.originatorName = originatorName; @@ -70,15 +79,6 @@ public class AlarmInfo extends Alarm { this.assigneeEmail = assigneeEmail; } - public AlarmInfo(Alarm alarm, AlarmInfo alarmInfo) { - super(alarm); - originatorName = alarmInfo.originatorName; - originatorLabel = alarmInfo.originatorLabel; - assigneeFirstName = alarmInfo.assigneeFirstName; - assigneeLastName = alarmInfo.assigneeLastName; - assigneeEmail = alarmInfo.assigneeEmail; - } - @Override public boolean equals(Object o) { if (this == o) return true; 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 053cc03eed..927312dc25 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 @@ -40,7 +40,7 @@ import java.util.Collection; */ public interface RuleEngineAlarmService { - Alarm createOrUpdateAlarm(Alarm alarm); + AlarmInfo createOrUpdateAlarm(Alarm alarm); Boolean deleteAlarm(TenantId tenantId, AlarmId alarmId); @@ -50,9 +50,9 @@ public interface RuleEngineAlarmService { ListenableFuture clearAlarmForResult(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs); - Alarm assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); + AlarmInfo assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs); - Alarm unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); + AlarmInfo unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs); ListenableFuture findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId); From 1a1360e51a421ed4647c0e5d7024946396d28edc Mon Sep 17 00:00:00 2001 From: zbeacon Date: Tue, 31 Jan 2023 20:20:55 +0200 Subject: [PATCH 26/27] Updated getting alarmData with assigned info --- .../thingsboard/server/dao/sql/query/AlarmDataAdapter.java | 6 +++--- .../server/dao/sql/query/DefaultAlarmQueryRepository.java | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java index e7ea6a1b66..a416e6d0e9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/AlarmDataAdapter.java @@ -89,9 +89,9 @@ public class AlarmDataAdapter { String assigneeEmail = null; if (assigneeIdObj != null) { alarm.setAssigneeId(new UserId((UUID) row.get(ModelConstants.ALARM_ASSIGNEE_ID_PROPERTY))); - assigneeFirstName = row.get(ModelConstants.ALARM_ASSIGNEE_FIRST_NAME_PROPERTY).toString(); - assigneeLastName = row.get(ModelConstants.ALARM_ASSIGNEE_LAST_NAME_PROPERTY).toString(); - assigneeEmail = row.get(ModelConstants.ALARM_ASSIGNEE_EMAIL_PROPERTY).toString(); + assigneeFirstName = (String) row.get(ModelConstants.ALARM_ASSIGNEE_FIRST_NAME_PROPERTY); + assigneeLastName = (String) row.get(ModelConstants.ALARM_ASSIGNEE_LAST_NAME_PROPERTY); + assigneeEmail = (String) row.get(ModelConstants.ALARM_ASSIGNEE_EMAIL_PROPERTY); } alarm.setPropagate((boolean) row.get(ModelConstants.ALARM_PROPAGATE_PROPERTY)); alarm.setPropagateToOwner((boolean) row.get(ModelConstants.ALARM_PROPAGATE_TO_OWNER_PROPERTY)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index 71af76ce5d..3f9ea5253c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -131,6 +131,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { " a.ack_ts as ack_ts," + " a.clear_ts as clear_ts," + " a.assign_ts as assign_ts," + + " a.assignee_id as assignee_id," + " a.additional_info as additional_info," + " a.end_ts as end_ts," + " a.originator_id as originator_id," + From 0eff914d692c58918fe202402a85df0a8fc28cd0 Mon Sep 17 00:00:00 2001 From: zbeacon Date: Wed, 15 Feb 2023 15:44:23 +0200 Subject: [PATCH 27/27] Fix for test --- .../service/entitiy/alarm/DefaultTbAlarmServiceTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index 3a80256a65..19efd8cff8 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -27,6 +27,7 @@ import org.springframework.test.context.junit4.SpringRunner; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.UserId; @@ -81,8 +82,8 @@ public class DefaultTbAlarmServiceTest { @Test public void testSave() throws ThingsboardException { - var alarm = new Alarm(); - when((Alarm) alarmSubscriptionService.createOrUpdateAlarm(alarm)).thenReturn(alarm); + var alarm = new AlarmInfo(); + when(alarmSubscriptionService.createOrUpdateAlarm(alarm)).thenReturn(alarm); service.save(alarm, new User()); verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any());