Resources access for Customer Users

This commit is contained in:
Andrii Shvaika 2023-06-08 17:44:20 +03:00
parent 1b15e78985
commit d34a65eada
13 changed files with 135 additions and 48 deletions

View File

@ -54,8 +54,8 @@ $$;
-- NOTIFICATION CONFIGS VERSION CONTROL END -- NOTIFICATION CONFIGS VERSION CONTROL END
ALTER TABLE resource ALTER TABLE resource
ADD COLUMN IF NOT EXISTS hash_code varchar; ADD COLUMN IF NOT EXISTS etag varchar;
UPDATE resource UPDATE resource
SET hash_code = encode(sha256(decode(resource.data, 'base64')),'hex') WHERE resource.data is not null; SET etag = encode(sha256(decode(resource.data, 'base64')),'hex') WHERE resource.data is not null;

View File

@ -15,8 +15,6 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -49,13 +47,13 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.resource.TbResourceService; import org.thingsboard.server.service.resource.TbResourceService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER;
import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS; import static org.thingsboard.server.controller.ControllerConstants.PAGE_DATA_PARAMETERS;
@ -82,6 +80,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@RequiredArgsConstructor @RequiredArgsConstructor
public class TbResourceController extends BaseController { public class TbResourceController extends BaseController {
private static final String DOWNLOAD_RESOURCE_IF_NOT_CHANGED = "Download Resource based on the provided Resource Id or return 304 status code if resource was not changed.";
private final TbResourceService tbResourceService; private final TbResourceService tbResourceService;
public static final String RESOURCE_ID = "resourceId"; public static final String RESOURCE_ID = "resourceId";
@ -105,39 +104,44 @@ public class TbResourceController extends BaseController {
.body(resource); .body(resource);
} }
@ApiOperation(value = "Download LWM2M Resource (downloadLwm2mResourceIfChanged)", notes = "Download Resource based on the provided Resource Id or return 304 status code if resource was not changed." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @ApiOperation(value = "Download LWM2M Resource (downloadLwm2mResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/lwm2m/{resourceId}/download", method = RequestMethod.GET) @RequestMapping(value = "/resource/lwm2m/{resourceId}/download", method = RequestMethod.GET, produces = "application/xml")
@ResponseBody @ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadLwm2mResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) public ResponseEntity<org.springframework.core.io.Resource> downloadLwm2mResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId, @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException { @PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
return downloadResourceIfChanged(ResourceType.LWM2M_MODEL, strResourceId, etag); return downloadResourceIfChanged(ResourceType.LWM2M_MODEL, strResourceId, etag);
} }
@ApiOperation(value = "Download PKCS_12 Resource (downloadPkcs12ResourceIfChanged)", notes = "Download Resource based on the provided Resource Id or return 304 status code if resource was not changed." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @ApiOperation(value = "Download PKCS_12 Resource (downloadPkcs12ResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/pkcs12/{resourceId}/download", method = RequestMethod.GET) @RequestMapping(value = "/resource/pkcs12/{resourceId}/download", method = RequestMethod.GET, produces = "application/x-pkcs12")
@ResponseBody @ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadPkcs12ResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) public ResponseEntity<org.springframework.core.io.Resource> downloadPkcs12ResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId, @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException { @PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
return downloadResourceIfChanged(ResourceType.PKCS_12, strResourceId, etag); return downloadResourceIfChanged(ResourceType.PKCS_12, strResourceId, etag);
} }
@ApiOperation(value = "Download JKS Resource (downloadJksResourceIfChanged)", notes = "Download Resource based on the provided Resource Id or return 304 status code if resource was not changed." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @ApiOperation(value = "Download JKS Resource (downloadJksResourceIfChanged)",
notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/jks/{resourceId}/download", method = RequestMethod.GET) @RequestMapping(value = "/resource/jks/{resourceId}/download", method = RequestMethod.GET, produces = "application/x-java-keystore")
@ResponseBody @ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadJksResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) public ResponseEntity<org.springframework.core.io.Resource> downloadJksResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId, @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException { @PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
return downloadResourceIfChanged(ResourceType.JKS, strResourceId, etag); return downloadResourceIfChanged(ResourceType.JKS, strResourceId, etag);
} }
@ApiOperation(value = "Download JS Resource (downloadJsResourceIfChanged)", notes = "Download Resource based on the provided Resource Id or return 304 status code if resource was not changed." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @ApiOperation(value = "Download JS Resource (downloadJsResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/resource/js/{resourceId}/download", method = RequestMethod.GET) @RequestMapping(value = "/resource/js/{resourceId}/download", method = RequestMethod.GET, produces = "application/javascript")
@ResponseBody @ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadJsResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION) public ResponseEntity<org.springframework.core.io.Resource> downloadJsResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId, @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException { @PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
return downloadResourceIfChanged(ResourceType.JS_MODULE, strResourceId, etag); return downloadResourceIfChanged(ResourceType.JS_MODULE, strResourceId, etag);
} }
@ -277,9 +281,9 @@ public class TbResourceController extends BaseController {
if (etag != null) { if (etag != null) {
TbResourceInfo tbResourceInfo = checkResourceInfoId(resourceId, Operation.READ); TbResourceInfo tbResourceInfo = checkResourceInfoId(resourceId, Operation.READ);
if (etag.equals(tbResourceInfo.getHashCode())) { if (etag.equals(tbResourceInfo.getEtag())) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED) return ResponseEntity.status(HttpStatus.NOT_MODIFIED)
.eTag(tbResourceInfo.getHashCode()) .eTag(tbResourceInfo.getEtag())
.build(); .build();
} }
} }
@ -293,7 +297,7 @@ public class TbResourceController extends BaseController {
.contentLength(resource.contentLength()) .contentLength(resource.contentLength())
.header("Content-Type", type.getMediaType()) .header("Content-Type", type.getMediaType())
.cacheControl(CacheControl.noCache()) .cacheControl(CacheControl.noCache())
.eTag(tbResource.getHashCode()) .eTag(tbResource.getEtag())
.body(resource); .body(resource);
} }
} }

