Browse Source

Merge remote-tracking branch 'origin/develop/3.5' into feature/notification-system

# Conflicts:
#	application/src/main/java/org/thingsboard/server/controller/BaseController.java
pull/7911/head
ViacheslavKlimov 3 years ago
parent
commit
dd5c970b3a
  1. 17
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  2. 54
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  3. 334
      application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java
  4. 39
      common/data/src/main/java/org/thingsboard/server/common/data/UserEmailInfo.java
  5. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java
  6. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  7. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java

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

@ -97,6 +97,8 @@ import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.query.EntityDataSortOrder;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.common.data.rpc.Rpc;
import org.thingsboard.server.common.data.rule.RuleChain;
@ -169,6 +171,8 @@ import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.StringUtils.isNotEmpty;
import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD;
import static org.thingsboard.server.controller.ControllerConstants.INCORRECT_TENANT_ID;
import static org.thingsboard.server.controller.UserController.YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION;
import static org.thingsboard.server.dao.service.Validator.validateId;
@ -850,4 +854,17 @@ public abstract class BaseController {
return deferredResult;
}
protected EntityDataSortOrder createEntityDataSortOrder(String sortProperty, String sortOrder) {
if (isNotEmpty(sortProperty)) {
EntityDataSortOrder entityDataSortOrder = new EntityDataSortOrder();
entityDataSortOrder.setKey(new EntityKey(ENTITY_FIELD, sortProperty));
if (isNotEmpty(sortOrder)) {
entityDataSortOrder.setDirection(EntityDataSortOrder.Direction.valueOf(sortOrder));
}
return entityDataSortOrder;
} else {
return null;
}
}
}

