Added alarm assignment feature and tests for it
This commit is contained in:
		
							parent
							
								
									94ebcad963
								
							
						
					
					
						commit
						0dcde60443
					
				
							
								
								
									
										27
									
								
								application/src/main/data/upgrade/3.4.2/schema_update.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								application/src/main/data/upgrade/3.4.2/schema_update.sql
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
@ -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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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'";
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -73,7 +73,7 @@ public abstract class AbstractTbEntityService {
 | 
			
		||||
 | 
			
		||||
    protected ListenableFuture<Void> removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) {
 | 
			
		||||
        ListenableFuture<PageData<AlarmInfo>> 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<List<AlarmId>> alarmIdsFuture = Futures.transform(alarmsFuture, page ->
 | 
			
		||||
                page.getData().stream().map(AlarmInfo::getId).collect(Collectors.toList()), dbExecutor);
 | 
			
		||||
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
@ -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<Void> assign(Alarm alarm, User user, UserId assigneeId) {
 | 
			
		||||
        long assignTs = System.currentTimeMillis();
 | 
			
		||||
        ListenableFuture<Boolean> 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<Void> unassign(Alarm alarm, User user) {
 | 
			
		||||
        long assignTs = System.currentTimeMillis();
 | 
			
		||||
        ListenableFuture<Boolean> 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();
 | 
			
		||||
 | 
			
		||||
@ -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<Void> clear(Alarm alarm, User user);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> assign(Alarm alarm, User user, UserId assigneeId);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> unassign(Alarm alarm, User user);
 | 
			
		||||
 | 
			
		||||
    Boolean delete(Alarm alarm, User user);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, alarmQuery);
 | 
			
		||||
        boolean hasNext = true;
 | 
			
		||||
        while (hasNext) {
 | 
			
		||||
 | 
			
		||||
@ -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<Boolean> assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs) {
 | 
			
		||||
        ListenableFuture<AlarmOperationResult> result = alarmService.assignAlarm(tenantId, alarmId, assigneeId, assignTs);
 | 
			
		||||
        Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor);
 | 
			
		||||
        return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Boolean> unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs) {
 | 
			
		||||
        ListenableFuture<AlarmOperationResult> result = alarmService.unassignAlarm(tenantId, alarmId, assignTs);
 | 
			
		||||
        Futures.addCallback(result, new AlarmUpdateCallback(), wsCallBackExecutor);
 | 
			
		||||
        return Futures.transform(result, AlarmOperationResult::isSuccessful, wsCallBackExecutor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Alarm> 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
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmOperationResult> clearAlarm(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<AlarmOperationResult> assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<AlarmOperationResult> unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs);
 | 
			
		||||
 | 
			
		||||
    Alarm findAlarmById(TenantId tenantId, AlarmId alarmId);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId);
 | 
			
		||||
@ -59,7 +64,7 @@ public interface AlarmService {
 | 
			
		||||
    ListenableFuture<PageData<AlarmInfo>> findCustomerAlarms(TenantId tenantId, CustomerId customerId, AlarmQuery query);
 | 
			
		||||
 | 
			
		||||
    AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus,
 | 
			
		||||
                                           AlarmStatus alarmStatus);
 | 
			
		||||
                                           AlarmStatus alarmStatus, UserId assigneeUserId);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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";
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmId> 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<String> propagateRelationTypes;
 | 
			
		||||
@ -96,10 +101,12 @@ public class Alarm extends BaseData<AlarmId> 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();
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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),
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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<Alarm> {
 | 
			
		||||
 | 
			
		||||
    PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
 | 
			
		||||
 | 
			
		||||
    Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status);
 | 
			
		||||
    Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> status, UserId assigneeUserId);
 | 
			
		||||
 | 
			
		||||
    PageData<AlarmId> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmOperationResult> assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) {
 | 
			
		||||
        return getAndUpdateAsync(tenantId, alarmId, new Function<Alarm, AlarmOperationResult>() {
 | 
			
		||||
            @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<AlarmOperationResult> unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTime) {
 | 
			
		||||
        return getAndUpdateAsync(tenantId, alarmId, new Function<Alarm, AlarmOperationResult>() {
 | 
			
		||||
            @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<AlarmStatus> statusList = null;
 | 
			
		||||
        if (alarmSearchStatus != null) {
 | 
			
		||||
            statusList = alarmSearchStatus.getStatuses();
 | 
			
		||||
@ -336,7 +373,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
 | 
			
		||||
            statusList = Collections.singleton(alarmStatus);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Set<AlarmSeverity> alarmSeverities = alarmDao.findAlarmSeverities(tenantId, entityId, statusList);
 | 
			
		||||
        Set<AlarmSeverity> 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) {
 | 
			
		||||
 | 
			
		||||
@ -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) {
 | 
			
		||||
 | 
			
		||||
@ -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";
 | 
			
		||||
 | 
			
		||||
@ -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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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<T extends Alarm> 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(",")));
 | 
			
		||||
 | 
			
		||||
@ -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<EntityAlarm> {
 | 
			
		||||
    @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<EntityAlarm> {
 | 
			
		||||
        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<EntityAlarm> {
 | 
			
		||||
        if (customerId != null) {
 | 
			
		||||
            result.setCustomerId(new CustomerId(customerId));
 | 
			
		||||
        }
 | 
			
		||||
        if (assigneeId != null) {
 | 
			
		||||
            result.setAssigneeId(new UserId(assigneeId));
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,7 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
 | 
			
		||||
            "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<AlarmEntity, UUID> {
 | 
			
		||||
                    "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<AlarmEntity, UUID> {
 | 
			
		||||
                                     @Param("startTime") Long startTime,
 | 
			
		||||
                                     @Param("endTime") Long endTime,
 | 
			
		||||
                                     @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses,
 | 
			
		||||
                                     @Param("assigneeId") UUID assigneeId,
 | 
			
		||||
                                     @Param("searchText") String searchText,
 | 
			
		||||
                                     Pageable pageable);
 | 
			
		||||
 | 
			
		||||
@ -80,6 +83,7 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
 | 
			
		||||
            "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<AlarmEntity, UUID> {
 | 
			
		||||
                    "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<AlarmEntity, UUID> {
 | 
			
		||||
                                        @Param("startTime") Long startTime,
 | 
			
		||||
                                        @Param("endTime") Long endTime,
 | 
			
		||||
                                        @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses,
 | 
			
		||||
                                        @Param("assigneeId") UUID assigneeId,
 | 
			
		||||
                                        @Param("searchText") String searchText,
 | 
			
		||||
                                        Pageable pageable);
 | 
			
		||||
 | 
			
		||||
@ -105,6 +111,7 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
 | 
			
		||||
            "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<AlarmEntity, UUID> {
 | 
			
		||||
                    "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<AlarmEntity, UUID> {
 | 
			
		||||
                                             @Param("startTime") Long startTime,
 | 
			
		||||
                                             @Param("endTime") Long endTime,
 | 
			
		||||
                                             @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses,
 | 
			
		||||
                                             @Param("assigneeId") UUID assigneeId,
 | 
			
		||||
                                             @Param("searchText") String searchText,
 | 
			
		||||
                                             Pageable pageable);
 | 
			
		||||
 | 
			
		||||
@ -133,11 +142,13 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
 | 
			
		||||
            "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<AlarmSeverity> findAlarmSeverities(@Param("tenantId") UUID tenantId,
 | 
			
		||||
                                           @Param("affectedEntityId") UUID affectedEntityId,
 | 
			
		||||
                                           @Param("affectedEntityType") String affectedEntityType,
 | 
			
		||||
                                           @Param("alarmStatuses") Set<AlarmStatus> alarmStatuses);
 | 
			
		||||
                                           @Param("alarmStatuses") Set<AlarmStatus> 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<UUID> findAlarmsIdsByEndTsBeforeAndTenantId(@Param("time") Long time, @Param("tenantId") UUID tenantId, Pageable pageable);
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmEntity, Alarm> 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<AlarmEntity, Alarm> 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<AlarmEntity, Alarm> 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<AlarmEntity, Alarm> 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<AlarmEntity, Alarm> 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<AlarmEntity, Alarm> implements A
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> statuses) {
 | 
			
		||||
        return alarmRepository.findAlarmSeverities(tenantId.getId(), entityId.getId(), entityId.getEntityType().name(), statuses);
 | 
			
		||||
    public Set<AlarmSeverity> findAlarmSeverities(TenantId tenantId, EntityId entityId, Set<AlarmStatus> 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
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmOperationResult> clearAlarmForResult(TenantId tenantId, AlarmId alarmId, JsonNode details, long clearTs);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Boolean> assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTs);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Boolean> unassignAlarm(TenantId tenantId, AlarmId alarmId, long assignTs);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, AlarmId alarmId);
 | 
			
		||||
 | 
			
		||||
    Alarm findAlarmById(TenantId tenantId, AlarmId alarmId);
 | 
			
		||||
@ -61,7 +66,7 @@ public interface RuleEngineAlarmService {
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<PageData<AlarmInfo>> 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<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -116,7 +116,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fetchAlarms(pageLink: TimePageLink): Observable<PageData<AlarmInfo>> {
 | 
			
		||||
    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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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<AlarmSeverity, string>(
 | 
			
		||||
export interface Alarm extends BaseData<AlarmId> {
 | 
			
		||||
  tenantId: TenantId;
 | 
			
		||||
  customerId: CustomerId;
 | 
			
		||||
  assigneeId: UserId;
 | 
			
		||||
  type: string;
 | 
			
		||||
  originator: EntityId;
 | 
			
		||||
  severity: AlarmSeverity;
 | 
			
		||||
@ -97,6 +99,7 @@ export interface Alarm extends BaseData<AlarmId> {
 | 
			
		||||
  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}`;
 | 
			
		||||
 | 
			
		||||
@ -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, string>(
 | 
			
		||||
    [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'],
 | 
			
		||||
 | 
			
		||||
@ -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",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user