115 changed files with 2131 additions and 162 deletions
@ -0,0 +1,127 @@ |
|||
/** |
|||
* 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.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; |
|||
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 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.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; |
|||
|
|||
@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. " + |
|||
"\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')") |
|||
@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); |
|||
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
|||
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); |
|||
alarmComment.setAlarmId(alarmId); |
|||
return tbAlarmCommentService.saveAlarmComment(alarm, 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 void 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); |
|||
|
|||
AlarmCommentId alarmCommentId = new AlarmCommentId(toUUID(strCommentId)); |
|||
AlarmComment alarmComment = checkAlarmCommentId(alarmCommentId, alarmId); |
|||
tbAlarmCommentService.deleteAlarmComment(alarm, alarmComment, getCurrentUser()); |
|||
} |
|||
|
|||
@ApiOperation(value = "Get Alarm comments (getAlarmComments)", |
|||
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) |
|||
@ResponseBody |
|||
public PageData<AlarmCommentInfo> getAlarmComments( |
|||
@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) |
|||
@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, |
|||
@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 |
|||
) throws Exception { |
|||
checkParameter(ALARM_ID, strAlarmId); |
|||
AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
|||
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)); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
/** |
|||
* 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.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.UserId; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
|
|||
@Service |
|||
@AllArgsConstructor |
|||
public class DefaultTbAlarmCommentService extends AbstractTbEntityService implements TbAlarmCommentService{ |
|||
@Override |
|||
public AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException { |
|||
ActionType actionType = alarmComment.getId() == null ? ActionType.ADDED_COMMENT : ActionType.UPDATED_COMMENT; |
|||
UserId userId = user.getId(); |
|||
alarmComment.setUserId(userId); |
|||
try { |
|||
AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment)); |
|||
notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, actionType, user); |
|||
return savedAlarmComment; |
|||
} catch (Exception e) { |
|||
notificationEntityService.logEntityAction(alarm.getTenantId(), emptyId(EntityType.ALARM), alarm, actionType, user, e, alarmComment); |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) { |
|||
alarmCommentService.deleteAlarmComment(alarm.getTenantId(), alarmComment.getId()); |
|||
notificationEntityService.notifyAlarmComment(alarm, alarmComment, ActionType.DELETED_COMMENT, user); |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
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; |
|||
|
|||
public interface TbAlarmCommentService { |
|||
AlarmComment saveAlarmComment(Alarm alarm, AlarmComment alarmComment, User user) throws ThingsboardException; |
|||
|
|||
void deleteAlarmComment(Alarm alarm, AlarmComment alarmComment, User user); |
|||
} |
|||
@ -0,0 +1,363 @@ |
|||
/** |
|||
* 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.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.AlarmCommentType; |
|||
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(alarm, alarm.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ADDED_COMMENT, 1, createdComment); |
|||
} |
|||
|
|||
@Test |
|||
public void testCreateAlarmCommentViaTenant() throws Exception { |
|||
loginTenantAdmin(); |
|||
|
|||
Mockito.reset(tbClusterService, auditLogService); |
|||
|
|||
AlarmComment createdComment = createAlarmComment(alarm.getId()); |
|||
Assert.assertEquals(AlarmCommentType.OTHER, createdComment.getType()); |
|||
|
|||
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ADDED_COMMENT, 1, createdComment); |
|||
} |
|||
|
|||
@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")); |
|||
|
|||
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED_COMMENT, 1, savedComment); |
|||
} |
|||
|
|||
@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")); |
|||
|
|||
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED_COMMENT, 1, updatedAlarmComment); |
|||
} |
|||
|
|||
@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(alarm.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(alarm.getId(), savedComment); |
|||
} |
|||
|
|||
@Test |
|||
public void testDeleteAlarmСommentViaCustomer() throws Exception { |
|||
loginCustomerUser(); |
|||
AlarmComment alarmComment = createAlarmComment(alarm.getId()); |
|||
|
|||
Mockito.reset(tbClusterService, auditLogService); |
|||
|
|||
doDelete("/api/alarm/" + alarm.getId() + "/comment/" + alarmComment.getId()) |
|||
.andExpect(status().isOk()); |
|||
|
|||
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED_COMMENT, 1, alarmComment); |
|||
} |
|||
|
|||
@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()); |
|||
|
|||
testLogEntityAction(alarm, alarm.getId(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED_COMMENT, 1, alarmComment); |
|||
} |
|||
|
|||
@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 testFindAlarmCommentsViaCustomerUser() throws Exception { |
|||
loginCustomerUser(); |
|||
|
|||
List<AlarmComment> 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<PageData<AlarmCommentInfo>>() {} |
|||
); |
|||
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<AlarmComment> 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<AlarmCommentInfo> pageData = doGetTyped( |
|||
"/api/alarm/" + alarm.getId() + "/comment" + "?page=0&pageSize=1", new TypeReference<PageData<AlarmCommentInfo>>() {} |
|||
); |
|||
|
|||
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; |
|||
} |
|||
} |
|||
@ -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 { |
|||
} |
|||
@ -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.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.doNothing; |
|||
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(alarmComment); |
|||
service.saveAlarmComment(alarm, alarmComment, new User()); |
|||
|
|||
verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any()); |
|||
} |
|||
|
|||
@Test |
|||
public void testDelete() { |
|||
var alarmId = new AlarmId(UUID.randomUUID()); |
|||
var alarmCommentId = new AlarmCommentId(UUID.randomUUID()); |
|||
|
|||
doNothing().when(alarmCommentService).deleteAlarmComment(Mockito.any(), eq(alarmCommentId)); |
|||
service.deleteAlarmComment(new Alarm(alarmId), new AlarmComment(alarmCommentId), new User()); |
|||
|
|||
verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any()); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* 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.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; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
|
|||
public interface AlarmCommentService { |
|||
AlarmComment createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment); |
|||
|
|||
void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); |
|||
|
|||
PageData<AlarmCommentInfo> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink); |
|||
|
|||
ListenableFuture<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId); |
|||
|
|||
AlarmComment findAlarmCommentById(TenantId tenantId, AlarmCommentId alarmCommentId); |
|||
|
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
/** |
|||
* 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.annotation.JsonProperty; |
|||
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.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 |
|||
@Builder |
|||
@AllArgsConstructor |
|||
public class AlarmComment extends BaseData<AlarmCommentId> implements HasName { |
|||
@ApiModelProperty(position = 3, value = "JSON object with Alarm id.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) |
|||
private EntityId alarmId; |
|||
@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. System type means comment was created by TB. OTHER type means comment was created by user.", example = "SYSTEM/OTHER", accessMode = ApiModelProperty.AccessMode.READ_ONLY) |
|||
private AlarmCommentType type; |
|||
@ApiModelProperty(position = 6, value = "JSON object with text of comment.", dataType = "com.fasterxml.jackson.databind.JsonNode") |
|||
@NoXss |
|||
@Length(fieldName = "comment", max = 10000) |
|||
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 |
|||
@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(); |
|||
} |
|||
|
|||
public AlarmComment(AlarmComment alarmComment) { |
|||
super(alarmComment.getId()); |
|||
this.createdTime = alarmComment.getCreatedTime(); |
|||
this.alarmId = alarmComment.getAlarmId(); |
|||
this.type = alarmComment.getType(); |
|||
this.comment = alarmComment.getComment(); |
|||
this.userId = alarmComment.getUserId(); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
/** |
|||
* 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; |
|||
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 first name", example = "John") |
|||
private String firstName; |
|||
|
|||
@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(); |
|||
} |
|||
|
|||
public AlarmCommentInfo(AlarmComment alarmComment) { |
|||
super(alarmComment); |
|||
} |
|||
|
|||
public AlarmCommentInfo(AlarmComment alarmComment, String firstName, String lastName, String email) { |
|||
super(alarmComment); |
|||
this.firstName = firstName; |
|||
this.lastName = lastName; |
|||
this.email = email; |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.alarm; |
|||
|
|||
public enum AlarmCommentType { |
|||
|
|||
SYSTEM, OTHER; |
|||
|
|||
} |
|||
@ -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.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 { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@JsonCreator |
|||
public AlarmCommentId(@JsonProperty("id") UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
public static AlarmCommentId fromString(String commentId) { |
|||
return new AlarmCommentId(UUID.fromString(commentId)); |
|||
} |
|||
} |
|||
@ -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.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; |
|||
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> { |
|||
|
|||
AlarmComment createAlarmComment(TenantId tenantId, AlarmComment alarmComment); |
|||
|
|||
void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId); |
|||
|
|||
AlarmComment findAlarmCommentById(TenantId tenantId, UUID key); |
|||
|
|||
PageData<AlarmCommentInfo> findAlarmComments(TenantId tenantId, AlarmId id, PageLink pageLink); |
|||
|
|||
ListenableFuture<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, UUID key); |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
/** |
|||
* 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.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.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.alarm.AlarmComment; |
|||
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; |
|||
import org.thingsboard.server.common.data.alarm.AlarmCommentType; |
|||
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.service.DataValidator; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.dao.service.Validator.validateId; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class BaseAlarmCommentService extends AbstractEntityService implements AlarmCommentService{ |
|||
|
|||
@Autowired |
|||
private AlarmCommentDao alarmCommentDao; |
|||
|
|||
@Autowired |
|||
private DataValidator<AlarmComment> alarmCommentDataValidator; |
|||
|
|||
@Override |
|||
public AlarmComment createOrUpdateAlarmComment(TenantId tenantId, AlarmComment alarmComment) { |
|||
alarmCommentDataValidator.validate(alarmComment, c -> tenantId); |
|||
if (alarmComment.getId() == null) { |
|||
return createAlarmComment(tenantId, alarmComment); |
|||
} else { |
|||
return updateAlarmComment(tenantId, alarmComment); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void deleteAlarmComment(TenantId tenantId, AlarmCommentId alarmCommentId) { |
|||
log.debug("Deleting Alarm Comment with id: {}", alarmCommentId); |
|||
alarmCommentDao.deleteAlarmComment(tenantId, alarmCommentId); |
|||
} |
|||
|
|||
@Override |
|||
public PageData<AlarmCommentInfo> findAlarmComments(TenantId tenantId, AlarmId alarmId, PageLink pageLink) { |
|||
log.trace("Executing findAlarmComments by alarmId [{}]", alarmId); |
|||
return alarmCommentDao.findAlarmComments(tenantId, alarmId, pageLink); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, AlarmCommentId alarmCommentId) { |
|||
log.trace("Executing findAlarmCommentByIdAsync by alarmCommentId [{}]", alarmCommentId); |
|||
validateId(alarmCommentId, "Incorrect alarmCommentId " + alarmCommentId); |
|||
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 AlarmComment createAlarmComment(TenantId tenantId, AlarmComment alarmComment) { |
|||
log.debug("New Alarm comment : {}", alarmComment); |
|||
if (alarmComment.getType() == null) { |
|||
alarmComment.setType(AlarmCommentType.OTHER); |
|||
} |
|||
if (alarmComment.getId() == null) { |
|||
UUID uuid = Uuids.timeBased(); |
|||
alarmComment.setId(new AlarmCommentId(uuid)); |
|||
alarmComment.setCreatedTime(Uuids.unixTimestamp(uuid)); |
|||
} |
|||
return alarmCommentDao.createAlarmComment(tenantId, alarmComment); |
|||
} |
|||
|
|||
private AlarmComment updateAlarmComment(TenantId tenantId, AlarmComment newAlarmComment) { |
|||
log.debug("Update Alarm comment : {}", newAlarmComment); |
|||
|
|||
AlarmComment existing = alarmCommentDao.findAlarmCommentById(tenantId, newAlarmComment.getId().getId()); |
|||
if (existing != null) { |
|||
if (newAlarmComment.getComment() != null) { |
|||
JsonNode comment = newAlarmComment.getComment(); |
|||
((ObjectNode) comment).put("edited", "true"); |
|||
((ObjectNode) comment).put("editedOn", System.currentTimeMillis()); |
|||
existing.setComment(comment); |
|||
} |
|||
return alarmCommentDao.save(tenantId, existing); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
/** |
|||
* 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.alarm.AlarmCommentType; |
|||
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<T extends AlarmComment> extends BaseSqlEntity<T> implements BaseEntity<T> { |
|||
|
|||
@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 AlarmCommentType 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()); |
|||
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)); |
|||
if (userId != null) { |
|||
alarmComment.setUserId(new UserId(userId)); |
|||
} |
|||
alarmComment.setType(type); |
|||
alarmComment.setComment(comment); |
|||
return alarmComment; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/** |
|||
* 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.hibernate.annotations.TypeDef; |
|||
import org.thingsboard.server.common.data.alarm.AlarmComment; |
|||
import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; |
|||
import org.thingsboard.server.dao.util.mapping.JsonStringType; |
|||
|
|||
import javax.persistence.Entity; |
|||
import javax.persistence.Table; |
|||
|
|||
import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COMMENT_COLUMN_FAMILY_NAME; |
|||
|
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@Entity |
|||
@TypeDef(name = "json", typeClass = JsonStringType.class) |
|||
@Table(name = ALARM_COMMENT_COLUMN_FAMILY_NAME) |
|||
|
|||
public class AlarmCommentEntity extends AbstractAlarmCommentEntity<AlarmComment> { |
|||
|
|||
public AlarmCommentEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public AlarmCommentEntity(AlarmCommentInfo alarmCommentInfo) { |
|||
super(alarmCommentInfo); |
|||
} |
|||
|
|||
public AlarmCommentEntity(AlarmComment alarmComment) { |
|||
super(alarmComment); |
|||
} |
|||
|
|||
@Override |
|||
public AlarmComment toData() { |
|||
return super.toAlarmComment(); |
|||
} |
|||
|
|||
} |
|||
@ -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.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<AlarmCommentInfo> { |
|||
|
|||
private String firstName; |
|||
private String lastName; |
|||
|
|||
private String email; |
|||
|
|||
public AlarmCommentInfoEntity() { |
|||
super(); |
|||
} |
|||
|
|||
public AlarmCommentInfoEntity(AlarmCommentEntity alarmCommentEntity) { |
|||
super(alarmCommentEntity); |
|||
} |
|||
|
|||
public AlarmCommentInfoEntity(AlarmCommentEntity alarmCommentEntity, String firstName, String lastName, String email) { |
|||
super(alarmCommentEntity); |
|||
this.firstName = firstName; |
|||
this.lastName = lastName; |
|||
this.email = email; |
|||
} |
|||
|
|||
@Override |
|||
public AlarmCommentInfo toData() { |
|||
return new AlarmCommentInfo(super.toAlarmComment(), this.firstName, this.lastName, this.email); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* 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.alarm.AlarmComment; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.service.DataValidator; |
|||
|
|||
@Component |
|||
@AllArgsConstructor |
|||
public class AlarmCommentDataValidator extends DataValidator<AlarmComment> { |
|||
|
|||
@Override |
|||
protected void validateDataImpl(TenantId tenantId, AlarmComment alarmComment) { |
|||
if (alarmComment.getComment() == null) { |
|||
throw new DataValidationException("Alarm comment should be specified!"); |
|||
} |
|||
if (alarmComment.getAlarmId() == null) { |
|||
throw new DataValidationException("Alarm id should be specified!"); |
|||
} |
|||
} |
|||
} |
|||
@ -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.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<AlarmCommentEntity, UUID> { |
|||
|
|||
@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 = "" + |
|||
"SELECT count(a) " + |
|||
"FROM AlarmCommentEntity a " + |
|||
"WHERE a.alarmId = :alarmId ") |
|||
Page<AlarmCommentInfoEntity> findAllByAlarmId(@Param("alarmId") UUID alarmId, |
|||
Pageable pageable); |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
/** |
|||
* 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.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.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; |
|||
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; |
|||
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<AlarmCommentEntity, AlarmComment> implements AlarmCommentDao { |
|||
private final SqlPartitioningRepository partitioningRepository; |
|||
@Value("${sql.alarm_comments.partition_size:168}") |
|||
private int partitionSizeInHours; |
|||
|
|||
@Autowired |
|||
private AlarmCommentRepository alarmCommentRepository; |
|||
|
|||
@Override |
|||
public AlarmComment createAlarmComment(TenantId tenantId, AlarmComment alarmComment){ |
|||
log.trace("Saving entity {}", alarmComment); |
|||
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(TenantId tenantId, AlarmCommentId alarmCommentId){ |
|||
log.trace("Try to delete entity alarm comment by id using [{}]", alarmCommentId); |
|||
alarmCommentRepository.deleteById(alarmCommentId.getId()); |
|||
} |
|||
|
|||
@Override |
|||
public PageData<AlarmCommentInfo> findAlarmComments(TenantId tenantId, AlarmId id, PageLink pageLink){ |
|||
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<AlarmComment> findAlarmCommentByIdAsync(TenantId tenantId, UUID key) { |
|||
log.trace("Try to find alarm comment by id using [{}]", key); |
|||
return findByIdAsync(tenantId, key); |
|||
} |
|||
|
|||
@Override |
|||
protected Class<AlarmCommentEntity> getEntityClass() { |
|||
return AlarmCommentEntity.class; |
|||
} |
|||
|
|||
@Override |
|||
protected JpaRepository<AlarmCommentEntity, UUID> getRepository() { |
|||
return alarmCommentRepository; |
|||
} |
|||
} |
|||
@ -0,0 +1,164 @@ |
|||
/** |
|||
* 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; |
|||
|
|||
import static org.thingsboard.server.common.data.alarm.AlarmCommentType.OTHER; |
|||
|
|||
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.setFirstName("John"); |
|||
user.setLastName("Brown"); |
|||
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); |
|||
|
|||
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<AlarmCommentInfo> alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); |
|||
Assert.assertNotNull(alarmComments.getData()); |
|||
Assert.assertEquals(1, alarmComments.getData().size()); |
|||
Assert.assertEquals(createdComment, new AlarmComment(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); |
|||
|
|||
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); |
|||
|
|||
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<AlarmCommentInfo> alarmComments = alarmCommentService.findAlarmComments(tenantId, alarm.getId(), new PageLink(10, 0)); |
|||
Assert.assertNotNull(alarmComments.getData()); |
|||
Assert.assertEquals(1, alarmComments.getData().size()); |
|||
Assert.assertEquals(updatedComment, new AlarmComment(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); |
|||
|
|||
Assert.assertNotNull(createdComment); |
|||
Assert.assertNotNull(createdComment.getId()); |
|||
|
|||
alarmCommentService.deleteAlarmComment(tenantId, createdComment.getId()); |
|||
|
|||
AlarmComment fetched = alarmCommentService.findAlarmCommentByIdAsync(tenantId, createdComment.getId()).get(); |
|||
|
|||
Assert.assertNull("Alarm comment was returned when it was expected to be null", fetched); |
|||
} |
|||
} |
|||
@ -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 { |
|||
} |
|||
@ -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.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.AlarmCommentType; |
|||
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, AlarmCommentType.OTHER); |
|||
saveAlarmComment(commentId2, alarmId1, userId, AlarmCommentType.OTHER); |
|||
saveAlarmComment(commentId3, alarmId2, userId, AlarmCommentType.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, AlarmCommentType 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); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue