Browse Source

Merge with 2.5.3

pull/3217/head
Andrii Shvaika 6 years ago
parent
commit
9e331a1768
  1. 31
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  2. 56
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  3. 2
      application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java
  4. 57
      application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
  5. 17
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  6. 374
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  7. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java
  8. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  9. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java
  10. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
  11. 2
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  12. 4
      common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java
  13. 2
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  14. 3
      dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java
  15. 1
      dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
  16. 1
      dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java
  17. 17
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java
  18. 45
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  19. 15
      dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java
  20. 16
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
  21. 3
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java
  22. 10
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java
  23. 2
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  24. 11
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  25. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  26. 4
      ui-ngx/package-lock.json
  27. 8
      ui-ngx/src/app/shared/models/audit-log.models.ts
  28. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json

31
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
@ -26,26 +27,27 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm; 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.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.asset.AssetInfo;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
@ -73,7 +75,6 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
@ -640,6 +641,12 @@ public abstract class BaseController {
case ALARM_CLEAR: case ALARM_CLEAR:
msgType = DataConstants.ALARM_CLEAR; msgType = DataConstants.ALARM_CLEAR;
break; break;
case ASSIGNED_FROM_TENANT:
msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT;
break;
case ASSIGNED_TO_TENANT:
msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT;
break;
} }
if (!StringUtils.isEmpty(msgType)) { if (!StringUtils.isEmpty(msgType)) {
try { try {
@ -659,6 +666,16 @@ public abstract class BaseController {
String strCustomerName = extractParameter(String.class, 2, additionalInfo); String strCustomerName = extractParameter(String.class, 2, additionalInfo);
metaData.putValue("unassignedCustomerId", strCustomerId); metaData.putValue("unassignedCustomerId", strCustomerId);
metaData.putValue("unassignedCustomerName", strCustomerName); metaData.putValue("unassignedCustomerName", strCustomerName);
} else if (actionType == ActionType.ASSIGNED_FROM_TENANT) {
String strTenantId = extractParameter(String.class, 0, additionalInfo);
String strTenantName = extractParameter(String.class, 1, additionalInfo);
metaData.putValue("assignedFromTenantId", strTenantId);
metaData.putValue("assignedFromTenantName", strTenantName);
} else if (actionType == ActionType.ASSIGNED_TO_TENANT) {
String strTenantId = extractParameter(String.class, 0, additionalInfo);
String strTenantName = extractParameter(String.class, 1, additionalInfo);
metaData.putValue("assignedToTenantId", strTenantId);
metaData.putValue("assignedToTenantName", strTenantName);
} }
ObjectNode entityNode; ObjectNode entityNode;
if (entity != null) { if (entity != null) {
@ -722,5 +739,13 @@ public abstract class BaseController {
return result; return result;
} }
protected <E extends HasName> String entityToStr(E entity) {
try {
return json.writeValueAsString(json.valueToTree(entity));
} catch (JsonProcessingException e) {
log.warn("[{}] Failed to convert entity to string!", entity, e);
}
return null;
}
} }

56
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -40,8 +40,10 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
@ -49,6 +51,9 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.device.claim.ClaimResponse; import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.exception.IncorrectParameterException;
@ -71,6 +76,7 @@ public class DeviceController extends BaseController {
private static final String DEVICE_ID = "deviceId"; private static final String DEVICE_ID = "deviceId";
private static final String DEVICE_NAME = "deviceName"; private static final String DEVICE_NAME = "deviceName";
private static final String TENANT_ID = "tenantId";
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET)
@ -547,4 +553,54 @@ public class DeviceController extends BaseController {
} }
return DataConstants.DEFAULT_SECRET_KEY; return DataConstants.DEFAULT_SECRET_KEY;
} }
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}/device/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public Device assignDeviceToTenant(@PathVariable(TENANT_ID) String strTenantId,
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
checkParameter(DEVICE_ID, strDeviceId);
try {
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_TENANT);
TenantId newTenantId = new TenantId(toUUID(strTenantId));
Tenant newTenant = tenantService.findTenantById(newTenantId);
if (newTenant == null) {
throw new ThingsboardException("Could not find the specified Tenant!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device);
logEntityAction(getCurrentUser(), deviceId, assignedDevice,
assignedDevice.getCustomerId(),
ActionType.ASSIGNED_TO_TENANT, null, strTenantId, newTenant.getName());
Tenant currentTenant = tenantService.findTenantById(getTenantId());
pushAssignedFromNotification(currentTenant, newTenantId, assignedDevice);
return assignedDevice;
} catch (Exception e) {
logEntityAction(getCurrentUser(), emptyId(EntityType.DEVICE), null,
null,
ActionType.ASSIGNED_TO_TENANT, e, strTenantId);
throw handleException(e);
}
}
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = entityToStr(assignedDevice);
if (data != null) {
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
}
}
private TbMsgMetaData getMetaDataForAssignedFrom(Tenant tenant) {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("assignedFromTenantId", tenant.getId().getId().toString());
metaData.putValue("assignedFromTenantName", tenant.getName());
return metaData;
}
} }

2
application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java

