Browse Source

Tenant/Device REST API controllers

pull/3477/head
Igor Kulikov 6 years ago
parent
commit
2e6a98d8e0
  1. 42
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  2. 192
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  3. 3
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  4. 162
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  5. 39
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  6. 4
      application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
  7. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java
  8. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
  9. 1
      application/src/main/resources/thingsboard.yml
  10. 3
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  11. 266
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
  12. 255
      application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java
  13. 23
      application/src/test/java/org/thingsboard/server/controller/sql/DeviceProfileControllerSqlTest.java
  14. 23
      application/src/test/java/org/thingsboard/server/controller/sql/TenantProfileControllerSqlTest.java
  15. 2
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  16. 5
      common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java
  17. 24
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  18. 16
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java
  19. 2
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java
  20. 7
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

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

@ -33,12 +33,14 @@ import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
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.HasTenantId;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
@ -52,12 +54,14 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
@ -82,6 +86,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -89,6 +94,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
@ -134,6 +140,9 @@ public abstract class BaseController {
@Autowired
protected TenantService tenantService;
@Autowired
protected TenantProfileService tenantProfileService;
@Autowired
protected CustomerService customerService;
@ -143,6 +152,9 @@ public abstract class BaseController {
@Autowired
protected DeviceService deviceService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected AssetService assetService;
@ -312,6 +324,18 @@ public abstract class BaseController {
}
}
TenantProfile checkTenantProfileId(TenantProfileId tenantProfileId, Operation operation) throws ThingsboardException {
try {
validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId);
TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId);
checkNotNull(tenantProfile);
accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation);
return tenantProfile;
} catch (Exception e) {
throw handleException(e, false);
}
}
protected TenantId getTenantId() throws ThingsboardException {
return getCurrentUser().getTenantId();
}
@ -360,12 +384,18 @@ public abstract class BaseController {
case DEVICE:
checkDeviceId(new DeviceId(entityId.getId()), operation);
return;
case DEVICE_PROFILE:
checkDeviceProfileId(new DeviceProfileId(entityId.getId()), operation);
return;
case CUSTOMER:
checkCustomerId(new CustomerId(entityId.getId()), operation);
return;
case TENANT:
checkTenantId(new TenantId(entityId.getId()), operation);
return;
case TENANT_PROFILE:
checkTenantProfileId(new TenantProfileId(entityId.getId()), operation);
return;
case RULE_CHAIN:
checkRuleChain(new RuleChainId(entityId.getId()), operation);
return;
@ -422,6 +452,18 @@ public abstract class BaseController {
}
}
DeviceProfile checkDeviceProfileId(DeviceProfileId deviceProfileId, Operation operation) throws ThingsboardException {
try {
validateId(deviceProfileId, "Incorrect deviceProfileId " + deviceProfileId);
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(getCurrentUser().getTenantId(), deviceProfileId);
checkNotNull(deviceProfile);
accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile);
return deviceProfile;
} catch (Exception e) {
throw handleException(e, false);
}
}
protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation) throws ThingsboardException {
try {
validateId(entityViewId, "Incorrect entityViewId " + entityViewId);

192
application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java

@ -0,0 +1,192 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@Slf4j
public class DeviceProfileController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public DeviceProfile getDeviceProfileById(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkDeviceProfileId(deviceProfileId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getDeviceProfileInfoById(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
return checkNotNull(deviceProfileService.findDeviceProfileInfoById(getTenantId(), deviceProfileId));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getDefaultDeviceProfileInfo() throws ThingsboardException {
try {
return checkNotNull(deviceProfileService.findDefaultDeviceProfileInfo(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile saveDeviceProfile(@RequestBody DeviceProfile deviceProfile) throws ThingsboardException {
try {
deviceProfile.setTenantId(getTenantId());
checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile,
null,
savedDeviceProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
return savedDeviceProfile;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile,
null, deviceProfile.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteDeviceProfile(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE);
deviceProfileService.deleteDeviceProfile(getTenantId(), deviceProfileId);
logEntityAction(deviceProfileId, deviceProfile,
null,
ActionType.DELETED, null, strDeviceProfileId);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE_PROFILE),
null,
null,
ActionType.DELETED, e, strDeviceProfileId);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfile/{deviceProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public DeviceProfile setDefaultDeviceProfile(@PathVariable("deviceProfileId") String strDeviceProfileId) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
try {
DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId));
DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.WRITE);
DeviceProfile previousDefaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(getTenantId());
if (deviceProfileService.setDefaultDeviceProfile(getTenantId(), deviceProfileId)) {
if (previousDefaultDeviceProfile != null) {
previousDefaultDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), previousDefaultDeviceProfile.getId());
logEntityAction(previousDefaultDeviceProfile.getId(), previousDefaultDeviceProfile,
null, ActionType.UPDATED, null);
}
deviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfileId);
logEntityAction(deviceProfile.getId(), deviceProfile,
null, ActionType.UPDATED, null);
}
return deviceProfile;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.DEVICE_PROFILE),
null,
null,
ActionType.UPDATED, e, strDeviceProfileId);
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/deviceProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<DeviceProfile> getDeviceProfiles(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfiles(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/deviceProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityInfo> getDeviceProfileInfos(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(deviceProfileService.findDeviceProfileInfos(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
}

3
application/src/main/java/org/thingsboard/server/controller/TenantController.java

@ -58,8 +58,7 @@ public class TenantController extends BaseController {
checkParameter("tenantId", strTenantId);
try {
TenantId tenantId = new TenantId(toUUID(strTenantId));
checkTenantId(tenantId, Operation.READ);
return checkNotNull(tenantService.findTenantById(tenantId));
return checkTenantId(tenantId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}

162
application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java

@ -0,0 +1,162 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@Slf4j
public class TenantProfileController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.GET)
@ResponseBody
public TenantProfile getTenantProfileById(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkTenantProfileId(tenantProfileId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfileInfo/{tenantProfileId}", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getTenantProfileInfoById(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
return checkNotNull(tenantProfileService.findTenantProfileInfoById(getTenantId(), tenantProfileId));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfileInfo/default", method = RequestMethod.GET)
@ResponseBody
public EntityInfo getDefaultTenantProfileInfo() throws ThingsboardException {
try {
return checkNotNull(tenantProfileService.findDefaultTenantProfileInfo(getTenantId()));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile", method = RequestMethod.POST)
@ResponseBody
public TenantProfile saveTenantProfile(@RequestBody TenantProfile tenantProfile) throws ThingsboardException {
try {
boolean newTenantProfile = tenantProfile.getId() == null;
if (newTenantProfile) {
accessControlService
.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, Operation.CREATE);
} else {
checkEntityId(tenantProfile.getId(), Operation.WRITE);
}
tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile));
return tenantProfile;
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteTenantProfile(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
checkTenantProfileId(tenantProfileId, Operation.DELETE);
tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfile/{tenantProfileId}/default", method = RequestMethod.POST)
@ResponseBody
public TenantProfile setDefaultTenantProfile(@PathVariable("tenantProfileId") String strTenantProfileId) throws ThingsboardException {
checkParameter("tenantProfileId", strTenantProfileId);
try {
TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId));
TenantProfile tenantProfile = checkTenantProfileId(tenantProfileId, Operation.WRITE);
tenantProfileService.setDefaultTenantProfile(getTenantId(), tenantProfileId);
return tenantProfile;
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfiles", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<TenantProfile> getTenantProfiles(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfiles(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenantProfileInfos", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody
public PageData<EntityInfo> getTenantProfileInfos(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(tenantProfileService.findTenantProfileInfos(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
}

39
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -27,6 +27,7 @@ import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
@ -35,6 +36,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
@ -48,6 +50,7 @@ import org.thingsboard.server.controller.HttpValidationCallback;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.rule.RuleChainService;
@ -72,6 +75,7 @@ import java.util.function.BiConsumer;
@Component
public class AccessValidator {
public static final String ONLY_SYSTEM_ADMINISTRATOR_IS_ALLOWED_TO_PERFORM_THIS_OPERATION = "Only system administrator is allowed to perform this operation!";
public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!";
public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!";
public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!";
@ -89,6 +93,9 @@ public class AccessValidator {
@Autowired
protected DeviceService deviceService;
@Autowired
protected DeviceProfileService deviceProfileService;
@Autowired
protected AssetService assetService;
@ -162,6 +169,9 @@ public class AccessValidator {
case DEVICE:
validateDevice(currentUser, operation, entityId, callback);
return;
case DEVICE_PROFILE:
validateDeviceProfile(currentUser, operation, entityId, callback);
return;
case ASSET:
validateAsset(currentUser, operation, entityId, callback);
return;
@ -174,6 +184,9 @@ public class AccessValidator {
case TENANT:
validateTenant(currentUser, operation, entityId, callback);
return;
case TENANT_PROFILE:
validateTenantProfile(currentUser, operation, entityId, callback);
return;
case USER:
validateUser(currentUser, operation, entityId, callback);
return;
@ -206,6 +219,24 @@ public class AccessValidator {
}
}
private void validateDeviceProfile(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(currentUser.getTenantId(), new DeviceProfileId(entityId.getId()));
if (deviceProfile == null) {
callback.onSuccess(ValidationResult.entityNotFound("Device profile with requested id wasn't found!"));
} else {
try {
accessControlService.checkPermission(currentUser, Resource.DEVICE_PROFILE, operation, entityId, deviceProfile);
} catch (ThingsboardException e) {
callback.onSuccess(ValidationResult.accessDenied(e.getMessage()));
}
callback.onSuccess(ValidationResult.ok(deviceProfile));
}
}
}
private void validateAsset(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
@ -313,6 +344,14 @@ public class AccessValidator {
}
}
private void validateTenantProfile(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.ok(null));
} else {
callback.onSuccess(ValidationResult.accessDenied(ONLY_SYSTEM_ADMINISTRATOR_IS_ALLOWED_TO_PERFORM_THIS_OPERATION));
}
}
private void validateUser(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
ListenableFuture<User> userFuture = userService.findUserByIdAsync(currentUser.getTenantId(), new UserId(entityId.getId()));
Futures.addCallback(userFuture, getCallback(callback, user -> {

4
application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java

@ -31,7 +31,9 @@ public enum Resource {
RULE_CHAIN(EntityType.RULE_CHAIN),
USER(EntityType.USER),
WIDGETS_BUNDLE(EntityType.WIDGETS_BUNDLE),
WIDGET_TYPE(EntityType.WIDGET_TYPE);
WIDGET_TYPE(EntityType.WIDGET_TYPE),
TENANT_PROFILE(EntityType.TENANT_PROFILE),
DEVICE_PROFILE(EntityType.DEVICE_PROFILE);
private final EntityType entityType;

1
application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java

@ -39,6 +39,7 @@ public class SysAdminPermissions extends AbstractPermissions {
put(Resource.USER, userPermissionChecker);
put(Resource.WIDGETS_BUNDLE, systemEntityPermissionChecker);
put(Resource.WIDGET_TYPE, systemEntityPermissionChecker);
put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker);
}
private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() {

1
application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java

@ -42,6 +42,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
put(Resource.USER, userPermissionChecker);
put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker);
}
public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() {

1
application/src/main/resources/thingsboard.yml

@ -489,6 +489,7 @@ audit-log:
"rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}"
"alarm": "${AUDIT_LOG_MASK_ALARM:W}"
"entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}"
"device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}"
sink:
# Type of external sink. possible options: none, elasticsearch
type: "${AUDIT_LOG_SINK_TYPE:none}"

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

@ -61,6 +61,7 @@ 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.HasId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageLink;
@ -486,7 +487,7 @@ public abstract class AbstractWebTest {
return mapper.readerFor(type).readValue(content);
}
public class IdComparator<D extends BaseData<? extends UUIDBased>> implements Comparator<D> {
public class IdComparator<D extends HasId> implements Comparator<D> {
@Override
public int compare(D o1, D o2) {
return o1.getId().getId().compareTo(o2.getId().getId());

266
application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java

@ -0,0 +1,266 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest {
private IdComparator<DeviceProfile> idComparator = new IdComparator<>();
private IdComparator<EntityInfo> deviceProfileInfoIdComparator = new IdComparator<>();
private Tenant savedTenant;
private User tenantAdmin;
@Before
public void beforeTest() throws Exception {
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
}
@After
public void afterTest() throws Exception {
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
}
@Test
public void testSaveDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(savedDeviceProfile);
Assert.assertNotNull(savedDeviceProfile.getId());
Assert.assertTrue(savedDeviceProfile.getCreatedTime() > 0);
Assert.assertEquals(deviceProfile.getName(), savedDeviceProfile.getName());
Assert.assertEquals(deviceProfile.getDescription(), savedDeviceProfile.getDescription());
Assert.assertEquals(deviceProfile.getProfileData(), savedDeviceProfile.getProfileData());
Assert.assertEquals(deviceProfile.isDefault(), savedDeviceProfile.isDefault());
Assert.assertEquals(deviceProfile.getDefaultRuleChainId(), savedDeviceProfile.getDefaultRuleChainId());
savedDeviceProfile.setName("New device profile");
doPost("/api/deviceProfile", savedDeviceProfile, DeviceProfile.class);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName());
}
@Test
public void testFindDeviceProfileById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertNotNull(foundDeviceProfile);
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
}
@Test
public void testFindDeviceProfileInfoById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
EntityInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), EntityInfo.class);
Assert.assertNotNull(foundDeviceProfileInfo);
Assert.assertEquals(savedDeviceProfile.getId(), foundDeviceProfileInfo.getId());
Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfileInfo.getName());
}
@Test
public void testFindDefaultDeviceProfileInfo() throws Exception {
EntityInfo foundDefaultDeviceProfileInfo = doGet("/api/deviceProfileInfo/default", EntityInfo.class);
Assert.assertNotNull(foundDefaultDeviceProfileInfo);
Assert.assertNotNull(foundDefaultDeviceProfileInfo.getId());
Assert.assertNotNull(foundDefaultDeviceProfileInfo.getName());
Assert.assertEquals("Default", foundDefaultDeviceProfileInfo.getName());
}
@Test
public void testSetDefaultDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", null, DeviceProfile.class);
Assert.assertNotNull(defaultDeviceProfile);
EntityInfo foundDefaultDeviceProfile = doGet("/api/deviceProfileInfo/default", EntityInfo.class);
Assert.assertNotNull(foundDefaultDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getName(), foundDefaultDeviceProfile.getName());
Assert.assertEquals(savedDeviceProfile.getId(), foundDefaultDeviceProfile.getId());
}
@Test
public void testSaveDeviceProfileWithEmptyName() throws Exception {
DeviceProfile deviceProfile = new DeviceProfile();
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device profile name should be specified")));
}
@Test
public void testSaveDeviceProfileWithSameName() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile");
doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device profile with such name already exists")));
}
@Test
public void testDeleteDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
.andExpect(status().isNotFound());
}
@Test
public void testFindDeviceProfiles() throws Exception {
List<DeviceProfile> deviceProfiles = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData<DeviceProfile> pageData = doGetTypedWithPageLink("/api/deviceProfiles?",
new TypeReference<PageData<DeviceProfile>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
deviceProfiles.addAll(pageData.getData());
for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
}
List<DeviceProfile> loadedDeviceProfiles = new ArrayList<>();
pageLink = new PageLink(17);
do {
pageData = doGetTypedWithPageLink("/api/deviceProfiles?",
new TypeReference<PageData<DeviceProfile>>(){}, pageLink);
loadedDeviceProfiles.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Collections.sort(deviceProfiles, idComparator);
Collections.sort(loadedDeviceProfiles, idComparator);
Assert.assertEquals(deviceProfiles, loadedDeviceProfiles);
for (DeviceProfile deviceProfile : loadedDeviceProfiles) {
if (!deviceProfile.isDefault()) {
doDelete("/api/deviceProfile/" + deviceProfile.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/deviceProfiles?",
new TypeReference<PageData<DeviceProfile>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
}
@Test
public void testFindDeviceProfileInfos() throws Exception {
List<DeviceProfile> deviceProfiles = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData<DeviceProfile> deviceProfilePageData = doGetTypedWithPageLink("/api/deviceProfiles?",
new TypeReference<PageData<DeviceProfile>>(){}, pageLink);
Assert.assertFalse(deviceProfilePageData.hasNext());
Assert.assertEquals(1, deviceProfilePageData.getTotalElements());
deviceProfiles.addAll(deviceProfilePageData.getData());
for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
}
List<EntityInfo> loadedDeviceProfileInfos = new ArrayList<>();
pageLink = new PageLink(17);
PageData<EntityInfo> pageData;
do {
pageData = doGetTypedWithPageLink("/api/deviceProfileInfos?",
new TypeReference<PageData<EntityInfo>>(){}, pageLink);
loadedDeviceProfileInfos.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Collections.sort(deviceProfiles, idComparator);
Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator);
List<EntityInfo> deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new EntityInfo(deviceProfile.getId(),
deviceProfile.getName())).collect(Collectors.toList());
Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos);
for (DeviceProfile deviceProfile : deviceProfiles) {
if (!deviceProfile.isDefault()) {
doDelete("/api/deviceProfile/" + deviceProfile.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/deviceProfileInfos?",
new TypeReference<PageData<EntityInfo>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
}
private DeviceProfile createDeviceProfile(String name) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setDescription(name + " Test");
deviceProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(new RuleChainId(Uuids.timeBased()));
return deviceProfile;
}
}

255
application/src/test/java/org/thingsboard/server/controller/BaseTenantProfileControllerTest.java

@ -0,0 +1,255 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseTenantProfileControllerTest extends AbstractControllerTest {
private IdComparator<TenantProfile> idComparator = new IdComparator<>();
private IdComparator<EntityInfo> tenantProfileInfoIdComparator = new IdComparator<>();
@Autowired
private TenantProfileService tenantProfileService;
@After
public void after() {
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
public void testSaveTenantProfile() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
Assert.assertNotNull(savedTenantProfile);
Assert.assertNotNull(savedTenantProfile.getId());
Assert.assertTrue(savedTenantProfile.getCreatedTime() > 0);
Assert.assertEquals(tenantProfile.getName(), savedTenantProfile.getName());
Assert.assertEquals(tenantProfile.getDescription(), savedTenantProfile.getDescription());
Assert.assertEquals(tenantProfile.getProfileData(), savedTenantProfile.getProfileData());
Assert.assertEquals(tenantProfile.isDefault(), savedTenantProfile.isDefault());
Assert.assertEquals(tenantProfile.isIsolatedTbCore(), savedTenantProfile.isIsolatedTbCore());
Assert.assertEquals(tenantProfile.isIsolatedTbRuleEngine(), savedTenantProfile.isIsolatedTbRuleEngine());
savedTenantProfile.setName("New tenant profile");
doPost("/api/tenantProfile", savedTenantProfile, TenantProfile.class);
TenantProfile foundTenantProfile = doGet("/api/tenantProfile/"+savedTenantProfile.getId().getId().toString(), TenantProfile.class);
Assert.assertEquals(foundTenantProfile.getName(), savedTenantProfile.getName());
}
@Test
public void testFindTenantProfileById() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
TenantProfile foundTenantProfile = doGet("/api/tenantProfile/"+savedTenantProfile.getId().getId().toString(), TenantProfile.class);
Assert.assertNotNull(foundTenantProfile);
Assert.assertEquals(savedTenantProfile, foundTenantProfile);
}
@Test
public void testFindTenantProfileInfoById() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
EntityInfo foundTenantProfileInfo = doGet("/api/tenantProfileInfo/"+savedTenantProfile.getId().getId().toString(), EntityInfo.class);
Assert.assertNotNull(foundTenantProfileInfo);
Assert.assertEquals(savedTenantProfile.getId(), foundTenantProfileInfo.getId());
Assert.assertEquals(savedTenantProfile.getName(), foundTenantProfileInfo.getName());
}
@Test
public void testFindDefaultTenantProfileInfo() throws Exception {
loginSysAdmin();
EntityInfo foundDefaultTenantProfile = doGet("/api/tenantProfileInfo/default", EntityInfo.class);
Assert.assertNotNull(foundDefaultTenantProfile);
Assert.assertEquals("Default", foundDefaultTenantProfile.getName());
}
@Test
public void testSetDefaultTenantProfile() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile 1");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
TenantProfile defaultTenantProfile = doPost("/api/tenantProfile/"+savedTenantProfile.getId().getId().toString()+"/default", null, TenantProfile.class);
Assert.assertNotNull(defaultTenantProfile);
EntityInfo foundDefaultTenantProfile = doGet("/api/tenantProfileInfo/default", EntityInfo.class);
Assert.assertNotNull(foundDefaultTenantProfile);
Assert.assertEquals(savedTenantProfile.getName(), foundDefaultTenantProfile.getName());
Assert.assertEquals(savedTenantProfile.getId(), foundDefaultTenantProfile.getId());
}
@Test
public void testSaveTenantProfileWithEmptyName() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = new TenantProfile();
doPost("/api/tenantProfile", tenantProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Tenant profile name should be specified")));
}
@Test
public void testSaveTenantProfileWithSameName() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
doPost("/api/tenantProfile", tenantProfile).andExpect(status().isOk());
TenantProfile tenantProfile2 = this.createTenantProfile("Tenant Profile");
doPost("/api/tenantProfile", tenantProfile2).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Tenant profile with such name already exists")));
}
@Test
public void testDeleteTenantProfile() throws Exception {
loginSysAdmin();
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile");
TenantProfile savedTenantProfile = doPost("/api/tenantProfile", tenantProfile, TenantProfile.class);
doDelete("/api/tenantProfile/" + savedTenantProfile.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/tenantProfile/" + savedTenantProfile.getId().getId().toString())
.andExpect(status().isNotFound());
}
@Test
public void testFindTenantProfiles() throws Exception {
loginSysAdmin();
List<TenantProfile> tenantProfiles = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData<TenantProfile> pageData = doGetTypedWithPageLink("/api/tenantProfiles?",
new TypeReference<PageData<TenantProfile>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
tenantProfiles.addAll(pageData.getData());
for (int i=0;i<28;i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"+i);
tenantProfiles.add(doPost("/api/tenantProfile", tenantProfile, TenantProfile.class));
}
List<TenantProfile> loadedTenantProfiles = new ArrayList<>();
pageLink = new PageLink(17);
do {
pageData = doGetTypedWithPageLink("/api/tenantProfiles?",
new TypeReference<PageData<TenantProfile>>(){}, pageLink);
loadedTenantProfiles.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Collections.sort(tenantProfiles, idComparator);
Collections.sort(loadedTenantProfiles, idComparator);
Assert.assertEquals(tenantProfiles, loadedTenantProfiles);
for (TenantProfile tenantProfile : loadedTenantProfiles) {
if (!tenantProfile.isDefault()) {
doDelete("/api/tenantProfile/" + tenantProfile.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/tenantProfiles?",
new TypeReference<PageData<TenantProfile>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
}
@Test
public void testFindTenantProfileInfos() throws Exception {
loginSysAdmin();
List<TenantProfile> tenantProfiles = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData<TenantProfile> tenantProfilePageData = doGetTypedWithPageLink("/api/tenantProfiles?",
new TypeReference<PageData<TenantProfile>>(){}, pageLink);
Assert.assertFalse(tenantProfilePageData.hasNext());
Assert.assertEquals(1, tenantProfilePageData.getTotalElements());
tenantProfiles.addAll(tenantProfilePageData.getData());
for (int i=0;i<28;i++) {
TenantProfile tenantProfile = this.createTenantProfile("Tenant Profile"+i);
tenantProfiles.add(doPost("/api/tenantProfile", tenantProfile, TenantProfile.class));
}
List<EntityInfo> loadedTenantProfileInfos = new ArrayList<>();
pageLink = new PageLink(17);
PageData<EntityInfo> pageData;
do {
pageData = doGetTypedWithPageLink("/api/tenantProfileInfos?",
new TypeReference<PageData<EntityInfo>>(){}, pageLink);
loadedTenantProfileInfos.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Collections.sort(tenantProfiles, idComparator);
Collections.sort(loadedTenantProfileInfos, tenantProfileInfoIdComparator);
List<EntityInfo> tenantProfileInfos = tenantProfiles.stream().map(tenantProfile -> new EntityInfo(tenantProfile.getId(),
tenantProfile.getName())).collect(Collectors.toList());
Assert.assertEquals(tenantProfileInfos, loadedTenantProfileInfos);
for (TenantProfile tenantProfile : tenantProfiles) {
if (!tenantProfile.isDefault()) {
doDelete("/api/tenantProfile/" + tenantProfile.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/tenantProfileInfos?",
new TypeReference<PageData<EntityInfo>>(){}, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getTotalElements());
}
private TenantProfile createTenantProfile(String name) {
TenantProfile tenantProfile = new TenantProfile();
tenantProfile.setName(name);
tenantProfile.setDescription(name + " Test");
tenantProfile.setProfileData(JacksonUtil.OBJECT_MAPPER.createObjectNode());
tenantProfile.setDefault(false);
tenantProfile.setIsolatedTbCore(false);
tenantProfile.setIsolatedTbRuleEngine(false);
return tenantProfile;
}
}

23
application/src/test/java/org/thingsboard/server/controller/sql/DeviceProfileControllerSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller.sql;
import org.thingsboard.server.controller.BaseDeviceProfileControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@DaoSqlTest
public class DeviceProfileControllerSqlTest extends BaseDeviceProfileControllerTest {
}

23
application/src/test/java/org/thingsboard/server/controller/sql/TenantProfileControllerSqlTest.java

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller.sql;
import org.thingsboard.server.controller.BaseTenantProfileControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@DaoSqlTest
public class TenantProfileControllerSqlTest extends BaseTenantProfileControllerTest {
}

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

@ -28,7 +28,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn
@Data
@EqualsAndHashCode(callSuper = true)
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName {
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId {
private TenantId tenantId;
private String name;

5
common/data/src/main/java/org/thingsboard/server/common/data/EntityInfo.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -28,7 +30,8 @@ public class EntityInfo implements HasId<EntityId>, HasName {
private final EntityId id;
private final String name;
public EntityInfo(EntityId id, String name) {
@JsonCreator
public EntityInfo(@JsonProperty("id") EntityId id, @JsonProperty("name") String name) {
this.id = id;
this.name = name;
}

24
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -60,7 +60,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
@Autowired
private CacheManager cacheManager;
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId}")
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")
@Override
public DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId) {
log.trace("Executing findDeviceProfileById [{}]", deviceProfileId);
@ -68,7 +68,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return deviceProfileDao.findById(tenantId, deviceProfileId.getId());
}
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId}")
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'info', #deviceProfileId.id}")
@Override
public EntityInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId) {
log.trace("Executing findDeviceProfileById [{}]", deviceProfileId);
@ -92,11 +92,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
}
Cache cache = cacheManager.getCache(DEVICE_PROFILE_CACHE);
cache.evict(Collections.singletonList(savedDeviceProfile.getId()));
cache.evict(Arrays.asList("info", savedDeviceProfile.getId()));
cache.evict(Collections.singletonList(savedDeviceProfile.getId().getId()));
cache.evict(Arrays.asList("info", savedDeviceProfile.getId().getId()));
if (savedDeviceProfile.isDefault()) {
cache.evict(Arrays.asList("default", savedDeviceProfile.getTenantId()));
cache.evict(Arrays.asList("default", "info", savedDeviceProfile.getTenantId()));
cache.evict(Arrays.asList("default", savedDeviceProfile.getTenantId().getId()));
cache.evict(Arrays.asList("default", "info", savedDeviceProfile.getTenantId().getId()));
}
return savedDeviceProfile;
}
@ -149,7 +149,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return saveDeviceProfile(deviceProfile);
}
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'default', #tenantId}")
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'default', #tenantId.id}")
@Override
public DeviceProfile findDefaultDeviceProfile(TenantId tenantId) {
log.trace("Executing findDefaultDeviceProfile tenantId [{}]", tenantId);
@ -157,7 +157,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
return deviceProfileDao.findDefaultDeviceProfile(tenantId);
}
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'default', 'info', #tenantId}")
@Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{'default', 'info', #tenantId.id}")
@Override
public EntityInfo findDefaultDeviceProfileInfo(TenantId tenantId) {
log.trace("Executing findDefaultDeviceProfileInfo tenantId [{}]", tenantId);
@ -182,13 +182,13 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
previousDefaultDeviceProfile.setDefault(false);
deviceProfileDao.save(tenantId, previousDefaultDeviceProfile);
deviceProfileDao.save(tenantId, deviceProfile);
cache.evict(Collections.singletonList(previousDefaultDeviceProfile.getId()));
cache.evict(Arrays.asList("info", previousDefaultDeviceProfile.getId()));
cache.evict(Collections.singletonList(previousDefaultDeviceProfile.getId().getId()));
cache.evict(Arrays.asList("info", previousDefaultDeviceProfile.getId().getId()));
changed = true;
}
if (changed) {
cache.evict(Collections.singletonList(deviceProfile.getId()));
cache.evict(Arrays.asList("info", deviceProfile.getId()));
cache.evict(Collections.singletonList(deviceProfile.getId().getId()));
cache.evict(Arrays.asList("info", deviceProfile.getId().getId()));
cache.evict(Arrays.asList("default", tenantId));
cache.evict(Arrays.asList("default", "info", tenantId));
}

16
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java

@ -54,7 +54,7 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
@Autowired
private CacheManager cacheManager;
@Cacheable(cacheNames = TENANT_PROFILE_CACHE, key = "{#tenantProfileId}")
@Cacheable(cacheNames = TENANT_PROFILE_CACHE, key = "{#tenantProfileId.id}")
@Override
public TenantProfile findTenantProfileById(TenantId tenantId, TenantProfileId tenantProfileId) {
log.trace("Executing findTenantProfileById [{}]", tenantProfileId);
@ -62,7 +62,7 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
return tenantProfileDao.findById(tenantId, tenantProfileId.getId());
}
@Cacheable(cacheNames = TENANT_PROFILE_CACHE, key = "{'info', #tenantProfileId}")
@Cacheable(cacheNames = TENANT_PROFILE_CACHE, key = "{'info', #tenantProfileId.id}")
@Override
public EntityInfo findTenantProfileInfoById(TenantId tenantId, TenantProfileId tenantProfileId) {
log.trace("Executing findTenantProfileInfoById [{}]", tenantProfileId);
@ -86,8 +86,8 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
}
}
Cache cache = cacheManager.getCache(TENANT_PROFILE_CACHE);
cache.evict(Collections.singletonList(savedTenantProfile.getId()));
cache.evict(Arrays.asList("info", savedTenantProfile.getId()));
cache.evict(Collections.singletonList(savedTenantProfile.getId().getId()));
cache.evict(Arrays.asList("info", savedTenantProfile.getId().getId()));
if (savedTenantProfile.isDefault()) {
cache.evict(Collections.singletonList("default"));
cache.evict(Arrays.asList("default", "info"));
@ -176,13 +176,13 @@ public class TenantProfileServiceImpl extends AbstractEntityService implements T
previousDefaultTenantProfile.setDefault(false);
tenantProfileDao.save(tenantId, previousDefaultTenantProfile);
tenantProfileDao.save(tenantId, tenantProfile);
cache.evict(Collections.singletonList(previousDefaultTenantProfile.getId()));
cache.evict(Arrays.asList("info", previousDefaultTenantProfile.getId()));
cache.evict(Collections.singletonList(previousDefaultTenantProfile.getId().getId()));
cache.evict(Arrays.asList("info", previousDefaultTenantProfile.getId().getId()));
changed = true;
}
if (changed) {
cache.evict(Collections.singletonList(tenantProfile.getId()));
cache.evict(Arrays.asList("info", tenantProfile.getId()));
cache.evict(Collections.singletonList(tenantProfile.getId().getId()));
cache.evict(Arrays.asList("info", tenantProfile.getId().getId()));
cache.evict(Collections.singletonList("default"));
cache.evict(Arrays.asList("default", "info"));
}

2
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

@ -104,9 +104,9 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@Test
public void testFindDefaultDeviceProfileInfo() {
EntityInfo foundDefaultDeviceProfileInfo = deviceProfileService.findDefaultDeviceProfileInfo(tenantId);
Assert.assertNotNull(foundDefaultDeviceProfileInfo);
Assert.assertNotNull(foundDefaultDeviceProfileInfo.getId());
Assert.assertNotNull(foundDefaultDeviceProfileInfo.getName());
Assert.assertNotNull(foundDefaultDeviceProfileInfo);
}
@Test

7
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantProfileServiceTest.java

@ -60,8 +60,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, savedTenantProfile);
TenantProfile foundTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenantProfile.getId());
Assert.assertEquals(foundTenantProfile.getName(), savedTenantProfile.getName());
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
@ -71,7 +69,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
TenantProfile foundTenantProfile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, savedTenantProfile.getId());
Assert.assertNotNull(foundTenantProfile);
Assert.assertEquals(savedTenantProfile, foundTenantProfile);
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
@ -82,7 +79,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
Assert.assertNotNull(foundTenantProfileInfo);
Assert.assertEquals(savedTenantProfile.getId(), foundTenantProfileInfo.getId());
Assert.assertEquals(savedTenantProfile.getName(), foundTenantProfileInfo.getName());
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
@ -93,7 +89,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
TenantProfile foundDefaultTenantProfile = tenantProfileService.findDefaultTenantProfile(TenantId.SYS_TENANT_ID);
Assert.assertNotNull(foundDefaultTenantProfile);
Assert.assertEquals(savedTenantProfile, foundDefaultTenantProfile);
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
@ -105,7 +100,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
Assert.assertNotNull(foundDefaultTenantProfileInfo);
Assert.assertEquals(savedTenantProfile.getId(), foundDefaultTenantProfileInfo.getId());
Assert.assertEquals(savedTenantProfile.getName(), foundDefaultTenantProfileInfo.getName());
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test
@ -126,7 +120,6 @@ public class BaseTenantProfileServiceTest extends AbstractServiceTest {
defaultTenantProfile = tenantProfileService.findDefaultTenantProfile(TenantId.SYS_TENANT_ID);
Assert.assertNotNull(defaultTenantProfile);
Assert.assertEquals(savedTenantProfile2.getId(), defaultTenantProfile.getId());
tenantProfileService.deleteTenantProfiles(TenantId.SYS_TENANT_ID);
}
@Test(expected = DataValidationException.class)

Loading…
Cancel
Save