From 8a157397d48a2d0a96c6bd44debcee39a0874671 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 8 Dec 2022 17:04:30 +0200 Subject: [PATCH 01/16] added rest controller for alarm comments --- .../main/data/upgrade/3.5/schema_update.sql | 28 +++++ .../server/actors/ActorSystemContext.java | 5 + .../actors/ruleChain/DefaultTbContext.java | 6 + .../controller/AlarmCommentController.java | 108 ++++++++++++++++ .../server/controller/BaseController.java | 22 +++- .../controller/ControllerConstants.java | 2 + .../entitiy/AbstractTbEntityService.java | 3 + .../DefaultTbNotificationEntityService.java | 13 ++ .../entitiy/TbNotificationEntityService.java | 4 + .../alarm/DefaultTbAlarmCommentService.java | 50 ++++++++ .../entitiy/alarm/TbAlarmCommentService.java | 26 ++++ .../permission/CustomerUserPermissions.java | 14 +++ .../service/security/permission/Resource.java | 1 + .../permission/TenantAdminPermissions.java | 1 + .../src/main/resources/thingsboard.yml | 2 + .../alarm/AlarmCommentOperationResult.java | 37 ++++++ .../server/dao/alarm/AlarmCommentService.java | 35 ++++++ .../server/dao/alarm/AlarmService.java | 2 +- .../server/common/data/EntityType.java | 2 +- .../common/data/alarm/AlarmComment.java | 91 ++++++++++++++ .../common/data/alarm/AlarmCommentInfo.java | 67 ++++++++++ .../server/common/data/id/AlarmCommentId.java | 45 +++++++ .../common/data/id/EntityIdFactory.java | 2 + .../server/dao/alarm/AlarmCommentDao.java | 39 ++++++ .../dao/alarm/BaseAlarmCommentService.java | 105 ++++++++++++++++ .../server/dao/model/ModelConstants.java | 9 ++ .../dao/model/sql/AlarmCommentEntity.java | 119 ++++++++++++++++++ .../validator/AlarmCommentDataValidator.java | 44 +++++++ .../dao/sql/alarm/AlarmCommentRepository.java | 29 +++++ .../dao/sql/alarm/JpaAlarmCommentDao.java | 101 +++++++++++++++ .../rule/engine/api/TbContext.java | 3 + .../util/EntitiesFieldsAsyncLoader.java | 4 + 32 files changed, 1016 insertions(+), 3 deletions(-) create mode 100644 application/src/main/data/upgrade/3.5/schema_update.sql create mode 100644 application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java create mode 100644 application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java diff --git a/application/src/main/data/upgrade/3.5/schema_update.sql b/application/src/main/data/upgrade/3.5/schema_update.sql new file mode 100644 index 0000000000..506ac7e38c --- /dev/null +++ b/application/src/main/data/upgrade/3.5/schema_update.sql @@ -0,0 +1,28 @@ +-- +-- 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. +-- + +CREATE TABLE IF NOT EXISTS alarm_comment ( + id uuid NOT NULL, + tenant_id uuid NOT NULL, + customer_id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_id uuid NOT NULL, + user_id uuid, + type varchar(255) NOT NULL, + comment varchar(1000000), + CONSTRAINT fk_alarm_comment_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +) PARTITION BY RANGE (created_time); +CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id ASC); \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index e1a41fe401..82f9ec25b6 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -50,6 +50,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.audit.AuditLogService; @@ -268,6 +269,10 @@ public class ActorSystemContext { @Getter private AlarmSubscriptionService alarmService; + @Autowired + @Getter + private AlarmCommentService alarmCommentService; + @Autowired @Getter private JsInvokeService jsInvokeService; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index ef2de35912..826883aee2 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -71,6 +71,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgProcessingStackItem; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.cassandra.CassandraCluster; @@ -579,6 +580,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getAlarmService(); } + @Override + public AlarmCommentService getAlarmCommentService() { + return mainCtx.getAlarmCommentService(); + } + @Override public RuleChainService getRuleChainService() { return mainCtx.getRuleChainService(); diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java new file mode 100644 index 0000000000..c4c1bc8de2 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -0,0 +1,108 @@ +/** + * 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.controller; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; +import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.permission.Resource; + +import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; + +@RestController +@TbCoreComponent +@RequiredArgsConstructor +@RequestMapping("/api") +public class AlarmCommentController extends BaseController { + public static final String ALARM_ID = "alarmId"; + public static final String ALARM_COMMENT_ID = "commentId"; + + private final TbAlarmCommentService tbAlarmCommentService; + + @ApiOperation(value = "Create or update Alarm Comment ", + notes = "Creates or Updates the Alarm Comment. " + + "When creating comment, platform generates Alarm Comment Id as " + UUID_WIKI_LINK + + "The newly created Alarm Comment id will be present in the response. Specify existing Alarm Comment id to update the alarm. " + + "Referencing non-existing Alarm Comment Id will cause 'Not Found' error. " + + "\nRemove 'id' and optionally 'userId' from the request body example (below) to create new Alarm comment entity. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH + , produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.POST) + @ResponseBody + public AlarmComment saveAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException { + checkParameter(ALARM_ID, strAlarmId); + alarmComment.setTenantId(getTenantId()); + alarmComment.setAlarmId(new AlarmId(toUUID(strAlarmId))); + checkEntity(alarmComment.getId(), alarmComment, Resource.ALARM_COMMENT); + return tbAlarmCommentService.saveAlarmComment(alarmComment, getCurrentUser()); + } + + @ApiOperation(value = "Delete Alarm comment(deleteAlarmComment)", + notes = "Deletes the Alarm comment. Referencing non-existing Alarm comment 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}/comment/{commentId}", method = RequestMethod.DELETE) + @ResponseBody + public Boolean deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException { + checkParameter(ALARM_ID, strAlarmId); + AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strAlarmId)); + AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId, Operation.DELETE); + return tbAlarmCommentService.deleteAlarmComment(alarmComment, getCurrentUser()); + } + + @ApiOperation(value = "Get Alarm comments (getAlarmComments)", + notes = "Returns a page of alarm comments. " + + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET) + @ResponseBody + public PageData getAlarmComments( + @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) + @PathVariable(ALARM_ID) String strAlarmCommentId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page + ) throws Exception { + AlarmId alarmId = new AlarmId(toUUID(strAlarmCommentId)); + PageLink pageLink = createPageLink(pageSize, page, null, null, null); + return checkNotNull(alarmCommentService.findAlarmComments(alarmId, pageLink).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..965842af46 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -54,6 +54,7 @@ import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetInfo; @@ -64,6 +65,7 @@ import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.edge.EdgeInfo; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetProfileId; @@ -98,6 +100,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetProfileService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; @@ -131,7 +134,6 @@ import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.component.ComponentDiscoveryService; -import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.ota.OtaPackageStateService; @@ -200,6 +202,9 @@ public abstract class BaseController { @Autowired protected AlarmSubscriptionService alarmService; + @Autowired + protected AlarmCommentService alarmCommentService; + @Autowired protected DeviceCredentialsService deviceCredentialsService; @@ -531,6 +536,9 @@ public abstract class BaseController { case ALARM: checkAlarmId(new AlarmId(entityId.getId()), operation); return; + case ALARM_COMMENT: + checkAlarmCommentId(new AlarmCommentId(entityId.getId()), operation); + return; case DEVICE: checkDeviceId(new DeviceId(entityId.getId()), operation); return; @@ -713,6 +721,18 @@ public abstract class BaseController { } } + AlarmComment checkAlarmCommentId(AlarmCommentId alarmCommentId, Operation operation) throws ThingsboardException { + try { + validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); + AlarmComment alarmComment = alarmCommentService.findAlarmCommentByIdAsync(getCurrentUser().getTenantId(), alarmCommentId).get(); + checkNotNull(alarmComment, "Alarm comment with id [" + alarmCommentId + "] is not found"); + accessControlService.checkPermission(getCurrentUser(), Resource.ALARM_COMMENT, operation, alarmCommentId, alarmComment); + return alarmComment; + } catch (Exception e) { + throw handleException(e, false); + } + } + WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation) throws ThingsboardException { try { validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); 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..5e7622ece5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -44,6 +44,8 @@ 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 ALARM_COMMENT_ID_PARAM_DESCRIPTION = "A string value representing the alarm comment 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/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java index 9f34c061fe..10af591647 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 @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; @@ -65,6 +66,8 @@ public abstract class AbstractTbEntityService { @Autowired protected AlarmSubscriptionService alarmSubscriptionService; @Autowired + protected AlarmCommentService alarmCommentService; + @Autowired protected CustomerService customerService; @Autowired protected TbClusterService tbClusterService; 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..0bcd605928 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 @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.HasName; 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.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -229,6 +230,18 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType)); } + @Override + public void notifyCreateOrUpdateAlarmComment(AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo) { + logEntityAction(alarmComment.getTenantId(), alarmComment.getAlarmId(), alarmComment, alarmComment.getCustomerId(), actionType, user, additionalInfo); + // TODO: should we send notification to edge? + } + + @Override + public void notifyDeleteAlarmComment(AlarmComment alarmComment, User user, Object... additionalInfo) { + logEntityAction(alarmComment.getTenantId(), alarmComment.getAlarmId(), alarmComment, alarmComment.getCustomerId(), ActionType.DELETED, user, additionalInfo); + // TODO: should we send notification to edge? + } + @Override public void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, I entityId, E entity, User user, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index dc6e148cab..6719394d5b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.HasName; 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.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -102,6 +103,9 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo); + void notifyCreateOrUpdateAlarmComment(AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo); + + void notifyDeleteAlarmComment(AlarmComment alarmComment, User user, Object... additionalInfo); void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, I entityId, E entity, User user, ActionType actionType, boolean sendNotifyMsgToEdge, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java new file mode 100644 index 0000000000..e0bfaf10e4 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java @@ -0,0 +1,50 @@ +/** + * 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.service.entitiy.alarm; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.service.entitiy.AbstractTbEntityService; + +@Service +@AllArgsConstructor +public class DefaultTbAlarmCommentService extends AbstractTbEntityService implements TbAlarmCommentService{ + @Override + public AlarmComment saveAlarmComment(AlarmComment alarmComment, User user) throws ThingsboardException { + ActionType actionType = alarmComment.getId() == null ? ActionType.ADDED : ActionType.UPDATED; + UserId userId = user.getId(); + alarmComment.setUserId(userId); + try { + AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarmComment).getAlarmComment()); + notificationEntityService.notifyCreateOrUpdateAlarmComment(savedAlarmComment, actionType, user); + return savedAlarmComment; + } catch (Exception e) { + notificationEntityService.logEntityAction(alarmComment.getTenantId(), emptyId(EntityType.ALARM_COMMENT), alarmComment, actionType, user, e); + throw e; + } + } + @Override + public Boolean deleteAlarmComment(AlarmComment alarmComment, User user) { + notificationEntityService.notifyDeleteAlarmComment(alarmComment, user); + return alarmCommentService.deleteAlarmComment(alarmComment.getId()).isSuccessful(); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java new file mode 100644 index 0000000000..375b655af8 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java @@ -0,0 +1,26 @@ +/** + * 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.service.entitiy.alarm; + +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.exception.ThingsboardException; + +public interface TbAlarmCommentService { + AlarmComment saveAlarmComment(AlarmComment alarmComment, User user) throws ThingsboardException; + + Boolean deleteAlarmComment(AlarmComment alarmComment, User user); +} diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java index cdd84b0478..489d9deb81 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java @@ -32,6 +32,7 @@ public class CustomerUserPermissions extends AbstractPermissions { public CustomerUserPermissions() { super(); put(Resource.ALARM, customerAlarmPermissionChecker); + put(Resource.ALARM_COMMENT, customerAlarmCommentPermissionChecker); put(Resource.ASSET, customerEntityPermissionChecker); put(Resource.DEVICE, customerEntityPermissionChecker); put(Resource.CUSTOMER, customerPermissionChecker); @@ -59,6 +60,19 @@ public class CustomerUserPermissions extends AbstractPermissions { } }; + private static final PermissionChecker customerAlarmCommentPermissionChecker = new PermissionChecker() { + @Override + public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { + if (!user.getTenantId().equals(entity.getTenantId())) { + return false; + } + if (!(entity instanceof HasCustomerId)) { + return false; + } + return user.getCustomerId().equals(((HasCustomerId) entity).getCustomerId()); + } + }; + private static final PermissionChecker customerEntityPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_CREDENTIALS, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES, diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java index a9484a2bd3..0979c0969d 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java @@ -22,6 +22,7 @@ import java.util.Optional; public enum Resource { ADMIN_SETTINGS(), ALARM(EntityType.ALARM), + ALARM_COMMENT(EntityType.ALARM_COMMENT), DEVICE(EntityType.DEVICE), ASSET(EntityType.ASSET), CUSTOMER(EntityType.CUSTOMER), diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java index ef7991e5de..7027fda414 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java @@ -30,6 +30,7 @@ public class TenantAdminPermissions extends AbstractPermissions { super(); put(Resource.ADMIN_SETTINGS, PermissionChecker.allowAllPermissionChecker); put(Resource.ALARM, tenantEntityPermissionChecker); + put(Resource.ALARM_COMMENT, tenantEntityPermissionChecker); put(Resource.ASSET, tenantEntityPermissionChecker); put(Resource.DEVICE, tenantEntityPermissionChecker); put(Resource.CUSTOMER, tenantEntityPermissionChecker); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 6a00775a38..67f9928c18 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -277,6 +277,8 @@ sql: partition_size: "${SQL_EDGE_EVENTS_PARTITION_SIZE_HOURS:168}" # Number of hours to partition the events. The current value corresponds to one week. audit_logs: partition_size: "${SQL_AUDIT_LOGS_PARTITION_SIZE_HOURS:168}" # Default value - 1 week + alarm_comments: + partition_size: "${SQL_ALARM_COMMENTS_PARTITION_SIZE_HOURS:168}" # Default value - 1 week # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks batch_sort: "${SQL_BATCH_SORT:true}" # Specify whether to remove null characters from strValue of attributes and timeseries before insert diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java new file mode 100644 index 0000000000..3687a03eca --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java @@ -0,0 +1,37 @@ +/** + * 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.Data; +import org.thingsboard.server.common.data.alarm.AlarmComment; + +@Data +public class AlarmCommentOperationResult { + private final AlarmComment alarmComment; + private final boolean successful; + private final boolean created; + + + public AlarmCommentOperationResult(AlarmComment alarmComment, boolean successful) { + this(alarmComment, successful, false); + } + + public AlarmCommentOperationResult(AlarmComment alarmComment, boolean successful, boolean created) { + this.alarmComment = alarmComment; + this.successful = successful; + this.created = created; + } +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java new file mode 100644 index 0000000000..83e6216800 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java @@ -0,0 +1,35 @@ +/** + * 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 com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; + +public interface AlarmCommentService { + AlarmCommentOperationResult createOrUpdateAlarmComment(AlarmComment alarmComment); + + AlarmCommentOperationResult deleteAlarmComment(AlarmCommentId alarmCommentId); + + ListenableFuture> findAlarmComments(AlarmId alarmId, PageLink pageLink); + + ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); + +} 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..b5bbdc761c 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 @@ -18,12 +18,12 @@ package org.thingsboard.server.dao.alarm; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; 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.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; 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..44b175c20d 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,5 @@ 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, ALARM_COMMENT, 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/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java new file mode 100644 index 0000000000..ce2d11d12f --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -0,0 +1,91 @@ +/** + * 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.alarm; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasCustomerId; +import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.id.AlarmCommentId; +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; + +@ApiModel +@Data +@Builder +@AllArgsConstructor +public class AlarmComment extends BaseData implements HasName, HasTenantId, HasCustomerId { + @ApiModelProperty(position = 3, value = "JSON object with Tenant Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private TenantId tenantId; + + @ApiModelProperty(position = 4, value = "JSON object with Customer Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private CustomerId customerId; + @ApiModelProperty(position = 2, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private EntityId alarmId; + @ApiModelProperty(position = 3, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private UserId userId; + @ApiModelProperty(position = 4, value = "Defines origination of comment", example = "System/Other", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String type; + @ApiModelProperty(position = 5, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") + private transient JsonNode comment; + + @ApiModelProperty(position = 1, value = "JSON object with the alarm comment Id. " + + "Specify this field to update the alarm comment. " + + "Referencing non-existing alarm Id will cause error. " + + "Omit this field to create new alarm." ) + @Override + public AlarmCommentId getId() { + return super.getId(); + } + + @ApiModelProperty(position = 2, value = "Timestamp of the alarm comment creation, in milliseconds", example = "1634058704567", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Override + public long getCreatedTime() { + return super.getCreatedTime(); + } + + public AlarmComment() { + super(); + } + + public AlarmComment(AlarmCommentId id) { + super(id); + } + + @Override + public String getName() { + return comment.toString(); + } + + public AlarmComment(AlarmComment alarmComment) { + super(alarmComment.getId()); + this.createdTime = alarmComment.getCreatedTime(); + this.tenantId = alarmComment.getTenantId(); + this.customerId = alarmComment.getCustomerId(); + this.type = alarmComment.getType(); + this.comment = alarmComment.getComment(); + this.userId = alarmComment.getUserId(); + + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java new file mode 100644 index 0000000000..7cbff38d80 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java @@ -0,0 +1,67 @@ +/** + * 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.alarm; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel +public class AlarmCommentInfo extends AlarmComment{ + private static final long serialVersionUID = 2807343093519543377L; + + @ApiModelProperty(position = 19, value = "Alarm originator name", example = "Thermostat") + private String userName; + + public AlarmCommentInfo() { + super(); + } + + public AlarmCommentInfo(AlarmComment alarmComment) { + super(alarmComment); + } + + public AlarmCommentInfo(AlarmComment alarmComment, String userName) { + super(alarmComment); + this.userName = userName; + } + + public String getUserName() { + return userName; + } + + public void setOriginatorName(String originatorName) { + this.userName = originatorName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + AlarmCommentInfo alarmCommentInfo = (AlarmCommentInfo) o; + + return userName != null ? userName.equals(alarmCommentInfo.userName) : alarmCommentInfo.userName == null; + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (userName != null ? userName.hashCode() : 0); + return result; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java new file mode 100644 index 0000000000..b13b5837a0 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java @@ -0,0 +1,45 @@ +/** + * 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.id; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.thingsboard.server.common.data.EntityType; + +import java.util.UUID; + +@ApiModel +public class AlarmCommentId extends UUIDBased implements EntityId{ + + private static final long serialVersionUID = 2L; + + @JsonCreator + public AlarmCommentId(@JsonProperty("id") UUID id) { + super(id); + } + + public static AlarmCommentId fromString(String commentId) { + return new AlarmCommentId(UUID.fromString(commentId)); + } + + @ApiModelProperty(position = 2, required = true, value = "string", example = "ALARM_COMMENT", allowableValues = "ALARM_COMMENT") + @Override + public EntityType getEntityType() { + return EntityType.ALARM_COMMENT; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index c6a19e0040..ae647825cd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -53,6 +53,8 @@ public class EntityIdFactory { return new AssetId(uuid); case ALARM: return new AlarmId(uuid); + case ALARM_COMMENT: + return new AlarmCommentId(uuid); case RULE_CHAIN: return new RuleChainId(uuid); case RULE_NODE: diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java new file mode 100644 index 0000000000..e58ca14664 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java @@ -0,0 +1,39 @@ +/** + * 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 com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.Dao; + +import java.util.UUID; + +public interface AlarmCommentDao extends Dao { + AlarmComment createAlarmComment(AlarmComment alarmComment); + void deleteAlarmComment(AlarmCommentId alarmCommentId); + + AlarmComment findAlarmCommentById(TenantId tenantId, UUID key); + + PageData findAlarmComments(AlarmId id, PageLink pageLink); + + ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, UUID key); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java new file mode 100644 index 0000000000..d293531dd4 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -0,0 +1,105 @@ +/** + * 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 com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.service.DataValidator; + +import static org.thingsboard.server.dao.service.Validator.validateId; + +@Service +@Slf4j +public class BaseAlarmCommentService extends AbstractEntityService implements AlarmCommentService{ + + @Autowired + private AlarmCommentDao alarmCommentDao; + @Autowired + private EntityService entityService; + @Autowired + private DataValidator alarmCommentDataValidator; + @Override + public AlarmCommentOperationResult createOrUpdateAlarmComment(AlarmComment alarmComment) { + alarmCommentDataValidator.validate(alarmComment, AlarmComment::getTenantId); + alarmComment.setCustomerId(entityService.fetchEntityCustomerId(alarmComment.getTenantId(), alarmComment.getAlarmId())); + if (alarmComment.getId() == null) { + return createAlarmComment(alarmComment); + } else { + return updateAlarmComment(alarmComment); + } + } + + @Override + @Transactional + public AlarmCommentOperationResult deleteAlarmComment(AlarmCommentId alarmCommentId) { + log.debug("Deleting Alarm Comment with id: {}", alarmCommentId); + AlarmCommentOperationResult result = new AlarmCommentOperationResult(new AlarmComment(), true); + alarmCommentDao.deleteAlarmComment(alarmCommentId); + return result; + } + + @Override + public ListenableFuture> findAlarmComments(AlarmId alarmId, PageLink pageLink) { + PageData alarmComments = alarmCommentDao.findAlarmComments(alarmId, pageLink); + return Futures.immediateFuture(alarmComments); + } + + @Override + public ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) { + log.trace("Executing findAlarmCommentByIdAsync [{}]", alarmCommentId); + validateId(alarmCommentId, "Incorrect alarmId " + alarmCommentId); + return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId()); + } + + private AlarmCommentOperationResult createAlarmComment(AlarmComment alarmComment) { + log.debug("New Alarm comment : {}", alarmComment); + if (alarmComment.getType() == null) { + alarmComment.setType("OTHER"); + } + AlarmComment saved = alarmCommentDao.createAlarmComment(alarmComment); + return new AlarmCommentOperationResult(saved, true, true); + } + + private AlarmCommentOperationResult updateAlarmComment(AlarmComment newAlarmComment) { + log.debug("Update Alarm comment : {}", newAlarmComment); + + validateId(newAlarmComment.getId(), "Alarm comment id should be specified!"); + AlarmComment existing = alarmCommentDao.findAlarmCommentById(newAlarmComment.getTenantId(), newAlarmComment.getId().getId()); + if (existing != null) { + AlarmComment result = alarmCommentDao.save(newAlarmComment.getTenantId(), merge(existing, newAlarmComment)); + return new AlarmCommentOperationResult(result, true, true); + } + return null; + } + + private AlarmComment merge(AlarmComment existing, AlarmComment alarmComment) { + existing.setCustomerId(alarmComment.getCustomerId()); + existing.setComment(alarmComment.getComment()); + return existing; + } +} 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..bd462eb6b6 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 @@ -297,6 +297,15 @@ public class ModelConstants { public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id"; + public static final String ALARM_COMMENT_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String ALARM_COMMENT_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; + public static final String ALARM_COMMENT_COLUMN_FAMILY_NAME = "alarm_comment"; + public static final String ALARM_COMMENT_ALARM_ID = "alarm_id"; + public static final String ALARM_COMMENT_USER_ID = USER_ID_PROPERTY; + public static final String ALARM_COMMENT_TYPE = "type"; + public static final String ALARM_COMMENT_COMMENT = "comment"; + + /** * Cassandra entity relation constants. */ diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java new file mode 100644 index 0000000000..571c3007e1 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java @@ -0,0 +1,119 @@ +/** + * 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.model.sql; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; +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; +import org.thingsboard.server.dao.util.mapping.JsonStringType; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_ALARM_ID; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COMMENT; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TENANT_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TYPE; + +@Data +@EqualsAndHashCode(callSuper = true) +@Entity +@TypeDef(name = "json", typeClass = JsonStringType.class) +@Table(name = ALARM_COMMENT_COLUMN_FAMILY_NAME) + +public class AlarmCommentEntity extends BaseSqlEntity implements BaseEntity { + + @Column(name = ALARM_COMMENT_TENANT_ID_PROPERTY, columnDefinition = "uuid") + private UUID tenantId; + + @Column(name = ALARM_COMMENT_CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") + private UUID customerId; + @Column(name = ALARM_COMMENT_ALARM_ID, columnDefinition = "uuid") + private UUID alarmId; + + @Column(name = ModelConstants.ALARM_COMMENT_USER_ID) + private UUID userId; + + @Column(name = ALARM_COMMENT_TYPE) + private String type; + + @Type(type = "json") + @Column(name = ALARM_COMMENT_COMMENT) + private JsonNode comment; + + public AlarmCommentEntity() { + super(); + } + + public AlarmCommentEntity(AlarmComment alarmComment) { + if (alarmComment.getId() != null) { + this.setUuid(alarmComment.getUuidId()); + } + if (alarmComment.getTenantId() != null) { + this.tenantId = alarmComment.getTenantId().getId(); + } + if (alarmComment.getCustomerId() != null) { + this.customerId = alarmComment.getCustomerId().getId(); + } + this.setCreatedTime(alarmComment.getCreatedTime()); + this.setCreatedTime(alarmComment.getCreatedTime()); + if (alarmComment.getAlarmId() != null) { + this.alarmId = alarmComment.getAlarmId().getId(); + } + if (alarmComment.getUserId() != null) { + this.userId = alarmComment.getUserId().getId(); + } + if (alarmComment.getType() != null) { + this.type = alarmComment.getType(); + } + this.setComment(alarmComment.getComment()); + } + + @Override + public AlarmComment toData() { + AlarmComment alarmComment = new AlarmComment(new AlarmCommentId(id)); + alarmComment.setCreatedTime(createdTime); + alarmComment.setAlarmId(new AlarmId(alarmId)); + if (userId != null) { + alarmComment.setUserId(new UserId(userId)); + } + if (tenantId != null) { + alarmComment.setTenantId(TenantId.fromUUID(tenantId)); + } + if (customerId != null) { + alarmComment.setCustomerId(new CustomerId(customerId)); + } + alarmComment.setType(type); + alarmComment.setComment(comment); + return alarmComment; + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java new file mode 100644 index 0000000000..9969de6fe2 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java @@ -0,0 +1,44 @@ +/** + * 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.service.validator; + +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.tenant.TenantService; + +@Component +@AllArgsConstructor +public class AlarmCommentDataValidator extends DataValidator { + + private final TenantService tenantService; + + @Override + protected void validateDataImpl(TenantId tenantId, AlarmComment alarmComment) { + if (alarmComment.getTenantId() == null) { + throw new DataValidationException("Alarm comment should be assigned to tenant!"); + } else { + if (!tenantService.tenantExists(alarmComment.getTenantId())) { + throw new DataValidationException("Alarm comment is referencing to non-existent tenant!"); + } + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java new file mode 100644 index 0000000000..1517b35554 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java @@ -0,0 +1,29 @@ +/** + * 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.sql.alarm; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.thingsboard.server.dao.model.sql.AlarmCommentEntity; + +import java.util.UUID; + +public interface AlarmCommentRepository extends JpaRepository { + + Page findAllByAlarmId(UUID alarmId, Pageable pageable); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java new file mode 100644 index 0000000000..440510f37b --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java @@ -0,0 +1,101 @@ +/** + * 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.sql.alarm; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.DaoUtil; +import org.thingsboard.server.dao.alarm.AlarmCommentDao; +import org.thingsboard.server.dao.model.sql.AlarmCommentEntity; +import org.thingsboard.server.dao.sql.JpaAbstractDao; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; +import org.thingsboard.server.dao.util.SqlDao; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COLUMN_FAMILY_NAME; + +@Slf4j +@Component +@SqlDao +@RequiredArgsConstructor +public class JpaAlarmCommentDao extends JpaAbstractDao implements AlarmCommentDao { + private final SqlPartitioningRepository partitioningRepository; + @Value("${sql.alarm_comments.partition_size:168}") + private int partitionSizeInHours; + + @Autowired + private AlarmCommentRepository alarmCommentRepository; + + @Override + public AlarmComment createAlarmComment(AlarmComment alarmComment){ + log.debug("Saving entity {}", alarmComment); + if (alarmComment.getId() == null) { + UUID uuid = Uuids.timeBased(); + alarmComment.setId(new AlarmCommentId(uuid)); + alarmComment.setCreatedTime(Uuids.unixTimestamp(uuid)); + } + partitioningRepository.createPartitionIfNotExists(ALARM_COMMENT_COLUMN_FAMILY_NAME, alarmComment.getCreatedTime(), TimeUnit.HOURS.toMillis(partitionSizeInHours)); + AlarmCommentEntity saved = alarmCommentRepository.save(new AlarmCommentEntity(alarmComment)); + return DaoUtil.getData(saved); + } + + @Override + public void deleteAlarmComment(AlarmCommentId alarmCommentId){ + log.trace("Try to delete entity alarm comment by id using [{}]", alarmCommentId); + alarmCommentRepository.deleteById(alarmCommentId.getId()); + } + + @Override + public PageData findAlarmComments(AlarmId id, PageLink pageLink){ + log.trace("Try to find alarm comments by alard id using [{}]", id); + return DaoUtil.toPageData( + alarmCommentRepository.findAllByAlarmId(id.getId(), DaoUtil.toPageable(pageLink))); + } + + @Override + public AlarmComment findAlarmCommentById(TenantId tenantId, UUID key) { + return findById(tenantId, key); + } + + @Override + public ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, UUID key) { + return findByIdAsync(tenantId, key); + } + + @Override + protected Class getEntityClass() { + return AlarmCommentEntity.class; + } + + @Override + protected JpaRepository getRepository() { + return alarmCommentRepository; + } +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 9851eead80..3f18d165de 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.cassandra.CassandraCluster; @@ -231,6 +232,8 @@ public interface TbContext { RuleEngineAlarmService getAlarmService(); + AlarmCommentService getAlarmCommentService(); + RuleChainService getRuleChainService(); RuleEngineRpcService getRpcService(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java index 245b671cf5..558e197064 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityFieldsData; +import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; @@ -56,6 +57,9 @@ public class EntitiesFieldsAsyncLoader { case ALARM: return getAsync(ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), (AlarmId) original), EntityFieldsData::new); + case ALARM_COMMENT: + return getAsync(ctx.getAlarmCommentService().findAlarmCommentByIdAsync(ctx.getTenantId(), (AlarmCommentId) original), + EntityFieldsData::new); case RULE_CHAIN: return getAsync(ctx.getRuleChainService().findRuleChainByIdAsync(ctx.getTenantId(), (RuleChainId) original), EntityFieldsData::new); From 201078714c680fefd7c98383876a7ea81c0e4d35 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 14 Dec 2022 12:20:23 +0200 Subject: [PATCH 02/16] added alarm comment info object, refactoring --- .../main/data/upgrade/3.5/schema_update.sql | 2 - .../controller/AlarmCommentController.java | 43 +++++--- .../server/controller/BaseController.java | 6 +- .../DefaultTbNotificationEntityService.java | 8 +- .../entitiy/TbNotificationEntityService.java | 4 +- .../alarm/DefaultTbAlarmCommentService.java | 15 +-- .../entitiy/alarm/TbAlarmCommentService.java | 5 +- .../permission/CustomerUserPermissions.java | 15 +-- .../server/dao/alarm/AlarmCommentService.java | 7 +- .../common/data/alarm/AlarmComment.java | 15 +-- .../common/data/alarm/AlarmCommentInfo.java | 45 +++++++-- .../server/dao/alarm/AlarmCommentDao.java | 7 +- .../dao/alarm/BaseAlarmCommentService.java | 76 ++++++++++----- .../model/sql/AbstractAlarmCommentEntity.java | 97 +++++++++++++++++++ .../dao/model/sql/AlarmCommentEntity.java | 80 ++------------- .../dao/model/sql/AlarmCommentInfoEntity.java | 41 ++++++++ .../server/dao/service/DataValidator.java | 23 +++++ .../validator/AlarmCommentDataValidator.java | 16 +-- .../dao/sql/alarm/AlarmCommentRepository.java | 13 ++- .../dao/sql/alarm/JpaAlarmCommentDao.java | 17 ++-- .../resources/sql/schema-entities-idx.sql | 2 + .../main/resources/sql/schema-entities.sql | 10 ++ 22 files changed, 350 insertions(+), 197 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java diff --git a/application/src/main/data/upgrade/3.5/schema_update.sql b/application/src/main/data/upgrade/3.5/schema_update.sql index 506ac7e38c..e357089e97 100644 --- a/application/src/main/data/upgrade/3.5/schema_update.sql +++ b/application/src/main/data/upgrade/3.5/schema_update.sql @@ -16,8 +16,6 @@ CREATE TABLE IF NOT EXISTS alarm_comment ( id uuid NOT NULL, - tenant_id uuid NOT NULL, - customer_id uuid NOT NULL, created_time bigint NOT NULL, alarm_id uuid NOT NULL, user_id uuid, diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index c4c1bc8de2..256dad8f3d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -27,7 +27,9 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; @@ -36,12 +38,15 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; import org.thingsboard.server.service.security.permission.Operation; -import org.thingsboard.server.service.security.permission.Resource; import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_ALLOWABLE_VALUES; +import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK; @@ -69,10 +74,10 @@ public class AlarmCommentController extends BaseController { public AlarmComment saveAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = "A JSON value representing the comment.") @RequestBody AlarmComment alarmComment) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); - alarmComment.setTenantId(getTenantId()); - alarmComment.setAlarmId(new AlarmId(toUUID(strAlarmId))); - checkEntity(alarmComment.getId(), alarmComment, Resource.ALARM_COMMENT); - return tbAlarmCommentService.saveAlarmComment(alarmComment, getCurrentUser()); + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + alarmComment.setAlarmId(alarmId); + return tbAlarmCommentService.saveAlarmComment(alarm.getTenantId(), alarmComment, getCurrentUser()); } @ApiOperation(value = "Delete Alarm comment(deleteAlarmComment)", @@ -82,9 +87,12 @@ public class AlarmCommentController extends BaseController { @ResponseBody public Boolean deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); - AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strAlarmId)); - AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId, Operation.DELETE); - return tbAlarmCommentService.deleteAlarmComment(alarmComment, getCurrentUser()); + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + + AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strCommentId)); + AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId); + return tbAlarmCommentService.deleteAlarmComment(alarm.getTenantId(), alarmComment, getCurrentUser()); } @ApiOperation(value = "Get Alarm comments (getAlarmComments)", @@ -93,16 +101,23 @@ public class AlarmCommentController extends BaseController { @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET) @ResponseBody - public PageData getAlarmComments( + public PageData getAlarmComments( @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) - @PathVariable(ALARM_ID) String strAlarmCommentId, + @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) - @RequestParam int page + @RequestParam int page, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder ) throws Exception { - AlarmId alarmId = new AlarmId(toUUID(strAlarmCommentId)); - PageLink pageLink = createPageLink(pageSize, page, null, null, null); - return checkNotNull(alarmCommentService.findAlarmComments(alarmId, pageLink).get()); + checkParameter(ALARM_ID, strAlarmId); + AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); + Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + + PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder); + return checkNotNull(alarmCommentService.findAlarmComments(alarm.getTenantId(), alarmId, pageLink).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 965842af46..91de0bf8bd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -536,9 +536,6 @@ public abstract class BaseController { case ALARM: checkAlarmId(new AlarmId(entityId.getId()), operation); return; - case ALARM_COMMENT: - checkAlarmCommentId(new AlarmCommentId(entityId.getId()), operation); - return; case DEVICE: checkDeviceId(new DeviceId(entityId.getId()), operation); return; @@ -721,12 +718,11 @@ public abstract class BaseController { } } - AlarmComment checkAlarmCommentId(AlarmCommentId alarmCommentId, Operation operation) throws ThingsboardException { + AlarmComment checkAlarmCommentId(AlarmCommentId alarmCommentId) throws ThingsboardException { try { validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); AlarmComment alarmComment = alarmCommentService.findAlarmCommentByIdAsync(getCurrentUser().getTenantId(), alarmCommentId).get(); checkNotNull(alarmComment, "Alarm comment with id [" + alarmCommentId + "] is not found"); - accessControlService.checkPermission(getCurrentUser(), Resource.ALARM_COMMENT, operation, alarmCommentId, alarmComment); return alarmComment; } catch (Exception e) { throw handleException(e, false); 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 0bcd605928..7ac30abf78 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 @@ -231,14 +231,14 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyCreateOrUpdateAlarmComment(AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo) { - logEntityAction(alarmComment.getTenantId(), alarmComment.getAlarmId(), alarmComment, alarmComment.getCustomerId(), actionType, user, additionalInfo); + public void notifyCreateOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo) { + logEntityAction(tenantId, alarmComment.getAlarmId(), alarmComment, null, actionType, user, additionalInfo); // TODO: should we send notification to edge? } @Override - public void notifyDeleteAlarmComment(AlarmComment alarmComment, User user, Object... additionalInfo) { - logEntityAction(alarmComment.getTenantId(), alarmComment.getAlarmId(), alarmComment, alarmComment.getCustomerId(), ActionType.DELETED, user, additionalInfo); + public void notifyDeleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user, Object... additionalInfo) { + logEntityAction(tenantId, alarmComment.getAlarmId(), alarmComment, null, ActionType.DELETED, user, additionalInfo); // TODO: should we send notification to edge? } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 6719394d5b..060d0f7a2d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -103,9 +103,9 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo); - void notifyCreateOrUpdateAlarmComment(AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo); + void notifyCreateOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo); - void notifyDeleteAlarmComment(AlarmComment alarmComment, User user, Object... additionalInfo); + void notifyDeleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user, Object... additionalInfo); void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, I entityId, E entity, User user, ActionType actionType, boolean sendNotifyMsgToEdge, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java index e0bfaf10e4..8381d6be32 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -29,22 +30,22 @@ import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @AllArgsConstructor public class DefaultTbAlarmCommentService extends AbstractTbEntityService implements TbAlarmCommentService{ @Override - public AlarmComment saveAlarmComment(AlarmComment alarmComment, User user) throws ThingsboardException { + public AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) throws ThingsboardException { ActionType actionType = alarmComment.getId() == null ? ActionType.ADDED : ActionType.UPDATED; UserId userId = user.getId(); alarmComment.setUserId(userId); try { - AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarmComment).getAlarmComment()); - notificationEntityService.notifyCreateOrUpdateAlarmComment(savedAlarmComment, actionType, user); + AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment).getAlarmComment()); + notificationEntityService.notifyCreateOrUpdateAlarmComment(tenantId, savedAlarmComment, actionType, user); return savedAlarmComment; } catch (Exception e) { - notificationEntityService.logEntityAction(alarmComment.getTenantId(), emptyId(EntityType.ALARM_COMMENT), alarmComment, actionType, user, e); + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM_COMMENT), alarmComment, actionType, user, e); throw e; } } @Override - public Boolean deleteAlarmComment(AlarmComment alarmComment, User user) { - notificationEntityService.notifyDeleteAlarmComment(alarmComment, user); - return alarmCommentService.deleteAlarmComment(alarmComment.getId()).isSuccessful(); + public Boolean deleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) { + notificationEntityService.notifyDeleteAlarmComment(tenantId, alarmComment, user); + return alarmCommentService.deleteAlarmComment(tenantId, alarmComment.getId()).isSuccessful(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java index 375b655af8..7420b2e220 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java @@ -18,9 +18,10 @@ package org.thingsboard.server.service.entitiy.alarm; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.TenantId; public interface TbAlarmCommentService { - AlarmComment saveAlarmComment(AlarmComment alarmComment, User user) throws ThingsboardException; + AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) throws ThingsboardException; - Boolean deleteAlarmComment(AlarmComment alarmComment, User user); + Boolean deleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java index 489d9deb81..3c445b7682 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java @@ -32,7 +32,7 @@ public class CustomerUserPermissions extends AbstractPermissions { public CustomerUserPermissions() { super(); put(Resource.ALARM, customerAlarmPermissionChecker); - put(Resource.ALARM_COMMENT, customerAlarmCommentPermissionChecker); + put(Resource.ALARM_COMMENT, customerAlarmPermissionChecker); put(Resource.ASSET, customerEntityPermissionChecker); put(Resource.DEVICE, customerEntityPermissionChecker); put(Resource.CUSTOMER, customerPermissionChecker); @@ -60,19 +60,6 @@ public class CustomerUserPermissions extends AbstractPermissions { } }; - private static final PermissionChecker customerAlarmCommentPermissionChecker = new PermissionChecker() { - @Override - public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { - if (!user.getTenantId().equals(entity.getTenantId())) { - return false; - } - if (!(entity instanceof HasCustomerId)) { - return false; - } - return user.getCustomerId().equals(((HasCustomerId) entity).getCustomerId()); - } - }; - private static final PermissionChecker customerEntityPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_CREDENTIALS, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES, diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java index 83e6216800..3e92871b85 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.TenantId; @@ -24,11 +25,11 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; public interface AlarmCommentService { - AlarmCommentOperationResult createOrUpdateAlarmComment(AlarmComment alarmComment); + AlarmCommentOperationResult createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment); - AlarmCommentOperationResult deleteAlarmComment(AlarmCommentId alarmCommentId); + AlarmCommentOperationResult deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); - ListenableFuture> findAlarmComments(AlarmId alarmId, PageLink pageLink); + ListenableFuture> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index ce2d11d12f..3271fcf9ff 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -22,25 +22,16 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.BaseData; -import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; -import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.AlarmCommentId; -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; @ApiModel @Data @Builder @AllArgsConstructor -public class AlarmComment extends BaseData implements HasName, HasTenantId, HasCustomerId { - @ApiModelProperty(position = 3, value = "JSON object with Tenant Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) - private TenantId tenantId; - - @ApiModelProperty(position = 4, value = "JSON object with Customer Id", accessMode = ApiModelProperty.AccessMode.READ_ONLY) - private CustomerId customerId; +public class AlarmComment extends BaseData implements HasName { @ApiModelProperty(position = 2, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private EntityId alarmId; @ApiModelProperty(position = 3, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) @@ -81,11 +72,9 @@ public class AlarmComment extends BaseData implements HasName, H public AlarmComment(AlarmComment alarmComment) { super(alarmComment.getId()); this.createdTime = alarmComment.getCreatedTime(); - this.tenantId = alarmComment.getTenantId(); - this.customerId = alarmComment.getCustomerId(); + this.alarmId = alarmComment.getAlarmId(); this.type = alarmComment.getType(); this.comment = alarmComment.getComment(); this.userId = alarmComment.getUserId(); - } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java index 7cbff38d80..a9ece008ac 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java @@ -22,8 +22,11 @@ import io.swagger.annotations.ApiModelProperty; public class AlarmCommentInfo extends AlarmComment{ private static final long serialVersionUID = 2807343093519543377L; - @ApiModelProperty(position = 19, value = "Alarm originator name", example = "Thermostat") - private String userName; + @ApiModelProperty(position = 19, value = "User name", example = "John") + private String firstName; + + @ApiModelProperty(position = 19, value = "User name", example = "Brown") + private String lastName; public AlarmCommentInfo() { super(); @@ -33,17 +36,26 @@ public class AlarmCommentInfo extends AlarmComment{ super(alarmComment); } - public AlarmCommentInfo(AlarmComment alarmComment, String userName) { + public AlarmCommentInfo(AlarmComment alarmComment, String firstName, String lastName) { super(alarmComment); - this.userName = userName; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; } - public String getUserName() { - return userName; + public void setFirstName(String firstName) { + this.firstName = firstName; } - public void setOriginatorName(String originatorName) { - this.userName = originatorName; + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; } @Override @@ -54,14 +66,27 @@ public class AlarmCommentInfo extends AlarmComment{ AlarmCommentInfo alarmCommentInfo = (AlarmCommentInfo) o; - return userName != null ? userName.equals(alarmCommentInfo.userName) : alarmCommentInfo.userName == null; + if (firstName == null) { + if (alarmCommentInfo.firstName != null) + return false; + } else if (!firstName.equals(alarmCommentInfo.firstName)) + return false; + + if (lastName == null) { + if (alarmCommentInfo.lastName != null) + return false; + } else if (!lastName.equals(alarmCommentInfo.lastName)) + return false; + + return true; } @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (userName != null ? userName.hashCode() : 0); + result = 31 * result + (firstName != null ? firstName.hashCode() : 0); + result = 31 * result + (lastName != null ? lastName.hashCode() : 0); return result; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java index e58ca14664..04f2674d39 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.TenantId; @@ -27,12 +28,12 @@ import org.thingsboard.server.dao.Dao; import java.util.UUID; public interface AlarmCommentDao extends Dao { - AlarmComment createAlarmComment(AlarmComment alarmComment); - void deleteAlarmComment(AlarmCommentId alarmCommentId); + AlarmComment createAlarmComment(TenantId tenantId, AlarmComment alarmComment); + void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); AlarmComment findAlarmCommentById(TenantId tenantId, UUID key); - PageData findAlarmComments(AlarmId id, PageLink pageLink); + PageData findAlarmComments(TenantId tenantId, AlarmId id, PageLink pageLink); ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, UUID key); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index d293531dd4..194ef41ffe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -15,13 +15,18 @@ */ package org.thingsboard.server.dao.alarm; +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.TenantId; @@ -30,6 +35,11 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.service.DataValidator; +import org.thingsboard.server.dao.user.UserService; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -40,33 +50,50 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al @Autowired private AlarmCommentDao alarmCommentDao; @Autowired + private UserService userService; + @Autowired private EntityService entityService; @Autowired private DataValidator alarmCommentDataValidator; @Override - public AlarmCommentOperationResult createOrUpdateAlarmComment(AlarmComment alarmComment) { - alarmCommentDataValidator.validate(alarmComment, AlarmComment::getTenantId); - alarmComment.setCustomerId(entityService.fetchEntityCustomerId(alarmComment.getTenantId(), alarmComment.getAlarmId())); + public AlarmCommentOperationResult createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment) { + alarmCommentDataValidator.validate(alarmComment, tenantId); if (alarmComment.getId() == null) { - return createAlarmComment(alarmComment); + return createAlarmComment(tenantId, alarmComment); } else { - return updateAlarmComment(alarmComment); + return updateAlarmComment(tenantId, alarmComment); } } @Override @Transactional - public AlarmCommentOperationResult deleteAlarmComment(AlarmCommentId alarmCommentId) { + public AlarmCommentOperationResult deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId) { log.debug("Deleting Alarm Comment with id: {}", alarmCommentId); AlarmCommentOperationResult result = new AlarmCommentOperationResult(new AlarmComment(), true); - alarmCommentDao.deleteAlarmComment(alarmCommentId); + alarmCommentDao.deleteAlarmComment(tenantId, alarmCommentId); return result; } @Override - public ListenableFuture> findAlarmComments(AlarmId alarmId, PageLink pageLink) { - PageData alarmComments = alarmCommentDao.findAlarmComments(alarmId, pageLink); - return Futures.immediateFuture(alarmComments); + public ListenableFuture> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { + PageData alarmComments = alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); + return fetchAlarmCommentUserNames(tenantId,alarmComments); + } + + private ListenableFuture> fetchAlarmCommentUserNames(TenantId tenantId, PageData alarmComments) { + List> alarmCommentFutures = new ArrayList<>(alarmComments.getData().size()); + for (AlarmCommentInfo alarmCommentInfo : alarmComments.getData()) { + alarmCommentFutures.add(Futures.transform( + userService.findUserByIdAsync(tenantId, alarmCommentInfo.getUserId()), user -> { + alarmCommentInfo.setFirstName(user.getFirstName()); + alarmCommentInfo.setLastName(user.getLastName()); + return alarmCommentInfo; + }, MoreExecutors.directExecutor() + )); + } + return Futures.transform(Futures.successfulAsList(alarmCommentFutures), + alarmCommentInfos -> new PageData<>(alarmCommentInfos, alarmComments.getTotalPages(), alarmComments.getTotalElements(), + alarmComments.hasNext()), MoreExecutors.directExecutor()); } @Override @@ -76,30 +103,35 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId()); } - private AlarmCommentOperationResult createAlarmComment(AlarmComment alarmComment) { + private AlarmCommentOperationResult createAlarmComment(TenantId tenantId, AlarmComment alarmComment) { log.debug("New Alarm comment : {}", alarmComment); if (alarmComment.getType() == null) { alarmComment.setType("OTHER"); } - AlarmComment saved = alarmCommentDao.createAlarmComment(alarmComment); + if (alarmComment.getId() == null) { + UUID uuid = Uuids.timeBased(); + alarmComment.setId(new AlarmCommentId(uuid)); + alarmComment.setCreatedTime(Uuids.unixTimestamp(uuid)); + } + AlarmComment saved = alarmCommentDao.createAlarmComment(tenantId, alarmComment); return new AlarmCommentOperationResult(saved, true, true); } - private AlarmCommentOperationResult updateAlarmComment(AlarmComment newAlarmComment) { + private AlarmCommentOperationResult updateAlarmComment(TenantId tenantId, AlarmComment newAlarmComment) { log.debug("Update Alarm comment : {}", newAlarmComment); - validateId(newAlarmComment.getId(), "Alarm comment id should be specified!"); - AlarmComment existing = alarmCommentDao.findAlarmCommentById(newAlarmComment.getTenantId(), newAlarmComment.getId().getId()); + AlarmComment existing = alarmCommentDao.findAlarmCommentById(tenantId, newAlarmComment.getId().getId()); if (existing != null) { - AlarmComment result = alarmCommentDao.save(newAlarmComment.getTenantId(), merge(existing, newAlarmComment)); + if (newAlarmComment.getComment() != null) { + JsonNode comment = newAlarmComment.getComment(); + UUID uuid = Uuids.timeBased(); + ((ObjectNode) comment).put("edited", "true"); + ((ObjectNode) comment).put("editedOn", Uuids.unixTimestamp(uuid)); + existing.setComment(comment); + } + AlarmComment result = alarmCommentDao.save(tenantId, existing); return new AlarmCommentOperationResult(result, true, true); } return null; } - - private AlarmComment merge(AlarmComment existing, AlarmComment alarmComment) { - existing.setCustomerId(alarmComment.getCustomerId()); - existing.setComment(alarmComment.getComment()); - return existing; - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java new file mode 100644 index 0000000000..089ba0709a --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java @@ -0,0 +1,97 @@ +/** + * 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.model.sql; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +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; +import org.thingsboard.server.dao.util.mapping.JsonStringType; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; +import java.util.UUID; + +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_ALARM_ID; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COMMENT; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TYPE; + +@Data +@EqualsAndHashCode(callSuper = true) +@TypeDef(name = "json", typeClass = JsonStringType.class) +@MappedSuperclass +public abstract class AbstractAlarmCommentEntity extends BaseSqlEntity implements BaseEntity { + + @Column(name = ALARM_COMMENT_ALARM_ID, columnDefinition = "uuid") + private UUID alarmId; + + @Column(name = ModelConstants.ALARM_COMMENT_USER_ID) + private UUID userId; + + @Column(name = ALARM_COMMENT_TYPE) + private String type; + + @Type(type = "json") + @Column(name = ALARM_COMMENT_COMMENT) + private JsonNode comment; + + public AbstractAlarmCommentEntity() { + super(); + } + + public AbstractAlarmCommentEntity(AlarmComment alarmComment) { + if (alarmComment.getId() != null) { + this.setUuid(alarmComment.getUuidId()); + } + this.setCreatedTime(alarmComment.getCreatedTime()); + if (alarmComment.getAlarmId() != null) { + this.alarmId = alarmComment.getAlarmId().getId(); + } + if (alarmComment.getUserId() != null) { + this.userId = alarmComment.getUserId().getId(); + } + if (alarmComment.getType() != null) { + this.type = alarmComment.getType(); + } + this.setComment(alarmComment.getComment()); + } + + public AbstractAlarmCommentEntity(AlarmCommentEntity alarmCommentEntity) { + this.setId(alarmCommentEntity.getId()); + this.setCreatedTime(alarmCommentEntity.getCreatedTime()); + this.userId = alarmCommentEntity.getUserId(); + this.alarmId = alarmCommentEntity.getAlarmId(); + this.type = alarmCommentEntity.getType(); + this.comment = alarmCommentEntity.getComment(); + } + protected AlarmComment toAlarmComment() { + AlarmComment alarmComment = new AlarmComment(new AlarmCommentId(id)); + alarmComment.setCreatedTime(createdTime); + alarmComment.setAlarmId(new AlarmId(alarmId)); + alarmComment.setUserId(new UserId(userId)); + alarmComment.setType(type); + alarmComment.setComment(comment); + return alarmComment; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java index 571c3007e1..6f9a507cbd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentEntity.java @@ -15,33 +15,17 @@ */ package org.thingsboard.server.dao.model.sql; -import com.fasterxml.jackson.databind.JsonNode; import lombok.Data; import lombok.EqualsAndHashCode; -import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.alarm.AlarmComment; -import org.thingsboard.server.common.data.id.AlarmCommentId; -import org.thingsboard.server.common.data.id.AlarmId; -import org.thingsboard.server.common.data.id.CustomerId; -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; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.dao.util.mapping.JsonStringType; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; -import java.util.UUID; -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_ALARM_ID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COLUMN_FAMILY_NAME; -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COMMENT; -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_CUSTOMER_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TENANT_ID_PROPERTY; -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TYPE; @Data @EqualsAndHashCode(callSuper = true) @@ -49,71 +33,23 @@ import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_TYPE @TypeDef(name = "json", typeClass = JsonStringType.class) @Table(name = ALARM_COMMENT_COLUMN_FAMILY_NAME) -public class AlarmCommentEntity extends BaseSqlEntity implements BaseEntity { - - @Column(name = ALARM_COMMENT_TENANT_ID_PROPERTY, columnDefinition = "uuid") - private UUID tenantId; - - @Column(name = ALARM_COMMENT_CUSTOMER_ID_PROPERTY, columnDefinition = "uuid") - private UUID customerId; - @Column(name = ALARM_COMMENT_ALARM_ID, columnDefinition = "uuid") - private UUID alarmId; - - @Column(name = ModelConstants.ALARM_COMMENT_USER_ID) - private UUID userId; - - @Column(name = ALARM_COMMENT_TYPE) - private String type; - - @Type(type = "json") - @Column(name = ALARM_COMMENT_COMMENT) - private JsonNode comment; +public class AlarmCommentEntity extends AbstractAlarmCommentEntity { public AlarmCommentEntity() { super(); } + public AlarmCommentEntity(AlarmCommentInfo alarmCommentInfo) { + super(alarmCommentInfo); + } + public AlarmCommentEntity(AlarmComment alarmComment) { - if (alarmComment.getId() != null) { - this.setUuid(alarmComment.getUuidId()); - } - if (alarmComment.getTenantId() != null) { - this.tenantId = alarmComment.getTenantId().getId(); - } - if (alarmComment.getCustomerId() != null) { - this.customerId = alarmComment.getCustomerId().getId(); - } - this.setCreatedTime(alarmComment.getCreatedTime()); - this.setCreatedTime(alarmComment.getCreatedTime()); - if (alarmComment.getAlarmId() != null) { - this.alarmId = alarmComment.getAlarmId().getId(); - } - if (alarmComment.getUserId() != null) { - this.userId = alarmComment.getUserId().getId(); - } - if (alarmComment.getType() != null) { - this.type = alarmComment.getType(); - } - this.setComment(alarmComment.getComment()); + super(alarmComment); } @Override public AlarmComment toData() { - AlarmComment alarmComment = new AlarmComment(new AlarmCommentId(id)); - alarmComment.setCreatedTime(createdTime); - alarmComment.setAlarmId(new AlarmId(alarmId)); - if (userId != null) { - alarmComment.setUserId(new UserId(userId)); - } - if (tenantId != null) { - alarmComment.setTenantId(TenantId.fromUUID(tenantId)); - } - if (customerId != null) { - alarmComment.setCustomerId(new CustomerId(customerId)); - } - alarmComment.setType(type); - alarmComment.setComment(comment); - return alarmComment; + return super.toAlarmComment(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java new file mode 100644 index 0000000000..3d5dde1fd6 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java @@ -0,0 +1,41 @@ +/** + * 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.model.sql; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; + +@Data +@EqualsAndHashCode(callSuper = true) +public class AlarmCommentInfoEntity extends AbstractAlarmCommentEntity { + + private String firstName; + private String lastName; + + public AlarmCommentInfoEntity() { + super(); + } + + public AlarmCommentInfoEntity(AlarmCommentEntity alarmCommentEntity) { + super(alarmCommentEntity); + } + + @Override + public AlarmCommentInfo toData() { + return new AlarmCommentInfo(super.toAlarmComment(), this.firstName, this.lastName); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index beb4a7ebc1..6efe89df4f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -67,6 +67,29 @@ public abstract class DataValidator> { } } + public D validate(D data, TenantId tenantId) { + try { + if (data == null) { + throw new DataValidationException("Data object can't be null!"); + } + + ConstraintValidator.validateFields(data); + + validateDataImpl(tenantId, data); + D old; + if (data.getId() == null) { + validateCreate(tenantId, data); + old = null; + } else { + old = validateUpdate(tenantId, data); + } + return old; + } catch (DataValidationException e) { + log.error("{} object is invalid: [{}]", data == null ? "Data" : data.getClass().getSimpleName(), e.getMessage()); + throw e; + } + } + protected void validateDataImpl(TenantId tenantId, D data) { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java index 9969de6fe2..d85a58bc6d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmCommentDataValidator.java @@ -17,28 +17,22 @@ package org.thingsboard.server.dao.service.validator; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TenantService; @Component @AllArgsConstructor public class AlarmCommentDataValidator extends DataValidator { - private final TenantService tenantService; - @Override protected void validateDataImpl(TenantId tenantId, AlarmComment alarmComment) { - if (alarmComment.getTenantId() == null) { - throw new DataValidationException("Alarm comment should be assigned to tenant!"); - } else { - if (!tenantService.tenantExists(alarmComment.getTenantId())) { - throw new DataValidationException("Alarm comment is referencing to non-existent tenant!"); - } + if (alarmComment.getComment() == null) { + throw new DataValidationException("Alarm comment should be specified!"); + } + if (alarmComment.getAlarmId() == null) { + throw new DataValidationException("Alarm id should be specified!"); } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java index 1517b35554..be97cb1ee3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmCommentRepository.java @@ -18,12 +18,21 @@ package org.thingsboard.server.dao.sql.alarm; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.thingsboard.server.dao.model.sql.AlarmCommentEntity; +import org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity; import java.util.UUID; public interface AlarmCommentRepository extends JpaRepository { - Page findAllByAlarmId(UUID alarmId, Pageable pageable); - + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity(a) FROM AlarmCommentEntity a " + + "WHERE a.alarmId = :alarmId ", + countQuery = "" + + "SELECT count(a) " + + "FROM AlarmCommentEntity a " + + "WHERE a.alarmId = :alarmId ") + Page findAllByAlarmId(@Param("alarmId") UUID alarmId, + Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java index 440510f37b..39524b565f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.sql.alarm; -import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -24,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.TenantId; @@ -54,34 +54,29 @@ public class JpaAlarmCommentDao extends JpaAbstractDao findAlarmComments(AlarmId id, PageLink pageLink){ + public PageData findAlarmComments(TenantId tenantId, AlarmId id, PageLink pageLink){ log.trace("Try to find alarm comments by alard id using [{}]", id); return DaoUtil.toPageData( alarmCommentRepository.findAllByAlarmId(id.getId(), DaoUtil.toPageable(pageLink))); } - @Override + public AlarmComment findAlarmCommentById(TenantId tenantId, UUID key) { - return findById(tenantId, key); + return DaoUtil.getData(alarmCommentRepository.findById(key)); } @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..302e20a619 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -75,3 +75,5 @@ CREATE INDEX IF NOT EXISTS idx_rule_node_external_id ON rule_node(rule_chain_id, CREATE INDEX IF NOT EXISTS idx_rule_node_type ON rule_node(type); CREATE INDEX IF NOT EXISTS idx_api_usage_state_entity_id ON api_usage_state(entity_id); + +CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id ASC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 73039274a6..4bf12332b2 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -776,3 +776,13 @@ CREATE TABLE IF NOT EXISTS user_auth_settings ( user_id uuid UNIQUE NOT NULL CONSTRAINT fk_user_auth_settings_user_id REFERENCES tb_user(id), two_fa_settings varchar ); + +REATE TABLE IF NOT EXISTS alarm_comment ( + id uuid NOT NULL, + created_time bigint NOT NULL, + alarm_id uuid NOT NULL, + user_id uuid, + type varchar(255) NOT NULL, + comment varchar(1000000), + CONSTRAINT fk_alarm_comment_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE +) PARTITION BY RANGE (created_time); \ No newline at end of file From cdbb5232f12ebbe08be9263019fb073742fc073d Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 14 Dec 2022 12:29:38 +0200 Subject: [PATCH 03/16] updated sql schema update --- application/src/main/data/upgrade/3.5/schema_update.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/upgrade/3.5/schema_update.sql b/application/src/main/data/upgrade/3.5/schema_update.sql index e357089e97..bdc9d1b4fc 100644 --- a/application/src/main/data/upgrade/3.5/schema_update.sql +++ b/application/src/main/data/upgrade/3.5/schema_update.sql @@ -23,4 +23,4 @@ CREATE TABLE IF NOT EXISTS alarm_comment ( comment varchar(1000000), CONSTRAINT fk_alarm_comment_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE ) PARTITION BY RANGE (created_time); -CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id ASC); \ No newline at end of file +CREATE INDEX IF NOT EXISTS idx_alarm_comment_alarm_id ON alarm_comment(alarm_id); \ No newline at end of file From 81ed6a67020476dac2ca76a34fc0f61699e71ded Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 11:26:11 +0200 Subject: [PATCH 04/16] added tests for alarm comment services --- .../controller/AlarmCommentController.java | 4 +- .../DefaultTbNotificationEntityService.java | 10 +- .../entitiy/TbNotificationEntityService.java | 4 +- .../alarm/DefaultTbAlarmCommentService.java | 16 +- .../entitiy/alarm/TbAlarmCommentService.java | 5 +- .../src/main/resources/thingsboard.yml | 1 + .../controller/AbstractNotifyEntityTest.java | 8 +- .../BaseAlarmCommentControllerTest.java | 384 ++++++++++++++++++ .../sql/AlarmCommentControllerSqlTest.java | 23 ++ .../DefaultTbAlarmCommentServiceTest.java | 96 +++++ .../common/data/alarm/AlarmComment.java | 3 + .../common/data/alarm/AlarmCommentInfo.java | 2 +- .../dao/alarm/BaseAlarmCommentService.java | 11 +- .../main/resources/sql/schema-entities.sql | 2 +- .../dao/service/AbstractServiceTest.java | 3 + .../service/BaseAlarmCommentServiceTest.java | 160 ++++++++ .../sql/AlarmCommentServiceSqlTest.java | 23 ++ .../dao/sql/alarm/JpaAlarmCommentDaoTest.java | 90 ++++ 18 files changed, 816 insertions(+), 29 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java create mode 100644 application/src/test/java/org/thingsboard/server/controller/sql/AlarmCommentControllerSqlTest.java create mode 100644 application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/sql/AlarmCommentServiceSqlTest.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDaoTest.java diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index 256dad8f3d..1541b40955 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -77,7 +77,7 @@ public class AlarmCommentController extends BaseController { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); alarmComment.setAlarmId(alarmId); - return tbAlarmCommentService.saveAlarmComment(alarm.getTenantId(), alarmComment, getCurrentUser()); + return tbAlarmCommentService.saveAlarmComment(alarm, alarmComment, getCurrentUser()); } @ApiOperation(value = "Delete Alarm comment(deleteAlarmComment)", @@ -92,7 +92,7 @@ public class AlarmCommentController extends BaseController { AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strCommentId)); AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId); - return tbAlarmCommentService.deleteAlarmComment(alarm.getTenantId(), alarmComment, getCurrentUser()); + return tbAlarmCommentService.deleteAlarmComment(alarm, alarmComment, getCurrentUser()); } @ApiOperation(value = "Get Alarm comments (getAlarmComments)", 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 7ac30abf78..c06d6e8d04 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 @@ -231,15 +231,13 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyCreateOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo) { - logEntityAction(tenantId, alarmComment.getAlarmId(), alarmComment, null, actionType, user, additionalInfo); - // TODO: should we send notification to edge? + public void notifyCreateOrUpdateAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user) { + logEntityAction(alarm.getTenantId(), alarmComment.getId(), alarmComment, alarm.getCustomerId(), actionType, user); } @Override - public void notifyDeleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user, Object... additionalInfo) { - logEntityAction(tenantId, alarmComment.getAlarmId(), alarmComment, null, ActionType.DELETED, user, additionalInfo); - // TODO: should we send notification to edge? + public void notifyDeleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) { + logEntityAction(alarm.getTenantId(), alarmComment.getId(), alarmComment, alarm.getCustomerId(), ActionType.DELETED, user); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 060d0f7a2d..744fa9ddaa 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -103,9 +103,9 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, User user, Object... additionalInfo); - void notifyCreateOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment, ActionType actionType, User user, Object... additionalInfo); + void notifyCreateOrUpdateAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user); - void notifyDeleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user, Object... additionalInfo); + void notifyDeleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user); void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, I entityId, E entity, User user, ActionType actionType, boolean sendNotifyMsgToEdge, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java index 8381d6be32..5359f02b17 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java @@ -19,10 +19,10 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; 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.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -30,22 +30,22 @@ import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @AllArgsConstructor public class DefaultTbAlarmCommentService extends AbstractTbEntityService implements TbAlarmCommentService{ @Override - public AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) throws ThingsboardException { + public AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException { ActionType actionType = alarmComment.getId() == null ? ActionType.ADDED : ActionType.UPDATED; UserId userId = user.getId(); alarmComment.setUserId(userId); try { - AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment).getAlarmComment()); - notificationEntityService.notifyCreateOrUpdateAlarmComment(tenantId, savedAlarmComment, actionType, user); + AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment).getAlarmComment()); + notificationEntityService.notifyCreateOrUpdateAlarmComment(alarm, savedAlarmComment, actionType, user); return savedAlarmComment; } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM_COMMENT), alarmComment, actionType, user, e); + notificationEntityService.logEntityAction(alarm.getTenantId(), emptyId(EntityType.ALARM_COMMENT), alarmComment, actionType, user, e); throw e; } } @Override - public Boolean deleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) { - notificationEntityService.notifyDeleteAlarmComment(tenantId, alarmComment, user); - return alarmCommentService.deleteAlarmComment(tenantId, alarmComment.getId()).isSuccessful(); + public Boolean deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) { + notificationEntityService.notifyDeleteAlarmComment(alarm, alarmComment, user); + return alarmCommentService.deleteAlarmComment(alarm.getTenantId(), alarmComment.getId()).isSuccessful(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java index 7420b2e220..5c4b868097 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmCommentService.java @@ -16,12 +16,13 @@ package org.thingsboard.server.service.entitiy.alarm; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; public interface TbAlarmCommentService { - AlarmComment saveAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user) throws ThingsboardException; + AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException; - Boolean deleteAlarmComment(TenantId tenantId, AlarmComment alarmComment, User user); + Boolean deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user); } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 67f9928c18..cf42b8681f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -584,6 +584,7 @@ audit-log: "user": "${AUDIT_LOG_MASK_USER:W}" "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" "alarm": "${AUDIT_LOG_MASK_ALARM:W}" + "alarm_comment": "${AUDIT_LOG_MASK_ALARM_COMMENT:W}" "entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}" "device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}" "asset_profile": "${AUDIT_LOG_MASK_ASSET_PROFILE:W}" diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 39421a4364..373c5143ac 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -340,6 +340,12 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.argThat(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull()); } + protected void testPushMsgToRuleEngineTime(EntityId matcherOriginatorId, TenantId tenantId, HasName entity, int cntTime) { + tenantId = tenantId.isNullUid() && ((HasTenantId) entity).getTenantId() != null ? ((HasTenantId) entity).getTenantId() : tenantId; + Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), + Mockito.eq(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull()); + } + private void testNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) { EdgeEventActionType edgeEventActionType = ActionType.CREDENTIALS_UPDATED.equals(actionType) ? EdgeEventActionType.CREDENTIALS_UPDATED : edgeTypeByActionType(actionType); @@ -367,7 +373,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.verify(tbClusterService, times(cntTime)).pushMsgToCore(Mockito.any(ToDeviceActorNotificationMsg.class), Mockito.isNull()); } - private void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, + protected void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, int cntTime, Object... additionalInfo) { ArgumentMatcher matcherEntityEquals = entity == null ? Objects::isNull : argument -> argument.toString().equals(entity.toString()); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java new file mode 100644 index 0000000000..5fe3673154 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java @@ -0,0 +1,384 @@ +/** + * 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.controller; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.TextNode; +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.AdditionalAnswers; +import org.mockito.Mockito; +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.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.dao.alarm.AlarmDao; + +import java.util.LinkedList; +import java.util.List; + +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@Slf4j +@ContextConfiguration(classes = {BaseAlarmCommentControllerTest.Config.class}) +public abstract class BaseAlarmCommentControllerTest extends AbstractControllerTest { + + protected Device customerDevice; + protected Alarm alarm; + + static class Config { + @Bean + @Primary + public AlarmDao alarmDao(AlarmDao alarmDao) { + return Mockito.mock(AlarmDao.class, AdditionalAnswers.delegatesTo(alarmDao)); + } + } + + @Before + public void setup() throws Exception { + loginTenantAdmin(); + + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("Test device"); + device.setLabel("Label"); + device.setType("Type"); + device.setCustomerId(customerId); + customerDevice = doPost("/api/device", device, Device.class); + + alarm = Alarm.builder() + .tenantId(tenantId) + .customerId(customerId) + .originator(customerDevice.getId()) + .status(AlarmStatus.ACTIVE_UNACK) + .severity(AlarmSeverity.CRITICAL) + .type("test alarm type") + .build(); + + alarm = doPost("/api/alarm", alarm, Alarm.class); + + resetTokens(); + } + + @After + public void teardown() throws Exception { + Mockito.reset(tbClusterService, auditLogService); + loginSysAdmin(); + deleteDifferentTenant(); + } + + @Test + public void testCreateAlarmCommentViaCustomer() throws Exception { + loginCustomerUser(); + + Mockito.reset(tbClusterService, auditLogService); + + AlarmComment createdComment = createAlarmComment(alarm.getId()); + + testLogEntityAction(createdComment, createdComment.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ADDED, 1); + testPushMsgToRuleEngineTime(createdComment.getId(), tenantId, createdComment, 1); + } + + @Test + public void testCreateAlarmCommentViaTenant() throws Exception { + loginTenantAdmin(); + + Mockito.reset(tbClusterService, auditLogService); + + AlarmComment createdComment = createAlarmComment(alarm.getId()); + Assert.assertEquals("OTHER", createdComment.getType()); + + testLogEntityAction(createdComment, createdComment.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ADDED, 1); + testPushMsgToRuleEngineTime(createdComment.getId(), tenantId, createdComment, 1); + } + + @Test + public void testUpdateAlarmCommentViaCustomer() throws Exception { + loginCustomerUser(); + AlarmComment savedComment = createAlarmComment(alarm.getId()); + + Mockito.reset(tbClusterService, auditLogService); + + JsonNode newComment = JacksonUtil.newObjectNode().set("text", new TextNode("Updated comment")); + savedComment.setComment(newComment); + AlarmComment updatedAlarmComment = saveAlarmComment(alarm.getId(), savedComment); + + Assert.assertNotNull(updatedAlarmComment); + Assert.assertEquals(newComment.get("text"), updatedAlarmComment.getComment().get("text")); + Assert.assertEquals("true", updatedAlarmComment.getComment().get("edited").asText()); + Assert.assertNotNull(updatedAlarmComment.getComment().get("editedOn")); + + testNotifyEntityAllOneTime(updatedAlarmComment, updatedAlarmComment.getId(), updatedAlarmComment.getId(), + tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED); + } + + @Test + public void testUpdateAlarmViaTenant() throws Exception { + loginTenantAdmin(); + AlarmComment savedComment = createAlarmComment(alarm.getId()); + + Mockito.reset(tbClusterService, auditLogService); + + JsonNode newComment = JacksonUtil.newObjectNode().set("text", new TextNode("Updated comment")); + savedComment.setComment(newComment); + AlarmComment updatedAlarmComment = saveAlarmComment(alarm.getId(), savedComment); + + Assert.assertNotNull(updatedAlarmComment); + Assert.assertEquals(newComment.get("text"), updatedAlarmComment.getComment().get("text")); + Assert.assertEquals("true", updatedAlarmComment.getComment().get("edited").asText()); + Assert.assertNotNull(updatedAlarmComment.getComment().get("editedOn")); + + testNotifyEntityAllOneTime(updatedAlarmComment, updatedAlarmComment.getId(), updatedAlarmComment.getId(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED); + } + + @Test + public void testUpdateAlarmViaDifferentTenant() throws Exception { + loginTenantAdmin(); + AlarmComment savedComment = createAlarmComment(alarm.getId()); + + loginDifferentTenant(); + + Mockito.reset(tbClusterService, auditLogService); + JsonNode newComment = JacksonUtil.newObjectNode().set("text", new TextNode("Updated comment")); + savedComment.setComment(newComment); + + doPost("/api/alarm/" + alarm.getId() + "/comment", savedComment) + .andExpect(status().isForbidden()) + .andExpect(statusReason(containsString(msgErrorPermission))); + + testNotifyEntityNever(savedComment.getId(), savedComment); + } + + @Test + public void testUpdateAlarmViaDifferentCustomer() throws Exception { + loginCustomerUser(); + AlarmComment savedComment = createAlarmComment(alarm.getId()); + + loginDifferentCustomer(); + + Mockito.reset(tbClusterService, auditLogService); + JsonNode newComment = JacksonUtil.newObjectNode().set("text", new TextNode("Updated comment")); + savedComment.setComment(newComment); + + doPost("/api/alarm/" + alarm.getId() + "/comment", savedComment) + .andExpect(status().isForbidden()) + .andExpect(statusReason(containsString(msgErrorPermission))); + + testNotifyEntityNever(savedComment.getId(), savedComment); + } + + @Test + public void testDeleteAlarmViaCustomer() throws Exception { + loginCustomerUser(); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId()) + .andExpect(status().isOk()); + + testNotifyEntityOneTimeMsgToEdgeServiceNever(alarmComment, alarmComment.getId(), alarmComment.getId(), + tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED); + } + + @Test + public void testDeleteAlarmViaTenant() throws Exception { + loginTenantAdmin(); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId()) + .andExpect(status().isOk()); + + testNotifyEntityOneTimeMsgToEdgeServiceNever(alarmComment, alarmComment.getId(), alarmComment.getId(), + tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED); + } + + @Test + public void testDeleteAlarmViaDifferentTenant() throws Exception { + loginTenantAdmin(); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + loginDifferentTenant(); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId()) + .andExpect(status().isForbidden()) + .andExpect(statusReason(containsString(msgErrorPermission))); + + testNotifyEntityNever(alarm.getId(), alarm); + } + + @Test + public void testDeleteAlarmViaDifferentCustomer() throws Exception { + loginCustomerUser(); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + loginDifferentCustomer(); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId()) + .andExpect(status().isForbidden()) + .andExpect(statusReason(containsString(msgErrorPermission))); + + testNotifyEntityNever(alarm.getId(), alarm); + } + + @Test + public void testClearAlarmViaCustomer() throws Exception { + loginCustomerUser(); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + Mockito.reset(tbClusterService, auditLogService); + + doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isOk()); + + Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(AlarmStatus.CLEARED_UNACK, foundAlarm.getStatus()); + + } + + @Test + public void testFindAlarmCommentsViaCustomerUser() throws Exception { + loginCustomerUser(); + + List createdAlarmComments = new LinkedList<>(); + + final int size = 10; + for (int i = 0; i < size; i++) { + createdAlarmComments.add( + createAlarmComment(alarm.getId(), RandomStringUtils.randomAlphanumeric(10)) + ); + } + + var response = doGetTyped( + "/api/alarm/" + alarm.getId() + "/comment?page=0&pageSize=" + size, + new TypeReference>() {} + ); + var foundAlarmCommentInfos = response.getData(); + Assert.assertNotNull("Found pageData is null", foundAlarmCommentInfos); + Assert.assertNotEquals( + "Expected alarms are not found!", + 0, foundAlarmCommentInfos.size() + ); + + boolean allMatch = createdAlarmComments.stream() + .allMatch(alarmComment -> foundAlarmCommentInfos.stream() + .map(AlarmCommentInfo::getComment) + .anyMatch(comment -> alarmComment.getComment().equals(comment)) + ); + Assert.assertTrue("Created alarm comment doesn't match any found!", allMatch); + } + + @Test + public void testFindAlarmsViaDifferentCustomerUser() throws Exception { + loginCustomerUser(); + + final int size = 10; + List createdAlarmComments = new LinkedList<>(); + for (int i = 0; i < size; i++) { + createdAlarmComments.add( + createAlarmComment(alarm.getId(), RandomStringUtils.randomAlphanumeric(10)) + ); + } + + loginDifferentCustomer(); + doGet("/api/alarm/" + alarm.getId() + "/comment?page=0&pageSize=" + size) + .andExpect(status().isForbidden()) + .andExpect(statusReason(containsString(msgErrorPermission))); + } + + @Test + public void testFindAlarmCommentsViaPublicCustomer() throws Exception { + loginTenantAdmin(); + + Device device = new Device(); + device.setName("Test Public Device"); + device.setLabel("Label"); + device.setCustomerId(customerId); + device = doPost("/api/device", device, Device.class); + device = doPost("/api/customer/public/device/" + device.getUuidId(), Device.class); + + String publicId = device.getCustomerId().toString(); + + Alarm alarm = Alarm.builder() + .originator(device.getId()) + .status(AlarmStatus.ACTIVE_UNACK) + .severity(AlarmSeverity.CRITICAL) + .type("Test") + .build(); + + alarm = doPost("/api/alarm", alarm, Alarm.class); + + Mockito.reset(tbClusterService, auditLogService); + AlarmComment alarmComment = createAlarmComment(alarm.getId()); + + resetTokens(); + + JsonNode publicLoginRequest = JacksonUtil.toJsonNode("{\"publicId\": \"" + publicId + "\"}"); + JsonNode tokens = doPost("/api/auth/login/public", publicLoginRequest, JsonNode.class); + this.token = tokens.get("token").asText(); + + PageData pageData = doGetTyped( + "/api/alarm/" + alarm.getId() + "/comment" + "?page=0&pageSize=1", new TypeReference>() {} + ); + + Assert.assertNotNull("Found pageData is null", pageData); + Assert.assertNotEquals("Expected alarms are not found!", 0, pageData.getTotalElements()); + + AlarmCommentInfo alarmCommentInfo = pageData.getData().get(0); + boolean equals = alarmComment.getId().equals(alarmCommentInfo.getId()) && alarmComment.getComment().equals(alarmCommentInfo.getComment()); + Assert.assertTrue("Created alarm doesn't match the found one!", equals); + } + + private AlarmComment createAlarmComment(AlarmId alarmId, String text) { + AlarmComment alarmComment = AlarmComment.builder() + .comment(JacksonUtil.newObjectNode().set("text", new TextNode(text))) + .build(); + + return saveAlarmComment(alarmId, alarmComment); + } + private AlarmComment createAlarmComment(AlarmId alarmId) { + return createAlarmComment(alarmId, "Please take a look"); + } + private AlarmComment saveAlarmComment(AlarmId alarmId, AlarmComment alarmComment) { + alarmComment = doPost("/api/alarm/" + alarmId + "/comment", alarmComment, AlarmComment.class); + Assert.assertNotNull(alarmComment); + + return alarmComment; + } +} diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/AlarmCommentControllerSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/AlarmCommentControllerSqlTest.java new file mode 100644 index 0000000000..ecf2791c1c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/sql/AlarmCommentControllerSqlTest.java @@ -0,0 +1,23 @@ +/** + * 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.controller.sql; + +import org.thingsboard.server.controller.BaseAlarmCommentControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class AlarmCommentControllerSqlTest extends BaseAlarmCommentControllerTest { +} diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java new file mode 100644 index 0000000000..808af7d2a1 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java @@ -0,0 +1,96 @@ +/** + * 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.service.entitiy.alarmComment; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +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.AlarmComment; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.dao.alarm.AlarmCommentOperationResult; +import org.thingsboard.server.dao.alarm.AlarmCommentService; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.service.entitiy.TbNotificationEntityService; +import org.thingsboard.server.service.entitiy.alarm.DefaultTbAlarmCommentService; +import org.thingsboard.server.service.executors.DbCallbackExecutorService; +import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; + +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@Slf4j +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = DefaultTbAlarmCommentService.class) +@TestPropertySource(properties = { + "server.log_controller_error_stack_trace=false" +}) +public class DefaultTbAlarmCommentServiceTest { + + @MockBean + protected DbCallbackExecutorService dbExecutor; + @MockBean + protected TbNotificationEntityService notificationEntityService; + @MockBean + protected AlarmService alarmService; + @MockBean + protected AlarmCommentService alarmCommentService; + @MockBean + protected AlarmSubscriptionService alarmSubscriptionService; + @MockBean + protected CustomerService customerService; + @MockBean + protected TbClusterService tbClusterService; + @SpyBean + DefaultTbAlarmCommentService service; + + @Test + public void testSave() throws ThingsboardException { + var alarm = new Alarm(); + var alarmComment = new AlarmComment(); + when(alarmCommentService.createOrUpdateAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(new AlarmCommentOperationResult(alarmComment, true)); + service.saveAlarmComment(alarm, alarmComment, new User()); + + verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarmComment(any(), any(), any(), any()); + } + + @Test + public void testDelete() { + var alarmId = new AlarmId(UUID.randomUUID()); + var alarmCommentId = new AlarmCommentId(UUID.randomUUID()); + + when(alarmCommentService.deleteAlarmComment(Mockito.any(), eq(alarmCommentId))).thenReturn(new AlarmCommentOperationResult(new AlarmComment(), true)); + service.deleteAlarmComment(new Alarm(alarmId), new AlarmComment(alarmCommentId), new User()); + + verify(notificationEntityService, times(1)).notifyDeleteAlarmComment(any(), any(), any()); + } +} \ No newline at end of file diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index 3271fcf9ff..2e3d4eb459 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data.alarm; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -65,6 +66,8 @@ public class AlarmComment extends BaseData implements HasName { } @Override + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @ApiModelProperty(position = 5, required = true, value = "representing comment text", example = "Please take a look") public String getName() { return comment.toString(); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java index a9ece008ac..247e0e5236 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java @@ -19,7 +19,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @ApiModel -public class AlarmCommentInfo extends AlarmComment{ +public class AlarmCommentInfo extends AlarmComment { private static final long serialVersionUID = 2807343093519543377L; @ApiModelProperty(position = 19, value = "User name", example = "John") diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index 194ef41ffe..f55a3564d9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractEntityService; -import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.user.UserService; @@ -52,8 +51,6 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al @Autowired private UserService userService; @Autowired - private EntityService entityService; - @Autowired private DataValidator alarmCommentDataValidator; @Override public AlarmCommentOperationResult createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment) { @@ -77,7 +74,7 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al @Override public ListenableFuture> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { PageData alarmComments = alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); - return fetchAlarmCommentUserNames(tenantId,alarmComments); + return fetchAlarmCommentUserNames(tenantId, alarmComments); } private ListenableFuture> fetchAlarmCommentUserNames(TenantId tenantId, PageData alarmComments) { @@ -85,8 +82,10 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al for (AlarmCommentInfo alarmCommentInfo : alarmComments.getData()) { alarmCommentFutures.add(Futures.transform( userService.findUserByIdAsync(tenantId, alarmCommentInfo.getUserId()), user -> { - alarmCommentInfo.setFirstName(user.getFirstName()); - alarmCommentInfo.setLastName(user.getLastName()); + if (user != null) { + alarmCommentInfo.setFirstName(user.getFirstName()); + alarmCommentInfo.setLastName(user.getLastName()); + } return alarmCommentInfo; }, MoreExecutors.directExecutor() )); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4bf12332b2..290e330630 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -777,7 +777,7 @@ CREATE TABLE IF NOT EXISTS user_auth_settings ( two_fa_settings varchar ); -REATE TABLE IF NOT EXISTS alarm_comment ( +CREATE TABLE IF NOT EXISTS alarm_comment ( id uuid NOT NULL, created_time bigint NOT NULL, alarm_id uuid NOT NULL, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 5ea3874d19..61147120bc 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetProfileService; import org.thingsboard.server.dao.asset.AssetService; @@ -149,6 +150,8 @@ public abstract class AbstractServiceTest { @Autowired protected AlarmService alarmService; + @Autowired + protected AlarmCommentService alarmCommentService; @Autowired protected RuleChainService ruleChainService; 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 new file mode 100644 index 0000000000..e879910515 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmCommentServiceTest.java @@ -0,0 +1,160 @@ +/** + * 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.service; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +import org.thingsboard.common.util.JacksonUtil; +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.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.id.AssetId; +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.security.Authority; + +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { + + public static final String TEST_ALARM = "TEST_ALARM"; + private TenantId tenantId; + private Alarm alarm; + private User user; + + @Before + public void before() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + Assert.assertNotNull(savedTenant); + tenantId = savedTenant.getId(); + + alarm = Alarm.builder().tenantId(tenantId).originator(new AssetId(Uuids.timeBased())) + .type(TEST_ALARM) + .severity(AlarmSeverity.CRITICAL).status(AlarmStatus.ACTIVE_UNACK) + .startTs(System.currentTimeMillis()).build(); + alarm = alarmService.createOrUpdateAlarm(alarm).getAlarm(); + + user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setTenantId(tenantId); + user.setEmail("tenant@thingsboard.org"); + user = userService.saveUser(user); + } + + @After + public void after() { + alarmService.deleteAlarm(tenantId, alarm.getId()); + tenantService.deleteTenant(tenantId); + } + + + @Test + public void testSaveAndFetchAlarmComment() throws ExecutionException, InterruptedException { + AlarmComment alarmComment = AlarmComment.builder().alarmId(alarm.getId()) + .userId(user.getId()) + .type("OTHER") + .comment(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))) + .build(); + + AlarmComment createdComment = alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment).getAlarmComment(); + + Assert.assertNotNull(createdComment); + Assert.assertNotNull(createdComment.getId()); + + Assert.assertEquals(alarm.getId(), createdComment.getAlarmId()); + Assert.assertEquals(user.getId(), createdComment.getUserId()); + Assert.assertEquals("OTHER", createdComment.getType()); + Assert.assertTrue(createdComment.getCreatedTime() > 0); + + AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get(); + Assert.assertEquals(createdComment, fetched); + + PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)).get(); + Assert.assertNotNull(alarmComments.getData()); + Assert.assertEquals(1, alarmComments.getData().size()); + Assert.assertEquals(createdComment, alarmComments.getData().get(0)); + } + + @Test + public void testUpdateAlarmComment() throws ExecutionException, InterruptedException { + UserId userId = new UserId(UUID.randomUUID()); + AlarmComment alarmComment = AlarmComment.builder().alarmId(alarm.getId()) + .userId(userId) + .type("OTHER") + .comment(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))) + .build(); + + AlarmComment createdComment = alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment).getAlarmComment(); + + Assert.assertNotNull(createdComment); + Assert.assertNotNull(createdComment.getId()); + + //update comment + String newComment = "new comment"; + createdComment.setComment(JacksonUtil.newObjectNode().put("text", newComment)); + AlarmComment updatedComment = alarmCommentService.createOrUpdateAlarmComment(tenantId, createdComment).getAlarmComment(); + + Assert.assertEquals(alarm.getId(), updatedComment.getAlarmId()); + Assert.assertEquals(userId, updatedComment.getUserId()); + Assert.assertEquals("OTHER", updatedComment.getType()); + Assert.assertTrue(updatedComment.getCreatedTime() > 0); + Assert.assertEquals(newComment, updatedComment.getComment().get("text").asText()); + Assert.assertEquals("true", updatedComment.getComment().get("edited").asText()); + Assert.assertNotNull(updatedComment.getComment().get("editedOn").asText()); + + AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get(); + Assert.assertEquals(updatedComment, fetched); + + PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)).get(); + Assert.assertNotNull(alarmComments.getData()); + Assert.assertEquals(1, alarmComments.getData().size()); + Assert.assertEquals(new AlarmCommentInfo(updatedComment), alarmComments.getData().get(0)); + } + + @Test + public void testDeleteAlarmComment() throws ExecutionException, InterruptedException { + UserId userId = new UserId(UUID.randomUUID()); + AlarmComment alarmComment = AlarmComment.builder().alarmId(alarm.getId()) + .userId(userId) + .type("OTHER") + .comment(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))) + .build(); + + AlarmComment createdComment = alarmCommentService.createOrUpdateAlarmComment(tenantId, alarmComment).getAlarmComment(); + + Assert.assertNotNull(createdComment); + Assert.assertNotNull(createdComment.getId()); + + Assert.assertTrue("Alarm comment was not deleted when expected", alarmCommentService.deleteAlarmComment(tenantId, createdComment.getId()).isSuccessful()); + + AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get(); + + Assert.assertNull("Alarm comment was returned when it was expected to be null", fetched); + } +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/sql/AlarmCommentServiceSqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/sql/AlarmCommentServiceSqlTest.java new file mode 100644 index 0000000000..510b8659e9 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/sql/AlarmCommentServiceSqlTest.java @@ -0,0 +1,23 @@ +/** + * 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.service.sql; + +import org.thingsboard.server.dao.service.BaseAlarmCommentServiceTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class AlarmCommentServiceSqlTest extends BaseAlarmCommentServiceTest { +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDaoTest.java new file mode 100644 index 0000000000..8530525a63 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDaoTest.java @@ -0,0 +1,90 @@ +/** + * 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.sql.alarm; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.id.AlarmCommentId; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.alarm.AlarmCommentDao; +import org.thingsboard.server.dao.alarm.AlarmDao; + +import java.util.UUID; +import static org.junit.Assert.assertEquals; + +@Slf4j +public class JpaAlarmCommentDaoTest extends AbstractJpaDaoTest { + + @Autowired + private AlarmCommentDao alarmCommentDao; + @Autowired + private AlarmDao alarmDao; + + + @Test + public void testFindAlarmCommentsByAlarmId() { + log.info("Current system time in millis = {}", System.currentTimeMillis()); + UUID tenantId = UUID.randomUUID(); + UUID userId = UUID.randomUUID(); + UUID alarmId1 = UUID.randomUUID(); + UUID alarmId2 = UUID.randomUUID(); + UUID commentId1 = UUID.randomUUID(); + UUID commentId2 = UUID.randomUUID(); + UUID commentId3 = UUID.randomUUID(); + saveAlarm(alarmId1, UUID.randomUUID(), UUID.randomUUID(), "TEST_ALARM"); + saveAlarm(alarmId2, UUID.randomUUID(), UUID.randomUUID(), "TEST_ALARM"); + + saveAlarmComment(commentId1, alarmId1, userId, "OTHER"); + saveAlarmComment(commentId2, alarmId1, userId, "OTHER"); + saveAlarmComment(commentId3, alarmId2, userId, "OTHER"); + + int count = alarmCommentDao.findAlarmComments(TenantId.fromUUID(tenantId), new AlarmId(alarmId1), new PageLink(10, 0)).getData().size(); + assertEquals(2, count); + } + + private void saveAlarm(UUID id, UUID tenantId, UUID deviceId, String type) { + Alarm alarm = new Alarm(); + alarm.setId(new AlarmId(id)); + alarm.setTenantId(TenantId.fromUUID(tenantId)); + alarm.setOriginator(new DeviceId(deviceId)); + alarm.setType(type); + alarm.setPropagate(true); + alarm.setStartTs(System.currentTimeMillis()); + alarm.setEndTs(System.currentTimeMillis()); + alarm.setStatus(AlarmStatus.ACTIVE_UNACK); + alarmDao.save(TenantId.fromUUID(tenantId), alarm); + } + private void saveAlarmComment(UUID id, UUID alarmId, UUID userId, String type) { + AlarmComment alarmComment = new AlarmComment(); + alarmComment.setId(new AlarmCommentId(id)); + alarmComment.setAlarmId(TenantId.fromUUID(alarmId)); + alarmComment.setUserId(new UserId(userId)); + alarmComment.setType(type); + alarmComment.setComment(JacksonUtil.newObjectNode().put("text", RandomStringUtils.randomAlphanumeric(10))); + alarmCommentDao.createAlarmComment(TenantId.fromUUID(UUID.randomUUID()), alarmComment); + } +} From 7203c15dec6d47ae34f4d75bf308b473020e6280 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 15:07:50 +0200 Subject: [PATCH 05/16] fixed pull request comments --- .../main/data/upgrade/{3.5 => 3.4.3}/schema_update.sql | 0 .../server/controller/AlarmCommentController.java | 2 +- .../service/entitiy/TbNotificationEntityService.java | 1 + .../entitiy/alarm/DefaultTbAlarmCommentService.java | 1 + .../server/dao/alarm/AlarmCommentOperationResult.java | 1 - .../server/dao/alarm/AlarmCommentService.java | 2 +- .../server/common/data/alarm/AlarmComment.java | 8 ++++---- .../server/dao/alarm/BaseAlarmCommentService.java | 5 ++--- .../server/dao/model/sql/AlarmCommentInfoEntity.java | 9 +++++++++ .../server/dao/sql/alarm/AlarmCommentRepository.java | 3 ++- .../server/dao/sql/alarm/JpaAlarmCommentDao.java | 4 ++-- .../server/dao/service/BaseAlarmCommentServiceTest.java | 4 ++-- 12 files changed, 25 insertions(+), 15 deletions(-) rename application/src/main/data/upgrade/{3.5 => 3.4.3}/schema_update.sql (100%) diff --git a/application/src/main/data/upgrade/3.5/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.5/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/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index 1541b40955..db8853122b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -118,6 +118,6 @@ public class AlarmCommentController extends BaseController { Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder); - return checkNotNull(alarmCommentService.findAlarmComments(alarm.getTenantId(), alarmId, pageLink).get()); + return checkNotNull(alarmCommentService.findAlarmComments(alarm.getTenantId(), alarmId, pageLink)); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index 744fa9ddaa..6ef53fd7f6 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -106,6 +106,7 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user); void notifyDeleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user); + void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, I entityId, E entity, User user, ActionType actionType, boolean sendNotifyMsgToEdge, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java index 5359f02b17..5904745088 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java @@ -43,6 +43,7 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem throw e; } } + @Override public Boolean deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) { notificationEntityService.notifyDeleteAlarmComment(alarm, alarmComment, user); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java index 3687a03eca..3dc25e02ab 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentOperationResult.java @@ -24,7 +24,6 @@ public class AlarmCommentOperationResult { private final boolean successful; private final boolean created; - public AlarmCommentOperationResult(AlarmComment alarmComment, boolean successful) { this(alarmComment, successful, false); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java index 3e92871b85..04eac2cc15 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java @@ -29,7 +29,7 @@ public interface AlarmCommentService { AlarmCommentOperationResult deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); - ListenableFuture> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); + PageDatafindAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index 2e3d4eb459..05aecdc7f0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -33,13 +33,13 @@ import org.thingsboard.server.common.data.id.UserId; @Builder @AllArgsConstructor public class AlarmComment extends BaseData implements HasName { - @ApiModelProperty(position = 2, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @ApiModelProperty(position = 3, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private EntityId alarmId; - @ApiModelProperty(position = 3, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @ApiModelProperty(position = 4, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private UserId userId; - @ApiModelProperty(position = 4, value = "Defines origination of comment", example = "System/Other", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @ApiModelProperty(position = 5, value = "Defines origination of comment", example = "System/Other", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private String type; - @ApiModelProperty(position = 5, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") + @ApiModelProperty(position = 6, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") private transient JsonNode comment; @ApiModelProperty(position = 1, value = "JSON object with the alarm comment Id. " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index f55a3564d9..33258f58cd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -72,9 +72,8 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al } @Override - public ListenableFuture> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { - PageData alarmComments = alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); - return fetchAlarmCommentUserNames(tenantId, alarmComments); + public PageData findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { + return alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); } private ListenableFuture> fetchAlarmCommentUserNames(TenantId tenantId, PageData alarmComments) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java index 3d5dde1fd6..3bcb49f260 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java @@ -19,6 +19,9 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; +import java.util.HashMap; +import java.util.Map; + @Data @EqualsAndHashCode(callSuper = true) public class AlarmCommentInfoEntity extends AbstractAlarmCommentEntity { @@ -34,6 +37,12 @@ public class AlarmCommentInfoEntity extends AbstractAlarmCommentEntity { - @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity(a) FROM AlarmCommentEntity a " + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity(a, u.firstName, u.lastName) FROM AlarmCommentEntity a " + + "LEFT JOIN UserEntity u on u.id = a.userId " + "WHERE a.alarmId = :alarmId ", countQuery = "" + "SELECT count(a) " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java index 39524b565f..8b8b845b2e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java @@ -55,7 +55,7 @@ public class JpaAlarmCommentDao extends JpaAbstractDao alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)).get(); + PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); Assert.assertNotNull(alarmComments.getData()); Assert.assertEquals(1, alarmComments.getData().size()); Assert.assertEquals(createdComment, alarmComments.getData().get(0)); @@ -131,7 +131,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get(); Assert.assertEquals(updatedComment, fetched); - PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)).get(); + PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); Assert.assertNotNull(alarmComments.getData()); Assert.assertEquals(1, alarmComments.getData().size()); Assert.assertEquals(new AlarmCommentInfo(updatedComment), alarmComments.getData().get(0)); From 955369a7f15eb6a44b4537cf6028cfc1c3e58e05 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 15:14:45 +0200 Subject: [PATCH 06/16] refactoring --- .../dao/alarm/BaseAlarmCommentService.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index 33258f58cd..b7a1554d67 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -76,24 +76,6 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al return alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); } - private ListenableFuture> fetchAlarmCommentUserNames(TenantId tenantId, PageData alarmComments) { - List> alarmCommentFutures = new ArrayList<>(alarmComments.getData().size()); - for (AlarmCommentInfo alarmCommentInfo : alarmComments.getData()) { - alarmCommentFutures.add(Futures.transform( - userService.findUserByIdAsync(tenantId, alarmCommentInfo.getUserId()), user -> { - if (user != null) { - alarmCommentInfo.setFirstName(user.getFirstName()); - alarmCommentInfo.setLastName(user.getLastName()); - } - return alarmCommentInfo; - }, MoreExecutors.directExecutor() - )); - } - return Futures.transform(Futures.successfulAsList(alarmCommentFutures), - alarmCommentInfos -> new PageData<>(alarmCommentInfos, alarmComments.getTotalPages(), alarmComments.getTotalElements(), - alarmComments.hasNext()), MoreExecutors.directExecutor()); - } - @Override public ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) { log.trace("Executing findAlarmCommentByIdAsync [{}]", alarmCommentId); From df31723f580e9e595db04e0249c8d605f82917e6 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 15:37:37 +0200 Subject: [PATCH 07/16] pull request comments --- .../common/data/alarm/AlarmCommentInfo.java | 56 ++----------------- .../server/common/data/id/AlarmCommentId.java | 2 +- .../dao/alarm/BaseAlarmCommentService.java | 6 +- .../dao/sql/alarm/JpaAlarmCommentDao.java | 4 +- 4 files changed, 13 insertions(+), 55 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java index 247e0e5236..dbf603fdbc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java @@ -17,15 +17,19 @@ package org.thingsboard.server.common.data.alarm; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; @ApiModel +@Data +@EqualsAndHashCode(callSuper = true) public class AlarmCommentInfo extends AlarmComment { private static final long serialVersionUID = 2807343093519543377L; - @ApiModelProperty(position = 19, value = "User name", example = "John") + @ApiModelProperty(position = 19, value = "User first name", example = "John") private String firstName; - @ApiModelProperty(position = 19, value = "User name", example = "Brown") + @ApiModelProperty(position = 19, value = "User last name", example = "Brown") private String lastName; public AlarmCommentInfo() { @@ -41,52 +45,4 @@ public class AlarmCommentInfo extends AlarmComment { this.firstName = firstName; this.lastName = lastName; } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - AlarmCommentInfo alarmCommentInfo = (AlarmCommentInfo) o; - - if (firstName == null) { - if (alarmCommentInfo.firstName != null) - return false; - } else if (!firstName.equals(alarmCommentInfo.firstName)) - return false; - - if (lastName == null) { - if (alarmCommentInfo.lastName != null) - return false; - } else if (!lastName.equals(alarmCommentInfo.lastName)) - return false; - - return true; - - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (firstName != null ? firstName.hashCode() : 0); - result = 31 * result + (lastName != null ? lastName.hashCode() : 0); - return result; - } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java index b13b5837a0..3e0c415b0f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/AlarmCommentId.java @@ -26,7 +26,7 @@ import java.util.UUID; @ApiModel public class AlarmCommentId extends UUIDBased implements EntityId{ - private static final long serialVersionUID = 2L; + private static final long serialVersionUID = 1L; @JsonCreator public AlarmCommentId(@JsonProperty("id") UUID id) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index b7a1554d67..1de9080a00 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -63,7 +63,6 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al } @Override - @Transactional public AlarmCommentOperationResult deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId) { log.debug("Deleting Alarm Comment with id: {}", alarmCommentId); AlarmCommentOperationResult result = new AlarmCommentOperationResult(new AlarmComment(), true); @@ -73,13 +72,14 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al @Override public PageData findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { + log.trace("Executing findAlarmComments by alarmId [{}]", alarmId); return alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); } @Override public ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) { - log.trace("Executing findAlarmCommentByIdAsync [{}]", alarmCommentId); - validateId(alarmCommentId, "Incorrect alarmId " + alarmCommentId); + log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId); + validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java index 8b8b845b2e..f36405ce1c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java @@ -69,18 +69,20 @@ public class JpaAlarmCommentDao extends JpaAbstractDao findAlarmComments(TenantId tenantId, AlarmId id, PageLink pageLink){ - log.trace("Try to find alarm comments by alard id using [{}]", id); + log.trace("Try to find alarm comments by alarm id using [{}]", id); return DaoUtil.toPageData( alarmCommentRepository.findAllByAlarmId(id.getId(), DaoUtil.toPageable(pageLink))); } @Override public AlarmComment findAlarmCommentById(TenantId tenantId, UUID key) { + log.trace("Try to find alarm comment by id using [{}]", key); return DaoUtil.getData(alarmCommentRepository.findById(key)); } @Override public ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, UUID key) { + log.trace("Try to find alarm comment by id using [{}]", key); return findByIdAsync(tenantId, key); } From 5ba574af36ef80572e2c86bcf880ad0cd1e5acf0 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 15:42:41 +0200 Subject: [PATCH 08/16] fixed pull request comments --- .../java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java | 2 ++ .../thingsboard/server/dao/alarm/BaseAlarmCommentService.java | 3 +++ .../java/org/thingsboard/server/dao/model/ModelConstants.java | 1 - 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java index 04f2674d39..ff4c77bf7f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java @@ -28,7 +28,9 @@ import org.thingsboard.server.dao.Dao; import java.util.UUID; public interface AlarmCommentDao extends Dao { + AlarmComment createAlarmComment(TenantId tenantId, AlarmComment alarmComment); + void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); AlarmComment findAlarmCommentById(TenantId tenantId, UUID key); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index 1de9080a00..766cac8fbe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -48,10 +48,13 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al @Autowired private AlarmCommentDao alarmCommentDao; + @Autowired private UserService userService; + @Autowired private DataValidator alarmCommentDataValidator; + @Override public AlarmCommentOperationResult createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment) { alarmCommentDataValidator.validate(alarmComment, tenantId); 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 bd462eb6b6..fc5c663d7c 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 @@ -305,7 +305,6 @@ public class ModelConstants { public static final String ALARM_COMMENT_TYPE = "type"; public static final String ALARM_COMMENT_COMMENT = "comment"; - /** * Cassandra entity relation constants. */ From c81e442b35523d1d46e0e69eb33683b360b72acd Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 20 Dec 2022 18:05:33 +0200 Subject: [PATCH 09/16] fixed NPE --- .../server/dao/model/sql/AbstractAlarmCommentEntity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java index 089ba0709a..c8651b86c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmCommentEntity.java @@ -89,7 +89,9 @@ public abstract class AbstractAlarmCommentEntity extends AlarmComment alarmComment = new AlarmComment(new AlarmCommentId(id)); alarmComment.setCreatedTime(createdTime); alarmComment.setAlarmId(new AlarmId(alarmId)); - alarmComment.setUserId(new UserId(userId)); + if (userId != null) { + alarmComment.setUserId(new UserId(userId)); + } alarmComment.setType(type); alarmComment.setComment(comment); return alarmComment; From 2db28e2296787cd2de6202d88e07dafabe87eb8b Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 21 Dec 2022 13:41:42 +0200 Subject: [PATCH 10/16] fixed test --- .../thingsboard/server/dao/alarm/AlarmCommentService.java | 2 +- .../server/dao/service/BaseAlarmCommentServiceTest.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java index 04eac2cc15..4759e2c9f3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java @@ -29,7 +29,7 @@ public interface AlarmCommentService { AlarmCommentOperationResult deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); - PageDatafindAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); + PageData findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); 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 ccdbd08e98..7d9b258ba6 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 @@ -64,6 +64,8 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantId); user.setEmail("tenant@thingsboard.org"); + user.setFirstName("John"); + user.setLastName("Brown"); user = userService.saveUser(user); } @@ -98,7 +100,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); Assert.assertNotNull(alarmComments.getData()); Assert.assertEquals(1, alarmComments.getData().size()); - Assert.assertEquals(createdComment, alarmComments.getData().get(0)); + Assert.assertEquals(createdComment, new AlarmComment(alarmComments.getData().get(0))); } @Test @@ -134,7 +136,7 @@ public abstract class BaseAlarmCommentServiceTest extends AbstractServiceTest { PageData alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); Assert.assertNotNull(alarmComments.getData()); Assert.assertEquals(1, alarmComments.getData().size()); - Assert.assertEquals(new AlarmCommentInfo(updatedComment), alarmComments.getData().get(0)); + Assert.assertEquals(updatedComment, new AlarmComment(alarmComments.getData().get(0))); } @Test From 408afb67f33977449f9bb9e6d1b7c9f141a4efc0 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 21 Dec 2022 16:10:34 +0200 Subject: [PATCH 11/16] fixed test --- .../server/dao/alarm/AlarmCommentService.java | 2 ++ .../server/dao/alarm/BaseAlarmCommentService.java | 7 +++++++ .../rule/engine/util/TenantIdLoader.java | 6 ++++++ .../rule/engine/util/TenantIdLoaderTest.java | 13 +++++++++++++ 4 files changed, 28 insertions(+) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java index 4759e2c9f3..f9274f9a87 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentService.java @@ -33,4 +33,6 @@ public interface AlarmCommentService { ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); + AlarmComment findAlarmCommentById(TenantId tenantId, AlarmCommentId alarmCommentId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java index 766cac8fbe..96ecf8cf96 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmCommentService.java @@ -86,6 +86,13 @@ public class BaseAlarmCommentService extends AbstractEntityService implements Al return alarmCommentDao.findAlarmCommentByIdAsync(tenantId, alarmCommentId.getId()); } + @Override + public AlarmComment findAlarmCommentById(TenantId tenantId, AlarmCommentId alarmCommentId) { + log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId); + validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); + return alarmCommentDao.findById(tenantId, alarmCommentId.getId()); + } + private AlarmCommentOperationResult createAlarmComment(TenantId tenantId, AlarmComment alarmComment) { log.debug("New Alarm comment : {}", alarmComment); if (alarmComment.getType() == null) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/TenantIdLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/TenantIdLoader.java index b687246789..344e35084d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/TenantIdLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/TenantIdLoader.java @@ -18,6 +18,8 @@ package org.thingsboard.rule.engine.util; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasTenantId; +import org.thingsboard.server.common.data.alarm.AlarmComment; +import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.ApiUsageStateId; import org.thingsboard.server.common.data.id.AssetId; @@ -69,6 +71,10 @@ public class TenantIdLoader { case ALARM: tenantEntity = ctx.getAlarmService().findAlarmById(ctxTenantId, new AlarmId(id)); break; + case ALARM_COMMENT: + AlarmComment alarmComment = ctx.getAlarmCommentService().findAlarmCommentById(ctxTenantId, new AlarmCommentId(id)); + tenantEntity = ctx.getAlarmService().findAlarmById(ctxTenantId, new AlarmId(alarmComment.getAlarmId().getId())); + break; case RULE_CHAIN: tenantEntity = ctx.getRuleChainService().findRuleChainById(ctxTenantId, new RuleChainId(id)); break; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java index 8a53148204..4990439e60 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java @@ -41,9 +41,11 @@ import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; @@ -56,6 +58,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -93,6 +96,8 @@ public class TenantIdLoaderTest { @Mock private RuleEngineAlarmService alarmService; @Mock + private AlarmCommentService alarmCommentService; + @Mock private RuleChainService ruleChainService; @Mock private EntityViewService entityViewService; @@ -190,6 +195,14 @@ public class TenantIdLoaderTest { when(ctx.getAlarmService()).thenReturn(alarmService); doReturn(alarm).when(alarmService).findAlarmById(eq(tenantId), any()); + break; + case ALARM_COMMENT: + AlarmComment alarmComment = new AlarmComment(); + alarmComment.setAlarmId(new AlarmId(UUID.randomUUID())); + + when(ctx.getAlarmCommentService()).thenReturn(alarmCommentService); + doReturn(alarmComment).when(alarmCommentService).findAlarmCommentById(eq(tenantId), any()); + break; case RULE_CHAIN: RuleChain ruleChain = new RuleChain(); From 419380712e8a46b0c8bb33d023113cd9000b18d8 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 22 Dec 2022 12:37:48 +0200 Subject: [PATCH 12/16] fixed security test --- .../controller/AlarmCommentController.java | 7 ++++-- .../BaseAlarmCommentControllerTest.java | 23 ++++--------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index db8853122b..b884d5ab6a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.permission.Resource; import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES; @@ -88,7 +89,7 @@ public class AlarmCommentController extends BaseController { public Boolean deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + Alarm alarm = checkAlarmId(alarmId, Operation.DELETE); AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strCommentId)); AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId); @@ -115,7 +116,9 @@ public class AlarmCommentController extends BaseController { ) throws Exception { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); + Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get(); + checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found"); + checkEntityId(alarm.getOriginator(), Operation.READ); PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder); return checkNotNull(alarmCommentService.findAlarmComments(alarm.getTenantId(), alarmId, pageLink)); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java index 5fe3673154..087c77b391 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAlarmCommentControllerTest.java @@ -137,8 +137,8 @@ public abstract class BaseAlarmCommentControllerTest extends AbstractControllerT Assert.assertEquals("true", updatedAlarmComment.getComment().get("edited").asText()); Assert.assertNotNull(updatedAlarmComment.getComment().get("editedOn")); - testNotifyEntityAllOneTime(updatedAlarmComment, updatedAlarmComment.getId(), updatedAlarmComment.getId(), - tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED); + testLogEntityAction(updatedAlarmComment, updatedAlarmComment.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED, 1); + testPushMsgToRuleEngineTime(updatedAlarmComment.getId(), tenantId, updatedAlarmComment, 1); } @Test @@ -157,8 +157,8 @@ public abstract class BaseAlarmCommentControllerTest extends AbstractControllerT Assert.assertEquals("true", updatedAlarmComment.getComment().get("edited").asText()); Assert.assertNotNull(updatedAlarmComment.getComment().get("editedOn")); - testNotifyEntityAllOneTime(updatedAlarmComment, updatedAlarmComment.getId(), updatedAlarmComment.getId(), - tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED); + testLogEntityAction(updatedAlarmComment, updatedAlarmComment.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED, 1); + testPushMsgToRuleEngineTime(updatedAlarmComment.getId(), tenantId, updatedAlarmComment, 1); } @Test @@ -257,21 +257,6 @@ public abstract class BaseAlarmCommentControllerTest extends AbstractControllerT testNotifyEntityNever(alarm.getId(), alarm); } - @Test - public void testClearAlarmViaCustomer() throws Exception { - loginCustomerUser(); - AlarmComment alarmComment = createAlarmComment(alarm.getId()); - - Mockito.reset(tbClusterService, auditLogService); - - doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isOk()); - - Alarm foundAlarm = doGet("/api/alarm/" + alarm.getId(), Alarm.class); - Assert.assertNotNull(foundAlarm); - Assert.assertEquals(AlarmStatus.CLEARED_UNACK, foundAlarm.getStatus()); - - } - @Test public void testFindAlarmCommentsViaCustomerUser() throws Exception { loginCustomerUser(); From c89374e5069c0a174a7e9e32b594566442891e79 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 22 Dec 2022 13:56:45 +0200 Subject: [PATCH 13/16] added ttl service --- .../ttl/AlarmCommentsCleanUpService.java | 62 +++++++++++++++++++ .../src/main/resources/thingsboard.yml | 4 ++ .../alarm/DefaultTbAlarmServiceTest.java | 3 + .../server/dao/alarm/AlarmCommentDao.java | 1 + .../dao/sql/alarm/JpaAlarmCommentDao.java | 8 +++ 5 files changed, 78 insertions(+) create mode 100644 application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java new file mode 100644 index 0000000000..3ea68c90e3 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java @@ -0,0 +1,62 @@ +/** + * 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.service.ttl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.alarm.AlarmCommentDao; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; +import org.thingsboard.server.queue.discovery.PartitionService; + +import java.util.concurrent.TimeUnit; + +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COLUMN_FAMILY_NAME; +import static org.thingsboard.server.dao.model.ModelConstants.AUDIT_LOG_COLUMN_FAMILY_NAME; + +@Service +@ConditionalOnExpression("${sql.ttl.alarm_comments.enabled:true} && ${sql.ttl.alarm_comments.ttl:0} > 0") +@Slf4j +public class AlarmCommentsCleanUpService extends AbstractCleanUpService { + + private final AlarmCommentDao alarmCommentDao; + private final SqlPartitioningRepository partitioningRepository; + + @Value("${sql.ttl.alarm_comments.ttl:0}") + private long ttlInSec; + @Value("${sql.alarm_comments.partition_size:168}") + private int partitionSizeInHours; + + public AlarmCommentsCleanUpService(PartitionService partitionService, AlarmCommentDao alarmCommentDao, SqlPartitioningRepository partitioningRepository) { + super(partitionService); + this.alarmCommentDao = alarmCommentDao; + this.partitioningRepository = partitioningRepository; + } + + @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.audit_logs.checking_interval_ms})}", + fixedDelayString = "${sql.ttl.audit_logs.checking_interval_ms}") + public void cleanUp() { + long auditLogsExpTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec); + if (isSystemTenantPartitionMine()) { + alarmCommentDao.cleanUpAlarmComments(auditLogsExpTime); + } else { + partitioningRepository.cleanupPartitionsCache(ALARM_COMMENT_COLUMN_FAMILY_NAME, auditLogsExpTime, TimeUnit.HOURS.toMillis(partitionSizeInHours)); + } + } + +} diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index cf42b8681f..bc16437f2c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -314,6 +314,10 @@ sql: alarms: checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches + alarms_comments: + enabled: "${SQL_TTL_ALARM_COMMENTS_ENABLED:true}" + ttl: "${SQL_TTL_ALARM_COMMENTS_SECS:0}" # Disabled by default. Accuracy of the cleanup depends on the sql.alarm_comments.partition_size + checking_interval_ms: "${SQL_TTL_ALARM_COMMENTS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day rpc: enabled: "${SQL_TTL_RPC_ENABLED:true}" checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours 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 dba6546fc0..0314788065 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 @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.edge.EdgeService; @@ -62,6 +63,8 @@ public class DefaultTbAlarmServiceTest { @MockBean protected AlarmService alarmService; @MockBean + protected AlarmCommentService alarmCommentService; + @MockBean protected AlarmSubscriptionService alarmSubscriptionService; @MockBean protected CustomerService customerService; diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java index ff4c77bf7f..aa1d3913cb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmCommentDao.java @@ -39,4 +39,5 @@ public interface AlarmCommentDao extends Dao { ListenableFuture findAlarmCommentByIdAsync(TenantId tenantId, UUID key); + void cleanUpAlarmComments(long auditLogsExpTime); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java index f36405ce1c..5691f7a861 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmCommentDao.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.alarm.AlarmCommentDao; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.sql.AlarmCommentEntity; import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; @@ -53,6 +54,8 @@ public class JpaAlarmCommentDao extends JpaAbstractDao getEntityClass() { return AlarmCommentEntity.class; From ae62d2434c71154fdc2736eeb913ddef8bbf70bb Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 23 Dec 2022 11:18:35 +0200 Subject: [PATCH 14/16] updated swagger docs --- .../server/controller/AlarmCommentController.java | 13 ++++++++----- .../server/controller/ControllerConstants.java | 1 + .../service/ttl/AlarmCommentsCleanUpService.java | 10 +++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index b884d5ab6a..4a586027b4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -40,6 +40,8 @@ import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_COMMENT_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; @@ -66,7 +68,8 @@ public class AlarmCommentController extends BaseController { "When creating comment, platform generates Alarm Comment Id as " + UUID_WIKI_LINK + "The newly created Alarm Comment id will be present in the response. Specify existing Alarm Comment id to update the alarm. " + "Referencing non-existing Alarm Comment Id will cause 'Not Found' error. " + - "\nRemove 'id' and optionally 'userId' from the request body example (below) to create new Alarm comment entity. " + + "\n\n To create new Alarm comment entity it is enough to specify 'comment' json element with 'text' node, for example: {\"comment\": { \"text\": \"my comment\"}}. " + + "\n\n If comment type is not specified the default value 'OTHER' will be saved. If 'alarmId' or 'userId' specified in body it will be ignored." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH , produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @@ -81,12 +84,12 @@ public class AlarmCommentController extends BaseController { return tbAlarmCommentService.saveAlarmComment(alarm, alarmComment, getCurrentUser()); } - @ApiOperation(value = "Delete Alarm comment(deleteAlarmComment)", + @ApiOperation(value = "Delete Alarm comment (deleteAlarmComment)", notes = "Deletes the Alarm comment. Referencing non-existing Alarm comment 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}/comment/{commentId}", method = RequestMethod.DELETE) @ResponseBody - public Boolean deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException { + public Boolean deleteAlarmComment(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId, @ApiParam(value = ALARM_COMMENT_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_COMMENT_ID) String strCommentId) throws ThingsboardException { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmId(alarmId, Operation.DELETE); @@ -97,7 +100,7 @@ public class AlarmCommentController extends BaseController { } @ApiOperation(value = "Get Alarm comments (getAlarmComments)", - notes = "Returns a page of alarm comments. " + + notes = "Returns a page of alarm comments for specified alarm. " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/alarm/{alarmId}/comment", method = RequestMethod.GET) @@ -109,7 +112,7 @@ public class AlarmCommentController extends BaseController { @RequestParam int pageSize, @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @RequestParam int page, - @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_SORT_PROPERTY_ALLOWABLE_VALUES) + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) @RequestParam(required = false) String sortOrder 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 5e7622ece5..2deef1e13e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -102,6 +102,7 @@ public class ControllerConstants { protected static final String ASSET_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; protected static final String ASSET_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; + protected static final String ALARM_COMMENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime"; protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "ts, id"; protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root"; diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java index 3ea68c90e3..1c4c2e700b 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmCommentsCleanUpService.java @@ -48,14 +48,14 @@ public class AlarmCommentsCleanUpService extends AbstractCleanUpService { this.partitioningRepository = partitioningRepository; } - @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.audit_logs.checking_interval_ms})}", - fixedDelayString = "${sql.ttl.audit_logs.checking_interval_ms}") + @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.alarm_comments.checking_interval_ms})}", + fixedDelayString = "${sql.ttl.alarm_comments.checking_interval_ms}") public void cleanUp() { - long auditLogsExpTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec); + long commentsExpTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec); if (isSystemTenantPartitionMine()) { - alarmCommentDao.cleanUpAlarmComments(auditLogsExpTime); + alarmCommentDao.cleanUpAlarmComments(commentsExpTime); } else { - partitioningRepository.cleanupPartitionsCache(ALARM_COMMENT_COLUMN_FAMILY_NAME, auditLogsExpTime, TimeUnit.HOURS.toMillis(partitionSizeInHours)); + partitioningRepository.cleanupPartitionsCache(ALARM_COMMENT_COLUMN_FAMILY_NAME, commentsExpTime, TimeUnit.HOURS.toMillis(partitionSizeInHours)); } } From 0427425f8398768141ab716dffc9a7506795b8aa Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 9 Jan 2023 13:06:55 +0200 Subject: [PATCH 15/16] Added email for AlarmCommentInfo --- .../server/common/data/alarm/AlarmCommentInfo.java | 6 +++++- .../server/dao/model/sql/AlarmCommentInfoEntity.java | 7 +++++-- .../server/dao/sql/alarm/AlarmCommentRepository.java | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java index dbf603fdbc..66300e4cdb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmCommentInfo.java @@ -32,6 +32,9 @@ public class AlarmCommentInfo extends AlarmComment { @ApiModelProperty(position = 19, value = "User last name", example = "Brown") private String lastName; + @ApiModelProperty(position = 19, value = "User email address", example = "johnBrown@gmail.com") + private String email; + public AlarmCommentInfo() { super(); } @@ -40,9 +43,10 @@ public class AlarmCommentInfo extends AlarmComment { super(alarmComment); } - public AlarmCommentInfo(AlarmComment alarmComment, String firstName, String lastName) { + public AlarmCommentInfo(AlarmComment alarmComment, String firstName, String lastName, String email) { super(alarmComment); this.firstName = firstName; this.lastName = lastName; + this.email = email; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java index 3bcb49f260..bc9c5841c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmCommentInfoEntity.java @@ -29,6 +29,8 @@ public class AlarmCommentInfoEntity extends AbstractAlarmCommentEntity { - @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity(a, u.firstName, u.lastName) FROM AlarmCommentEntity a " + + @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmCommentInfoEntity(a, u.firstName, u.lastName, u.email) FROM AlarmCommentEntity a " + "LEFT JOIN UserEntity u on u.id = a.userId " + "WHERE a.alarmId = :alarmId ", countQuery = "" + From ed7cd2c25525d2436756eb0d89877caf49ac833f Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 9 Jan 2023 17:53:46 +0200 Subject: [PATCH 16/16] Added Noxss annotations --- .../thingsboard/server/common/data/alarm/AlarmComment.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java index 05aecdc7f0..dae96eb0c2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmComment.java @@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.AlarmCommentId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.validation.Length; +import org.thingsboard.server.common.data.validation.NoXss; @ApiModel @Data @@ -38,6 +40,8 @@ public class AlarmComment extends BaseData implements HasName { @ApiModelProperty(position = 4, value = "JSON object with User id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private UserId userId; @ApiModelProperty(position = 5, value = "Defines origination of comment", example = "System/Other", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @NoXss + @Length(fieldName = "type") private String type; @ApiModelProperty(position = 6, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") private transient JsonNode comment;