@ -18,6 +18,6 @@ package org.thingsboard.server.service.security.permission;
public enum Operation { public enum Operation {
ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER, RPC_CALL, ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER, RPC_CALL,
READ_CREDENTIALS, WRITE_CREDENTIALS, READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_TELEMETRY, WRITE_TELEMETRY, CLAIM_DEVICES READ_CREDENTIALS, WRITE_CREDENTIALS, READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_TELEMETRY, WRITE_TELEMETRY, CLAIM_DEVICES, ASSIGN_TO_TENANT
} }

57
application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java

@ -15,74 +15,17 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootContextLoader; import org.springframework.boot.test.context.SpringBootContextLoader;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.http.MockHttpInputMessage;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
import org.thingsboard.server.service.mail.TestMailService;
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest;
import org.thingsboard.server.service.security.auth.rest.LoginRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
@ActiveProfiles("test") @ActiveProfiles("test")
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)

17
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -218,6 +218,7 @@ public abstract class AbstractWebTest {
} }
private Tenant savedDifferentTenant; private Tenant savedDifferentTenant;
protected void loginDifferentTenant() throws Exception { protected void loginDifferentTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
@ -313,6 +314,10 @@ public abstract class AbstractWebTest {
return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass);
} }
protected <T> T doGet(String urlTemplate, Class<T> responseClass, ResultMatcher resultMatcher, Object... urlVariables) throws Exception {
return readResponse(doGet(urlTemplate, urlVariables).andExpect(resultMatcher), responseClass);
}
protected <T> T doGetAsync(String urlTemplate, Class<T> responseClass, Object... urlVariables) throws Exception { protected <T> T doGetAsync(String urlTemplate, Class<T> responseClass, Object... urlVariables) throws Exception {
return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass);
} }
@ -352,9 +357,9 @@ public abstract class AbstractWebTest {
return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType); return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType);
} }
protected <T> T doGetTypedWithTimePageLink(String urlTemplate, TypeReference<T> responseType, protected <T> T doGetTypedWithTimePageLink(String urlTemplate, TypeReference<T> responseType,
TimePageLink pageLink, TimePageLink pageLink,
Object... urlVariables) throws Exception { Object... urlVariables) throws Exception {
List<Object> pageLinkVariables = new ArrayList<>(); List<Object> pageLinkVariables = new ArrayList<>();
urlTemplate += "pageSize={pageSize}&page={page}"; urlTemplate += "pageSize={pageSize}&page={page}";
pageLinkVariables.add(pageLink.getPageSize()); pageLinkVariables.add(pageLink.getPageSize());
@ -395,11 +400,11 @@ public abstract class AbstractWebTest {
return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass); return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
} }
protected <T,R> R doPostWithResponse(String urlTemplate, T content, Class<R> responseClass, String... params) throws Exception { protected <T, R> R doPostWithResponse(String urlTemplate, T content, Class<R> responseClass, String... params) throws Exception {
return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass); return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
} }
protected <T,R> R doPostWithTypedResponse(String urlTemplate, T content, TypeReference<R> responseType, String... params) throws Exception { protected <T, R> R doPostWithTypedResponse(String urlTemplate, T content, TypeReference<R> responseType, String... params) throws Exception {
return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseType); return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseType);
} }
@ -430,7 +435,7 @@ public abstract class AbstractWebTest {
return mockMvc.perform(postRequest); return mockMvc.perform(postRequest);
} }
protected <T> ResultActions doPostAsync(String urlTemplate, T content, Long timeout, String... params) throws Exception { protected <T> ResultActions doPostAsync(String urlTemplate, T content, Long timeout, String... params) throws Exception {
MockHttpServletRequestBuilder postRequest = post(urlTemplate, params); MockHttpServletRequestBuilder postRequest = post(urlTemplate, params);
setJwtToken(postRequest); setJwtToken(postRequest);
String json = json(content); String json = json(content);

374
application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java

@ -15,74 +15,79 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import static org.hamcrest.Matchers.containsString;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.thingsboard.server.common.data.*; import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceCredentialsId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.core.type.TypeReference; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public abstract class BaseDeviceControllerTest extends AbstractControllerTest { public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
private IdComparator<Device> idComparator = new IdComparator<>(); private IdComparator<Device> idComparator = new IdComparator<>();
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class); savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant); Assert.assertNotNull(savedTenant);
tenantAdmin = new User(); tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId()); tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe"); tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs"); tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testSaveDevice() throws Exception { public void testSaveDevice() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
Assert.assertNotNull(savedDevice); Assert.assertNotNull(savedDevice);
Assert.assertNotNull(savedDevice.getId()); Assert.assertNotNull(savedDevice.getId());
Assert.assertTrue(savedDevice.getCreatedTime() > 0); Assert.assertTrue(savedDevice.getCreatedTime() > 0);
@ -90,9 +95,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertNotNull(savedDevice.getCustomerId()); Assert.assertNotNull(savedDevice.getCustomerId());
Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId()); Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId());
Assert.assertEquals(device.getName(), savedDevice.getName()); Assert.assertEquals(device.getName(), savedDevice.getName());
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
Assert.assertNotNull(deviceCredentials); Assert.assertNotNull(deviceCredentials);
Assert.assertNotNull(deviceCredentials.getId()); Assert.assertNotNull(deviceCredentials.getId());
@ -100,10 +105,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType()); Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType());
Assert.assertNotNull(deviceCredentials.getCredentialsId()); Assert.assertNotNull(deviceCredentials.getCredentialsId());
Assert.assertEquals(20, deviceCredentials.getCredentialsId().length()); Assert.assertEquals(20, deviceCredentials.getCredentialsId().length());
savedDevice.setName("My new device"); savedDevice.setName("My new device");
doPost("/api/device", savedDevice, Device.class); doPost("/api/device", savedDevice, Device.class);
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
} }
@ -115,10 +120,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
loginDifferentTenant(); loginDifferentTenant();
doPost("/api/device", savedDevice, Device.class, status().isForbidden()); doPost("/api/device", savedDevice, Device.class, status().isNotFound());
deleteDifferentTenant(); deleteDifferentTenant();
} }
@Test @Test
public void testFindDeviceById() throws Exception { public void testFindDeviceById() throws Exception {
Device device = new Device(); Device device = new Device();
@ -133,26 +138,27 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Test @Test
public void testFindDeviceTypesByTenantId() throws Exception { public void testFindDeviceTypesByTenantId() throws Exception {
List<Device> devices = new ArrayList<>(); List<Device> devices = new ArrayList<>();
for (int i=0;i<3;i++) { for (int i = 0; i < 3; i++) {
Device device = new Device(); Device device = new Device();
device.setName("My device B"+i); device.setName("My device B" + i);
device.setType("typeB"); device.setType("typeB");
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
for (int i=0;i<7;i++) { for (int i = 0; i < 7; i++) {
Device device = new Device(); Device device = new Device();
device.setName("My device C"+i); device.setName("My device C" + i);
device.setType("typeC"); device.setType("typeC");
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
for (int i=0;i<9;i++) { for (int i = 0; i < 9; i++) {
Device device = new Device(); Device device = new Device();
device.setName("My device A"+i); device.setName("My device A" + i);
device.setType("typeA"); device.setType("typeA");
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types", List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types",
new TypeReference<List<EntitySubtype>>(){}); new TypeReference<List<EntitySubtype>>() {
});
Assert.assertNotNull(deviceTypes); Assert.assertNotNull(deviceTypes);
Assert.assertEquals(3, deviceTypes.size()); Assert.assertEquals(3, deviceTypes.size());
@ -160,19 +166,19 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals("typeB", deviceTypes.get(1).getType()); Assert.assertEquals("typeB", deviceTypes.get(1).getType());
Assert.assertEquals("typeC", deviceTypes.get(2).getType()); Assert.assertEquals("typeC", deviceTypes.get(2).getType());
} }
@Test @Test
public void testDeleteDevice() throws Exception { public void testDeleteDevice() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doDelete("/api/device/"+savedDevice.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/device/"+savedDevice.getId().getId().toString()) doDelete("/api/device/" + savedDevice.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isOk());
doGet("/api/device/" + savedDevice.getId().getId().toString())
.andExpect(status().isNotFound());
} }
@Test @Test
@ -189,52 +195,51 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Device device = new Device(); Device device = new Device();
device.setType("default"); device.setType("default");
doPost("/api/device", device) doPost("/api/device", device)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device name should be specified"))); .andExpect(statusReason(containsString("Device name should be specified")));
} }
@Test @Test
public void testAssignUnassignDeviceToCustomer() throws Exception { public void testAssignUnassignDeviceToCustomer() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("My customer"); customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString() Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class); + "/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId());
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId());
Device unassignedDevice = Device unassignedDevice =
doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class); doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId());
foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId()); Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId());
} }
@Test @Test
public void testAssignDeviceToNonExistentCustomer() throws Exception { public void testAssignDeviceToNonExistentCustomer() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + Uuids.timeBased().toString() doPost("/api/customer/" + Uuids.timeBased().toString()
+ "/device/" + savedDevice.getId().getId().toString()) + "/device/" + savedDevice.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test @Test
public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant2 = new Tenant(); Tenant tenant2 = new Tenant();
tenant2.setTitle("Different tenant"); tenant2.setTitle("Different tenant");
Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
@ -246,103 +251,103 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
tenantAdmin2.setEmail("tenant3@thingsboard.org"); tenantAdmin2.setEmail("tenant3@thingsboard.org");
tenantAdmin2.setFirstName("Joe"); tenantAdmin2.setFirstName("Joe");
tenantAdmin2.setLastName("Downs"); tenantAdmin2.setLastName("Downs");
tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1");
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("Different customer"); customer.setTitle("Different customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
login(tenantAdmin.getEmail(), "testPassword1"); login(tenantAdmin.getEmail(), "testPassword1");
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + savedCustomer.getId().getId().toString() doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/device/" + savedDevice.getId().getId().toString()) + "/device/" + savedDevice.getId().getId().toString())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/"+savedTenant2.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testFindDeviceCredentialsByDeviceId() throws Exception { public void testFindDeviceCredentialsByDeviceId() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
} }
@Test @Test
public void testSaveDeviceCredentials() throws Exception { public void testSaveDeviceCredentials() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId("access_token"); deviceCredentials.setCredentialsId("access_token");
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isOk()); .andExpect(status().isOk());
DeviceCredentials foundDeviceCredentials = DeviceCredentials foundDeviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(deviceCredentials, foundDeviceCredentials); Assert.assertEquals(deviceCredentials, foundDeviceCredentials);
} }
@Test @Test
public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception { public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception {
DeviceCredentials deviceCredentials = new DeviceCredentials(); DeviceCredentials deviceCredentials = new DeviceCredentials();
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()); .andExpect(status().isBadRequest());
} }
@Test @Test
public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsType(null); deviceCredentials.setCredentialsType(null);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device credentials type should be specified"))); .andExpect(statusReason(containsString("Device credentials type should be specified")));
} }
@Test @Test
public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsId(null); deviceCredentials.setCredentialsId(null);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device credentials id should be specified"))); .andExpect(statusReason(containsString("Device credentials id should be specified")));
} }
@Test @Test
public void testSaveNonExistentDeviceCredentials() throws Exception { public void testSaveNonExistentDeviceCredentials() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(Uuids.timeBased())); DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(Uuids.timeBased()));
newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime()); newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime());
@ -350,29 +355,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType());
newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId());
doPost("/api/device/credentials", newDeviceCredentials) doPost("/api/device/credentials", newDeviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Unable to update non-existent device credentials"))); .andExpect(statusReason(containsString("Unable to update non-existent device credentials")));
} }
@Test @Test
public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased())); deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased()));
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test @Test
public void testFindTenantDevices() throws Exception { public void testFindTenantDevices() throws Exception {
List<Device> devices = new ArrayList<>(); List<Device> devices = new ArrayList<>();
for (int i=0;i<178;i++) { for (int i = 0; i < 178; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device"+i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
@ -380,28 +385,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Device> pageData = null; PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevices.addAll(pageData.getData()); loadedDevices.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devices, idComparator); Collections.sort(devices, idComparator);
Collections.sort(loadedDevices, idComparator); Collections.sort(loadedDevices, idComparator);
Assert.assertEquals(devices, loadedDevices); Assert.assertEquals(devices, loadedDevices);
} }
@Test @Test
public void testFindTenantDevicesByName() throws Exception { public void testFindTenantDevicesByName() throws Exception {
String title1 = "Device title 1"; String title1 = "Device title 1";
List<Device> devicesTitle1 = new ArrayList<>(); List<Device> devicesTitle1 = new ArrayList<>();
for (int i=0;i<143;i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title1+suffix; String name = title1 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
@ -409,37 +415,37 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
} }
String title2 = "Device title 2"; String title2 = "Device title 2";
List<Device> devicesTitle2 = new ArrayList<>(); List<Device> devicesTitle2 = new ArrayList<>();
for (int i=0;i<75;i++) { for (int i = 0; i < 75; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title2+suffix; String name = title2 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
devicesTitle2.add(doPost("/api/device", device, Device.class)); devicesTitle2.add(doPost("/api/device", device, Device.class));
} }
List<Device> loadedDevicesTitle1 = new ArrayList<>(); List<Device> loadedDevicesTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Device> pageData = null; PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevicesTitle1.addAll(pageData.getData()); loadedDevicesTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle1, idComparator); Collections.sort(devicesTitle1, idComparator);
Collections.sort(loadedDevicesTitle1, idComparator); Collections.sort(loadedDevicesTitle1, idComparator);
Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); Assert.assertEquals(devicesTitle1, loadedDevicesTitle1);
List<Device> loadedDevicesTitle2 = new ArrayList<>(); List<Device> loadedDevicesTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevicesTitle2.addAll(pageData.getData()); loadedDevicesTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
@ -449,25 +455,23 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Collections.sort(devicesTitle2, idComparator); Collections.sort(devicesTitle2, idComparator);
Collections.sort(loadedDevicesTitle2, idComparator); Collections.sort(loadedDevicesTitle2, idComparator);
Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); Assert.assertEquals(devicesTitle2, loadedDevicesTitle2);
for (Device device : loadedDevicesTitle1) { for (Device device : loadedDevicesTitle1) {
doDelete("/api/device/"+device.getId().getId().toString()) doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesTitle2) { for (Device device : loadedDevicesTitle2) {
doDelete("/api/device/"+device.getId().getId().toString()) doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
@ -480,10 +484,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title1 = "Device title 1"; String title1 = "Device title 1";
String type1 = "typeA"; String type1 = "typeA";
List<Device> devicesType1 = new ArrayList<>(); List<Device> devicesType1 = new ArrayList<>();
for (int i=0;i<143;i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title1+suffix; String name = title1 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type1); device.setType(type1);
@ -492,10 +496,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title2 = "Device title 2"; String title2 = "Device title 2";
String type2 = "typeB"; String type2 = "typeB";
List<Device> devicesType2 = new ArrayList<>(); List<Device> devicesType2 = new ArrayList<>();
for (int i=0;i<75;i++) { for (int i = 0; i < 75; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title2+suffix; String name = title2 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type2); device.setType(type2);
@ -536,7 +540,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(devicesType2, loadedDevicesType2); Assert.assertEquals(devicesType2, loadedDevicesType2);
for (Device device : loadedDevicesType1) { for (Device device : loadedDevicesType1) {
doDelete("/api/device/"+device.getId().getId().toString()) doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@ -547,7 +551,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesType2) { for (Device device : loadedDevicesType2) {
doDelete("/api/device/"+device.getId().getId().toString()) doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@ -557,42 +561,42 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@Test @Test
public void testFindCustomerDevices() throws Exception { public void testFindCustomerDevices() throws Exception {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("Test customer"); customer.setTitle("Test customer");
customer = doPost("/api/customer", customer, Customer.class); customer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
List<Device> devices = new ArrayList<>(); List<Device> devices = new ArrayList<>();
for (int i=0;i<128;i++) { for (int i = 0; i < 128; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device"+i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); device = doPost("/api/device", device, Device.class);
devices.add(doPost("/api/customer/" + customerId.getId().toString() devices.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class)); + "/device/" + device.getId().getId().toString(), Device.class));
} }
List<Device> loadedDevices = new ArrayList<>(); List<Device> loadedDevices = new ArrayList<>();
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Device> pageData = null; PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevices.addAll(pageData.getData()); loadedDevices.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devices, idComparator); Collections.sort(devices, idComparator);
Collections.sort(loadedDevices, idComparator); Collections.sort(loadedDevices, idComparator);
Assert.assertEquals(devices, loadedDevices); Assert.assertEquals(devices, loadedDevices);
} }
@Test @Test
public void testFindCustomerDevicesByName() throws Exception { public void testFindCustomerDevicesByName() throws Exception {
Customer customer = new Customer(); Customer customer = new Customer();
@ -602,52 +606,52 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title1 = "Device title 1"; String title1 = "Device title 1";
List<Device> devicesTitle1 = new ArrayList<>(); List<Device> devicesTitle1 = new ArrayList<>();
for (int i=0;i<125;i++) { for (int i = 0; i < 125; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title1+suffix; String name = title1 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); device = doPost("/api/device", device, Device.class);
devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class)); + "/device/" + device.getId().getId().toString(), Device.class));
} }
String title2 = "Device title 2"; String title2 = "Device title 2";
List<Device> devicesTitle2 = new ArrayList<>(); List<Device> devicesTitle2 = new ArrayList<>();
for (int i=0;i<143;i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title2+suffix; String name = title2 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); device = doPost("/api/device", device, Device.class);
devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString()
+ "/device/" + device.getId().getId().toString(), Device.class)); + "/device/" + device.getId().getId().toString(), Device.class));
} }
List<Device> loadedDevicesTitle1 = new ArrayList<>(); List<Device> loadedDevicesTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Device> pageData = null; PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevicesTitle1.addAll(pageData.getData()); loadedDevicesTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle1, idComparator); Collections.sort(devicesTitle1, idComparator);
Collections.sort(loadedDevicesTitle1, idComparator); Collections.sort(loadedDevicesTitle1, idComparator);
Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); Assert.assertEquals(devicesTitle1, loadedDevicesTitle1);
List<Device> loadedDevicesTitle2 = new ArrayList<>(); List<Device> loadedDevicesTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
loadedDevicesTitle2.addAll(pageData.getData()); loadedDevicesTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
@ -657,25 +661,23 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Collections.sort(devicesTitle2, idComparator); Collections.sort(devicesTitle2, idComparator);
Collections.sort(loadedDevicesTitle2, idComparator); Collections.sort(loadedDevicesTitle2, idComparator);
Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); Assert.assertEquals(devicesTitle2, loadedDevicesTitle2);
for (Device device : loadedDevicesTitle1) { for (Device device : loadedDevicesTitle1) {
doDelete("/api/customer/device/" + device.getId().getId().toString()) doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesTitle2) { for (Device device : loadedDevicesTitle2) {
doDelete("/api/customer/device/" + device.getId().getId().toString()) doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); new TypeReference<PageData<Device>>(){}, pageLink);
@ -693,10 +695,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title1 = "Device title 1"; String title1 = "Device title 1";
String type1 = "typeC"; String type1 = "typeC";
List<Device> devicesType1 = new ArrayList<>(); List<Device> devicesType1 = new ArrayList<>();
for (int i=0;i<125;i++) { for (int i = 0; i < 125; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title1+suffix; String name = title1 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type1); device.setType(type1);
@ -707,10 +709,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title2 = "Device title 2"; String title2 = "Device title 2";
String type2 = "typeD"; String type2 = "typeD";
List<Device> devicesType2 = new ArrayList<>(); List<Device> devicesType2 = new ArrayList<>();
for (int i=0;i<143;i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
String name = title2+suffix; String name = title2 + suffix;
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type2); device.setType(type2);
@ -775,4 +777,54 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@Test
public void testAssignDeviceToTenant() throws Exception {
Device device = new Device();
device.setName("My device");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
Device anotherDevice = new Device();
anotherDevice.setName("My device1");
anotherDevice.setType("default");
Device savedAnotherDevice = doPost("/api/device", anotherDevice, Device.class);
EntityRelation relation = new EntityRelation();
relation.setFrom(savedDevice.getId());
relation.setTo(savedAnotherDevice.getId());
relation.setTypeGroup(RelationTypeGroup.COMMON);
relation.setType("Contains");
doPost("/api/relation", relation).andExpect(status().isOk());
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("Different tenant");
Tenant savedDifferentTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedDifferentTenant);
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(savedDifferentTenant.getId());
user.setEmail("tenant9@thingsboard.org");
user.setFirstName("Sam");
user.setLastName("Downs");
createUserAndLogin(user, "testPassword1");
login("tenant2@thingsboard.org", "testPassword1");
Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class);
doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class, status().isNotFound());
login("tenant9@thingsboard.org", "testPassword1");
Device foundDevice1 = doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class);
Assert.assertNotNull(foundDevice1);
doGet("/api/relation?fromId=" + savedDevice.getId().getId() + "&fromType=DEVICE&relationType=Contains&toId=" + savedAnotherDevice.getId().getId() + "&toType=DEVICE", EntityRelation.class, status().isNotFound());
loginSysAdmin();
doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString())
.andExpect(status().isOk());
}
} }

3
common/dao-api/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java

@ -16,14 +16,12 @@
package org.thingsboard.server.dao.audit; package org.thingsboard.server.dao.audit;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.audit.AuditLog; import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
@ -49,5 +47,4 @@ public interface AuditLogService {
E entity, E entity,
ActionType actionType, ActionType actionType,
Exception e, Object... additionalInfo); Exception e, Object... additionalInfo);
} }

2
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -76,4 +76,6 @@ public interface DeviceService {
ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId); ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId);
Device assignDeviceToTenant(TenantId tenantId, Device device);
} }

2
common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java

@ -41,4 +41,6 @@ public interface EventService {
List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit); List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit);
void removeEvents(TenantId tenantId, EntityId entityId);
} }

3
common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java

@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
/** /**
* Created by ashvayka on 27.04.17. * Created by ashvayka on 27.04.17.
@ -77,6 +76,8 @@ public interface RelationService {
ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(TenantId tenantId, EntityRelationsQuery query); ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(TenantId tenantId, EntityRelationsQuery query);
void removeRelations(TenantId tenantId, EntityId entityId);
// TODO: This method may be useful for some validations in the future // TODO: This method may be useful for some validations in the future
// ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to); // ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to);

2
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -57,6 +57,8 @@ public class DataConstants {
public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED";
public static final String ALARM_ACK = "ALARM_ACK"; public static final String ALARM_ACK = "ALARM_ACK";
public static final String ALARM_CLEAR = "ALARM_CLEAR"; public static final String ALARM_CLEAR = "ALARM_CLEAR";
public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT";
public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT";
public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE"; public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE";

4
common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java

@ -40,7 +40,9 @@ public enum ActionType {
ALARM_CLEAR(false), ALARM_CLEAR(false),
LOGIN(false), LOGIN(false),
LOGOUT(false), LOGOUT(false),
LOCKOUT(false); LOCKOUT(false),
ASSIGNED_FROM_TENANT(false),
ASSIGNED_TO_TENANT(false);
private final boolean isRead; private final boolean isRead;

2
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -163,7 +163,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
try { try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get(); List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get();
if (entityViews != null && !entityViews.isEmpty()) { if (entityViews != null && !entityViews.isEmpty()) {
throw new DataValidationException("Can't delete asset that is assigned to entity views!"); throw new DataValidationException("Can't delete asset that has entity views!");
} }
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
log.error("Exception while finding entity views for assetId [{}]", assetId, e); log.error("Exception while finding entity views for assetId [{}]", assetId, e);

3
dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogDao.java

@ -23,11 +23,12 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.Dao;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface AuditLogDao { public interface AuditLogDao extends Dao<AuditLog> {
ListenableFuture<Void> saveByTenantId(AuditLog auditLog); ListenableFuture<Void> saveByTenantId(AuditLog auditLog);

1
dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java

@ -163,6 +163,7 @@ public class AuditLogServiceImpl implements AuditLogService {
case ALARM_ACK: case ALARM_ACK:
case ALARM_CLEAR: case ALARM_CLEAR:
case RELATIONS_DELETED: case RELATIONS_DELETED:
case ASSIGNED_TO_TENANT:
if (entity != null) { if (entity != null) {
ObjectNode entityNode = objectMapper.valueToTree(entity); ObjectNode entityNode = objectMapper.valueToTree(entity);
if (entityId.getEntityType() == EntityType.DASHBOARD) { if (entityId.getEntityType() == EntityType.DASHBOARD) {

1
dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java

@ -58,5 +58,4 @@ public class DummyAuditLogServiceImpl implements AuditLogService {
public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) {
return null; return null;
} }
} }

17
dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java

@ -166,4 +166,21 @@ public interface DeviceDao extends Dao<Device> {
* @return the list of tenant device type objects * @return the list of tenant device type objects
*/ */
ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId); ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId);
/**
* Find devices by tenantId and device id.
* @param tenantId the tenant Id
* @param id the device Id
* @return the device object
*/
Device findDeviceByTenantIdAndId(TenantId tenantId, UUID id);
/**
* Find devices by tenantId and device id.
* @param tenantId tenantId the tenantId
* @param id the deviceId
* @return the device object
*/
ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id);
} }