54
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -21,6 +21,7 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
@ -38,7 +39,9 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserEmailInfo;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
@ -46,6 +49,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityTypeFilter;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.security.UserSettings;
@ -53,6 +61,7 @@ import org.thingsboard.server.common.data.security.event.UserCredentialsInvalida
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.user.TbUserService;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.service.query.EntityQueryService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
@ -63,7 +72,10 @@ import org.thingsboard.server.service.security.system.SystemSecurityService;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEFAULT_DASHBOARD;
@ -106,6 +118,9 @@ public class UserController extends BaseController {
private final ApplicationEventPublisher eventPublisher;
private final TbUserService tbUserService;
@Autowired
private EntityQueryService entityQueryService;
@ApiOperation(value = "Get User (getUserById)",
notes = "Fetch the User object based on the provided User Id. " +
"If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
@ -304,6 +319,44 @@ public class UserController extends BaseController {
}
}
@ApiOperation(value = "Find users by query (findUsersByQuery)",
notes = "Returns page of user data objects. Search is been executed by email, firstName and " +
"lastName fields. " + PAGE_DATA_PARAMETERS + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/users/info", method = RequestMethod.GET)
@ResponseBody
public PageData<UserEmailInfo> findUsersByQuery(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page,
@ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
SecurityUser securityUser = getCurrentUser();
EntityTypeFilter entityFilter = new EntityTypeFilter();
entityFilter.setEntityType(EntityType.USER);
EntityDataPageLink pageLink = new EntityDataPageLink(pageSize, page, textSearch, createEntityDataSortOrder(sortProperty, sortOrder));
List<EntityKey> entityFields = Arrays.asList(new EntityKey(ENTITY_FIELD, "firstName"),
new EntityKey(ENTITY_FIELD, "lastName"),
new EntityKey(ENTITY_FIELD, "email"));
EntityDataQuery query = new EntityDataQuery(entityFilter, pageLink, entityFields, null, null);
return entityQueryService.findEntityDataByQuery(securityUser, query).mapData(entityData ->
{
Map<String, TsValue> fieldValues = entityData.getLatest().get(ENTITY_FIELD);
return new UserEmailInfo(UserId.fromString(entityData.getEntityId().getId().toString()),
fieldValues.get("email").getValue(),
fieldValues.get("firstName").getValue(),
fieldValues.get("lastName").getValue());
});
}
@ApiOperation(value = "Get Tenant Users (getTenantAdmins)",
notes = "Returns a page of users owned by tenant. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@ -434,4 +487,5 @@ public class UserController extends BaseController {
SecurityUser currentUser = getCurrentUser();
userSettingsService.deleteUserSettings(currentUser.getTenantId(), currentUser.getId(), Arrays.asList(paths.split(",")));
}
}

334
application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java

@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.UserEmailInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -48,6 +49,7 @@ import org.thingsboard.server.service.mail.TestMailService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -61,6 +63,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.SYSTEM_TENANT;
public abstract class BaseUserControllerTest extends AbstractControllerTest {
private IdComparator<User> idComparator = new IdComparator<>();
private IdComparator<UserEmailInfo> userDataIdComparator = new IdComparator<>();
private CustomerId customerNUULId = (CustomerId) createEntityId_NULL_UUID(new Customer());
@ -84,21 +87,15 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testSaveUser() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
User user = createTenantAdminUser();
String email = user.getEmail();
Mockito.reset(tbClusterService, auditLogService);
User savedUser = doPost("/api/user", user, User.class);
Assert.assertNotNull(savedUser);
Assert.assertNotNull(savedUser.getId());
Assert.assertTrue(savedUser.getCreatedTime() > 0);
Assert.assertEquals(user.getEmail(), savedUser.getEmail());
Assert.assertEquals(email, savedUser.getEmail());
User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class);
Assert.assertEquals(foundUser, savedUser);
@ -153,13 +150,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService);
String email = "tenant2@thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName(StringUtils.randomAlphabetic(300));
user.setLastName("Downs");
User user = createTenantAdminUser(StringUtils.randomAlphabetic(300), "Brown");
String msgError = msgErrorFieldLength("first name");
doPost("/api/user", user)
.andExpect(status().isBadRequest())
@ -186,12 +177,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testUpdateUserFromDifferentTenant() throws Exception {
loginSysAdmin();
User tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(tenantId);
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
User tenantAdmin = createTenantAdminUser();
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
loginDifferentTenant();
@ -211,14 +197,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testResetPassword() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
User user = createTenantAdminUser();
String email = user.getEmail();
User savedUser = createUserAndLogin(user, "testPassword1");
resetTokens();
@ -263,13 +243,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testFindUserById() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
User user = createTenantAdminUser();
User savedUser = doPost("/api/user", user, User.class);
User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class);
@ -283,15 +257,12 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService);
String email = TENANT_ADMIN_EMAIL;
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
user.setEmail(TENANT_ADMIN_EMAIL);
String msgError = "User with email '" + email + "' already present in database";
String msgError = "User with email '" + TENANT_ADMIN_EMAIL + "' already present in database";
doPost("/api/user", user)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
@ -308,12 +279,8 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService);
String email = "tenant_thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
User user = createTenantAdminUser();
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
String msgError = "Invalid email address format '" + email + "'";
doPost("/api/user", user)
@ -374,13 +341,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testDeleteUser() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
User user = createTenantAdminUser();
User savedUser = doPost("/api/user", user, User.class);
User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class);
@ -562,20 +523,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testFindCustomerUsers() throws Exception {
loginSysAdmin();
User tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(tenantId);
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
User tenantAdmin = createTenantAdminUser();
createUserAndLogin(tenantAdmin, "testPassword1");
Customer customer = new Customer();
customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = savedCustomer.getId();
CustomerId customerId = postCustomer();
List<User> customerUsers = new ArrayList<>();
for (int i = 0; i < 56; i++) {
@ -612,47 +563,22 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
public void testFindCustomerUsersByEmail() throws Exception {
loginSysAdmin();
User tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(tenantId);
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
User tenantAdmin = createTenantAdminUser();
createUserAndLogin(tenantAdmin, "testPassword1");
Customer customer = new Customer();
customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = savedCustomer.getId();
CustomerId customerId = postCustomer();
String email1 = "testEmail1";
List<User> customerUsersEmail1 = new ArrayList<>();
for (int i = 0; i < 74; i++) {
User user = new User();
user.setAuthority(Authority.CUSTOMER_USER);
user.setCustomerId(customerId);
String suffix = StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
String email = email1 + suffix + "@thingsboard.org";
email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
user.setEmail(email);
customerUsersEmail1.add(doPost("/api/user", user, User.class));
}
String email2 = "testEmail2";
List<User> customerUsersEmail2 = new ArrayList<>();
for (int i = 0; i < 92; i++) {
User user = new User();
user.setAuthority(Authority.CUSTOMER_USER);
user.setCustomerId(customerId);
String suffix = StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
String email = email2 + suffix + "@thingsboard.org";
email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
user.setEmail(email);
customerUsersEmail2.add(doPost("/api/user", user, User.class));
List<User> customerUsersEmail1 = new ArrayList<>();
List<User> customerUsersEmail2= new ArrayList<>();
for (int i = 0; i < 45; i++) {
User customerUser = createCustomerUser( customerId);
customerUser.setEmail(email1 + StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)) + "@thingsboard.org");
customerUsersEmail1.add(doPost("/api/user", customerUser, User.class));
customerUser.setEmail(email2 + StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)) + "@thingsboard.org");
customerUsersEmail2.add(doPost("/api/user", customerUser, User.class));
}
List<User> loadedCustomerUsersEmail1 = new ArrayList<>();
@ -720,14 +646,18 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
@Test
public void testDeleteUserWithDeleteRelationsOk() throws Exception {
UserId userId = createUser().getId();
loginSysAdmin();
User tenantAdminUser = createTenantAdminUser();
UserId userId = doPost("/api/user", tenantAdminUser, User.class).getId();
testEntityDaoWithRelationsOk(tenantId, userId, "/api/user/" + userId);
}
@Ignore
@Test
public void testDeleteUserExceptionWithRelationsTransactional() throws Exception {
UserId userId = createUser().getId();
loginSysAdmin();
User tenantAdminUser = createTenantAdminUser("Joe", "Downs");
UserId userId = doPost("/api/user", tenantAdminUser, User.class).getId();
testEntityDaoWithRelationsTransactionalException(userDao, tenantId, userId, "/api/user/" + userId);
}
@ -858,15 +788,197 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
Assert.assertEquals(expectedSettings, retrievedSettings);
}
private User createUser() throws Exception {
@Test
public void checkCustomerUserDoNotSeeTenantUsersOtherTenantUsersOtherCustomerUsers() throws Exception {
loginSysAdmin();
String searchText = "Joe";
loginDifferentTenant();
CustomerId customerId1 = postCustomer();
doPost("/api/user", createCustomerUser(searchText, "Ress", customerId1), User.class);
loginSysAdmin();
User tenantAdmin = createTenantAdminUser(searchText, "Brown");
createUserAndLogin(tenantAdmin, "testPassword1");
CustomerId customerId2 = postCustomer();
User user = createCustomerUser(searchText, "Downs", customerId2);
doPost("/api/user", user, User.class);
CustomerId customerId3 = postCustomer();
User user2 = createCustomerUser(customerId3);
createUserAndLogin(user2, "testPassword2");
PageLink pageLink = new PageLink(10, 0, searchText);
List<UserEmailInfo> usersInfo = getUsersInfo(pageLink);
Assert.assertEquals(usersInfo.size(), 0);
//clear users
loginDifferentTenant();
doDelete("/api/customer/" + customerId1.getId().toString())
.andExpect(status().isOk());
loginUser(tenantAdmin.getEmail(), "testPassword1");
doDelete("/api/customer/" + customerId2.getId().toString())
.andExpect(status().isOk());
doDelete("/api/customer/" + customerId3.getId().toString())
.andExpect(status().isOk());
}
@Test
public void shouldFindCustomerUsersBySearchText() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";
User tenantAdmin = createTenantAdminUser();
createUserAndLogin(tenantAdmin, "testPassword1");
String searchText = "Philip";
CustomerId customerId = postCustomer();
CustomerId customerId2 = postCustomer();
List<User> customerUsersContainingWord = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String suffix = StringUtils.randomAlphabetic((int) (5 + Math.random() * 10));
customerUsersContainingWord.add(doPost("/api/user", createCustomerUser(searchText + i, "Last" + i, customerId), User.class));
customerUsersContainingWord.add(doPost("/api/user", createCustomerUser(null, null, searchText + suffix + "@thingsboard.org", customerId), User.class));
doPost("/api/user", createCustomerUser(null, null, customerId), User.class);
suffix = StringUtils.randomAlphabetic((int) (5 + Math.random() * 10));
doPost("/api/user", createCustomerUser(searchText + i, "Last" + i, customerId2), User.class);
doPost("/api/user", createCustomerUser(null, null, searchText + suffix + "@thingsboard.org", customerId2), User.class);
}
createUserAndLogin(createCustomerUser(customerId), "testPassword2");
// find users by search text
PageLink pageLink = new PageLink(10, 0, searchText);
List<UserEmailInfo> usersInfo = getUsersInfo(pageLink);
List<UserEmailInfo> expectedUserInfos = customerUsersContainingWord.stream().map(customerUser -> new UserEmailInfo(customerUser.getId(),
customerUser.getEmail(), customerUser.getFirstName() == null ? "" : customerUser.getFirstName(),
customerUser.getLastName() == null ? "" : customerUser.getLastName()))
.sorted(userDataIdComparator).collect(Collectors.toList());
usersInfo.sort(userDataIdComparator);
Assert.assertEquals(expectedUserInfos, usersInfo);
// find user by full name
pageLink = new PageLink(10, 0, searchText + "5");
usersInfo = getUsersInfo(pageLink);
Assert.assertEquals(1, usersInfo.size());
//clear users
loginUser(tenantAdmin.getEmail(), "testPassword1");
doDelete("/api/customer/" + customerId.getId().toString())
.andExpect(status().isOk());
doDelete("/api/customer/" + customerId2.getId().toString())
.andExpect(status().isOk());
}
@Test
public void shouldFindTenantUsersBySearchText() throws Exception {
loginSysAdmin();
User tenantAdmin = createTenantAdminUser();
createUserAndLogin(tenantAdmin, "testPassword1");
CustomerId customerId = postCustomer();
CustomerId customerId2 = postCustomer();
String searchText = "Brown";
List<User> usersContainingWord = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String suffix = StringUtils.randomAlphabetic((int) (5 + Math.random() * 10));
usersContainingWord.add(doPost("/api/user", createCustomerUser("First" + i, searchText + i, customerId), User.class));
usersContainingWord.add(doPost("/api/user", createCustomerUser(null, null, searchText + suffix + "@thingsboard.org", customerId), User.class));
doPost("/api/user", createCustomerUser(null, null, customerId), User.class);
suffix = StringUtils.randomAlphabetic((int) (5 + Math.random() * 10));
usersContainingWord.add(doPost("/api/user", createCustomerUser("First" + i, searchText + i, customerId2), User.class));
usersContainingWord.add(doPost("/api/user", createCustomerUser(null, null, searchText + suffix + "@thingsboard.org", customerId2), User.class));
}
loginDifferentTenant();
CustomerId customerId3 = postCustomer();
doPost("/api/user", createCustomerUser("Jane", searchText, customerId3), User.class);
// find users by search text
loginUser(tenantAdmin.getEmail(), "testPassword1");
PageLink pageLink = new PageLink(10, 0, searchText);
List<UserEmailInfo> usersInfo = getUsersInfo(pageLink);
List<UserEmailInfo> expectedUserInfos = usersContainingWord.stream().map(customerUser -> new UserEmailInfo(customerUser.getId(),
customerUser.getEmail(), customerUser.getFirstName() == null ? "" : customerUser.getFirstName(),
customerUser.getLastName() == null ? "" : customerUser.getLastName()))
.sorted(userDataIdComparator).collect(Collectors.toList());
usersInfo.sort(userDataIdComparator);
Assert.assertEquals(expectedUserInfos, usersInfo);
// find user by full last name
pageLink = new PageLink(10, 0, searchText + "3");
usersInfo = getUsersInfo(pageLink);
Assert.assertEquals(2, usersInfo.size());
//clear users
doDelete("/api/customer/" + customerId.getId().toString())
.andExpect(status().isOk());
doDelete("/api/customer/" + customerId2.getId().toString())
.andExpect(status().isOk());
}
private CustomerId postCustomer() {
Customer customer = new Customer();
customer.setTitle(StringUtils.randomAlphabetic(9));
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
return savedCustomer.getId();
}
private static User createCustomerUser(CustomerId customerId) {
return createCustomerUser(null, null, customerId);
}
private static User createCustomerUser(String firstName, String lastName, CustomerId customerId) {
String suffix = StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
return createCustomerUser(firstName, lastName, "testMail" + suffix + "@thingsboard.org", customerId);
}
private static User createCustomerUser(String firstName, String lastName, String email, CustomerId customerId) {
User user = new User();
user.setAuthority(Authority.TENANT_ADMIN);
user.setTenantId(tenantId);
user.setAuthority(Authority.CUSTOMER_USER);
user.setFirstName(firstName);
user.setLastName(lastName);
user.setCustomerId(customerId);
user.setEmail(email);
user.setFirstName("Joe");
user.setLastName("Downs");
return doPost("/api/user", user, User.class);
return user;
}
private User createTenantAdminUser() {
return createTenantAdminUser(null, null);
}
private User createTenantAdminUser(String firstName, String lastName) {
String suffix = StringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
User tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(tenantId);
tenantAdmin.setEmail("testEmail" + suffix + "@thingsbord.org");
tenantAdmin.setFirstName(firstName);
tenantAdmin.setLastName(lastName);
return tenantAdmin;
}
private List<UserEmailInfo> getUsersInfo(PageLink pageLink) throws Exception {
List<UserEmailInfo> loadedCustomerUsers = new ArrayList<>();
PageData<UserEmailInfo> pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/users/info?", new TypeReference<>() {}, pageLink);
loadedCustomerUsers.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
return loadedCustomerUsers;
}
}

