Remove tenantId from image link; remove link from resource

This commit is contained in:
ViacheslavKlimov 2023-11-13 18:46:24 +02:00
parent d06cfa9ae0
commit 7489b87fa5
13 changed files with 137 additions and 103 deletions

View File

@ -28,6 +28,5 @@ $$
END;
$$;
ALTER TABLE resource ADD COLUMN IF NOT EXISTS media_type varchar(255);
ALTER TABLE resource ADD COLUMN IF NOT EXISTS link varchar(255);
-- RESOURCES UPDATE END

View File

@ -35,7 +35,6 @@ import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.StringUtils;
@ -93,7 +92,6 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Download Resource (downloadResource)", notes = "Download Resource based on the provided Resource Id." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/{resourceId}/download")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
@ -111,17 +109,10 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Download Image (downloadImageIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/images/{tenantId}/{resourceKey}", produces = "image/*")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadImageIfChanged(@PathVariable("tenantId") String tenantIdStr,
@PathVariable("resourceKey") String resourceKey,
@GetMapping(value = "/images/{resourceKey}", produces = "image/*")
public ResponseEntity<ByteArrayResource> downloadImageIfChanged(@PathVariable("resourceKey") String resourceKey,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
TenantId tenantId;
if (tenantIdStr.equals("system")) {
tenantId = TenantId.SYS_TENANT_ID;
} else {
tenantId = TenantId.fromUUID(toUUID(tenantIdStr));
}
TenantId tenantId = getTenantId();
return downloadResourceIfChanged(ResourceType.IMAGE, etag,
() -> resourceService.findResourceInfoByTenantIdAndKey(tenantId, ResourceType.IMAGE, resourceKey),
() -> resourceService.findResourceByTenantIdAndKey(tenantId, ResourceType.IMAGE, resourceKey));
@ -130,7 +121,6 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Download LWM2M Resource (downloadLwm2mResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/lwm2m/{resourceId}/download", produces = "application/xml")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadLwm2mResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
@ -140,7 +130,6 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Download PKCS_12 Resource (downloadPkcs12ResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/pkcs12/{resourceId}/download", method = RequestMethod.GET, produces = "application/x-pkcs12")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadPkcs12ResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
@ -151,7 +140,6 @@ public class TbResourceController extends BaseController {
notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/jks/{resourceId}/download", produces = "application/x-java-keystore")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadJksResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
@ -161,7 +149,6 @@ public class TbResourceController extends BaseController {
@ApiOperation(value = "Download JS Resource (downloadJsResourceIfChanged)", notes = DOWNLOAD_RESOURCE_IF_NOT_CHANGED + AVAILABLE_FOR_ANY_AUTHORIZED_USER)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@GetMapping(value = "/resource/js/{resourceId}/download", produces = "application/javascript")
@ResponseBody
public ResponseEntity<ByteArrayResource> downloadJsResourceIfChanged(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId,
@RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws ThingsboardException {
@ -174,7 +161,6 @@ public class TbResourceController extends BaseController {
produces = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/info/{resourceId}")
@ResponseBody
public TbResourceInfo getResourceInfoById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
@ -189,7 +175,6 @@ public class TbResourceController extends BaseController {
@Deprecated // resource's data should be fetched with a download request
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource/{resourceId}")
@ResponseBody
public TbResource getResourceById(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
@ -211,7 +196,6 @@ public class TbResourceController extends BaseController {
consumes = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PostMapping(value = "/resource")
@ResponseBody
public TbResourceInfo saveResource(@ApiParam(value = "A JSON value representing the Resource.")
@RequestBody TbResource resource) throws Exception {
resource.setTenantId(getTenantId());
@ -225,7 +209,6 @@ public class TbResourceController extends BaseController {
produces = "application/json")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@GetMapping(value = "/resource")
@ResponseBody
public PageData<TbResourceInfo> getResources(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@ -257,7 +240,6 @@ public class TbResourceController extends BaseController {
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/resource/lwm2m/page")
@ResponseBody
public List<LwM2mObject> getLwm2mListObjectsPage(@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@ -278,7 +260,6 @@ public class TbResourceController extends BaseController {
produces = "application/json")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@GetMapping(value = "/resource/lwm2m")
@ResponseBody
public List<LwM2mObject> getLwm2mListObjects(@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES, required = true)
@RequestParam String sortOrder,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = LWM2M_OBJECT_SORT_PROPERTY_ALLOWABLE_VALUES, required = true)
@ -292,7 +273,6 @@ public class TbResourceController extends BaseController {
notes = "Deletes the Resource. Referencing non-existing Resource Id will cause an error." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@DeleteMapping(value = "/resource/{resourceId}")
@ResponseBody
public void deleteResource(@ApiParam(value = RESOURCE_ID_PARAM_DESCRIPTION)
@PathVariable("resourceId") String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
@ -323,6 +303,7 @@ public class TbResourceController extends BaseController {
}
}
// TODO: rate limits
TbResource tbResource = resourceSupplier.get();
checkEntity(getCurrentUser(), tbResource, Operation.READ);
@ -336,4 +317,5 @@ public class TbResourceController extends BaseController {
.eTag(tbResource.getEtag())
.body(resource);
}
}

View File

@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.util.MediaTypeUtils;
import org.thingsboard.server.common.data.util.ImageUtils;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.resource.ResourceService;
@ -65,7 +65,7 @@ public class ImagesUpdater {
throw new IllegalArgumentException("Image name is missing for " + imageKey + ". Please add it to names.json file");
}
byte[] imageData = Files.readAllBytes(imageFile);
String mediaType = MediaTypeUtils.fileExtensionToMediaType("image", StringUtils.substringAfterLast(imageKey, "."));
String mediaType = ImageUtils.fileExtensionToMediaType("image", StringUtils.substringAfterLast(imageKey, "."));
try {
saveImage(TenantId.SYS_TENANT_ID, imageName, imageKey, imageData, mediaType, null);
} catch (Exception e) {
@ -191,7 +191,7 @@ public class ImagesUpdater {
}
String imageMediaType = StringUtils.substringBetween(data, "data:", ";base64");
String extension = MediaTypeUtils.mediaTypeToFileExtension(imageMediaType);
String extension = ImageUtils.mediaTypeToFileExtension(imageMediaType);
key += "." + extension;
byte[] imageData = Base64.getDecoder().decode(base64Data);
@ -203,14 +203,16 @@ public class ImagesUpdater {
String existingImageQuery) {
TbResourceInfo resourceInfo = resourceService.findResourceInfoByTenantIdAndKey(tenantId, ResourceType.IMAGE, key);
if (resourceInfo == null && !tenantId.isSysTenantId() && existingImageQuery != null) {
// TODO: need to search among tenant images too (custom widgets)
List<TbResourceInfo> existingSystemImages = resourceService.findByTenantIdAndDataAndKeyStartingWith(TenantId.SYS_TENANT_ID, imageData, existingImageQuery);
if (!existingSystemImages.isEmpty()) {
resourceInfo = existingSystemImages.get(0);
if (existingSystemImages.size() > 1) {
log.warn("Found more than one system image resources for key {}", existingImageQuery);
}
log.info("Using system image {} for {}", resourceInfo.getLink(), key);
return resourceInfo.getLink();
String link = resourceService.getResourceLink(resourceInfo);
log.info("Using system image {} for {}", link, key);
return link;
}
}
TbResource resource;
@ -222,7 +224,7 @@ public class ImagesUpdater {
} else if (tenantId.isSysTenantId()) {
resource = new TbResource(resourceInfo);
} else {
return resourceInfo.getLink();
return resourceService.getResourceLink(resourceInfo);
}
resource.setTitle(name);
resource.setFileName(key);
@ -231,7 +233,7 @@ public class ImagesUpdater {
resource = resourceService.saveResource(resource);
log.info("[{}] {} image '{}' ({})", tenantId, resourceInfo == null ? "Created" : "Updated",
resource.getTitle(), resource.getResourceKey());
return resource.getLink();
return resourceService.getResourceLink(resourceInfo);
}
private String getText(JsonNode jsonNode, String field) {

View File

@ -676,10 +676,9 @@ public class TbResourceControllerTest extends AbstractControllerTest {
resource.setBase64Data(TEST_DATA);
TbResource savedResource = save(resource);
assertThat(savedResource.getLink()).isEqualTo("/api/images/system/image.png");
loginTenantAdmin();
MockHttpServletResponse imageResponse = doGet(savedResource.getLink()).andExpect(status().isOk())
MockHttpServletResponse imageResponse = doGet(getImageLink(savedResource)).andExpect(status().isOk())
.andReturn().getResponse();
assertThat(imageResponse.getContentAsByteArray())
.isEqualTo(download(savedResource.getId()))
@ -701,9 +700,9 @@ public class TbResourceControllerTest extends AbstractControllerTest {
resource.setBase64Data(TEST_DATA);
TbResource savedResource = save(resource);
assertThat(savedResource.getLink()).isEqualTo("/api/images/" + tenantId + "/image.jpg");
String imageLink = getImageLink(savedResource);
MockHttpServletResponse imageResponse = doGet(savedResource.getLink()).andExpect(status().isOk())
MockHttpServletResponse imageResponse = doGet(imageLink).andExpect(status().isOk())
.andReturn().getResponse();
assertThat(imageResponse.getContentAsByteArray())
.isEqualTo(download(savedResource.getId()))
@ -711,7 +710,7 @@ public class TbResourceControllerTest extends AbstractControllerTest {
assertThat(imageResponse.getContentType()).isEqualTo("image/jpeg");
loginDifferentTenant();
doGet(savedResource.getLink()).andExpect(status().isForbidden());
doGet(imageLink).andExpect(status().isNotFound());
}
private TbResource save(TbResource tbResource) throws Exception {
@ -724,4 +723,8 @@ public class TbResourceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsByteArray();
}
private String getImageLink(TbResourceInfo resourceInfo) {
return "/api/images/" + (resourceInfo.getTenantId().isSysTenantId() ? "system/" : "") + resourceInfo.getResourceKey();
}
}

View File

@ -62,4 +62,6 @@ public interface ResourceService extends EntityDaoService {
List<TbResourceInfo> findByTenantIdAndDataAndKeyStartingWith(TenantId tenantId, byte[] data, String query);
String getResourceLink(TbResourceInfo resourceInfo);
}

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -56,8 +57,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
private String fileName;
@ApiModelProperty(position = 10, value = "Resource media type.", example = "image/png", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String mediaType;
@ApiModelProperty(position = 11, value = "Resource link (for IMAGE resource type).", example = "/api/images/system/my-image.png", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
private String link;
private ObjectNode descriptor;
public TbResourceInfo() {
super();
@ -77,7 +77,7 @@ public class TbResourceInfo extends BaseData<TbResourceId> implements HasName, H
this.etag = resourceInfo.etag;
this.fileName = resourceInfo.fileName;
this.mediaType = resourceInfo.mediaType;
this.link = resourceInfo.link;
this.descriptor = resourceInfo.descriptor;
}
@ApiModelProperty(position = 1, value = "JSON object with the Resource Id. " +

View File

@ -0,0 +1,96 @@
/**
* 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.common.data.util;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ImageUtils {
private static final Map<String, String> mediaTypeMappings = Map.of(
"jpeg", "jpg",
"svg+xml", "svg"
);
public static String mediaTypeToFileExtension(String mimeType) {
String subtype = MimeTypeUtils.parseMimeType(mimeType).getSubtype();
return mediaTypeMappings.getOrDefault(subtype, subtype);
}
public static String fileExtensionToMediaType(String type, String extension) {
String subtype = mediaTypeMappings.entrySet().stream()
.filter(mapping -> mapping.getValue().equals(extension))
.map(Map.Entry::getKey).findFirst().orElse(extension);
return new MimeType(type, subtype).toString();
}
public static ImageInfo processImage(byte[] imageData) throws IOException {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData));
ImageThumbnail thumbnail = getImageThumbnail(image, 250);
return new ImageInfo(image.getWidth(), image.getHeight(), thumbnail);
}
private static ImageThumbnail getImageThumbnail(BufferedImage originalImage, int maxDimension) throws IOException {
int originalWidth = originalImage.getWidth();
int originalHeight = originalImage.getHeight();
int thumbnailWidth;
int thumbnailHeight;
if (originalWidth <= maxDimension && originalHeight <= maxDimension) {
thumbnailWidth = originalWidth;
thumbnailHeight = originalHeight;
} else {
double aspectRatio = (double) originalWidth / originalHeight;
if (originalWidth > originalHeight) {
thumbnailWidth = maxDimension;
thumbnailHeight = (int) (maxDimension / aspectRatio);
} else {
thumbnailWidth = (int) (maxDimension * aspectRatio);
thumbnailHeight = maxDimension;
}
}
BufferedImage thumbnail = new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);
thumbnail.getGraphics().drawImage(originalImage, 0, 0, thumbnailWidth, thumbnailHeight, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(thumbnail, "ignored", os);
return new ImageThumbnail(thumbnail.getWidth(), thumbnail.getHeight(), os.toByteArray());
}
@Data
public static class ImageInfo {
private final int width;
private final int height;
private final ImageThumbnail thumbnail;
}
@Data
public static class ImageThumbnail {
private final int width;
private final int height;
private final byte[] data;
}
}

View File

@ -1,45 +0,0 @@
/**
* 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.common.data.util;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import java.util.Map;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MediaTypeUtils {
private static final Map<String, String> mappings = Map.of(
"jpeg", "jpg",
"svg+xml", "svg"
);
public static String mediaTypeToFileExtension(String mimeType) {
String subtype = MimeTypeUtils.parseMimeType(mimeType).getSubtype();
return mappings.getOrDefault(subtype, subtype);
}
public static String fileExtensionToMediaType(String type, String extension) {
String subtype = mappings.entrySet().stream()
.filter(mapping -> mapping.getValue().equals(extension))
.map(Map.Entry::getKey).findFirst().orElse(extension);
return new MimeType(type, subtype).toString();
}
}

View File

@ -500,7 +500,6 @@ public class ModelConstants {
public static final String RESOURCE_DATA_COLUMN = "data";
public static final String RESOURCE_ETAG_COLUMN = "etag";
public static final String RESOURCE_MEDIA_TYPE_COLUMN = "media_type";
public static final String RESOURCE_LINK_COLUMN = "link";
/**
* Ota Package constants.

View File

@ -33,7 +33,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLU
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_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_LINK_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_MEDIA_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
@ -74,9 +73,6 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
@Column(name = RESOURCE_MEDIA_TYPE_COLUMN)
private String mediaType;
@Column(name = RESOURCE_LINK_COLUMN)
private String link;
public TbResourceEntity() {
}
@ -96,7 +92,6 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
this.data = resource.getData();
this.etag = resource.getEtag();
this.mediaType = resource.getMediaType();
this.link = resource.getLink();
}
@Override
@ -112,7 +107,6 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements BaseE
resource.setData(data);
resource.setEtag(etag);
resource.setMediaType(mediaType);
resource.setLink(link);
return resource;
}

View File

@ -32,7 +32,6 @@ import java.util.UUID;
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_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_LINK_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_MEDIA_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
@ -70,9 +69,6 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
@Column(name = RESOURCE_MEDIA_TYPE_COLUMN)
private String mediaType;
@Column(name = RESOURCE_LINK_COLUMN)
private String link;
public TbResourceInfoEntity() {
}
@ -89,7 +85,6 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
this.hashCode = resource.getEtag();
this.fileName = resource.getFileName();
this.mediaType = resource.getMediaType();
this.link = resource.getLink();
}
@Override
@ -104,7 +99,6 @@ public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implemen
resource.setEtag(hashCode);
resource.setFileName(fileName);
resource.setMediaType(mediaType);
resource.setLink(link);
return resource;
}
}

View File

@ -77,11 +77,10 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
}
if (resource.getData() != null) {
resource.setEtag(calculateEtag(resource.getData()));
}
if (resource.getResourceType() == ResourceType.IMAGE) {
resource.setLink(String.format("/api/images/%s/%s",
tenantId.isSysTenantId() ? "system" : tenantId.getId(),
resource.getResourceKey()));
// FIXME: skip SVG (?)
}
}
try {
TbResource saved;
@ -226,6 +225,16 @@ public class BaseResourceService extends AbstractCachedEntityService<ResourceInf
return resourceInfoDao.findByTenantIdAndEtagAndKeyStartingWith(tenantId, etag, query);
}
@Override
public String getResourceLink(TbResourceInfo resourceInfo) {
String link = "/api/images/";
if (resourceInfo.getTenantId().isSysTenantId()) {
link += "system/";
}
link += resourceInfo.getResourceKey();
return link;
}
private String calculateEtag(byte[] data) {
return Hashing.sha256().hashBytes(data).toString();
}

View File

@ -717,7 +717,6 @@ CREATE TABLE IF NOT EXISTS resource (
data bytea,
etag varchar,
media_type varchar(255),
link varchar(255),
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
);