Version control support for resources
This commit is contained in:
		
							parent
							
								
									6eadef0d68
								
							
						
					
					
						commit
						72ae6eb708
					
				@ -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
 | 
			
		||||
 | 
			
		||||
@ -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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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());
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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.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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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() {
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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 {
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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));
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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()))
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user