45
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -28,6 +28,8 @@ import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -50,6 +52,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.PaginatedRemover;
@ -98,6 +101,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
@Autowired @Autowired
private CacheManager cacheManager; private CacheManager cacheManager;
@Autowired
private EventService eventService;
@Override @Override
public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceInfoById [{}]", deviceId); log.trace("Executing findDeviceInfoById [{}]", deviceId);
@ -109,14 +115,22 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { public Device findDeviceById(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId); log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
return deviceDao.findById(tenantId, deviceId.getId()); if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
return deviceDao.findById(tenantId, deviceId.getId());
} else {
return deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId());
}
} }
@Override @Override
public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) { public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) {
log.trace("Executing findDeviceById [{}]", deviceId); log.trace("Executing findDeviceById [{}]", deviceId);
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
return deviceDao.findByIdAsync(tenantId, deviceId.getId()); if (TenantId.SYS_TENANT_ID.equals(tenantId)) {
return deviceDao.findByIdAsync(tenantId, deviceId.getId());
} else {
return deviceDao.findDeviceByTenantIdAndIdAsync(tenantId, deviceId.getId());
}
} }
@Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}") @Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}")
@ -187,7 +201,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
try { try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get();
if (entityViews != null && !entityViews.isEmpty()) { if (entityViews != null && !entityViews.isEmpty()) {
throw new DataValidationException("Can't delete device that is assigned to entity views!"); throw new DataValidationException("Can't delete device that has entity views!");
} }
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); log.error("Exception while finding entity views for deviceId [{}]", deviceId, e);
@ -353,6 +367,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} }
@Transactional
@CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}")
@Override
public Device assignDeviceToTenant(TenantId tenantId, Device device) {
log.trace("Executing assignDeviceToTenant [{}][{}]", tenantId, device);
try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), device.getId()).get();
if (!CollectionUtils.isEmpty(entityViews)) {
throw new DataValidationException("Can't assign device that has entity views to another tenant!");
}
} catch (ExecutionException | InterruptedException e) {
log.error("Exception while finding entity views for deviceId [{}]", device.getId(), e);
throw new RuntimeException("Exception while finding entity views for deviceId [" + device.getId() + "]", e);
}
eventService.removeEvents(device.getTenantId(), device.getId());
relationService.removeRelations(device.getTenantId(), device.getId());
device.setTenantId(tenantId);
device.setCustomerId(null);
return doSaveDevice(device, null);
}
private DataValidator<Device> deviceValidator = private DataValidator<Device> deviceValidator =
new DataValidator<Device>() { new DataValidator<Device>() {

15
dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java

@ -92,6 +92,21 @@ public class BaseEventService implements EventService {
return eventDao.findLatestEvents(tenantId.getId(), entityId, eventType, limit); return eventDao.findLatestEvents(tenantId.getId(), entityId, eventType, limit);
} }
@Override
public void removeEvents(TenantId tenantId, EntityId entityId) {
PageData<Event> eventPageData;
TimePageLink eventPageLink = new TimePageLink(1000);
do {
eventPageData = findEvents(tenantId, entityId, eventPageLink);
for (Event event : eventPageData.getData()) {
eventDao.removeById(tenantId, event.getUuidId());
}
if (eventPageData.hasNext()) {
eventPageLink = eventPageLink.nextPageLink();
}
} while (eventPageData.hasNext());
}
private DataValidator<Event> eventValidator = private DataValidator<Event> eventValidator =
new DataValidator<Event>() { new DataValidator<Event>() {
@Override @Override

16
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

@ -506,6 +506,22 @@ public class BaseRelationService implements RelationService {
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} }
@Override
public void removeRelations(TenantId tenantId, EntityId entityId) {
Cache cache = cacheManager.getCache(RELATIONS_CACHE);
List<EntityRelation> relations = new ArrayList<>();
for (RelationTypeGroup relationTypeGroup : RelationTypeGroup.values()) {
relations.addAll(findByFrom(tenantId, entityId, relationTypeGroup));
relations.addAll(findByTo(tenantId, entityId, relationTypeGroup));
}
for (EntityRelation relation : relations) {
cacheEviction(relation, cache);
deleteRelation(tenantId, relation);
}
}
protected void validate(EntityRelation relation) { protected void validate(EntityRelation relation) {
if (relation == null) { if (relation == null) {
throw new DataValidationException("Relation type should be specified!"); throw new DataValidationException("Relation type should be specified!");

3
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java

@ -127,4 +127,7 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(UUID tenantId, UUID customerId, List<UUID> deviceIds); List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(UUID tenantId, UUID customerId, List<UUID> deviceIds);
List<DeviceEntity> findDevicesByTenantIdAndIdIn(UUID tenantId, List<UUID> deviceIds); List<DeviceEntity> findDevicesByTenantIdAndIdIn(UUID tenantId, List<UUID> deviceIds);
DeviceEntity findByTenantIdAndId(UUID tenantId, UUID id);
} }

10
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java

@ -175,6 +175,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
return service.submit(() -> convertTenantDeviceTypesToDto(tenantId, deviceRepository.findTenantDeviceTypes(tenantId))); return service.submit(() -> convertTenantDeviceTypesToDto(tenantId, deviceRepository.findTenantDeviceTypes(tenantId)));
} }
@Override
public Device findDeviceByTenantIdAndId(TenantId tenantId, UUID id) {
return DaoUtil.getData(deviceRepository.findByTenantIdAndId(tenantId.getId(), id));
}
@Override
public ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id) {
return service.submit(() -> DaoUtil.getData(deviceRepository.findByTenantIdAndId(tenantId.getId(), id)));
}
private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) {
List<EntitySubtype> list = Collections.emptyList(); List<EntitySubtype> list = Collections.emptyList();
if (types != null && !types.isEmpty()) { if (types != null && !types.isEmpty()) {

2
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -113,7 +113,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
public User saveUser(User user) { public User saveUser(User user) {
log.trace("Executing saveUser [{}]", user); log.trace("Executing saveUser [{}]", user);
userValidator.validate(user, User::getTenantId); userValidator.validate(user, User::getTenantId);
if (user.getId() == null && !userLoginCaseSensitive) { if (!userLoginCaseSensitive) {
user.setEmail(user.getEmail().toLowerCase()); user.setEmail(user.getEmail().toLowerCase());
} }
User savedUser = userDao.save(user.getTenantId(), user); User savedUser = userDao.save(user.getTenantId(), user);

11
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java

@ -25,8 +25,10 @@ import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@ -56,8 +58,13 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig
@Override @Override
protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) { protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) {
String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData()); String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData());
ListenableFuture<Alarm> latest = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), alarmType); ListenableFuture<Alarm> alarmFuture;
return Futures.transformAsync(latest, a -> { if(msg.getOriginator().getEntityType().equals(EntityType.ALARM)){
alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), new AlarmId(msg.getOriginator().getId()));
} else {
alarmFuture = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), alarmType);
}
return Futures.transformAsync(alarmFuture, a -> {
if (a != null && !a.getStatus().isCleared()) { if (a != null && !a.getStatus().isCleared()) {
return clearAlarm(ctx, msg, a); return clearAlarm(ctx, msg, a);
} }

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java

@ -16,8 +16,13 @@
package org.thingsboard.rule.engine.filter; package org.thingsboard.rule.engine.filter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@ -30,7 +35,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
configClazz = EmptyNodeConfiguration.class, configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event",
"Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned",
"Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other"}, "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant"},
nodeDescription = "Route incoming messages by Message Type", nodeDescription = "Route incoming messages by Message Type",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
@ -81,6 +86,10 @@ public class TbMsgTypeSwitchNode implements TbNode {
relationType = "Alarm Cleared"; relationType = "Alarm Cleared";
} else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) { } else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) {
relationType = "RPC Request to Device"; relationType = "RPC Request to Device";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_FROM_TENANT)) {
relationType = "Entity Assigned From Tenant";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) {
relationType = "Entity Assigned To Tenant";
} else { } else {
relationType = "Other"; relationType = "Other";
} }

