Version control support for resources

This commit is contained in:
ViacheslavKlimov 2023-11-16 15:13:00 +02:00
parent 6eadef0d68
commit 72ae6eb708
25 changed files with 259 additions and 34 deletions

View File

@ -30,5 +30,6 @@ $$;
ALTER TABLE resource
ADD COLUMN IF NOT EXISTS descriptor varchar,
ADD COLUMN IF NOT EXISTS preview bytea;
ALTER TABLE resource ADD COLUMN IF NOT EXISTS external_id uuid
-- RESOURCES UPDATE END

View File

@ -35,7 +35,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
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.ResourceType;
import org.thingsboard.server.common.data.TbResource;
@ -88,7 +87,7 @@ public class ImageController extends BaseController {
image.setResourceType(ResourceType.IMAGE);
ImageDescriptor descriptor = new ImageDescriptor();
descriptor.setMediaType(file.getContentType());
image.setDescriptor(JacksonUtil.valueToTree(descriptor));
image.setDescriptorValue(descriptor);
image.setData(file.getBytes());
return tbImageService.save(image, user);
}
@ -99,11 +98,12 @@ public class ImageController extends BaseController {
@PathVariable String key,
@RequestPart MultipartFile file) throws Exception {
TbResourceInfo imageInfo = checkImageInfo(type, key, Operation.WRITE);
ImageDescriptor descriptor = imageInfo.getDescriptor(ImageDescriptor.class);
TbResource image = new TbResource(imageInfo);
image.setData(file.getBytes());
descriptor.setMediaType(file.getContentType());
image.updateDescriptor(ImageDescriptor.class, descriptor -> {
descriptor.setMediaType(file.getContentType());
return descriptor;
});
return tbImageService.save(image, getCurrentUser());
}

View File

@ -53,6 +53,7 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
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)",
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,

View File

@ -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
public <I extends EntityId> I getExternalIdByInternal(I internalId) {
ExportableEntityDao<I, ?> dao = getExportableEntityDao(internalId.getEntityType());

View File

@ -35,6 +35,8 @@ public interface ExportableEntitiesService {
<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> void removeById(TenantId tenantId, I id);

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -20,13 +20,9 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
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.WidgetsBundleExportData;
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.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;

View File

@ -208,10 +208,10 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
}
if (config.isAllEntities()) {
DaoUtil.processInBatches(pageLink -> exportableEntitiesService.findEntitiesByTenantId(ctx.getTenantId(), entityType, pageLink)
, 100, entity -> {
DaoUtil.processInBatches(pageLink -> exportableEntitiesService.findEntitiesIdsByTenantId(ctx.getTenantId(), entityType, pageLink),
100, entityId -> {
try {
ctx.add(saveEntityData(ctx, entity.getId()));
ctx.add(saveEntityData(ctx, entityId));
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@ -34,7 +34,7 @@ public interface ResourceService extends EntityDaoService {
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);

View File

@ -16,7 +16,6 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -34,10 +33,8 @@ public class TbResource extends TbResourceInfo {
private static final long serialVersionUID = 7379609705527272306L;
@JsonIgnore
private byte[] data;
@JsonIgnore
private byte[] preview;
public TbResource() {

View File

@ -19,7 +19,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
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.NoXss;
import java.util.function.UnaryOperator;
@ApiModel
@Slf4j
@Data
@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;
@ -52,15 +53,17 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
private String resourceKey;
@ApiModelProperty(position = 7, value = "Resource search text.", example = "19_1.0:binaryappdatacontainer", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String searchText;
@ApiModelProperty(position = 8, value = "Resource etag.", example = "33a64df551425fcc55e4d42a148795d9f25f89d4", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String etag;
@NoXss
@Length(fieldName = "file name")
@ApiModelProperty(position = 9, value = "Resource file name.", example = "19.xml", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String fileName;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private JsonNode descriptor;
private TbResourceId externalId;
public TbResourceInfo() {
super();
}
@ -78,13 +81,14 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
this.searchText = resourceInfo.searchText;
this.etag = resourceInfo.etag;
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. " +
"Specify this field to update the Resource. " +
"Referencing non-existing Resource Id will cause error. " +
"Omit this field to create new Resource." )
"Omit this field to create new Resource.")
@Override
public TbResourceId getId() {
return super.getId();
@ -97,7 +101,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
}
@Override
@JsonIgnore
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getName() {
return title;
}
@ -107,9 +111,19 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
return searchText != null ? searchText : title;
}
@JsonIgnore
public <T> T getDescriptor(Class<T> type) throws JsonProcessingException {
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;
}
}

View File

@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.Dashboard;
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.TbResource;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetProfile;
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 = "NOTIFICATION_TEMPLATE", value = NotificationTemplate.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)
public @interface JsonTbEntity {

View File

@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.page.PageLink;
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);
@ -30,6 +30,10 @@ public interface ExportableEntityDao<I extends EntityId, T extends ExportableEnt
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);
}

View File

@ -32,6 +32,7 @@ import javax.persistence.Entity;
import javax.persistence.Table;
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_DESCRIPTOR_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)
private byte[] preview;
@Column(name = EXTERNAL_ID_PROPERTY)
private UUID externalId;
public TbResourceEntity() {
}
@ -102,6 +106,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> {
this.etag = resource.getEtag();
this.descriptor = resource.getDescriptor();
this.preview = resource.getPreview();
this.externalId = getUuid(resource.getExternalId());
}
@Override
@ -118,6 +123,7 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> {
resource.setEtag(etag);
resource.setDescriptor(descriptor);
resource.setPreview(preview);
resource.setExternalId(getEntityId(externalId, TbResourceId::new));
return resource;
}

View File

@ -33,6 +33,7 @@ import javax.persistence.Entity;
import javax.persistence.Table;
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_ETAG_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)
private JsonNode descriptor;
@Column(name = EXTERNAL_ID_PROPERTY)
private UUID externalId;
public TbResourceInfoEntity() {
}
@ -91,6 +95,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
this.hashCode = resource.getEtag();
this.fileName = resource.getFileName();
this.descriptor = resource.getDescriptor();
this.externalId = getUuid(resource.getExternalId());
}
@Override
@ -105,6 +110,7 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
resource.setEtag(hashCode);
resource.setFileName(fileName);
resource.setDescriptor(descriptor);
resource.setExternalId(getEntityId(externalId, TbResourceId::new));
return resource;
}
}

