Commit 5fd155543f3d8e9ea88f27bc1a97b82a62275b06

Authored by Andrii Shvaika
1 parent 91d614ba

User controller

@@ -181,9 +181,9 @@ public abstract class BaseController { @@ -181,9 +181,9 @@ public abstract class BaseController {
181 public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; 181 public static final String RULE_CHAIN_ID_PARAM_DESCRIPTION = "A string value representing the rule chain id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'";
182 182
183 protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority."; 183 protected static final String SYSTEM_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' authority.";
184 - protected static final String SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority."; 184 + protected static final String SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'SYS_ADMIN' or 'TENANT_ADMIN' authority.";
185 protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority."; 185 protected static final String TENANT_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' authority.";
186 - protected static final String TENANT_AND_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority."; 186 + protected static final String TENANT_OR_USER_AUTHORITY_PARAGRAPH = "\n\nAvailable for users with 'TENANT_ADMIN' or 'CUSTOMER_USER' authority.";
187 187
188 protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page"; 188 protected static final String PAGE_SIZE_DESCRIPTION = "Maximum amount of entities in a one page";
189 protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0"; 189 protected static final String PAGE_NUMBER_DESCRIPTION = "Sequence number of page starting from 0";
@@ -196,6 +196,7 @@ public abstract class BaseController { @@ -196,6 +196,7 @@ public abstract class BaseController {
196 protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; 196 protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title.";
197 protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; 197 protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty.";
198 protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; 198 protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name.";
  199 + protected static final String USER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the user email.";
199 protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name."; 200 protected static final String TENANT_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant name.";
200 protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name."; 201 protected static final String TENANT_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the tenant profile name.";
201 protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name."; 202 protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name.";
@@ -209,6 +210,7 @@ public abstract class BaseController { @@ -209,6 +210,7 @@ public abstract class BaseController {
209 protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city"; 210 protected static final String CUSTOMER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, city";
210 protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response"; 211 protected static final String RPC_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, expirationTime, request, response";
211 protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle"; 212 protected static final String DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, deviceProfileName, label, customerTitle";
  213 + protected static final String USER_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, firstName, lastName, email";
212 protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email"; 214 protected static final String TENANT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, title, email, country, state, city, address, address2, zip, phone, email";
213 protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault"; 215 protected static final String TENANT_PROFILE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, description, isDefault";
214 protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name"; 216 protected static final String TENANT_PROFILE_INFO_SORT_PROPERTY_ALLOWABLE_VALUES = "id, name";
@@ -103,8 +103,8 @@ public class DeviceController extends BaseController { @@ -103,8 +103,8 @@ public class DeviceController extends BaseController {
103 103
104 @ApiOperation(value = "Get Device (getDeviceById)", 104 @ApiOperation(value = "Get Device (getDeviceById)",
105 notes = "Fetch the Device object based on the provided Device Id. " + 105 notes = "Fetch the Device object based on the provided Device Id. " +
106 - "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " +  
107 - "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer.") 106 + "If the user has the authority of 'TENANT_ADMIN', the server checks that the device is owned by the same tenant. " +
  107 + "If the user has the authority of 'CUSTOMER_USER', the server checks that the device is assigned to the same customer.")
108 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 108 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
109 @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) 109 @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET)
110 @ResponseBody 110 @ResponseBody
@@ -81,7 +81,7 @@ public class DeviceProfileController extends BaseController { @@ -81,7 +81,7 @@ public class DeviceProfileController extends BaseController {
81 81
82 @ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)", 82 @ApiOperation(value = "Get Device Profile Info (getDeviceProfileInfoById)",
83 notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. " 83 notes = "Fetch the Device Profile Info object based on the provided Device Profile Id. "
84 - + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, 84 + + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH,
85 produces = "application/json") 85 produces = "application/json")
86 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 86 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
87 @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET) 87 @RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET)
@@ -100,7 +100,7 @@ public class DeviceProfileController extends BaseController { @@ -100,7 +100,7 @@ public class DeviceProfileController extends BaseController {
100 100
101 @ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)", 101 @ApiOperation(value = "Get Default Device Profile (getDefaultDeviceProfileInfo)",
102 notes = "Fetch the Default Device Profile Info object. " + 102 notes = "Fetch the Default Device Profile Info object. " +
103 - DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, 103 + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH,
104 produces = "application/json") 104 produces = "application/json")
105 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 105 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
106 @RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET) 106 @RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@@ -321,7 +321,7 @@ public class DeviceProfileController extends BaseController { @@ -321,7 +321,7 @@ public class DeviceProfileController extends BaseController {
321 321
322 @ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)", 322 @ApiOperation(value = "Get Device Profiles for transport type (getDeviceProfileInfos)",
323 notes = "Returns a page of devices profile info objects owned by tenant. " + 323 notes = "Returns a page of devices profile info objects owned by tenant. " +
324 - PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_AND_USER_AUTHORITY_PARAGRAPH, 324 + PAGE_DATA_PARAMETERS + DEVICE_PROFILE_INFO_DESCRIPTION + TENANT_OR_USER_AUTHORITY_PARAGRAPH,
325 produces = "application/json") 325 produces = "application/json")
326 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 326 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
327 @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) 327 @RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@@ -497,7 +497,7 @@ public class EntityQueryController extends BaseController { @@ -497,7 +497,7 @@ public class EntityQueryController extends BaseController {
497 "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + 497 "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" +
498 ENTITY_FILTERS + 498 ENTITY_FILTERS +
499 KEY_FILTERS + 499 KEY_FILTERS +
500 - TENANT_AND_USER_AUTHORITY_PARAGRAPH;; 500 + TENANT_OR_USER_AUTHORITY_PARAGRAPH;;
501 501
502 private static final String ENTITY_DATA_QUERY_DESCRIPTION = 502 private static final String ENTITY_DATA_QUERY_DESCRIPTION =
503 "Allows to run complex queries over platform entities (devices, assets, customers, etc) " + 503 "Allows to run complex queries over platform entities (devices, assets, customers, etc) " +
@@ -580,7 +580,7 @@ public class EntityQueryController extends BaseController { @@ -580,7 +580,7 @@ public class EntityQueryController extends BaseController {
580 "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" + 580 "\n\n Example mentioned above search all devices which have attribute 'active' set to 'true'. Now let's review available entity filters and key filters syntax:" +
581 ENTITY_FILTERS + 581 ENTITY_FILTERS +
582 KEY_FILTERS + 582 KEY_FILTERS +
583 - TENANT_AND_USER_AUTHORITY_PARAGRAPH; 583 + TENANT_OR_USER_AUTHORITY_PARAGRAPH;
584 584
585 585
586 private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " + 586 private static final String ALARM_DATA_QUERY_DESCRIPTION = "This method description defines how Alarm Data Query extends the Entity Data Query. " +
@@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController { @@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController {
91 "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + 91 "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " +
92 "the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; 92 "the result of this call is the response from device, or 504 Gateway Timeout if device is offline.";
93 93
94 - private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; 94 + private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH;
95 95
96 - private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH; 96 + private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_OR_USER_AUTHORITY_PARAGRAPH;
97 97
98 @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) 98 @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION)
99 @ApiResponses(value = { 99 @ApiResponses(value = {
@@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController { @@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController {
131 return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); 131 return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
132 } 132 }
133 133
134 - @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) 134 + @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_OR_USER_AUTHORITY_PARAGRAPH)
135 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 135 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
136 @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) 136 @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET)
137 @ResponseBody 137 @ResponseBody
@@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController { @@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController {
147 } 147 }
148 } 148 }
149 149
150 - @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_AND_USER_AUTHORITY_PARAGRAPH) 150 + @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_OR_USER_AUTHORITY_PARAGRAPH)
151 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 151 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
152 @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) 152 @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET)
153 @ResponseBody 153 @ResponseBody
@@ -57,7 +57,7 @@ public class TenantController extends BaseController { @@ -57,7 +57,7 @@ public class TenantController extends BaseController {
57 private TenantService tenantService; 57 private TenantService tenantService;
58 58
59 @ApiOperation(value = "Get Tenant (getTenantById)", 59 @ApiOperation(value = "Get Tenant (getTenantById)",
60 - notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) 60 + notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
61 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 61 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
62 @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET) 62 @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET)
63 @ResponseBody 63 @ResponseBody
@@ -79,7 +79,7 @@ public class TenantController extends BaseController { @@ -79,7 +79,7 @@ public class TenantController extends BaseController {
79 79
80 @ApiOperation(value = "Get Tenant Info (getTenantInfoById)", 80 @ApiOperation(value = "Get Tenant Info (getTenantInfoById)",
81 notes = "Fetch the Tenant Info object based on the provided Tenant Id. " + 81 notes = "Fetch the Tenant Info object based on the provided Tenant Id. " +
82 - TENANT_INFO_DESCRIPTION + SYSTEM_AND_TENANT_AUTHORITY_PARAGRAPH) 82 + TENANT_INFO_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
83 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 83 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
84 @RequestMapping(value = "/tenant/info/{tenantId}", method = RequestMethod.GET) 84 @RequestMapping(value = "/tenant/info/{tenantId}", method = RequestMethod.GET)
85 @ResponseBody 85 @ResponseBody
@@ -108,11 +108,6 @@ public class TenantProfileController extends BaseController { @@ -108,11 +108,6 @@ public class TenantProfileController extends BaseController {
108 "Let's review the example of tenant profile data below: " + 108 "Let's review the example of tenant profile data below: " +
109 "\n\n" + MARKDOWN_CODE_BLOCK_START + 109 "\n\n" + MARKDOWN_CODE_BLOCK_START +
110 "{\n" + 110 "{\n" +
111 - " \"id\": {\n" +  
112 - " \"entityType\": \"TENANT_PROFILE\",\n" +  
113 - " \"id\": \"0f2978a0-0d46-11eb-ab90-09ceaa526dd8\"\n" +  
114 - " },\n" +  
115 - " \"createdTime\": 1602588011818,\n" +  
116 " \"name\": \"Default\",\n" + 111 " \"name\": \"Default\",\n" +
117 " \"description\": \"Default tenant profile\",\n" + 112 " \"description\": \"Default tenant profile\",\n" +
118 " \"isolatedTbCore\": false,\n" + 113 " \"isolatedTbCore\": false,\n" +
@@ -15,9 +15,9 @@ @@ -15,9 +15,9 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 -import com.fasterxml.jackson.databind.ObjectMapper;  
20 import com.fasterxml.jackson.databind.node.ObjectNode; 18 import com.fasterxml.jackson.databind.node.ObjectNode;
  19 +import io.swagger.annotations.ApiOperation;
  20 +import io.swagger.annotations.ApiParam;
21 import lombok.Getter; 21 import lombok.Getter;
22 import lombok.RequiredArgsConstructor; 22 import lombok.RequiredArgsConstructor;
23 import org.springframework.beans.factory.annotation.Value; 23 import org.springframework.beans.factory.annotation.Value;
@@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -32,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam;
32 import org.springframework.web.bind.annotation.ResponseBody; 32 import org.springframework.web.bind.annotation.ResponseBody;
33 import org.springframework.web.bind.annotation.ResponseStatus; 33 import org.springframework.web.bind.annotation.ResponseStatus;
34 import org.springframework.web.bind.annotation.RestController; 34 import org.springframework.web.bind.annotation.RestController;
35 -import org.thingsboard.common.util.JacksonUtil;  
36 import org.thingsboard.rule.engine.api.MailService; 35 import org.thingsboard.rule.engine.api.MailService;
37 import org.thingsboard.server.common.data.EntityType; 36 import org.thingsboard.server.common.data.EntityType;
38 import org.thingsboard.server.common.data.User; 37 import org.thingsboard.server.common.data.User;
@@ -52,6 +51,7 @@ import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEven @@ -52,6 +51,7 @@ import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEven
52 import org.thingsboard.server.common.data.security.model.JwtToken; 51 import org.thingsboard.server.common.data.security.model.JwtToken;
53 import org.thingsboard.server.queue.util.TbCoreComponent; 52 import org.thingsboard.server.queue.util.TbCoreComponent;
54 import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; 53 import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
  54 +import org.thingsboard.server.service.security.model.JwtTokenPair;
55 import org.thingsboard.server.service.security.model.SecurityUser; 55 import org.thingsboard.server.service.security.model.SecurityUser;
56 import org.thingsboard.server.service.security.model.UserPrincipal; 56 import org.thingsboard.server.service.security.model.UserPrincipal;
57 import org.thingsboard.server.service.security.model.token.JwtTokenFactory; 57 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
@@ -82,20 +82,27 @@ public class UserController extends BaseController { @@ -82,20 +82,27 @@ public class UserController extends BaseController {
82 private final SystemSecurityService systemSecurityService; 82 private final SystemSecurityService systemSecurityService;
83 private final ApplicationEventPublisher eventPublisher; 83 private final ApplicationEventPublisher eventPublisher;
84 84
  85 + @ApiOperation(value = "Get User (getUserById)",
  86 + notes = "Fetch the User object based on the provided User Id. " +
  87 + "If the user has the authority of 'SYS_ADMIN', the server does not perform additional checks. " +
  88 + "If the user has the authority of 'TENANT_ADMIN', the server checks that the requested user is owned by the same tenant. " +
  89 + "If the user has the authority of 'CUSTOMER_USER', the server checks that the requested user is owned by the same customer.")
85 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 90 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
86 @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET) 91 @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
87 @ResponseBody 92 @ResponseBody
88 - public User getUserById(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { 93 + public User getUserById(
  94 + @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
  95 + @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
89 checkParameter(USER_ID, strUserId); 96 checkParameter(USER_ID, strUserId);
90 try { 97 try {
91 UserId userId = new UserId(toUUID(strUserId)); 98 UserId userId = new UserId(toUUID(strUserId));
92 User user = checkUserId(userId, Operation.READ); 99 User user = checkUserId(userId, Operation.READ);
93 - if(user.getAdditionalInfo().isObject()) { 100 + if (user.getAdditionalInfo().isObject()) {
94 ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo(); 101 ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo();
95 processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD); 102 processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD);
96 processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD); 103 processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD);
97 UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); 104 UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
98 - if(userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) { 105 + if (userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) {
99 additionalInfo.put("userCredentialsEnabled", true); 106 additionalInfo.put("userCredentialsEnabled", true);
100 } 107 }
101 } 108 }
@@ -105,6 +112,10 @@ public class UserController extends BaseController { @@ -105,6 +112,10 @@ public class UserController extends BaseController {
105 } 112 }
106 } 113 }
107 114
  115 + @ApiOperation(value = "Check Token Access Enabled (isUserTokenAccessEnabled)",
  116 + notes = "Checks that the system is configured to allow administrators to impersonate themself as other users. " +
  117 + "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to login as any tenant administrator. " +
  118 + "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to login as any customer user. ")
108 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 119 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
109 @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET) 120 @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET)
110 @ResponseBody 121 @ResponseBody
@@ -112,10 +123,16 @@ public class UserController extends BaseController { @@ -112,10 +123,16 @@ public class UserController extends BaseController {
112 return userTokenAccessEnabled; 123 return userTokenAccessEnabled;
113 } 124 }
114 125
  126 + @ApiOperation(value = "Get User Token (getUserToken)",
  127 + notes = "Returns the token of the User based on the provided User Id. " +
  128 + "If the user who performs the request has the authority of 'SYS_ADMIN', it is possible to get the token of any tenant administrator. " +
  129 + "If the user who performs the request has the authority of 'TENANT_ADMIN', it is possible to get the token of any customer user that belongs to the same tenant. ")
115 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 130 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
116 @RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET) 131 @RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET)
117 @ResponseBody 132 @ResponseBody
118 - public JsonNode getUserToken(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { 133 + public JwtTokenPair getUserToken(
  134 + @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
  135 + @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
119 checkParameter(USER_ID, strUserId); 136 checkParameter(USER_ID, strUserId);
120 try { 137 try {
121 if (!userTokenAccessEnabled) { 138 if (!userTokenAccessEnabled) {
@@ -130,22 +147,26 @@ public class UserController extends BaseController { @@ -130,22 +147,26 @@ public class UserController extends BaseController {
130 SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal); 147 SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
131 JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); 148 JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
132 JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); 149 JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
133 - ObjectMapper objectMapper = new ObjectMapper();  
134 - ObjectNode tokenObject = objectMapper.createObjectNode();  
135 - tokenObject.put("token", accessToken.getToken());  
136 - tokenObject.put("refreshToken", refreshToken.getToken());  
137 - return tokenObject; 150 + return new JwtTokenPair(accessToken.getToken(), refreshToken.getToken());
138 } catch (Exception e) { 151 } catch (Exception e) {
139 throw handleException(e); 152 throw handleException(e);
140 } 153 }
141 } 154 }
142 155
  156 + @ApiOperation(value = "Save Or update User (saveUser)",
  157 + notes = "Create or update the User. When creating user, platform generates User Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
  158 + "The newly created User Id will be present in the response. " +
  159 + "Specify existing User Id to update the device. " +
  160 + "Referencing non-existing User Id will cause 'Not Found' error." +
  161 + "\n\nDevice email is unique for entire platform setup.")
143 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 162 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
144 @RequestMapping(value = "/user", method = RequestMethod.POST) 163 @RequestMapping(value = "/user", method = RequestMethod.POST)
145 @ResponseBody 164 @ResponseBody
146 - public User saveUser(@RequestBody User user,  
147 - @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,  
148 - HttpServletRequest request) throws ThingsboardException { 165 + public User saveUser(
  166 + @ApiParam(value = "A JSON value representing the User.", required = true)
  167 + @RequestBody User user,
  168 + @ApiParam(value = "Send activation email (or use activation link)", defaultValue = "true")
  169 + @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, HttpServletRequest request) throws ThingsboardException {
149 try { 170 try {
150 171
151 if (Authority.TENANT_ADMIN.equals(getCurrentUser().getAuthority())) { 172 if (Authority.TENANT_ADMIN.equals(getCurrentUser().getAuthority())) {
@@ -188,10 +209,13 @@ public class UserController extends BaseController { @@ -188,10 +209,13 @@ public class UserController extends BaseController {
188 } 209 }
189 } 210 }
190 211
  212 + @ApiOperation(value = "Send or re-send the activation email",
  213 + notes = "Force send the activation email to the user. Useful to resend the email if user has accidentally deleted it. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
191 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 214 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
192 @RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST) 215 @RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST)
193 @ResponseStatus(value = HttpStatus.OK) 216 @ResponseStatus(value = HttpStatus.OK)
194 public void sendActivationEmail( 217 public void sendActivationEmail(
  218 + @ApiParam(value = "Email of the user", required = true)
195 @RequestParam(value = "email") String email, 219 @RequestParam(value = "email") String email,
196 HttpServletRequest request) throws ThingsboardException { 220 HttpServletRequest request) throws ThingsboardException {
197 try { 221 try {
@@ -214,10 +238,14 @@ public class UserController extends BaseController { @@ -214,10 +238,14 @@ public class UserController extends BaseController {
214 } 238 }
215 } 239 }
216 240
  241 + @ApiOperation(value = "Get the activation link (getActivationLink)",
  242 + notes = "Get the activation link for the user. " +
  243 + "The base url for activation link is configurable in the general settings of system administrator. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
217 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 244 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
218 @RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain") 245 @RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain")
219 @ResponseBody 246 @ResponseBody
220 public String getActivationLink( 247 public String getActivationLink(
  248 + @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
221 @PathVariable(USER_ID) String strUserId, 249 @PathVariable(USER_ID) String strUserId,
222 HttpServletRequest request) throws ThingsboardException { 250 HttpServletRequest request) throws ThingsboardException {
223 checkParameter(USER_ID, strUserId); 251 checkParameter(USER_ID, strUserId);
@@ -239,10 +267,15 @@ public class UserController extends BaseController { @@ -239,10 +267,15 @@ public class UserController extends BaseController {
239 } 267 }
240 } 268 }
241 269
  270 + @ApiOperation(value = "Delete User (deleteUser)",
  271 + notes = "Deletes the User, it's credentials and all the relations (from and to the User). " +
  272 + "Referencing non-existing User Id will cause an error. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
242 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 273 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
243 @RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE) 274 @RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE)
244 @ResponseStatus(value = HttpStatus.OK) 275 @ResponseStatus(value = HttpStatus.OK)
245 - public void deleteUser(@PathVariable(USER_ID) String strUserId) throws ThingsboardException { 276 + public void deleteUser(
  277 + @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
  278 + @PathVariable(USER_ID) String strUserId) throws ThingsboardException {
246 checkParameter(USER_ID, strUserId); 279 checkParameter(USER_ID, strUserId);
247 try { 280 try {
248 UserId userId = new UserId(toUUID(strUserId)); 281 UserId userId = new UserId(toUUID(strUserId));
@@ -267,14 +300,22 @@ public class UserController extends BaseController { @@ -267,14 +300,22 @@ public class UserController extends BaseController {
267 } 300 }
268 } 301 }
269 302
  303 + @ApiOperation(value = "Get Users (getUsers)",
  304 + notes = "Returns a page of users owned by tenant or customer. The scope depends on authority of the user that performs the request." +
  305 + PAGE_DATA_PARAMETERS + TENANT_OR_USER_AUTHORITY_PARAGRAPH)
270 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 306 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
271 @RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET) 307 @RequestMapping(value = "/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
272 @ResponseBody 308 @ResponseBody
273 public PageData<User> getUsers( 309 public PageData<User> getUsers(
  310 + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
274 @RequestParam int pageSize, 311 @RequestParam int pageSize,
  312 + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
275 @RequestParam int page, 313 @RequestParam int page,
  314 + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
276 @RequestParam(required = false) String textSearch, 315 @RequestParam(required = false) String textSearch,
  316 + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
277 @RequestParam(required = false) String sortProperty, 317 @RequestParam(required = false) String sortProperty,
  318 + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
278 @RequestParam(required = false) String sortOrder) throws ThingsboardException { 319 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
279 try { 320 try {
280 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); 321 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
@@ -289,15 +330,23 @@ public class UserController extends BaseController { @@ -289,15 +330,23 @@ public class UserController extends BaseController {
289 } 330 }
290 } 331 }
291 332
  333 + @ApiOperation(value = "Get Tenant Users (getTenantAdmins)",
  334 + notes = "Returns a page of users owned by tenant. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH)
292 @PreAuthorize("hasAuthority('SYS_ADMIN')") 335 @PreAuthorize("hasAuthority('SYS_ADMIN')")
293 @RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) 336 @RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
294 @ResponseBody 337 @ResponseBody
295 public PageData<User> getTenantAdmins( 338 public PageData<User> getTenantAdmins(
296 - @PathVariable("tenantId") String strTenantId, 339 + @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION, required = true)
  340 + @PathVariable(TENANT_ID) String strTenantId,
  341 + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
297 @RequestParam int pageSize, 342 @RequestParam int pageSize,
  343 + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
298 @RequestParam int page, 344 @RequestParam int page,
  345 + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
299 @RequestParam(required = false) String textSearch, 346 @RequestParam(required = false) String textSearch,
  347 + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
300 @RequestParam(required = false) String sortProperty, 348 @RequestParam(required = false) String sortProperty,
  349 + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
301 @RequestParam(required = false) String sortOrder) throws ThingsboardException { 350 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
302 checkParameter("tenantId", strTenantId); 351 checkParameter("tenantId", strTenantId);
303 try { 352 try {
@@ -309,15 +358,23 @@ public class UserController extends BaseController { @@ -309,15 +358,23 @@ public class UserController extends BaseController {
309 } 358 }
310 } 359 }
311 360
  361 + @ApiOperation(value = "Get Customer Users (getCustomerUsers)",
  362 + notes = "Returns a page of users owned by customer. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
312 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 363 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
313 @RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) 364 @RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET)
314 @ResponseBody 365 @ResponseBody
315 public PageData<User> getCustomerUsers( 366 public PageData<User> getCustomerUsers(
316 - @PathVariable("customerId") String strCustomerId, 367 + @ApiParam(value = CUSTOMER_ID_PARAM_DESCRIPTION, required = true)
  368 + @PathVariable(CUSTOMER_ID) String strCustomerId,
  369 + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
317 @RequestParam int pageSize, 370 @RequestParam int pageSize,
  371 + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
318 @RequestParam int page, 372 @RequestParam int page,
  373 + @ApiParam(value = USER_TEXT_SEARCH_DESCRIPTION)
319 @RequestParam(required = false) String textSearch, 374 @RequestParam(required = false) String textSearch,
  375 + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = USER_SORT_PROPERTY_ALLOWABLE_VALUES)
320 @RequestParam(required = false) String sortProperty, 376 @RequestParam(required = false) String sortProperty,
  377 + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
321 @RequestParam(required = false) String sortOrder) throws ThingsboardException { 378 @RequestParam(required = false) String sortOrder) throws ThingsboardException {
322 checkParameter("customerId", strCustomerId); 379 checkParameter("customerId", strCustomerId);
323 try { 380 try {
@@ -331,11 +388,16 @@ public class UserController extends BaseController { @@ -331,11 +388,16 @@ public class UserController extends BaseController {
331 } 388 }
332 } 389 }
333 390
  391 + @ApiOperation(value = "Enable/Disable User credentials (setUserCredentialsEnabled)",
  392 + notes = "Enables or Disables user credentials. Useful when you would like to block user account without deleting it. " + PAGE_DATA_PARAMETERS + TENANT_AUTHORITY_PARAGRAPH)
334 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 393 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
335 @RequestMapping(value = "/user/{userId}/userCredentialsEnabled", method = RequestMethod.POST) 394 @RequestMapping(value = "/user/{userId}/userCredentialsEnabled", method = RequestMethod.POST)
336 @ResponseBody 395 @ResponseBody
337 - public void setUserCredentialsEnabled(@PathVariable(USER_ID) String strUserId,  
338 - @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException { 396 + public void setUserCredentialsEnabled(
  397 + @ApiParam(value = USER_ID_PARAM_DESCRIPTION)
  398 + @PathVariable(USER_ID) String strUserId,
  399 + @ApiParam(value = "Disable (\"true\") or enable (\"false\") the credentials.", defaultValue = "true")
  400 + @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException {
339 checkParameter(USER_ID, strUserId); 401 checkParameter(USER_ID, strUserId);
340 try { 402 try {
341 UserId userId = new UserId(toUUID(strUserId)); 403 UserId userId = new UserId(toUUID(strUserId));