Version control support for resources
This commit is contained in:
parent
6eadef0d68
commit
72ae6eb708
@ -30,5 +30,6 @@ $$;
|
|||||||
ALTER TABLE resource
|
ALTER TABLE resource
|
||||||
ADD COLUMN IF NOT EXISTS descriptor varchar,
|
ADD COLUMN IF NOT EXISTS descriptor varchar,
|
||||||
ADD COLUMN IF NOT EXISTS preview bytea;
|
ADD COLUMN IF NOT EXISTS preview bytea;
|
||||||
|
ALTER TABLE resource ADD COLUMN IF NOT EXISTS external_id uuid
|
||||||
|
|
||||||
-- RESOURCES UPDATE END
|
-- RESOURCES UPDATE END
|
||||||
|
|||||||
@ -35,7 +35,6 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import org.springframework.web.bind.annotation.RequestPart;
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
|
||||||
import org.thingsboard.server.common.data.ImageDescriptor;
|
import org.thingsboard.server.common.data.ImageDescriptor;
|
||||||
import org.thingsboard.server.common.data.ResourceType;
|
import org.thingsboard.server.common.data.ResourceType;
|
||||||
import org.thingsboard.server.common.data.TbResource;
|
import org.thingsboard.server.common.data.TbResource;
|
||||||
@ -88,7 +87,7 @@ public class ImageController extends BaseController {
|
|||||||
image.setResourceType(ResourceType.IMAGE);
|
image.setResourceType(ResourceType.IMAGE);
|
||||||
ImageDescriptor descriptor = new ImageDescriptor();
|
ImageDescriptor descriptor = new ImageDescriptor();
|
||||||
descriptor.setMediaType(file.getContentType());
|
descriptor.setMediaType(file.getContentType());
|
||||||
image.setDescriptor(JacksonUtil.valueToTree(descriptor));
|
image.setDescriptorValue(descriptor);
|
||||||
image.setData(file.getBytes());
|
image.setData(file.getBytes());
|
||||||
return tbImageService.save(image, user);
|
return tbImageService.save(image, user);
|
||||||
}
|
}
|
||||||
@ -99,11 +98,12 @@ public class ImageController extends BaseController {
|
|||||||
@PathVariable String key,
|
@PathVariable String key,
|
||||||
@RequestPart MultipartFile file) throws Exception {
|
@RequestPart MultipartFile file) throws Exception {
|
||||||
TbResourceInfo imageInfo = checkImageInfo(type, key, Operation.WRITE);
|
TbResourceInfo imageInfo = checkImageInfo(type, key, Operation.WRITE);
|
||||||
ImageDescriptor descriptor = imageInfo.getDescriptor(ImageDescriptor.class);
|
|
||||||
|
|
||||||
TbResource image = new TbResource(imageInfo);
|
TbResource image = new TbResource(imageInfo);
|
||||||
image.setData(file.getBytes());
|
image.setData(file.getBytes());
|
||||||
|
image.updateDescriptor(ImageDescriptor.class, descriptor -> {
|
||||||
descriptor.setMediaType(file.getContentType());
|
descriptor.setMediaType(file.getContentType());
|
||||||
|
return descriptor;
|
||||||
|
});
|
||||||
return tbImageService.save(image, getCurrentUser());
|
return tbImageService.save(image, getCurrentUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@ 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.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -226,6 +227,30 @@ public class TbResourceController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "Get All Resource Infos (getAllResources)",
|
||||||
|
notes = "Returns a page of Resource Info objects owned by tenant. " +
|
||||||
|
PAGE_DATA_PARAMETERS + RESOURCE_INFO_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
|
||||||
|
produces = "application/json")
|
||||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
|
||||||
|
@GetMapping(value = "/resource/tenant")
|
||||||
|
public PageData<TbResourceInfo> getTenantResources(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
|
||||||
|
@RequestParam int pageSize,
|
||||||
|
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
|
||||||
|
@RequestParam int page,
|
||||||
|
@ApiParam(value = RESOURCE_TEXT_SEARCH_DESCRIPTION)
|
||||||
|
@RequestParam(required = false) String textSearch,
|
||||||
|
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RESOURCE_SORT_PROPERTY_ALLOWABLE_VALUES)
|
||||||
|
@RequestParam(required = false) String sortProperty,
|
||||||
|
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
|
||||||
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
|
||||||
|
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
|
||||||
|
TbResourceInfoFilter filter = TbResourceInfoFilter.builder()
|
||||||
|
.tenantId(getTenantId())
|
||||||
|
.resourceTypes(EnumSet.allOf(ResourceType.class))
|
||||||
|
.build();
|
||||||
|
return checkNotNull(resourceService.findTenantResourcesByTenantId(filter, pageLink));
|
||||||
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjectsPage)",
|
@ApiOperation(value = "Get LwM2M Objects (getLwm2mListObjectsPage)",
|
||||||
notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " +
|
notes = "Returns a page of LwM2M objects parsed from Resources with type 'LWM2M_MODEL' owned by tenant or sysadmin. " +
|
||||||
PAGE_DATA_PARAMETERS + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
|
PAGE_DATA_PARAMETERS + LWM2M_OBJECT_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
|
||||||
|
|||||||
@ -118,6 +118,16 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <I extends EntityId> PageData<I> findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) {
|
||||||
|
ExportableEntityDao<I, ?> dao = getExportableEntityDao(entityType);
|
||||||
|
if (dao != null) {
|
||||||
|
return dao.findIdsByTenantId(tenantId.getId(), pageLink);
|
||||||
|
} else {
|
||||||
|
return new PageData<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <I extends EntityId> I getExternalIdByInternal(I internalId) {
|
public <I extends EntityId> I getExternalIdByInternal(I internalId) {
|
||||||
ExportableEntityDao<I, ?> dao = getExportableEntityDao(internalId.getEntityType());
|
ExportableEntityDao<I, ?> dao = getExportableEntityDao(internalId.getEntityType());
|
||||||
|
|||||||
@ -35,6 +35,8 @@ public interface ExportableEntitiesService {
|
|||||||
|
|
||||||
<E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);
|
<E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);
|
||||||
|
|
||||||
|
<I extends EntityId> PageData<I> findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);
|
||||||
|
|
||||||
<I extends EntityId> I getExternalIdByInternal(I internalId);
|
<I extends EntityId> I getExternalIdByInternal(I internalId);
|
||||||
|
|
||||||
<I extends EntityId> void removeById(TenantId tenantId, I id);
|
<I extends EntityId> void removeById(TenantId tenantId, I id);
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2023 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.service.sync.ie.exporting.impl;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
|
import org.thingsboard.server.common.data.TbResource;
|
||||||
|
import org.thingsboard.server.common.data.id.TbResourceId;
|
||||||
|
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
|
||||||
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@TbCoreComponent
|
||||||
|
public class ResourceExportService extends BaseEntityExportService<TbResourceId, TbResource, EntityExportData<TbResource>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<EntityType> getSupportedEntityTypes() {
|
||||||
|
return Set.of(EntityType.TB_RESOURCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2023 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.service.sync.ie.importing.impl;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
|
import org.thingsboard.server.common.data.TbResource;
|
||||||
|
import org.thingsboard.server.common.data.User;
|
||||||
|
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||||
|
import org.thingsboard.server.common.data.id.TbResourceId;
|
||||||
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
|
import org.thingsboard.server.common.data.sync.ie.EntityExportData;
|
||||||
|
import org.thingsboard.server.dao.resource.ResourceService;
|
||||||
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
|
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@TbCoreComponent
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ResourceImportService extends BaseEntityImportService<TbResourceId, TbResource, EntityExportData<TbResource>> {
|
||||||
|
|
||||||
|
private final ResourceService resourceService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setOwner(TenantId tenantId, TbResource resource, IdProvider idProvider) {
|
||||||
|
resource.setTenantId(tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbResource prepare(EntitiesImportCtx ctx, TbResource resource, TbResource oldResource, EntityExportData<TbResource> exportData, IdProvider idProvider) {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbResource findExistingEntity(EntitiesImportCtx ctx, TbResource resource, IdProvider idProvider) {
|
||||||
|
TbResource existingResource = super.findExistingEntity(ctx, resource, idProvider);
|
||||||
|
if (existingResource == null && ctx.isFindExistingByName()) {
|
||||||
|
existingResource = resourceService.findResourceByTenantIdAndKey(ctx.getTenantId(), resource.getResourceType(), resource.getResourceKey());
|
||||||
|
}
|
||||||
|
return existingResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean compare(EntitiesImportCtx ctx, EntityExportData<TbResource> exportData, TbResource prepared, TbResource existing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbResource deepCopy(TbResource resource) {
|
||||||
|
return new TbResource(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbResource saveOrUpdate(EntitiesImportCtx ctx, TbResource resource, EntityExportData<TbResource> exportData, IdProvider idProvider) {
|
||||||
|
return resourceService.saveResource(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEntitySaved(User user, TbResource savedResource, TbResource oldResource) throws ThingsboardException {
|
||||||
|
super.onEntitySaved(user, savedResource, oldResource);
|
||||||
|
clusterService.onResourceChange(savedResource, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityType getEntityType() {
|
||||||
|
return EntityType.TB_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -20,13 +20,9 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.thingsboard.server.common.data.EntityType;
|
import org.thingsboard.server.common.data.EntityType;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.WidgetTypeId;
|
import org.thingsboard.server.common.data.id.WidgetTypeId;
|
||||||
import org.thingsboard.server.common.data.id.WidgetsBundleId;
|
|
||||||
import org.thingsboard.server.common.data.sync.ie.WidgetTypeExportData;
|
import org.thingsboard.server.common.data.sync.ie.WidgetTypeExportData;
|
||||||
import org.thingsboard.server.common.data.sync.ie.WidgetsBundleExportData;
|
|
||||||
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
|
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
|
||||||
import org.thingsboard.server.common.data.widget.WidgetsBundle;
|
|
||||||
import org.thingsboard.server.dao.widget.WidgetTypeService;
|
import org.thingsboard.server.dao.widget.WidgetTypeService;
|
||||||
import org.thingsboard.server.dao.widget.WidgetsBundleService;
|
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
|
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
|
||||||
|
|
||||||
|
|||||||
@ -208,10 +208,10 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.isAllEntities()) {
|
if (config.isAllEntities()) {
|
||||||
DaoUtil.processInBatches(pageLink -> exportableEntitiesService.findEntitiesByTenantId(ctx.getTenantId(), entityType, pageLink)
|
DaoUtil.processInBatches(pageLink -> exportableEntitiesService.findEntitiesIdsByTenantId(ctx.getTenantId(), entityType, pageLink),
|
||||||
, 100, entity -> {
|
100, entityId -> {
|
||||||
try {
|
try {
|
||||||
ctx.add(saveEntityData(ctx, entity.getId()));
|
ctx.add(saveEntityData(ctx, entityId));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public interface ResourceService extends EntityDaoService {
|
|||||||
|
|
||||||
TbResource saveResource(TbResource resource, boolean doValidate);
|
TbResource saveResource(TbResource resource, boolean doValidate);
|
||||||
|
|
||||||
TbResource findResourceByTenantIdAndKey(TenantId tenantId, ResourceType resourceType, String resourceId);
|
TbResource findResourceByTenantIdAndKey(TenantId tenantId, ResourceType resourceType, String resourceKey);
|
||||||
|
|
||||||
TbResource findResourceById(TenantId tenantId, TbResourceId resourceId);
|
TbResource findResourceById(TenantId tenantId, TbResourceId resourceId);
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
package org.thingsboard.server.common.data;
|
package org.thingsboard.server.common.data;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -34,10 +33,8 @@ public class TbResource extends TbResourceInfo {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 7379609705527272306L;
|
private static final long serialVersionUID = 7379609705527272306L;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
private byte[] data;
|
private byte[] data;
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
private byte[] preview;
|
private byte[] preview;
|
||||||
|
|
||||||
public TbResource() {
|
public TbResource() {
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -30,11 +29,13 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.common.data.validation.Length;
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
@ApiModel
|
@ApiModel
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, HasTenantId {
|
public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, HasTenantId, ExportableEntity<TbResourceId> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 7282664529021651736L;
|
private static final long serialVersionUID = 7282664529021651736L;
|
||||||
|
|
||||||
@ -52,15 +53,17 @@ 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 etag.", example = "33a64df551425fcc55e4d42a148795d9f25f89d4", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
|
@ApiModelProperty(position = 8, value = "Resource etag.", example = "33a64df551425fcc55e4d42a148795d9f25f89d4", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
|
||||||
private String etag;
|
private String etag;
|
||||||
@NoXss
|
@NoXss
|
||||||
@Length(fieldName = "file name")
|
@Length(fieldName = "file name")
|
||||||
@ApiModelProperty(position = 9, value = "Resource file name.", example = "19.xml", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
|
@ApiModelProperty(position = 9, value = "Resource file name.", example = "19.xml", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
|
||||||
private String fileName;
|
private String fileName;
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
|
||||||
private JsonNode descriptor;
|
private JsonNode descriptor;
|
||||||
|
|
||||||
|
private TbResourceId externalId;
|
||||||
|
|
||||||
public TbResourceInfo() {
|
public TbResourceInfo() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@ -78,7 +81,8 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
|
|||||||
this.searchText = resourceInfo.searchText;
|
this.searchText = resourceInfo.searchText;
|
||||||
this.etag = resourceInfo.etag;
|
this.etag = resourceInfo.etag;
|
||||||
this.fileName = resourceInfo.fileName;
|
this.fileName = resourceInfo.fileName;
|
||||||
this.descriptor = resourceInfo.descriptor;
|
this.descriptor = resourceInfo.descriptor != null ? resourceInfo.descriptor.deepCopy() : null;
|
||||||
|
this.externalId = resourceInfo.externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " +
|
@ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " +
|
||||||
@ -97,7 +101,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@JsonIgnore
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
@ -107,9 +111,19 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
|
|||||||
return searchText != null ? searchText : title;
|
return searchText != null ? searchText : title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public <T> T getDescriptor(Class<T> type) throws JsonProcessingException {
|
public <T> T getDescriptor(Class<T> type) throws JsonProcessingException {
|
||||||
return descriptor != null ? mapper.treeToValue(descriptor, type) : null;
|
return descriptor != null ? mapper.treeToValue(descriptor, type) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> void updateDescriptor(Class<T> type, UnaryOperator<T> updater) throws JsonProcessingException {
|
||||||
|
T descriptor = getDescriptor(type);
|
||||||
|
descriptor = updater.apply(descriptor);
|
||||||
|
setDescriptorValue(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public void setDescriptorValue(Object value) {
|
||||||
|
this.descriptor = value != null ? mapper.valueToTree(value) : null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.Dashboard;
|
|||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
import org.thingsboard.server.common.data.EntityView;
|
import org.thingsboard.server.common.data.EntityView;
|
||||||
|
import org.thingsboard.server.common.data.TbResource;
|
||||||
import org.thingsboard.server.common.data.asset.Asset;
|
import org.thingsboard.server.common.data.asset.Asset;
|
||||||
import org.thingsboard.server.common.data.asset.AssetProfile;
|
import org.thingsboard.server.common.data.asset.AssetProfile;
|
||||||
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
|
import org.thingsboard.server.common.data.notification.rule.NotificationRule;
|
||||||
@ -56,7 +57,8 @@ import java.lang.annotation.Target;
|
|||||||
@Type(name = "WIDGET_TYPE", value = WidgetTypeDetails.class),
|
@Type(name = "WIDGET_TYPE", value = WidgetTypeDetails.class),
|
||||||
@Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class),
|
@Type(name = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.class),
|
||||||
@Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class),
|
@Type(name = "NOTIFICATION_TARGET", value = NotificationTarget.class),
|
||||||
@Type(name = "NOTIFICATION_RULE", value = NotificationRule.class)
|
@Type(name = "NOTIFICATION_RULE", value = NotificationRule.class),
|
||||||
|
@Type(name = "TB_RESOURCE", value = TbResource.class)
|
||||||
})
|
})
|
||||||
@JsonIgnoreProperties(value = {"tenantId", "createdTime"}, ignoreUnknown = true)
|
@JsonIgnoreProperties(value = {"tenantId", "createdTime"}, ignoreUnknown = true)
|
||||||
public @interface JsonTbEntity {
|
public @interface JsonTbEntity {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.page.PageLink;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface ExportableEntityDao<I extends EntityId, T extends ExportableEntity<?>> extends Dao<T> {
|
public interface ExportableEntityDao<I extends EntityId, T extends ExportableEntity<I>> extends Dao<T> {
|
||||||
|
|
||||||
T findByTenantIdAndExternalId(UUID tenantId, UUID externalId);
|
T findByTenantIdAndExternalId(UUID tenantId, UUID externalId);
|
||||||
|
|
||||||
@ -30,6 +30,10 @@ public interface ExportableEntityDao<I extends EntityId, T extends ExportableEnt
|
|||||||
|
|
||||||
PageData<T> findByTenantId(UUID tenantId, PageLink pageLink);
|
PageData<T> findByTenantId(UUID tenantId, PageLink pageLink);
|
||||||
|
|
||||||
|
default PageData<I> findIdsByTenantId(UUID tenantId, PageLink pageLink) {
|
||||||
|
return findByTenantId(tenantId, pageLink).mapData(ExportableEntity::getId);
|
||||||
|
}
|
||||||
|
|
||||||
I getExternalIdByInternal(I internalId);
|
I getExternalIdByInternal(I internalId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,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.EXTERNAL_ID_PROPERTY;
|
||||||
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_DESCRIPTOR_COLUMN;
|
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DESCRIPTOR_COLUMN;
|
||||||
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_COLUMN;
|
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_COLUMN;
|
||||||
@ -82,6 +83,9 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> {
|
|||||||
@Column(name = RESOURCE_PREVIEW_COLUMN)
|
@Column(name = RESOURCE_PREVIEW_COLUMN)
|
||||||
private byte[] preview;
|
private byte[] preview;
|
||||||
|
|
||||||
|
@Column(name = EXTERNAL_ID_PROPERTY)
|
||||||
|
private UUID externalId;
|
||||||
|
|
||||||
public TbResourceEntity() {
|
public TbResourceEntity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +106,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> {
|
|||||||
this.etag = resource.getEtag();
|
this.etag = resource.getEtag();
|
||||||
this.descriptor = resource.getDescriptor();
|
this.descriptor = resource.getDescriptor();
|
||||||
this.preview = resource.getPreview();
|
this.preview = resource.getPreview();
|
||||||
|
this.externalId = getUuid(resource.getExternalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -118,6 +123,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> {
|
|||||||
resource.setEtag(etag);
|
resource.setEtag(etag);
|
||||||
resource.setDescriptor(descriptor);
|
resource.setDescriptor(descriptor);
|
||||||
resource.setPreview(preview);
|
resource.setPreview(preview);
|
||||||
|
resource.setExternalId(getEntityId(externalId, TbResourceId::new));
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,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.EXTERNAL_ID_PROPERTY;
|
||||||
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DESCRIPTOR_COLUMN;
|
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DESCRIPTOR_COLUMN;
|
||||||
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_COLUMN;
|
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ETAG_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;
|
||||||
@ -75,6 +76,9 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
|
|||||||
@Column(name = RESOURCE_DESCRIPTOR_COLUMN)
|
@Column(name = RESOURCE_DESCRIPTOR_COLUMN)
|
||||||
private JsonNode descriptor;
|
private JsonNode descriptor;
|
||||||
|
|
||||||
|
@Column(name = EXTERNAL_ID_PROPERTY)
|
||||||
|
private UUID externalId;
|
||||||
|
|
||||||
public TbResourceInfoEntity() {
|
public TbResourceInfoEntity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +95,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
|
|||||||
this.hashCode = resource.getEtag();
|
this.hashCode = resource.getEtag();
|
||||||
this.fileName = resource.getFileName();
|
this.fileName = resource.getFileName();
|
||||||
this.descriptor = resource.getDescriptor();
|
this.descriptor = resource.getDescriptor();
|
||||||
|
this.externalId = getUuid(resource.getExternalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -105,6 +110,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
|
|||||||
resource.setEtag(hashCode);
|
resource.setEtag(hashCode);
|
||||||
resource.setFileName(fileName);
|
resource.setFileName(fileName);
|
||||||
resource.setDescriptor(descriptor);
|
resource.setDescriptor(descriptor);
|
||||||
|
resource.setExternalId(getEntityId(externalId, TbResourceId::new));
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic
|
|||||||
Pair<ImageDescriptor, byte[]> result = processImage(image.getData(), descriptor);
|
Pair<ImageDescriptor, byte[]> result = processImage(image.getData(), descriptor);
|
||||||
descriptor = result.getLeft();
|
descriptor = result.getLeft();
|
||||||
image.setEtag(descriptor.getEtag());
|
image.setEtag(descriptor.getEtag());
|
||||||
image.setDescriptor(JacksonUtil.valueToTree(descriptor));
|
image.setDescriptorValue(descriptor);
|
||||||
image.setPreview(result.getRight());
|
image.setPreview(result.getRight());
|
||||||
|
|
||||||
return new TbResourceInfo(doSaveResource(image));
|
return new TbResourceInfo(doSaveResource(image));
|
||||||
|
|||||||
@ -96,8 +96,7 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
|
|||||||
publishEvictEvent(new ResourceInfoEvictEvent(tenantId, resource.getId()));
|
publishEvictEvent(new ResourceInfoEvictEvent(tenantId, resource.getId()));
|
||||||
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
|
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
|
||||||
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) {
|
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) {
|
||||||
String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName";
|
throw new DataValidationException("Resource with such key already exists!");
|
||||||
throw new DataValidationException("Resource with such " + field + " already exists!");
|
|
||||||
} else {
|
} else {
|
||||||
throw t;
|
throw t;
|
||||||
}
|
}
|
||||||
@ -202,6 +201,11 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
|
|||||||
return Optional.ofNullable(findResourceInfoById(tenantId, new TbResourceId(entityId.getId())));
|
return Optional.ofNullable(findResourceInfoById(tenantId, new TbResourceId(entityId.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteEntity(TenantId tenantId, EntityId id) {
|
||||||
|
deleteResource(tenantId, (TbResourceId) id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityType getEntityType() {
|
public EntityType getEntityType() {
|
||||||
return EntityType.TB_RESOURCE;
|
return EntityType.TB_RESOURCE;
|
||||||
|
|||||||
@ -22,11 +22,12 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.common.data.page.PageData;
|
import org.thingsboard.server.common.data.page.PageData;
|
||||||
import org.thingsboard.server.common.data.page.PageLink;
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
import org.thingsboard.server.dao.Dao;
|
import org.thingsboard.server.dao.Dao;
|
||||||
|
import org.thingsboard.server.dao.ExportableEntityDao;
|
||||||
import org.thingsboard.server.dao.TenantEntityWithDataDao;
|
import org.thingsboard.server.dao.TenantEntityWithDataDao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface TbResourceDao extends Dao<TbResource>, TenantEntityWithDataDao {
|
public interface TbResourceDao extends Dao<TbResource>, TenantEntityWithDataDao, ExportableEntityDao<TbResourceId, TbResource> {
|
||||||
|
|
||||||
TbResource findResourceByTenantIdAndKey(TenantId tenantId, ResourceType resourceType, String resourceId);
|
TbResource findResourceByTenantIdAndKey(TenantId tenantId, ResourceType resourceType, String resourceId);
|
||||||
|
|
||||||
|
|||||||
@ -109,6 +109,27 @@ public class JpaTbResourceDao extends JpaAbstractDao<TbResourceEntity, TbResourc
|
|||||||
return resourceRepository.sumDataSizeByTenantId(tenantId.getId());
|
return resourceRepository.sumDataSizeByTenantId(tenantId.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbResource findByTenantIdAndExternalId(UUID tenantId, UUID externalId) {
|
||||||
|
return DaoUtil.getData(resourceRepository.findByTenantIdAndExternalId(tenantId, externalId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageData<TbResource> findByTenantId(UUID tenantId, PageLink pageLink) {
|
||||||
|
return findAllByTenantId(TenantId.fromUUID(tenantId), pageLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageData<TbResourceId> findIdsByTenantId(UUID tenantId, PageLink pageLink) {
|
||||||
|
return DaoUtil.pageToPageData(resourceRepository.findIdsByTenantId(tenantId, DaoUtil.toPageable(pageLink))
|
||||||
|
.map(TbResourceId::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbResourceId getExternalIdByInternal(TbResourceId internalId) {
|
||||||
|
return DaoUtil.toEntityId(resourceRepository.getExternalIdByInternal(internalId.getId()), TbResourceId::new);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityType getEntityType() {
|
public EntityType getEntityType() {
|
||||||
return EntityType.TB_RESOURCE;
|
return EntityType.TB_RESOURCE;
|
||||||
|
|||||||
@ -20,12 +20,13 @@ import org.springframework.data.domain.Pageable;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.thingsboard.server.dao.ExportableEntityRepository;
|
||||||
import org.thingsboard.server.dao.model.sql.TbResourceEntity;
|
import org.thingsboard.server.dao.model.sql.TbResourceEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface TbResourceRepository extends JpaRepository<TbResourceEntity, UUID> {
|
public interface TbResourceRepository extends JpaRepository<TbResourceEntity, UUID> , ExportableEntityRepository<TbResourceEntity> {
|
||||||
|
|
||||||
TbResourceEntity findByTenantIdAndResourceTypeAndResourceKey(UUID tenantId, String resourceType, String resourceKey);
|
TbResourceEntity findByTenantIdAndResourceTypeAndResourceKey(UUID tenantId, String resourceType, String resourceKey);
|
||||||
|
|
||||||
@ -87,4 +88,10 @@ public interface TbResourceRepository extends JpaRepository<TbResourceEntity, UU
|
|||||||
@Query(value = "SELECT COALESCE(preview, data) FROM resource WHERE id = :id", nativeQuery = true)
|
@Query(value = "SELECT COALESCE(preview, data) FROM resource WHERE id = :id", nativeQuery = true)
|
||||||
byte[] getPreviewById(@Param("id") UUID id);
|
byte[] getPreviewById(@Param("id") UUID id);
|
||||||
|
|
||||||
|
@Query("SELECT externalId FROM TbResourceInfoEntity WHERE id = :id")
|
||||||
|
UUID getExternalIdByInternal(@Param("id") UUID internalId);
|
||||||
|
|
||||||
|
@Query("SELECT id FROM TbResourceInfoEntity WHERE tenantId = :tenantId")
|
||||||
|
Page<UUID> findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,6 +204,12 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
|
|||||||
DaoUtil.toPageable(pageLink)));
|
DaoUtil.toPageable(pageLink)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageData<WidgetTypeId> findIdsByTenantId(UUID tenantId, PageLink pageLink) {
|
||||||
|
return DaoUtil.pageToPageData(widgetTypeRepository.findIdsByTenantId(tenantId, DaoUtil.toPageable(pageLink))
|
||||||
|
.map(WidgetTypeId::new));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WidgetTypeId getExternalIdByInternal(WidgetTypeId internalId) {
|
public WidgetTypeId getExternalIdByInternal(WidgetTypeId internalId) {
|
||||||
return Optional.ofNullable(widgetTypeRepository.getExternalIdById(internalId.getId()))
|
return Optional.ofNullable(widgetTypeRepository.getExternalIdById(internalId.getId()))
|
||||||
|
|||||||
@ -76,7 +76,10 @@ public interface WidgetTypeRepository extends JpaRepository<WidgetTypeDetailsEnt
|
|||||||
@Query("SELECT externalId FROM WidgetTypeDetailsEntity WHERE id = :id")
|
@Query("SELECT externalId FROM WidgetTypeDetailsEntity WHERE id = :id")
|
||||||
UUID getExternalIdById(@Param("id") UUID id);
|
UUID getExternalIdById(@Param("id") UUID id);
|
||||||
|
|
||||||
@Query("SELECT id FROM WidgetTypeEntity")
|
@Query("SELECT id FROM WidgetTypeDetailsEntity")
|
||||||
Page<UUID> findAllIds(Pageable pageable);
|
Page<UUID> findAllIds(Pageable pageable);
|
||||||
|
|
||||||
|
@Query("SELECT id FROM WidgetTypeDetailsEntity WHERE tenantId = :tenantId")
|
||||||
|
Page<UUID> findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -718,6 +718,7 @@ CREATE TABLE IF NOT EXISTS resource (
|
|||||||
etag varchar,
|
etag varchar,
|
||||||
descriptor varchar,
|
descriptor varchar,
|
||||||
preview bytea,
|
preview bytea,
|
||||||
|
external_id uuid,
|
||||||
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
|
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user