View File

@ -59,7 +59,7 @@ public class BaseImageService extends BaseResourceService implements ImageServic
Pair<ImageDescriptor, byte[]> result = processImage(image.getData(), descriptor);
descriptor = result.getLeft();
image.setEtag(descriptor.getEtag());
image.setDescriptor(JacksonUtil.valueToTree(descriptor));
image.setDescriptorValue(descriptor);
image.setPreview(result.getRight());
return new TbResourceInfo(doSaveResource(image));

View File

@ -96,8 +96,7 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
publishEvictEvent(new ResourceInfoEvictEvent(tenantId, resource.getId()));
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
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 " + field + " already exists!");
throw new DataValidationException("Resource with such key already exists!");
} else {
throw t;
}
@ -202,6 +201,11 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
return Optional.ofNullable(findResourceInfoById(tenantId, new TbResourceId(entityId.getId())));
}
@Override
public void deleteEntity(TenantId tenantId, EntityId id) {
deleteResource(tenantId, (TbResourceId) id);
}
@Override
public EntityType getEntityType() {
return EntityType.TB_RESOURCE;

View File

@ -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.PageLink;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.ExportableEntityDao;
import org.thingsboard.server.dao.TenantEntityWithDataDao;
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);

View File

@ -109,6 +109,27 @@ public class JpaTbResourceDao extends JpaAbstractDao<TbResourceEntity, TbResourc
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
public EntityType getEntityType() {
return EntityType.TB_RESOURCE;

View File

@ -59,8 +59,8 @@ public interface TbResourceInfoRepository extends JpaRepository<TbResourceInfoEn
@Query(value = "SELECT r.resource_key FROM resource r WHERE r.tenant_id = :tenantId AND r.resource_type = :resourceType " +
"AND starts_with(r.resource_key, :resourceKeyStartsWith)", nativeQuery = true)
List<String> findKeysByTenantIdAndResourceTypeAndResourceKeyStartingWith(@Param("tenantId") UUID tenantId,
@Param("resourceType") String resourceType,
@Param("resourceKeyStartsWith") String resourceKeyStartsWith);
@Param("resourceType") String resourceType,
@Param("resourceKeyStartsWith") String resourceKeyStartsWith);
List<TbResourceInfoEntity> findByTenantIdAndHashCodeAndResourceKeyStartingWith(UUID tenantId, String hashCode, String query);

View File

@ -20,12 +20,13 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.dao.ExportableEntityRepository;
import org.thingsboard.server.dao.model.sql.TbResourceEntity;
import java.util.List;
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);
@ -87,4 +88,10 @@ public interface TbResourceRepository extends JpaRepository<TbResourceEntity, UU
@Query(value = "SELECT COALESCE(preview, data) FROM resource WHERE id = :id", nativeQuery = true)
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);
}

View File

@ -121,7 +121,7 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
}
@Override
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) {
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) {
boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter);
boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter);
boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty();
@ -204,6 +204,12 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
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
public WidgetTypeId getExternalIdByInternal(WidgetTypeId internalId) {
return Optional.ofNullable(widgetTypeRepository.getExternalIdById(internalId.getId()))

View File

@ -76,7 +76,10 @@ public interface WidgetTypeRepository extends JpaRepository<WidgetTypeDetailsEnt
@Query("SELECT externalId FROM WidgetTypeDetailsEntity WHERE id = :id")
UUID getExternalIdById(@Param("id") UUID id);
@Query("SELECT id FROM WidgetTypeEntity")
@Query("SELECT id FROM WidgetTypeDetailsEntity")
Page<UUID> findAllIds(Pageable pageable);
@Query("SELECT id FROM WidgetTypeDetailsEntity WHERE tenantId = :tenantId")
Page<UUID> findIdsByTenantId(@Param("tenantId") UUID tenantId, Pageable pageable);
}

View File

@ -718,6 +718,7 @@ CREATE TABLE IF NOT EXISTS resource (
etag varchar,
descriptor varchar,
preview bytea,
external_id uuid,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
);