39
common/data/src/main/java/org/thingsboard/server/common/data/UserEmailInfo.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.UserId;
@ApiModel
@Data
@AllArgsConstructor
public class UserEmailInfo implements HasId<UserId> {
@ApiModelProperty(position = 1, value = "User id")
private UserId id;
@ApiModelProperty(position = 2, value = "User email", example = "john@gmail.com")
private String email;
@ApiModelProperty(position = 3, value = "User first name", example = "John")
private String firstName;
@ApiModelProperty(position = 4, value = "User last name", example = "Brown")
private String lastName;
}

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java

@ -41,7 +41,7 @@ import java.util.concurrent.ExecutionException;
type = ComponentType.ENRICHMENT,
name = "fetch device credentials",
configClazz = TbFetchDeviceCredentialsNodeConfiguration.class,
nodeDescription = "Fetch device credentials for message originator",
nodeDescription = "Enrich the message body or metadata with the device credentials",
nodeDetails = "Adds <b>credentialsType</b> and <b>credentials</b> properties to the message metadata if the " +
"configuration parameter <b>fetchToMetadata</b> is set to <code>true</code>, otherwise, adds properties " +
"to the message data. If originator type is not <b>DEVICE</b> or rule node failed to get device credentials " +

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java

@ -34,7 +34,7 @@ import org.thingsboard.server.common.msg.TbMsg;
@RuleNode(type = ComponentType.ENRICHMENT,
name = "originator attributes",
configClazz = TbGetAttributesNodeConfiguration.class,
nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Data or Metadata",
nodeDescription = "Enrich the message body or metadata with the originator attributes and/or timeseries data",
nodeDetails = "If Attributes enrichment configured, <b>CLIENT/SHARED/SERVER</b> attributes are added into Message data/metadata " +
"with specific prefix: <i>cs/shared/ss</i>. Latest telemetry value added into Message data/metadata without prefix. " +
"To access those attributes in other nodes this template can be used " +

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java

@ -38,7 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
@RuleNode(type = ComponentType.ENRICHMENT,
name = "customer details",
configClazz = TbGetCustomerDetailsNodeConfiguration.class,
nodeDescription = "Adds fields from Customer details to the message body or metadata",
nodeDescription = "Enrich the message body or metadata with the corresponding customer details: title, address, email, phone, etc.",
nodeDetails = "If checkbox: <b>Add selected details to the message metadata</b> is selected, existing fields will be added to the message metadata instead of message data.<br><br>" +
"<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
"If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",

Loading…
Cancel
Save