View File

@ -170,7 +170,7 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements
resource.setResourceKey(resource.getFileName()); resource.setResourceKey(resource.getFileName());
} }
HashCode hashCode = Hashing.sha256().hashBytes(Base64.getDecoder().decode(resource.getData().getBytes())); HashCode hashCode = Hashing.sha256().hashBytes(Base64.getDecoder().decode(resource.getData().getBytes()));
resource.setHashCode(hashCode.toString()); resource.setEtag(hashCode.toString());
return resourceService.saveResource(resource); return resourceService.saveResource(resource);
} }
} }

View File

@ -19,9 +19,13 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
@ -44,6 +48,7 @@ public class CustomerUserPermissions extends AbstractPermissions {
put(Resource.RPC, rpcPermissionChecker); put(Resource.RPC, rpcPermissionChecker);
put(Resource.DEVICE_PROFILE, profilePermissionChecker); put(Resource.DEVICE_PROFILE, profilePermissionChecker);
put(Resource.ASSET_PROFILE, profilePermissionChecker); put(Resource.ASSET_PROFILE, profilePermissionChecker);
put(Resource.TB_RESOURCE, customerResourcePermissionChecker);
} }
private static final PermissionChecker customerAlarmPermissionChecker = new PermissionChecker() { private static final PermissionChecker customerAlarmPermissionChecker = new PermissionChecker() {
@ -95,6 +100,26 @@ public class CustomerUserPermissions extends AbstractPermissions {
}; };
private static final PermissionChecker customerResourcePermissionChecker =
new PermissionChecker.GenericPermissionChecker<TbResourceId, TbResourceInfo>(Operation.READ) {
@Override
@SuppressWarnings("unchecked")
public boolean hasPermission(SecurityUser user, Operation operation, TbResourceId resourceId, TbResourceInfo resource) {
if (operation != Operation.READ) {
return false;
}
if (resource.getResourceType() == null || !resource.getResourceType().isCustomerAccess()) {
return false;
}
if (resource.getTenantId() == null || resource.getTenantId().isNullUid()) {
return true;
}
return user.getTenantId().equals(resource.getTenantId());
}
};
private static final PermissionChecker customerDashboardPermissionChecker = private static final PermissionChecker customerDashboardPermissionChecker =
new PermissionChecker.GenericPermissionChecker<DashboardId, DashboardInfo>(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) { new PermissionChecker.GenericPermissionChecker<DashboardId, DashboardInfo>(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) {

View File

@ -166,6 +166,8 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
private static final String CUSTOMER_USER_PASSWORD = "customer"; private static final String CUSTOMER_USER_PASSWORD = "customer";
protected static final String DIFFERENT_CUSTOMER_USER_EMAIL = "testdifferentcustomer@thingsboard.org"; protected static final String DIFFERENT_CUSTOMER_USER_EMAIL = "testdifferentcustomer@thingsboard.org";
protected static final String DIFFERENT_TENANT_CUSTOMER_USER_EMAIL = "testdifferenttenantcustomer@thingsboard.org";
private static final String DIFFERENT_CUSTOMER_USER_PASSWORD = "diffcustomer"; private static final String DIFFERENT_CUSTOMER_USER_PASSWORD = "diffcustomer";
/** /**
@ -191,9 +193,13 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
protected CustomerId customerId; protected CustomerId customerId;
protected TenantId differentTenantId; protected TenantId differentTenantId;
protected CustomerId differentCustomerId; protected CustomerId differentCustomerId;
protected CustomerId differentTenantCustomerId;
protected UserId customerUserId; protected UserId customerUserId;
protected UserId differentCustomerUserId; protected UserId differentCustomerUserId;
protected UserId differentTenantCustomerUserId;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private HttpMessageConverter mappingJackson2HttpMessageConverter; private HttpMessageConverter mappingJackson2HttpMessageConverter;
@ -365,7 +371,9 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
protected Tenant savedDifferentTenant; protected Tenant savedDifferentTenant;
protected User savedDifferentTenantUser; protected User savedDifferentTenantUser;
private Customer savedDifferentCustomer; private Customer savedDifferentCustomer;
private Customer savedDifferentTenantCustomer;
protected User differentCustomerUser; protected User differentCustomerUser;
protected User differentTenantCustomerUser;
protected void loginDifferentTenant() throws Exception { protected void loginDifferentTenant() throws Exception {
if (savedDifferentTenant != null) { if (savedDifferentTenant != null) {
@ -407,6 +415,24 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
} }
} }
protected void loginDifferentTenantCustomer() throws Exception {
if (savedDifferentTenantCustomer != null) {
login(savedDifferentTenantCustomer.getEmail(), CUSTOMER_USER_PASSWORD);
} else {
createDifferentTenantCustomer();
loginDifferentTenant();
differentTenantCustomerUser = new User();
differentTenantCustomerUser.setAuthority(Authority.CUSTOMER_USER);
differentTenantCustomerUser.setTenantId(savedDifferentTenantCustomer.getTenantId());
differentTenantCustomerUser.setCustomerId(savedDifferentTenantCustomer.getId());
differentTenantCustomerUser.setEmail(DIFFERENT_TENANT_CUSTOMER_USER_EMAIL);
differentTenantCustomerUser = createUserAndLogin(differentTenantCustomerUser, DIFFERENT_CUSTOMER_USER_PASSWORD);
differentTenantCustomerUserId = differentTenantCustomerUser.getId();
}
}
protected void createDifferentCustomer() throws Exception { protected void createDifferentCustomer() throws Exception {
loginTenantAdmin(); loginTenantAdmin();
@ -419,6 +445,18 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
resetTokens(); resetTokens();
} }
protected void createDifferentTenantCustomer() throws Exception {
loginDifferentTenant();
Customer customer = new Customer();
customer.setTitle("Different tenant customer");
savedDifferentTenantCustomer = doPost("/api/customer", customer, Customer.class);
Assert.assertNotNull(savedDifferentTenantCustomer);
differentTenantCustomerId = savedDifferentTenantCustomer.getId();
resetTokens();
}
protected void deleteDifferentTenant() throws Exception { protected void deleteDifferentTenant() throws Exception {
if (savedDifferentTenant != null) { if (savedDifferentTenant != null) {
loginSysAdmin(); loginSysAdmin();

View File

@ -526,7 +526,6 @@ public class TbResourceControllerTest extends AbstractControllerTest {
.andExpect(status().isNotModified()); .andExpect(status().isNotModified());
} }
@Ignore
@Test @Test
public void testDownloadTbResourceIfChangedAsPublicCustomer() throws Exception { public void testDownloadTbResourceIfChangedAsPublicCustomer() throws Exception {
loginTenantAdmin(); loginTenantAdmin();
@ -571,6 +570,25 @@ public class TbResourceControllerTest extends AbstractControllerTest {
.andExpect(status().isNotModified()); .andExpect(status().isNotModified());
} }
@Test
public void testDownloadTbResourceIfChangedAsCustomerOfDifferentTenant() throws Exception {
loginTenantAdmin();
Mockito.reset(tbClusterService, auditLogService);
TbResource resource = new TbResource();
resource.setResourceType(ResourceType.JS_MODULE);
resource.setTitle("Js resource");
resource.setFileName(JS_TEST_FILE_NAME);
resource.setData(TEST_DATA);
TbResource savedResource = save(resource);
loginDifferentTenant();
loginDifferentTenantCustomer();
doGet("/api/resource/js/" + savedResource.getId().getId().toString() + "/download")
.andExpect(status().isForbidden());
}
private TbResource save(TbResource tbResource) throws Exception { private TbResource save(TbResource tbResource) throws Exception {
return doPostWithTypedResponse("/api/resource", tbResource, new TypeReference<>(){}); return doPostWithTypedResponse("/api/resource", tbResource, new TypeReference<>(){});
} }

View File

@ -15,19 +15,21 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import lombok.Getter;
public enum ResourceType { public enum ResourceType {
LWM2M_MODEL("application/xml"), LWM2M_MODEL("application/xml", false),
JKS("application/x-java-keystore"), JKS("application/x-java-keystore", false),
PKCS_12("application/x-pkcs12"), PKCS_12("application/x-pkcs12", false),
JS_MODULE("application/javascript"); JS_MODULE("application/javascript", true);
@Getter
private final String mediaType; private final String mediaType;
@Getter
private final boolean customerAccess;
ResourceType(String mediaType) { ResourceType(String mediaType, boolean customerAccess) {
this.mediaType = mediaType; this.mediaType = mediaType;
} this.customerAccess = customerAccess;
public String getMediaType() {
return mediaType;
} }
} }

View File

@ -75,7 +75,7 @@ public class TbResource extends TbResourceInfo {
builder.append(", data="); builder.append(", data=");
builder.append(data); builder.append(data);
builder.append(", hashCode="); builder.append(", hashCode=");
builder.append(getHashCode()); builder.append(getEtag());
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }

View File

@ -48,8 +48,8 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
private String resourceKey; private String resourceKey;
@ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", accessMode = ApiModelProperty.AccessMode.READ_ONLY) @ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String searchText; private String searchText;
@ApiModelProperty(position = 8, value = "Resource hash code.", example = "33a64df551425fcc55e4d42a148795d9f25f89d4", accessMode = ApiModelProperty.AccessMode.READ_ONLY) @ApiModelProperty(position = 8, value = "Resource etag.", example = "33a64df551425fcc55e4d42a148795d9f25f89d4", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String hashCode; private String etag;
public TbResourceInfo() { public TbResourceInfo() {
super(); super();
@ -66,7 +66,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
this.resourceType = resourceInfo.getResourceType(); this.resourceType = resourceInfo.getResourceType();
this.resourceKey = resourceInfo.getResourceKey(); this.resourceKey = resourceInfo.getResourceKey();
this.searchText = resourceInfo.getSearchText(); this.searchText = resourceInfo.getSearchText();
this.hashCode = resourceInfo.getHashCode(); this.etag = resourceInfo.getEtag();
} }
@ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " + @ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " +
@ -111,7 +111,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
builder.append(", resourceKey="); builder.append(", resourceKey=");
builder.append(resourceKey); builder.append(resourceKey);
builder.append(", hashCode="); builder.append(", hashCode=");
builder.append(hashCode); builder.append(etag);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }

View File

@ -480,7 +480,7 @@ public class ModelConstants {
public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY; public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY;
public static final String RESOURCE_FILE_NAME_COLUMN = "file_name"; public static final String RESOURCE_FILE_NAME_COLUMN = "file_name";
public static final String RESOURCE_DATA_COLUMN = "data"; public static final String RESOURCE_DATA_COLUMN = "data";
public static final String RESOURCE_HASH_CODE_COLUMN = "hash_code"; public static final String RESOURCE_ETAG_COLUMN = "etag";
/** /**
* Ota Package constants. * Ota Package constants.

View File

@ -31,7 +31,7 @@ import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_FILE_NAME_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_FILE_NAME_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_HASH_CODE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
@ -66,8 +66,8 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
@Column(name = RESOURCE_DATA_COLUMN) @Column(name = RESOURCE_DATA_COLUMN)
private String data; private String data;
@Column(name = RESOURCE_HASH_CODE_COLUMN) @Column(name = RESOURCE_ETAG_COLUMN)
private String hashCode; private String etag;
public TbResourceEntity() { public TbResourceEntity() {
} }
@ -86,7 +86,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
this.searchText = resource.getSearchText(); this.searchText = resource.getSearchText();
this.fileName = resource.getFileName(); this.fileName = resource.getFileName();
this.data = resource.getData(); this.data = resource.getData();
this.hashCode = resource.getHashCode(); this.etag = resource.getEtag();
} }
@Override @Override
@ -100,7 +100,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
resource.setSearchText(searchText); resource.setSearchText(searchText);
resource.setFileName(fileName); resource.setFileName(fileName);
resource.setData(data); resource.setData(data);
resource.setHashCode(hashCode); resource.setEtag(etag);
return resource; return resource;
} }

View File

@ -29,7 +29,7 @@ import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import java.util.UUID; import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_HASH_CODE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
@ -58,7 +58,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
@Column(name = SEARCH_TEXT_PROPERTY) @Column(name = SEARCH_TEXT_PROPERTY)
private String searchText; private String searchText;
@Column(name = RESOURCE_HASH_CODE_COLUMN) @Column(name = RESOURCE_ETAG_COLUMN)
private String hashCode; private String hashCode;
public TbResourceInfoEntity() { public TbResourceInfoEntity() {
@ -74,7 +74,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
this.resourceType = resource.getResourceType().name(); this.resourceType = resource.getResourceType().name();
this.resourceKey = resource.getResourceKey(); this.resourceKey = resource.getResourceKey();
this.searchText = resource.getSearchText(); this.searchText = resource.getSearchText();
this.hashCode = resource.getHashCode(); this.hashCode = resource.getEtag();
} }
@Override @Override
@ -86,7 +86,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
resource.setResourceType(ResourceType.valueOf(resourceType)); resource.setResourceType(ResourceType.valueOf(resourceType));
resource.setResourceKey(resourceKey); resource.setResourceKey(resourceKey);
resource.setSearchText(searchText); resource.setSearchText(searchText);
resource.setHashCode(hashCode); resource.setEtag(hashCode);
return resource; return resource;
} }
} }

View File

@ -697,7 +697,7 @@ CREATE TABLE IF NOT EXISTS resource (
search_text varchar(255), search_text varchar(255),
file_name varchar(255) NOT NULL, file_name varchar(255) NOT NULL,
data varchar, data varchar,
hash_code varchar, etag varchar,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key) CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
); );