4
ui-ngx/package-lock.json

@ -8997,10 +8997,10 @@
"integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw==" "integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw=="
}, },
"ngx-flowchart": { "ngx-flowchart": {
"version": "git://github.com/thingsboard/ngx-flowchart.git#7a02f4748b5e7821a883c903107af5f20415d026", "version": "git://github.com/thingsboard/ngx-flowchart.git#a4157b0eef2eb3646ef920447c7b06b39d54f87f",
"from": "git://github.com/thingsboard/ngx-flowchart.git#master", "from": "git://github.com/thingsboard/ngx-flowchart.git#master",
"requires": { "requires": {
"tslib": "^1.13.0" "tslib": "^1.10.0"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {

8
ui-ngx/src/app/shared/models/audit-log.models.ts

@ -49,7 +49,9 @@ export enum ActionType {
ALARM_CLEAR = 'ALARM_CLEAR', ALARM_CLEAR = 'ALARM_CLEAR',
LOGIN = 'LOGIN', LOGIN = 'LOGIN',
LOGOUT = 'LOGOUT', LOGOUT = 'LOGOUT',
LOCKOUT = 'LOCKOUT' LOCKOUT = 'LOCKOUT',
ASSIGNED_FROM_TENANT = 'ASSIGNED_FROM_TENANT',
ASSIGNED_TO_TENANT = 'ASSIGNED_TO_TENANT'
} }
export enum ActionStatus { export enum ActionStatus {
@ -79,7 +81,9 @@ export const actionTypeTranslations = new Map<ActionType, string>(
[ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'], [ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'],
[ActionType.LOGIN, 'audit-log.type-login'], [ActionType.LOGIN, 'audit-log.type-login'],
[ActionType.LOGOUT, 'audit-log.type-logout'], [ActionType.LOGOUT, 'audit-log.type-logout'],
[ActionType.LOCKOUT, 'audit-log.type-lockout'] [ActionType.LOCKOUT, 'audit-log.type-lockout'],
[ActionType.ASSIGNED_FROM_TENANT, 'audit-log.type-assigned-from-tenant'],
[ActionType.ASSIGNED_TO_TENANT, 'audit-log.type-assigned-to-tenant']
] ]
); );

4
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -371,7 +371,9 @@
"action-data": "Action data", "action-data": "Action data",
"failure-details": "Failure details", "failure-details": "Failure details",
"search": "Search audit logs", "search": "Search audit logs",
"clear-search": "Clear search" "clear-search": "Clear search",
"type-assigned-from-tenant": "Assigned from Tenant",
"type-assigned-to-tenant": "Assigned to Tenant"
}, },
"confirm-on-exit": { "confirm-on-exit": {
"message": "You have unsaved changes. Are you sure you want to leave this page?", "message": "You have unsaved changes. Are you sure you want to leave this page?",

Loading…
Cancel
Save