From 1ca2479c043259c936b863853bcf9b6c42d075be Mon Sep 17 00:00:00 2001 From: amvanbaren Date: Thu, 15 Dec 2022 12:36:19 +0200 Subject: [PATCH] Web extension resources return incorrect MIME type Use [Content_Types].xml to set FileResource contentType Add test case for default content type: application/octet-stream Add migration to set FileResource.contentType Set contentType for RESOURCE type Prepend dot ('.') if extension doesn't start with a dot. Fix loggers Make migration run on every startup for testing purposes read inputstream before loading content types Get existing resource from db make uploadFile transactional move Transactional to MigrationService move transactional get file delete file use content of resource --- .../eclipse/openvsx/ExtensionProcessor.java | 58 +++++- .../openvsx/adapter/LocalVSCodeService.java | 2 +- .../openvsx/entities/FileResource.java | 10 + .../ExtractResourcesJobRequestHandler.java | 11 +- .../migration/ExtractResourcesJobService.java | 29 --- .../openvsx/migration/MigrationRunner.java | 15 ++ .../openvsx/migration/MigrationService.java | 53 ++++- .../RenameDownloadsJobRequestHandler.java | 14 +- .../migration/RenameDownloadsService.java | 10 - .../SetContentTypeJobRequestHandler.java | 63 ++++++ .../migration/SetContentTypeJobService.java | 35 ++++ .../SetPreReleaseJobRequestHandler.java | 11 +- .../migration/SetPreReleaseJobService.java | 48 ----- .../FileResourceJooqRepository.java | 17 +- .../repositories/RepositoryService.java | 8 + .../storage/AzureBlobStorageService.java | 21 +- .../storage/GoogleCloudStorageService.java | 21 +- .../eclipse/openvsx/storage/StorageUtil.java | 13 -- .../openvsx/storage/StorageUtilService.java | 12 +- .../org/eclipse/openvsx/jooq/Indexes.java | 3 + .../org/eclipse/openvsx/jooq/Keys.java | 4 + .../org/eclipse/openvsx/jooq/Public.java | 7 + .../org/eclipse/openvsx/jooq/Tables.java | 6 + .../AdminStatisticsExtensionsByRating.java | 7 +- ...isticsPublishersByExtensionsPublished.java | 7 +- .../eclipse/openvsx/jooq/tables/Download.java | 7 + .../openvsx/jooq/tables/Extension.java | 7 +- .../openvsx/jooq/tables/ExtensionReview.java | 13 +- .../openvsx/jooq/tables/ExtensionVersion.java | 13 +- .../tables/ExtractResourcesMigrationItem.java | 146 ++++++++++++++ .../openvsx/jooq/tables/FileResource.java | 22 ++- .../jooq/tables/NamespaceMembership.java | 13 +- .../openvsx/jooq/tables/PersistedLog.java | 7 +- .../jooq/tables/PersonalAccessToken.java | 7 +- .../jooq/tables/SpringSessionAttributes.java | 7 +- .../ExtractResourcesMigrationItemRecord.java | 180 +++++++++++++++++ .../tables/records/FileResourceRecord.java | 57 +++++- .../V1_29__FileResource_ContentType.sql | 7 + .../org/eclipse/openvsx/RegistryAPITest.java | 3 + .../openvsx/adapter/VSCodeAPITest.java | 187 ++++++++++++++---- .../RepositoryServiceSmokeTest.java | 1 + 41 files changed, 950 insertions(+), 212 deletions(-) create mode 100644 server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobRequestHandler.java create mode 100644 server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobService.java create mode 100644 server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtractResourcesMigrationItem.java create mode 100644 server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtractResourcesMigrationItemRecord.java create mode 100644 server/src/main/resources/db/migration/V1_29__FileResource_ContentType.sql diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java index 912affd60..da8c253be 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java @@ -9,6 +9,7 @@ ********************************************************************************/ package org.eclipse.openvsx; +import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.nio.file.Path; @@ -36,6 +37,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.util.Pair; +import org.springframework.http.MediaType; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; /** * Processes uploaded extension files and extracts their metadata. @@ -282,17 +288,22 @@ private List getEngines(JsonNode node) { } public List getFileResources(ExtensionVersion extVersion) { - var resources = new ArrayList(); + readInputStream(); + var contentTypes = loadContentTypes(); var mappers = List.>of( this::getManifest, this::getReadme, this::getChangelog, this::getLicense, this::getIcon ); - mappers.forEach(mapper -> Optional.of(extVersion).map(mapper).ifPresent(resources::add)); - return resources; + return mappers.stream() + .map(mapper -> mapper.apply(extVersion)) + .filter(Objects::nonNull) + .map(resource -> setContentType(resource, contentTypes)) + .collect(Collectors.toList()); } public void processEachResource(ExtensionVersion extVersion, Consumer processor) { readInputStream(); + var contentTypes = loadContentTypes(); zipFile.stream() .filter(zipEntry -> !zipEntry.isDirectory()) .map(zipEntry -> { @@ -311,6 +322,7 @@ public void processEachResource(ExtensionVersion extVersion, Consumer loadContentTypes() { + var bytes = ArchiveUtil.readEntry(zipFile, "[Content_Types].xml"); + var contentTypes = parseContentTypesXml(bytes); + contentTypes.putIfAbsent(".vsix", "application/zip"); + return contentTypes; + } + + private Map parseContentTypesXml(byte[] content) { + var contentTypes = new HashMap(); + try (var input = new ByteArrayInputStream(content)) { + var document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input); + var elements = document.getDocumentElement().getElementsByTagName("Default"); + for(var i = 0; i < elements.getLength(); i++) { + var element = elements.item(i); + var attributes = element.getAttributes(); + var extension = attributes.getNamedItem("Extension").getTextContent(); + if(!extension.startsWith(".")) { + extension = "." + extension; + } + + var contentType = attributes.getNamedItem("ContentType").getTextContent(); + contentTypes.put(extension, contentType); + } + } catch (IOException | ParserConfigurationException | SAXException e) { + logger.error("failed to read content types", e); + contentTypes.clear(); + } + + return contentTypes; + } + + private FileResource setContentType(FileResource resource, Map contentTypes) { + var resourceName = Optional.ofNullable(resource.getName()).orElse(""); + var fileExtensionIndex = resourceName.lastIndexOf('.'); + var fileExtension = fileExtensionIndex != -1 ? resourceName.substring(fileExtensionIndex) : ""; + var contentType = contentTypes.getOrDefault(fileExtension, MediaType.APPLICATION_OCTET_STREAM_VALUE); + resource.setContentType(contentType); + return resource; + } + private void detectLicense(byte[] content, ExtensionVersion extVersion) { if (Strings.isNullOrEmpty(extVersion.getLicense())) { var detection = new LicenseDetection(); diff --git a/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java b/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java index c68ccdb96..b2a2506a2 100644 --- a/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java +++ b/server/src/main/java/org/eclipse/openvsx/adapter/LocalVSCodeService.java @@ -404,7 +404,7 @@ private ResponseEntity browseFile( String version ) { if (resource.getStorageType().equals(FileResource.STORAGE_DB)) { - var headers = storageUtil.getFileResponseHeaders(resource.getName()); + var headers = storageUtil.getFileResponseHeaders(resource); return new ResponseEntity<>(resource.getContent(), headers, HttpStatus.OK); } else { var namespace = new Namespace(); diff --git a/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java b/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java index 4b87db181..e13774796 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java @@ -45,6 +45,8 @@ public class FileResource { @Basic(fetch = FetchType.LAZY) byte[] content; + String contentType; + @Column(length = 32) String storageType; @@ -88,6 +90,14 @@ public void setContent(byte[] content) { this.content = content; } + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + public String getStorageType() { return storageType; } diff --git a/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobRequestHandler.java b/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobRequestHandler.java index da3d0619f..209f08896 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobRequestHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobRequestHandler.java @@ -10,8 +10,8 @@ package org.eclipse.openvsx.migration; import org.eclipse.openvsx.ExtensionProcessor; +import org.eclipse.openvsx.entities.ExtensionVersion; import org.jobrunr.jobs.annotations.Job; -import org.jobrunr.jobs.context.JobRunrDashboardLogger; import org.jobrunr.jobs.lambdas.JobRequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +21,7 @@ @Component public class ExtractResourcesJobRequestHandler implements JobRequestHandler { - protected final Logger logger = new JobRunrDashboardLogger(LoggerFactory.getLogger(ExtractResourcesJobRequestHandler.class)); + protected final Logger logger = LoggerFactory.getLogger(ExtractResourcesJobRequestHandler.class); @Autowired ExtractResourcesJobService service; @@ -32,12 +32,12 @@ public class ExtractResourcesJobRequestHandler implements JobRequestHandler { @@ -48,5 +48,6 @@ public void run(MigrationJobRequest jobRequest) throws Exception { } service.deleteWebResources(extVersion); + migrations.deleteFile(extensionFile); } } diff --git a/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobService.java b/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobService.java index 1473c03e7..ac0348873 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobService.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/ExtractResourcesJobService.java @@ -12,20 +12,11 @@ import org.eclipse.openvsx.entities.ExtensionVersion; import org.eclipse.openvsx.entities.FileResource; import org.eclipse.openvsx.repositories.RepositoryService; -import org.eclipse.openvsx.storage.AzureBlobStorageService; -import org.eclipse.openvsx.storage.GoogleCloudStorageService; -import org.eclipse.openvsx.storage.IStorageService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpMethod; -import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; import javax.persistence.EntityManager; import javax.transaction.Transactional; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.AbstractMap; import java.util.Map; @@ -35,22 +26,9 @@ public class ExtractResourcesJobService { @Autowired RepositoryService repositories; - @Autowired - RestTemplate restTemplate; - @Autowired EntityManager entityManager; - @Autowired - AzureBlobStorageService azureStorage; - - @Autowired - GoogleCloudStorageService googleStorage; - - public ExtensionVersion getExtension(long entityId) { - return entityManager.find(ExtensionVersion.class, entityId); - } - @Transactional public void deleteResources(ExtensionVersion extVersion) { repositories.deleteFileResources(extVersion, "resource"); @@ -61,13 +39,6 @@ public void deleteWebResources(ExtensionVersion extVersion) { repositories.deleteFileResources(extVersion, "web-resource"); } - @Transactional - public Map.Entry getDownload(ExtensionVersion extVersion) { - var download = repositories.findFileByType(extVersion, FileResource.DOWNLOAD); - var content = download.getStorageType().equals(FileResource.STORAGE_DB) ? download.getContent() : null; - return new AbstractMap.SimpleEntry<>(download, content); - } - @Transactional public void persistResource(FileResource resource) { entityManager.persist(resource); diff --git a/server/src/main/java/org/eclipse/openvsx/migration/MigrationRunner.java b/server/src/main/java/org/eclipse/openvsx/migration/MigrationRunner.java index 3b3128294..dde34f46f 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/MigrationRunner.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/MigrationRunner.java @@ -20,6 +20,8 @@ import javax.transaction.Transactional; import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.UUID; @Component @@ -41,6 +43,8 @@ public void runMigrations(ApplicationStartedEvent event) { extractResourcesMigration(); setPreReleaseMigration(); renameDownloadsMigration(); + resetContentTypeMigration(); // TODO remove when done debugging + setContentTypeMigration(); } private void extractResourcesMigration() { @@ -61,6 +65,17 @@ private void renameDownloadsMigration() { repositories.findNotMigratedRenamedDownloads().forEach(item -> enqueueJob(jobName, handler, item)); } + // TODO remove when done debugging + private void resetContentTypeMigration() { + repositories.findMigratedContentTypes().forEach(item -> item.setMigrationScheduled(false)); + } + + private void setContentTypeMigration() { + var jobName = "SetContentTypeMigration" + LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); // TODO remove when done debugging + var handler = SetContentTypeJobRequestHandler.class; + repositories.findNotMigratedContentTypes().forEach(item -> enqueueJob(jobName, handler, item)); + } + private void enqueueJob(String jobName, Class> handler, MigrationItem item) { var jobIdText = jobName + "::itemId=" + item.getId(); var jobId = UUID.nameUUIDFromBytes(jobIdText.getBytes(StandardCharsets.UTF_8)); diff --git a/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java b/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java index b71e75ebb..b7a21a377 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java @@ -9,7 +9,9 @@ * ****************************************************************************** */ package org.eclipse.openvsx.migration; +import org.eclipse.openvsx.entities.ExtensionVersion; import org.eclipse.openvsx.entities.FileResource; +import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.storage.AzureBlobStorageService; import org.eclipse.openvsx.storage.GoogleCloudStorageService; import org.eclipse.openvsx.storage.IStorageService; @@ -19,14 +21,23 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import javax.persistence.EntityManager; +import javax.transaction.Transactional; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.AbstractMap; import java.util.Map; @Component public class MigrationService { + @Autowired + EntityManager entityManager; + + @Autowired + RepositoryService repositories; + @Autowired RestTemplate restTemplate; @@ -36,20 +47,38 @@ public class MigrationService { @Autowired GoogleCloudStorageService googleStorage; + public T find(MigrationJobRequest jobRequest, Class clazz) { + return entityManager.find(clazz, jobRequest.getEntityId()); + } + + @Transactional + public Map.Entry getDownload(ExtensionVersion extVersion) { + var download = repositories.findFileByType(extVersion, FileResource.DOWNLOAD); + var content = download.getStorageType().equals(FileResource.STORAGE_DB) ? download.getContent() : null; + return new AbstractMap.SimpleEntry<>(download, content); + } + + @Transactional + public byte[] getContent(FileResource download) { + download = entityManager.merge(download); + return download.getStorageType().equals(FileResource.STORAGE_DB) ? download.getContent() : null; + } + @Retryable - public Path getExtensionFile(Map.Entry entry) { + public Path getFile(Map.Entry entry) { Path extensionFile; + var resource = entry.getKey(); try { - extensionFile = Files.createTempFile("extension_", ".vsix"); + var suffixIndex = resource.getName().lastIndexOf('.'); + extensionFile = Files.createTempFile("file_", resource.getName().substring(suffixIndex)); } catch (IOException e) { - throw new RuntimeException("Failed to create extension file", e); + throw new RuntimeException("Failed to create file", e); } var content = entry.getValue(); if(content == null) { - var download = entry.getKey(); - var storage = getStorage(download); - var uri = storage.getLocation(download); + var storage = getStorage(resource); + var uri = storage.getLocation(resource); restTemplate.execute(uri, HttpMethod.GET, null, response -> { try(var out = Files.newOutputStream(extensionFile)) { response.getBody().transferTo(out); @@ -61,19 +90,29 @@ public Path getExtensionFile(Map.Entry entry) { try { Files.write(extensionFile, content); } catch (IOException e) { - throw new RuntimeException("Failed to write to extension file", e); + throw new RuntimeException("Failed to write to file", e); } } return extensionFile; } + public void deleteFile(Path filePath) { + try { + Files.delete(filePath); + } catch (IOException e) { + throw new RuntimeException("Failed to delete file"); + } + } + @Retryable + @Transactional public void uploadResource(FileResource resource) { if(resource.getStorageType().equals(FileResource.STORAGE_DB)) { return; } + resource = entityManager.merge(resource); var storage = getStorage(resource); storage.uploadFile(resource); resource.setContent(null); diff --git a/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsJobRequestHandler.java b/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsJobRequestHandler.java index 08a48d142..dd9bcf678 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsJobRequestHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsJobRequestHandler.java @@ -9,6 +9,7 @@ * ****************************************************************************** */ package org.eclipse.openvsx.migration; +import org.eclipse.openvsx.entities.FileResource; import org.jobrunr.jobs.lambdas.JobRequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +21,7 @@ @Component public class RenameDownloadsJobRequestHandler implements JobRequestHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(RenameDownloadsJobRequestHandler.class); + protected final Logger logger = LoggerFactory.getLogger(RenameDownloadsJobRequestHandler.class); @Autowired MigrationService migrations; @@ -30,22 +31,23 @@ public class RenameDownloadsJobRequestHandler implements JobRequestHandler(download, content)); + logger.info("Renaming download {}", download.getName()); + var content = migrations.getContent(download); + var extensionFile = migrations.getFile(new AbstractMap.SimpleEntry<>(download, content)); var newDownload = service.cloneResource(download, name); migrations.uploadResource(newDownload, extensionFile); migrations.deleteResource(download); download.setName(name); service.updateResource(download); - LOGGER.info("Updated download name to: {}", name); + migrations.deleteFile(extensionFile); + logger.info("Updated download name to: {}", name); } } diff --git a/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsService.java b/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsService.java index 4ea580051..e9d2fc7ea 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsService.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/RenameDownloadsService.java @@ -36,12 +36,6 @@ public String getNewBinaryName(FileResource resource) { return resourceName; } - @Transactional - public byte[] getContent(FileResource download) { - download = entityManager.merge(download); - return download.getStorageType().equals(FileResource.STORAGE_DB) ? download.getContent() : null; - } - @Transactional public FileResource cloneResource(FileResource resource, String name) { resource = entityManager.merge(resource); @@ -54,10 +48,6 @@ public FileResource cloneResource(FileResource resource, String name) { return clone; } - public FileResource getResource(MigrationJobRequest jobRequest) { - return entityManager.find(FileResource.class, jobRequest.getEntityId()); - } - @Transactional public void updateResource(FileResource resource) { entityManager.merge(resource); diff --git a/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobRequestHandler.java b/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobRequestHandler.java new file mode 100644 index 000000000..abfab7a65 --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobRequestHandler.java @@ -0,0 +1,63 @@ +/** ****************************************************************************** + * Copyright (c) 2022 Precies. Software Ltd and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * ****************************************************************************** */ +package org.eclipse.openvsx.migration; + +import org.eclipse.openvsx.ExtensionProcessor; +import org.eclipse.openvsx.entities.ExtensionVersion; +import org.eclipse.openvsx.entities.FileResource; +import org.jobrunr.jobs.annotations.Job; +import org.jobrunr.jobs.lambdas.JobRequestHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.AbstractMap; +import java.util.function.Consumer; + +@Component +public class SetContentTypeJobRequestHandler implements JobRequestHandler { + + protected final Logger logger = LoggerFactory.getLogger(SetContentTypeJobRequestHandler.class); + + @Autowired + MigrationService migrations; + + @Autowired + SetContentTypeJobService service; + + @Override + @Job(name = "Set content type for published file resources", retries = 3) + public void run(MigrationJobRequest jobRequest) throws Exception { + var extVersion = migrations.find(jobRequest, ExtensionVersion.class); + logger.info("Set content type for: {}.{}-{}@{}", extVersion.getExtension().getNamespace().getName(), extVersion.getExtension().getName(), extVersion.getVersion(), extVersion.getTargetPlatform()); + + var entry = migrations.getDownload(extVersion); + var extensionFile = migrations.getFile(entry); + try (var processor = new ExtensionProcessor(extensionFile)) { + Consumer consumer = resource -> { + var existingResource = service.getExistingResource(extVersion, resource); + if(existingResource == null) { + return; + } + + var resourceFile = migrations.getFile(new AbstractMap.SimpleEntry<>(existingResource, resource.getContent())); + migrations.deleteResource(existingResource); + migrations.uploadResource(existingResource, resourceFile); + migrations.deleteFile(resourceFile); + }; + + processor.getFileResources(extVersion).forEach(consumer); + processor.processEachResource(extVersion, consumer); + } + + migrations.deleteFile(extensionFile); + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobService.java b/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobService.java new file mode 100644 index 000000000..f063d2a4b --- /dev/null +++ b/server/src/main/java/org/eclipse/openvsx/migration/SetContentTypeJobService.java @@ -0,0 +1,35 @@ +/** ****************************************************************************** + * Copyright (c) 2022 Precies. Software Ltd and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * ****************************************************************************** */ +package org.eclipse.openvsx.migration; + +import org.eclipse.openvsx.entities.ExtensionVersion; +import org.eclipse.openvsx.entities.FileResource; +import org.eclipse.openvsx.repositories.RepositoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; + +@Component +public class SetContentTypeJobService { + + @Autowired + RepositoryService repositories; + + @Transactional + public FileResource getExistingResource(ExtensionVersion extVersion, FileResource resource) { + var existingResource = repositories.findFileByTypeAndName(extVersion, resource.getType(), resource.getName()); + if(existingResource != null) { + existingResource.setContentType(resource.getContentType()); + } + + return existingResource; + } +} diff --git a/server/src/main/java/org/eclipse/openvsx/migration/SetPreReleaseJobRequestHandler.java b/server/src/main/java/org/eclipse/openvsx/migration/SetPreReleaseJobRequestHandler.java index ac1227808..95ae47317 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/SetPreReleaseJobRequestHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/SetPreReleaseJobRequestHandler.java @@ -10,7 +10,6 @@ package org.eclipse.openvsx.migration; import org.jobrunr.jobs.annotations.Job; -import org.jobrunr.jobs.context.JobRunrDashboardLogger; import org.jobrunr.jobs.lambdas.JobRequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +19,10 @@ @Component public class SetPreReleaseJobRequestHandler implements JobRequestHandler { - protected final Logger logger = new JobRunrDashboardLogger(LoggerFactory.getLogger(ExtractResourcesJobRequestHandler.class)); + protected final Logger logger = LoggerFactory.getLogger(SetPreReleaseJobRequestHandler.class); + + @Autowired + MigrationService migrations; @Autowired SetPreReleaseJobService service; @@ -30,9 +32,10 @@ public class SetPreReleaseJobRequestHandler implements JobRequestHandler getExtensionVersions(MigrationJobRequest jobReques return extension.getVersions(); } - @Transactional - public Map.Entry getDownload(ExtensionVersion extVersion) { - var download = repositories.findFileByType(extVersion, FileResource.DOWNLOAD); - var content = download.getStorageType().equals(FileResource.STORAGE_DB) ? download.getContent() : null; - return new AbstractMap.SimpleEntry<>(download, content); - } - - @Retryable - public Path getExtensionFile(Map.Entry entry) { - Path extensionFile; - try { - extensionFile = Files.createTempFile("extension_", ".vsix"); - } catch (IOException e) { - throw new RuntimeException("Failed to create extension file", e); - } - - var content = entry.getValue(); - if(content == null) { - var download = entry.getKey(); - var storage = getStorage(download); - var uri = storage.getLocation(download); - restTemplate.execute(uri, HttpMethod.GET, null, response -> { - try(var out = Files.newOutputStream(extensionFile)) { - response.getBody().transferTo(out); - } - - return extensionFile; - }); - } else { - try { - Files.write(extensionFile, content); - } catch (IOException e) { - throw new RuntimeException("Failed to write to extension file", e); - } - } - - return extensionFile; - } - @Transactional public void updatePreviewAndPreRelease(ExtensionVersion extVersion, Path extensionFile) { try(var extProcessor = new ExtensionProcessor(extensionFile)) { @@ -106,13 +67,4 @@ public void updatePreviewAndPreRelease(ExtensionVersion extVersion, Path extensi entityManager.merge(extVersion); } - - private IStorageService getStorage(FileResource resource) { - var storages = Map.of( - FileResource.STORAGE_AZURE, azureStorage, - FileResource.STORAGE_GOOGLE, googleStorage - ); - - return storages.get(resource.getStorageType()); - } } diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/FileResourceJooqRepository.java b/server/src/main/java/org/eclipse/openvsx/repositories/FileResourceJooqRepository.java index 7f7cd7dc6..dcfc42946 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/FileResourceJooqRepository.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/FileResourceJooqRepository.java @@ -28,7 +28,12 @@ public class FileResourceJooqRepository { DSLContext dsl; public List findAll(Collection extensionIds, Collection types) { - return dsl.select(FILE_RESOURCE.ID, FILE_RESOURCE.EXTENSION_ID, FILE_RESOURCE.NAME, FILE_RESOURCE.TYPE) + return dsl.select( + FILE_RESOURCE.ID, + FILE_RESOURCE.EXTENSION_ID, + FILE_RESOURCE.NAME, + FILE_RESOURCE.TYPE + ) .from(FILE_RESOURCE) .where(FILE_RESOURCE.EXTENSION_ID.in(extensionIds)) .and(FILE_RESOURCE.TYPE.in(types)) @@ -37,7 +42,15 @@ public List findAll(Collection extensionIds, Collection findAllResources(long extVersionId, String prefix) { - return dsl.select(FILE_RESOURCE.ID, FILE_RESOURCE.EXTENSION_ID, FILE_RESOURCE.NAME, FILE_RESOURCE.TYPE, FILE_RESOURCE.STORAGE_TYPE, FILE_RESOURCE.CONTENT) + return dsl.select( + FILE_RESOURCE.ID, + FILE_RESOURCE.EXTENSION_ID, + FILE_RESOURCE.NAME, + FILE_RESOURCE.TYPE, + FILE_RESOURCE.STORAGE_TYPE, + FILE_RESOURCE.CONTENT, + FILE_RESOURCE.CONTENT_TYPE + ) .from(FILE_RESOURCE) .where(FILE_RESOURCE.TYPE.eq(FileResource.RESOURCE)) .and(FILE_RESOURCE.EXTENSION_ID.eq(extVersionId)) diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java b/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java index ddcc08b76..6f06a2517 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java @@ -402,7 +402,15 @@ public Streamable findNotMigratedRenamedDownloads() { return findNotMigratedItems("V1_28__MigrationItem.sql"); } + public Streamable findNotMigratedContentTypes() { + return findNotMigratedItems("V1_29__FileResource_ContentType.sql"); + } + private Streamable findNotMigratedItems(String migrationScript) { return migrationItemRepo.findByMigrationScriptAndMigrationScheduledFalseOrderById(migrationScript); } + + public Streamable findMigratedContentTypes() { + return migrationItemRepo.findByMigrationScript("V1_29__FileResource_ContentType.sql"); + } } \ No newline at end of file diff --git a/server/src/main/java/org/eclipse/openvsx/storage/AzureBlobStorageService.java b/server/src/main/java/org/eclipse/openvsx/storage/AzureBlobStorageService.java index e69270923..bbe9c0403 100644 --- a/server/src/main/java/org/eclipse/openvsx/storage/AzureBlobStorageService.java +++ b/server/src/main/java/org/eclipse/openvsx/storage/AzureBlobStorageService.java @@ -22,6 +22,7 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; +import javax.transaction.Transactional; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; @@ -65,19 +66,21 @@ public void uploadFile(FileResource resource) { + blobName + ": missing Azure blob service endpoint"); } - uploadFile(resource.getContent(), resource.getName(), blobName); + uploadFile(resource, blobName); } - protected void uploadFile(byte[] content, String fileName, String blobName) { + protected void uploadFile(FileResource resource, String blobName) { var blobClient = getContainerClient().getBlobClient(blobName); var headers = new BlobHttpHeaders(); - headers.setContentType(StorageUtil.getFileType(fileName).toString()); - if (fileName.endsWith(".vsix")) { - headers.setContentDisposition("attachment; filename=\"" + fileName + "\""); + headers.setContentType(resource.getContentType()); + if (resource.getName().endsWith(".vsix")) { + headers.setContentDisposition("attachment; filename=\"" + resource.getName() + "\""); } else { - var cacheControl = StorageUtil.getCacheControl(fileName); + var cacheControl = StorageUtil.getCacheControl(resource.getName()); headers.setCacheControl(cacheControl.getHeaderValue()); } + + var content = resource.getContent(); try (var dataStream = new ByteArrayInputStream(content)) { blobClient.upload(dataStream, content.length, true); blobClient.setHttpHeaders(headers); @@ -94,13 +97,13 @@ public void uploadFile(FileResource resource, Path filePath) { + blobName + ": missing Azure blob service endpoint"); } - uploadFile(filePath, resource.getName(), blobName); + uploadFile(filePath, resource.getName(), blobName, resource.getContentType()); } - protected void uploadFile(Path filePath, String fileName, String blobName) { + protected void uploadFile(Path filePath, String fileName, String blobName, String contentType) { var blobClient = getContainerClient().getBlobClient(blobName); var headers = new BlobHttpHeaders(); - headers.setContentType(StorageUtil.getFileType(fileName).toString()); + headers.setContentType(contentType); if (fileName.endsWith(".vsix")) { headers.setContentDisposition("attachment; filename=\"" + fileName + "\""); } else { diff --git a/server/src/main/java/org/eclipse/openvsx/storage/GoogleCloudStorageService.java b/server/src/main/java/org/eclipse/openvsx/storage/GoogleCloudStorageService.java index 48fe33bcd..14a001ff0 100644 --- a/server/src/main/java/org/eclipse/openvsx/storage/GoogleCloudStorageService.java +++ b/server/src/main/java/org/eclipse/openvsx/storage/GoogleCloudStorageService.java @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import javax.transaction.Transactional; import java.io.IOException; import java.net.URI; import java.nio.ByteBuffer; @@ -68,19 +69,19 @@ public void uploadFile(FileResource resource) { + objectId + ": missing Google bucket id"); } - uploadFile(resource.getContent(), resource.getName(), objectId); + uploadFile(resource, objectId); } - protected void uploadFile(byte[] content, String fileName, String objectId) { + protected void uploadFile(FileResource resource, String objectId) { var blobInfoBuilder = BlobInfo.newBuilder(BlobId.of(bucketId, objectId)) - .setContentType(StorageUtil.getFileType(fileName).toString()); - if (fileName.endsWith(".vsix")) { - blobInfoBuilder.setContentDisposition("attachment; filename=\"" + fileName + "\""); + .setContentType(resource.getContentType()); + if (resource.getName().endsWith(".vsix")) { + blobInfoBuilder.setContentDisposition("attachment; filename=\"" + resource.getName() + "\""); } else { - var cacheControl = StorageUtil.getCacheControl(fileName); + var cacheControl = StorageUtil.getCacheControl(resource.getName()); blobInfoBuilder.setCacheControl(cacheControl.getHeaderValue()); } - getStorage().create(blobInfoBuilder.build(), content); + getStorage().create(blobInfoBuilder.build(), resource.getContent()); } @Override @@ -91,12 +92,12 @@ public void uploadFile(FileResource resource, Path filePath) { + objectId + ": missing Google bucket id"); } - uploadFile(filePath, resource.getName(), objectId); + uploadFile(filePath, resource.getName(), objectId, resource.getContentType()); } - protected void uploadFile(Path filePath, String fileName, String objectId) { + protected void uploadFile(Path filePath, String fileName, String objectId, String contentType) { var blobInfoBuilder = BlobInfo.newBuilder(BlobId.of(bucketId, objectId)) - .setContentType(StorageUtil.getFileType(fileName).toString()); + .setContentType(contentType); if (fileName.endsWith(".vsix")) { blobInfoBuilder.setContentDisposition("attachment; filename=\"" + fileName + "\""); } else { diff --git a/server/src/main/java/org/eclipse/openvsx/storage/StorageUtil.java b/server/src/main/java/org/eclipse/openvsx/storage/StorageUtil.java index 63e897fc4..a5b83c804 100644 --- a/server/src/main/java/org/eclipse/openvsx/storage/StorageUtil.java +++ b/server/src/main/java/org/eclipse/openvsx/storage/StorageUtil.java @@ -11,26 +11,13 @@ package org.eclipse.openvsx.storage; import org.springframework.http.CacheControl; -import org.springframework.http.MediaType; -import java.net.URLConnection; import java.util.concurrent.TimeUnit; class StorageUtil { private StorageUtil(){} - static MediaType getFileType(String fileName) { - if (fileName.endsWith(".vsix")) - return MediaType.APPLICATION_OCTET_STREAM; - if (fileName.endsWith(".json")) - return MediaType.APPLICATION_JSON; - var contentType = URLConnection.guessContentTypeFromName(fileName); - if (contentType != null) - return MediaType.parseMediaType(contentType); - return MediaType.TEXT_PLAIN; - } - static CacheControl getCacheControl(String fileName) { // Files are requested with a version string in the URL, so their content cannot change return CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic(); diff --git a/server/src/main/java/org/eclipse/openvsx/storage/StorageUtilService.java b/server/src/main/java/org/eclipse/openvsx/storage/StorageUtilService.java index bb5f5fbd8..d1f075255 100644 --- a/server/src/main/java/org/eclipse/openvsx/storage/StorageUtilService.java +++ b/server/src/main/java/org/eclipse/openvsx/storage/StorageUtilService.java @@ -10,6 +10,7 @@ package org.eclipse.openvsx.storage; import com.google.common.base.Strings; + import com.google.common.collect.Maps; import org.eclipse.openvsx.cache.CacheService; import org.eclipse.openvsx.entities.Download; @@ -24,6 +25,7 @@ import org.springframework.http.CacheControl; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -215,9 +217,13 @@ public void increaseDownloadCount(FileResource resource) { } } - public HttpHeaders getFileResponseHeaders(String fileName) { + public HttpHeaders getFileResponseHeaders(FileResource resource) { + return getFileResponseHeaders(resource.getName(), resource.getContentType()); + } + + private HttpHeaders getFileResponseHeaders(String fileName, String contentType) { var headers = new HttpHeaders(); - headers.setContentType(StorageUtil.getFileType(fileName)); + headers.setContentType(MediaType.parseMediaType(contentType)); if (fileName.endsWith(".vsix")) { headers.add("Content-Disposition", "attachment; filename=\"" + fileName + "\""); } else { @@ -230,7 +236,7 @@ public HttpHeaders getFileResponseHeaders(String fileName) { public ResponseEntity getFileResponse(FileResource resource) { resource = entityManager.merge(resource); if (resource.getStorageType().equals(FileResource.STORAGE_DB)) { - var headers = getFileResponseHeaders(resource.getName()); + var headers = getFileResponseHeaders(resource); return new ResponseEntity<>(resource.getContent(), headers, HttpStatus.OK); } else { return ResponseEntity.status(HttpStatus.FOUND) diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Indexes.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Indexes.java index a0f80e314..6c6ed0e15 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Indexes.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Indexes.java @@ -4,6 +4,7 @@ package org.eclipse.openvsx.jooq; +import org.eclipse.openvsx.jooq.tables.Download; import org.eclipse.openvsx.jooq.tables.Extension; import org.eclipse.openvsx.jooq.tables.ExtensionReview; import org.eclipse.openvsx.jooq.tables.ExtensionVersion; @@ -28,12 +29,14 @@ public class Indexes { // INDEX definitions // ------------------------------------------------------------------------- + public static final Index DOWNLOAD_TIMESTAMP_BRIN_IDX = Internal.createIndex(DSL.name("download_timestamp_brin_idx"), Download.DOWNLOAD, new OrderField[] { Download.DOWNLOAD.TIMESTAMP }, false); public static final Index EXTENSION__NAMESPACE_ID__IDX = Internal.createIndex(DSL.name("extension__namespace_id__idx"), Extension.EXTENSION, new OrderField[] { Extension.EXTENSION.NAMESPACE_ID }, false); public static final Index EXTENSION_REVIEW__EXTENSION_ID__IDX = Internal.createIndex(DSL.name("extension_review__extension_id__idx"), ExtensionReview.EXTENSION_REVIEW, new OrderField[] { ExtensionReview.EXTENSION_REVIEW.EXTENSION_ID }, false); public static final Index EXTENSION_REVIEW__USER_ID__IDX = Internal.createIndex(DSL.name("extension_review__user_id__idx"), ExtensionReview.EXTENSION_REVIEW, new OrderField[] { ExtensionReview.EXTENSION_REVIEW.USER_ID }, false); public static final Index EXTENSION_VERSION__EXTENSION_ID__IDX = Internal.createIndex(DSL.name("extension_version__extension_id__idx"), ExtensionVersion.EXTENSION_VERSION, new OrderField[] { ExtensionVersion.EXTENSION_VERSION.EXTENSION_ID }, false); public static final Index EXTENSION_VERSION__PUBLISHED_WITH_ID__IDX = Internal.createIndex(DSL.name("extension_version__published_with_id__idx"), ExtensionVersion.EXTENSION_VERSION, new OrderField[] { ExtensionVersion.EXTENSION_VERSION.PUBLISHED_WITH_ID }, false); public static final Index FILE_RESOURCE_EXTENSION_IDX = Internal.createIndex(DSL.name("file_resource_extension_idx"), FileResource.FILE_RESOURCE, new OrderField[] { FileResource.FILE_RESOURCE.EXTENSION_ID }, false); + public static final Index FILE_RESOURCE_TYPE_IDX = Internal.createIndex(DSL.name("file_resource_type_idx"), FileResource.FILE_RESOURCE, new OrderField[] { FileResource.FILE_RESOURCE.TYPE }, false); public static final Index FLYWAY_SCHEMA_HISTORY_S_IDX = Internal.createIndex(DSL.name("flyway_schema_history_s_idx"), FlywaySchemaHistory.FLYWAY_SCHEMA_HISTORY, new OrderField[] { FlywaySchemaHistory.FLYWAY_SCHEMA_HISTORY.SUCCESS }, false); public static final Index NAMESPACE_MEMBERSHIP__NAMESPACE__IDX = Internal.createIndex(DSL.name("namespace_membership__namespace__idx"), NamespaceMembership.NAMESPACE_MEMBERSHIP, new OrderField[] { NamespaceMembership.NAMESPACE_MEMBERSHIP.NAMESPACE }, false); public static final Index NAMESPACE_MEMBERSHIP__USER_DATA__IDX = Internal.createIndex(DSL.name("namespace_membership__user_data__idx"), NamespaceMembership.NAMESPACE_MEMBERSHIP, new OrderField[] { NamespaceMembership.NAMESPACE_MEMBERSHIP.USER_DATA }, false); diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Keys.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Keys.java index cc0544e41..183920cf4 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Keys.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Keys.java @@ -13,6 +13,7 @@ import org.eclipse.openvsx.jooq.tables.Extension; import org.eclipse.openvsx.jooq.tables.ExtensionReview; import org.eclipse.openvsx.jooq.tables.ExtensionVersion; +import org.eclipse.openvsx.jooq.tables.ExtractResourcesMigrationItem; import org.eclipse.openvsx.jooq.tables.FileResource; import org.eclipse.openvsx.jooq.tables.FlywaySchemaHistory; import org.eclipse.openvsx.jooq.tables.Namespace; @@ -32,6 +33,7 @@ import org.eclipse.openvsx.jooq.tables.records.ExtensionRecord; import org.eclipse.openvsx.jooq.tables.records.ExtensionReviewRecord; import org.eclipse.openvsx.jooq.tables.records.ExtensionVersionRecord; +import org.eclipse.openvsx.jooq.tables.records.ExtractResourcesMigrationItemRecord; import org.eclipse.openvsx.jooq.tables.records.FileResourceRecord; import org.eclipse.openvsx.jooq.tables.records.FlywaySchemaHistoryRecord; import org.eclipse.openvsx.jooq.tables.records.NamespaceMembershipRecord; @@ -69,6 +71,8 @@ public class Keys { public static final UniqueKey EXTENSION_REVIEW_PKEY = Internal.createUniqueKey(ExtensionReview.EXTENSION_REVIEW, DSL.name("extension_review_pkey"), new TableField[] { ExtensionReview.EXTENSION_REVIEW.ID }, true); public static final UniqueKey EXTENSION_VERSION_PKEY = Internal.createUniqueKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("extension_version_pkey"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.ID }, true); public static final UniqueKey UNIQUE_EXTENSION_VERSION = Internal.createUniqueKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("unique_extension_version"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.EXTENSION_ID, ExtensionVersion.EXTENSION_VERSION.TARGET_PLATFORM, ExtensionVersion.EXTENSION_VERSION.VERSION }, true); + public static final UniqueKey EXTRACT_RESOURCES_MIGRATION_ITEM_PKEY = Internal.createUniqueKey(ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM, DSL.name("extract_resources_migration_item_pkey"), new TableField[] { ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM.ID }, true); + public static final UniqueKey UNIQUE_EXTENSION_ID = Internal.createUniqueKey(ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM, DSL.name("unique_extension_id"), new TableField[] { ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM.EXTENSION_ID }, true); public static final UniqueKey FILE_RESOURCE_PKEY = Internal.createUniqueKey(FileResource.FILE_RESOURCE, DSL.name("file_resource_pkey"), new TableField[] { FileResource.FILE_RESOURCE.ID }, true); public static final UniqueKey FLYWAY_SCHEMA_HISTORY_PK = Internal.createUniqueKey(FlywaySchemaHistory.FLYWAY_SCHEMA_HISTORY, DSL.name("flyway_schema_history_pk"), new TableField[] { FlywaySchemaHistory.FLYWAY_SCHEMA_HISTORY.INSTALLED_RANK }, true); public static final UniqueKey NAMESPACE_PKEY = Internal.createUniqueKey(Namespace.NAMESPACE, DSL.name("namespace_pkey"), new TableField[] { Namespace.NAMESPACE.ID }, true); diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Public.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Public.java index ed50f6e32..6e03fd43b 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Public.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Public.java @@ -16,6 +16,7 @@ import org.eclipse.openvsx.jooq.tables.Extension; import org.eclipse.openvsx.jooq.tables.ExtensionReview; import org.eclipse.openvsx.jooq.tables.ExtensionVersion; +import org.eclipse.openvsx.jooq.tables.ExtractResourcesMigrationItem; import org.eclipse.openvsx.jooq.tables.FileResource; import org.eclipse.openvsx.jooq.tables.FlywaySchemaHistory; import org.eclipse.openvsx.jooq.tables.Namespace; @@ -90,6 +91,11 @@ public class Public extends SchemaImpl { */ public final ExtensionVersion EXTENSION_VERSION = ExtensionVersion.EXTENSION_VERSION; + /** + * The table public.extract_resources_migration_item. + */ + public final ExtractResourcesMigrationItem EXTRACT_RESOURCES_MIGRATION_ITEM = ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM; + /** * The table public.file_resource. */ @@ -174,6 +180,7 @@ public final List> getTables() { Extension.EXTENSION, ExtensionReview.EXTENSION_REVIEW, ExtensionVersion.EXTENSION_VERSION, + ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM, FileResource.FILE_RESOURCE, FlywaySchemaHistory.FLYWAY_SCHEMA_HISTORY, Namespace.NAMESPACE, diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Tables.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Tables.java index 4334e9223..d57a85c2d 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Tables.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/Tables.java @@ -13,6 +13,7 @@ import org.eclipse.openvsx.jooq.tables.Extension; import org.eclipse.openvsx.jooq.tables.ExtensionReview; import org.eclipse.openvsx.jooq.tables.ExtensionVersion; +import org.eclipse.openvsx.jooq.tables.ExtractResourcesMigrationItem; import org.eclipse.openvsx.jooq.tables.FileResource; import org.eclipse.openvsx.jooq.tables.FlywaySchemaHistory; import org.eclipse.openvsx.jooq.tables.Namespace; @@ -76,6 +77,11 @@ public class Tables { */ public static final ExtensionVersion EXTENSION_VERSION = ExtensionVersion.EXTENSION_VERSION; + /** + * The table public.extract_resources_migration_item. + */ + public static final ExtractResourcesMigrationItem EXTRACT_RESOURCES_MIGRATION_ITEM = ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM; + /** * The table public.file_resource. */ diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsExtensionsByRating.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsExtensionsByRating.java index 04d3cb840..ea408cbea 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsExtensionsByRating.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsExtensionsByRating.java @@ -103,8 +103,13 @@ public Schema getSchema() { return Arrays.>asList(Keys.ADMIN_STATISTICS_EXTENSIONS_BY_RATING__ADMIN_STATISTICS_EXTENSIONS_BY_RATING_FKEY); } + private transient AdminStatistics _adminStatistics; + public AdminStatistics adminStatistics() { - return new AdminStatistics(this, Keys.ADMIN_STATISTICS_EXTENSIONS_BY_RATING__ADMIN_STATISTICS_EXTENSIONS_BY_RATING_FKEY); + if (_adminStatistics == null) + _adminStatistics = new AdminStatistics(this, Keys.ADMIN_STATISTICS_EXTENSIONS_BY_RATING__ADMIN_STATISTICS_EXTENSIONS_BY_RATING_FKEY); + + return _adminStatistics; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsPublishersByExtensionsPublished.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsPublishersByExtensionsPublished.java index 57592196f..46e554e11 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsPublishersByExtensionsPublished.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/AdminStatisticsPublishersByExtensionsPublished.java @@ -103,8 +103,13 @@ public Schema getSchema() { return Arrays.>asList(Keys.ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED__ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED_FKEY); } + private transient AdminStatistics _adminStatistics; + public AdminStatistics adminStatistics() { - return new AdminStatistics(this, Keys.ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED__ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED_FKEY); + if (_adminStatistics == null) + _adminStatistics = new AdminStatistics(this, Keys.ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED__ADMIN_STATISTICS_PUBLISHERS_BY_EXTENSIONS_PUBLISHED_FKEY); + + return _adminStatistics; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Download.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Download.java index bef8680f3..55b29733e 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Download.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Download.java @@ -8,11 +8,13 @@ import java.util.Arrays; import java.util.List; +import org.eclipse.openvsx.jooq.Indexes; import org.eclipse.openvsx.jooq.Keys; import org.eclipse.openvsx.jooq.Public; import org.eclipse.openvsx.jooq.tables.records.DownloadRecord; import org.jooq.Field; import org.jooq.ForeignKey; +import org.jooq.Index; import org.jooq.Name; import org.jooq.Record; import org.jooq.Row4; @@ -105,6 +107,11 @@ public Schema getSchema() { return Public.PUBLIC; } + @Override + public List getIndexes() { + return Arrays.asList(Indexes.DOWNLOAD_TIMESTAMP_BRIN_IDX); + } + @Override public UniqueKey getPrimaryKey() { return Keys.DOWNLOAD_PKEY; diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Extension.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Extension.java index 8d6f25542..1b1a6b0a5 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Extension.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/Extension.java @@ -152,8 +152,13 @@ public List> getKeys() { return Arrays.>asList(Keys.EXTENSION__FK64IMD3NRJ67D50TPKJS94NGMN); } + private transient Namespace _namespace; + public Namespace namespace() { - return new Namespace(this, Keys.EXTENSION__FK64IMD3NRJ67D50TPKJS94NGMN); + if (_namespace == null) + _namespace = new Namespace(this, Keys.EXTENSION__FK64IMD3NRJ67D50TPKJS94NGMN); + + return _namespace; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionReview.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionReview.java index 957d3806d..b2d4304a8 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionReview.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionReview.java @@ -147,12 +147,21 @@ public List> getKeys() { return Arrays.>asList(Keys.EXTENSION_REVIEW__FKGD2DQDC23OGBNOBX8AFJFPNKP, Keys.EXTENSION_REVIEW__FKINJBN9GRK135Y6IK0UT4UJP0W); } + private transient Extension _extension; + private transient UserData _userData; + public Extension extension() { - return new Extension(this, Keys.EXTENSION_REVIEW__FKGD2DQDC23OGBNOBX8AFJFPNKP); + if (_extension == null) + _extension = new Extension(this, Keys.EXTENSION_REVIEW__FKGD2DQDC23OGBNOBX8AFJFPNKP); + + return _extension; } public UserData userData() { - return new UserData(this, Keys.EXTENSION_REVIEW__FKINJBN9GRK135Y6IK0UT4UJP0W); + if (_userData == null) + _userData = new UserData(this, Keys.EXTENSION_REVIEW__FKINJBN9GRK135Y6IK0UT4UJP0W); + + return _userData; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionVersion.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionVersion.java index 274e23d0e..ce81ecad4 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionVersion.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtensionVersion.java @@ -231,12 +231,21 @@ public List> getKeys() { return Arrays.>asList(Keys.EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT, Keys.EXTENSION_VERSION__FK70KHJ8PM0VACASUIIAQ0W0R80); } + private transient Extension _extension; + private transient PersonalAccessToken _personalAccessToken; + public Extension extension() { - return new Extension(this, Keys.EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT); + if (_extension == null) + _extension = new Extension(this, Keys.EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT); + + return _extension; } public PersonalAccessToken personalAccessToken() { - return new PersonalAccessToken(this, Keys.EXTENSION_VERSION__FK70KHJ8PM0VACASUIIAQ0W0R80); + if (_personalAccessToken == null) + _personalAccessToken = new PersonalAccessToken(this, Keys.EXTENSION_VERSION__FK70KHJ8PM0VACASUIIAQ0W0R80); + + return _personalAccessToken; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtractResourcesMigrationItem.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtractResourcesMigrationItem.java new file mode 100644 index 000000000..e6f33d4ce --- /dev/null +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/ExtractResourcesMigrationItem.java @@ -0,0 +1,146 @@ +/* + * This file is generated by jOOQ. + */ +package org.eclipse.openvsx.jooq.tables; + + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.openvsx.jooq.Keys; +import org.eclipse.openvsx.jooq.Public; +import org.eclipse.openvsx.jooq.tables.records.ExtractResourcesMigrationItemRecord; +import org.jooq.Field; +import org.jooq.ForeignKey; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Row3; +import org.jooq.Schema; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; +import org.jooq.impl.TableImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class ExtractResourcesMigrationItem extends TableImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of public.extract_resources_migration_item + */ + public static final ExtractResourcesMigrationItem EXTRACT_RESOURCES_MIGRATION_ITEM = new ExtractResourcesMigrationItem(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return ExtractResourcesMigrationItemRecord.class; + } + + /** + * The column public.extract_resources_migration_item.id. + */ + public final TableField ID = createField(DSL.name("id"), SQLDataType.BIGINT.nullable(false), this, ""); + + /** + * The column public.extract_resources_migration_item.extension_id. + */ + public final TableField EXTENSION_ID = createField(DSL.name("extension_id"), SQLDataType.BIGINT.nullable(false), this, ""); + + /** + * The column public.extract_resources_migration_item.migration_scheduled. + */ + public final TableField MIGRATION_SCHEDULED = createField(DSL.name("migration_scheduled"), SQLDataType.BOOLEAN.nullable(false), this, ""); + + private ExtractResourcesMigrationItem(Name alias, Table aliased) { + this(alias, aliased, null); + } + + private ExtractResourcesMigrationItem(Name alias, Table aliased, Field[] parameters) { + super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); + } + + /** + * Create an aliased public.extract_resources_migration_item table reference + */ + public ExtractResourcesMigrationItem(String alias) { + this(DSL.name(alias), EXTRACT_RESOURCES_MIGRATION_ITEM); + } + + /** + * Create an aliased public.extract_resources_migration_item table reference + */ + public ExtractResourcesMigrationItem(Name alias) { + this(alias, EXTRACT_RESOURCES_MIGRATION_ITEM); + } + + /** + * Create a public.extract_resources_migration_item table reference + */ + public ExtractResourcesMigrationItem() { + this(DSL.name("extract_resources_migration_item"), null); + } + + public ExtractResourcesMigrationItem(Table child, ForeignKey key) { + super(child, key, EXTRACT_RESOURCES_MIGRATION_ITEM); + } + + @Override + public Schema getSchema() { + return Public.PUBLIC; + } + + @Override + public UniqueKey getPrimaryKey() { + return Keys.EXTRACT_RESOURCES_MIGRATION_ITEM_PKEY; + } + + @Override + public List> getKeys() { + return Arrays.>asList(Keys.EXTRACT_RESOURCES_MIGRATION_ITEM_PKEY, Keys.UNIQUE_EXTENSION_ID); + } + + @Override + public ExtractResourcesMigrationItem as(String alias) { + return new ExtractResourcesMigrationItem(DSL.name(alias), this); + } + + @Override + public ExtractResourcesMigrationItem as(Name alias) { + return new ExtractResourcesMigrationItem(alias, this); + } + + /** + * Rename this table + */ + @Override + public ExtractResourcesMigrationItem rename(String name) { + return new ExtractResourcesMigrationItem(DSL.name(name), null); + } + + /** + * Rename this table + */ + @Override + public ExtractResourcesMigrationItem rename(Name name) { + return new ExtractResourcesMigrationItem(name, null); + } + + // ------------------------------------------------------------------------- + // Row3 type methods + // ------------------------------------------------------------------------- + + @Override + public Row3 fieldsRow() { + return (Row3) super.fieldsRow(); + } +} diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/FileResource.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/FileResource.java index 13ac0947f..44341d510 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/FileResource.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/FileResource.java @@ -16,7 +16,7 @@ import org.jooq.Index; import org.jooq.Name; import org.jooq.Record; -import org.jooq.Row6; +import org.jooq.Row7; import org.jooq.Schema; import org.jooq.Table; import org.jooq.TableField; @@ -78,6 +78,11 @@ public Class getRecordType() { */ public final TableField STORAGE_TYPE = createField(DSL.name("storage_type"), SQLDataType.VARCHAR(32), this, ""); + /** + * The column public.file_resource.content_type. + */ + public final TableField CONTENT_TYPE = createField(DSL.name("content_type"), SQLDataType.VARCHAR(255), this, ""); + private FileResource(Name alias, Table aliased) { this(alias, aliased, null); } @@ -118,7 +123,7 @@ public Schema getSchema() { @Override public List getIndexes() { - return Arrays.asList(Indexes.FILE_RESOURCE_EXTENSION_IDX); + return Arrays.asList(Indexes.FILE_RESOURCE_EXTENSION_IDX, Indexes.FILE_RESOURCE_TYPE_IDX); } @Override @@ -136,8 +141,13 @@ public List> getKeys() { return Arrays.>asList(Keys.FILE_RESOURCE__FILE_RESOURCE_EXTENSION_FKEY); } + private transient ExtensionVersion _extensionVersion; + public ExtensionVersion extensionVersion() { - return new ExtensionVersion(this, Keys.FILE_RESOURCE__FILE_RESOURCE_EXTENSION_FKEY); + if (_extensionVersion == null) + _extensionVersion = new ExtensionVersion(this, Keys.FILE_RESOURCE__FILE_RESOURCE_EXTENSION_FKEY); + + return _extensionVersion; } @Override @@ -167,11 +177,11 @@ public FileResource rename(Name name) { } // ------------------------------------------------------------------------- - // Row6 type methods + // Row7 type methods // ------------------------------------------------------------------------- @Override - public Row6 fieldsRow() { - return (Row6) super.fieldsRow(); + public Row7 fieldsRow() { + return (Row7) super.fieldsRow(); } } diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/NamespaceMembership.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/NamespaceMembership.java index 6e4b9e00a..af323e774 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/NamespaceMembership.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/NamespaceMembership.java @@ -126,12 +126,21 @@ public List> getKeys() { return Arrays.>asList(Keys.NAMESPACE_MEMBERSHIP__FKGFHWHKNULA6DO2N6WYVQETM3N, Keys.NAMESPACE_MEMBERSHIP__FKNSAMEKUTXYWVSB3S1MJDCJKYP); } + private transient Namespace _namespace; + private transient UserData _userData; + public Namespace namespace() { - return new Namespace(this, Keys.NAMESPACE_MEMBERSHIP__FKGFHWHKNULA6DO2N6WYVQETM3N); + if (_namespace == null) + _namespace = new Namespace(this, Keys.NAMESPACE_MEMBERSHIP__FKGFHWHKNULA6DO2N6WYVQETM3N); + + return _namespace; } public UserData userData() { - return new UserData(this, Keys.NAMESPACE_MEMBERSHIP__FKNSAMEKUTXYWVSB3S1MJDCJKYP); + if (_userData == null) + _userData = new UserData(this, Keys.NAMESPACE_MEMBERSHIP__FKNSAMEKUTXYWVSB3S1MJDCJKYP); + + return _userData; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersistedLog.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersistedLog.java index 40cae9057..015e4f6d5 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersistedLog.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersistedLog.java @@ -127,8 +127,13 @@ public List> getKeys() { return Arrays.>asList(Keys.PERSISTED_LOG__PERSISTED_LOG_USER_DATA_FKEY); } + private transient UserData _userData; + public UserData userData() { - return new UserData(this, Keys.PERSISTED_LOG__PERSISTED_LOG_USER_DATA_FKEY); + if (_userData == null) + _userData = new UserData(this, Keys.PERSISTED_LOG__PERSISTED_LOG_USER_DATA_FKEY); + + return _userData; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersonalAccessToken.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersonalAccessToken.java index de5c8a5aa..5f91c0acc 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersonalAccessToken.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/PersonalAccessToken.java @@ -135,8 +135,13 @@ public List> getKeys() { return Arrays.>asList(Keys.PERSONAL_ACCESS_TOKEN__FKTQJVMHOIG3WTTJ6DL1IBCAJ3L); } + private transient UserData _userData; + public UserData userData() { - return new UserData(this, Keys.PERSONAL_ACCESS_TOKEN__FKTQJVMHOIG3WTTJ6DL1IBCAJ3L); + if (_userData == null) + _userData = new UserData(this, Keys.PERSONAL_ACCESS_TOKEN__FKTQJVMHOIG3WTTJ6DL1IBCAJ3L); + + return _userData; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/SpringSessionAttributes.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/SpringSessionAttributes.java index cdd3a8799..fdae9bd6a 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/SpringSessionAttributes.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/SpringSessionAttributes.java @@ -114,8 +114,13 @@ public List> getKeys() { return Arrays.>asList(Keys.SPRING_SESSION_ATTRIBUTES__SPRING_SESSION_ATTRIBUTES_FK); } + private transient SpringSession _springSession; + public SpringSession springSession() { - return new SpringSession(this, Keys.SPRING_SESSION_ATTRIBUTES__SPRING_SESSION_ATTRIBUTES_FK); + if (_springSession == null) + _springSession = new SpringSession(this, Keys.SPRING_SESSION_ATTRIBUTES__SPRING_SESSION_ATTRIBUTES_FK); + + return _springSession; } @Override diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtractResourcesMigrationItemRecord.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtractResourcesMigrationItemRecord.java new file mode 100644 index 000000000..12fc46973 --- /dev/null +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtractResourcesMigrationItemRecord.java @@ -0,0 +1,180 @@ +/* + * This file is generated by jOOQ. + */ +package org.eclipse.openvsx.jooq.tables.records; + + +import org.eclipse.openvsx.jooq.tables.ExtractResourcesMigrationItem; +import org.jooq.Field; +import org.jooq.Record1; +import org.jooq.Record3; +import org.jooq.Row3; +import org.jooq.impl.UpdatableRecordImpl; + + +/** + * This class is generated by jOOQ. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +public class ExtractResourcesMigrationItemRecord extends UpdatableRecordImpl implements Record3 { + + private static final long serialVersionUID = 1L; + + /** + * Setter for public.extract_resources_migration_item.id. + */ + public void setId(Long value) { + set(0, value); + } + + /** + * Getter for public.extract_resources_migration_item.id. + */ + public Long getId() { + return (Long) get(0); + } + + /** + * Setter for public.extract_resources_migration_item.extension_id. + */ + public void setExtensionId(Long value) { + set(1, value); + } + + /** + * Getter for public.extract_resources_migration_item.extension_id. + */ + public Long getExtensionId() { + return (Long) get(1); + } + + /** + * Setter for public.extract_resources_migration_item.migration_scheduled. + */ + public void setMigrationScheduled(Boolean value) { + set(2, value); + } + + /** + * Getter for public.extract_resources_migration_item.migration_scheduled. + */ + public Boolean getMigrationScheduled() { + return (Boolean) get(2); + } + + // ------------------------------------------------------------------------- + // Primary key information + // ------------------------------------------------------------------------- + + @Override + public Record1 key() { + return (Record1) super.key(); + } + + // ------------------------------------------------------------------------- + // Record3 type implementation + // ------------------------------------------------------------------------- + + @Override + public Row3 fieldsRow() { + return (Row3) super.fieldsRow(); + } + + @Override + public Row3 valuesRow() { + return (Row3) super.valuesRow(); + } + + @Override + public Field field1() { + return ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM.ID; + } + + @Override + public Field field2() { + return ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM.EXTENSION_ID; + } + + @Override + public Field field3() { + return ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM.MIGRATION_SCHEDULED; + } + + @Override + public Long component1() { + return getId(); + } + + @Override + public Long component2() { + return getExtensionId(); + } + + @Override + public Boolean component3() { + return getMigrationScheduled(); + } + + @Override + public Long value1() { + return getId(); + } + + @Override + public Long value2() { + return getExtensionId(); + } + + @Override + public Boolean value3() { + return getMigrationScheduled(); + } + + @Override + public ExtractResourcesMigrationItemRecord value1(Long value) { + setId(value); + return this; + } + + @Override + public ExtractResourcesMigrationItemRecord value2(Long value) { + setExtensionId(value); + return this; + } + + @Override + public ExtractResourcesMigrationItemRecord value3(Boolean value) { + setMigrationScheduled(value); + return this; + } + + @Override + public ExtractResourcesMigrationItemRecord values(Long value1, Long value2, Boolean value3) { + value1(value1); + value2(value2); + value3(value3); + return this; + } + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + /** + * Create a detached ExtractResourcesMigrationItemRecord + */ + public ExtractResourcesMigrationItemRecord() { + super(ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM); + } + + /** + * Create a detached, initialised ExtractResourcesMigrationItemRecord + */ + public ExtractResourcesMigrationItemRecord(Long id, Long extensionId, Boolean migrationScheduled) { + super(ExtractResourcesMigrationItem.EXTRACT_RESOURCES_MIGRATION_ITEM); + + setId(id); + setExtensionId(extensionId); + setMigrationScheduled(migrationScheduled); + } +} diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/FileResourceRecord.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/FileResourceRecord.java index 8203f55f1..8fa2ce38c 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/FileResourceRecord.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/FileResourceRecord.java @@ -7,8 +7,8 @@ import org.eclipse.openvsx.jooq.tables.FileResource; import org.jooq.Field; import org.jooq.Record1; -import org.jooq.Record6; -import org.jooq.Row6; +import org.jooq.Record7; +import org.jooq.Row7; import org.jooq.impl.UpdatableRecordImpl; @@ -16,7 +16,7 @@ * This class is generated by jOOQ. */ @SuppressWarnings({ "all", "unchecked", "rawtypes" }) -public class FileResourceRecord extends UpdatableRecordImpl implements Record6 { +public class FileResourceRecord extends UpdatableRecordImpl implements Record7 { private static final long serialVersionUID = 1L; @@ -104,6 +104,20 @@ public String getStorageType() { return (String) get(5); } + /** + * Setter for public.file_resource.content_type. + */ + public void setContentType(String value) { + set(6, value); + } + + /** + * Getter for public.file_resource.content_type. + */ + public String getContentType() { + return (String) get(6); + } + // ------------------------------------------------------------------------- // Primary key information // ------------------------------------------------------------------------- @@ -114,17 +128,17 @@ public Record1 key() { } // ------------------------------------------------------------------------- - // Record6 type implementation + // Record7 type implementation // ------------------------------------------------------------------------- @Override - public Row6 fieldsRow() { - return (Row6) super.fieldsRow(); + public Row7 fieldsRow() { + return (Row7) super.fieldsRow(); } @Override - public Row6 valuesRow() { - return (Row6) super.valuesRow(); + public Row7 valuesRow() { + return (Row7) super.valuesRow(); } @Override @@ -157,6 +171,11 @@ public Field field6() { return FileResource.FILE_RESOURCE.STORAGE_TYPE; } + @Override + public Field field7() { + return FileResource.FILE_RESOURCE.CONTENT_TYPE; + } + @Override public Long component1() { return getId(); @@ -187,6 +206,11 @@ public String component6() { return getStorageType(); } + @Override + public String component7() { + return getContentType(); + } + @Override public Long value1() { return getId(); @@ -217,6 +241,11 @@ public String value6() { return getStorageType(); } + @Override + public String value7() { + return getContentType(); + } + @Override public FileResourceRecord value1(Long value) { setId(value); @@ -254,13 +283,20 @@ public FileResourceRecord value6(String value) { } @Override - public FileResourceRecord values(Long value1, String value2, byte[] value3, Long value4, String value5, String value6) { + public FileResourceRecord value7(String value) { + setContentType(value); + return this; + } + + @Override + public FileResourceRecord values(Long value1, String value2, byte[] value3, Long value4, String value5, String value6, String value7) { value1(value1); value2(value2); value3(value3); value4(value4); value5(value5); value6(value6); + value7(value7); return this; } @@ -278,7 +314,7 @@ public FileResourceRecord() { /** * Create a detached, initialised FileResourceRecord */ - public FileResourceRecord(Long id, String type, byte[] content, Long extensionId, String name, String storageType) { + public FileResourceRecord(Long id, String type, byte[] content, Long extensionId, String name, String storageType, String contentType) { super(FileResource.FILE_RESOURCE); setId(id); @@ -287,5 +323,6 @@ public FileResourceRecord(Long id, String type, byte[] content, Long extensionId setExtensionId(extensionId); setName(name); setStorageType(storageType); + setContentType(contentType); } } diff --git a/server/src/main/resources/db/migration/V1_29__FileResource_ContentType.sql b/server/src/main/resources/db/migration/V1_29__FileResource_ContentType.sql new file mode 100644 index 000000000..99c938250 --- /dev/null +++ b/server/src/main/resources/db/migration/V1_29__FileResource_ContentType.sql @@ -0,0 +1,7 @@ +ALTER TABLE file_resource ADD COLUMN content_type CHARACTER VARYING(255); + +INSERT INTO migration_item(id, migration_script, entity_id, migration_scheduled) +SELECT nextval('hibernate_sequence'), 'V1_29__FileResource_ContentType.sql', ev.id, FALSE +FROM extension_version ev +JOIN extension e ON e.id = ev.extension_id +ORDER BY e.download_count DESC; \ No newline at end of file diff --git a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java index a007ff656..f2d244291 100644 --- a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java @@ -1882,6 +1882,7 @@ private FileResource mockReadme(String targetPlatform) { resource.setName("README"); resource.setType(FileResource.README); resource.setContent("Please read me".getBytes()); + resource.setContentType(MediaType.TEXT_PLAIN_VALUE); resource.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(resource)).thenReturn(resource); Mockito.when(repositories.findFileByName(extVersion, "README")) @@ -1896,6 +1897,7 @@ private FileResource mockChangelog() { resource.setName("CHANGELOG"); resource.setType(FileResource.CHANGELOG); resource.setContent("All notable changes is documented here".getBytes()); + resource.setContentType(MediaType.TEXT_PLAIN_VALUE); resource.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(resource)).thenReturn(resource); Mockito.when(repositories.findFileByName(extVersion, "CHANGELOG")) @@ -1910,6 +1912,7 @@ private FileResource mockLicense() { resource.setName("LICENSE"); resource.setType(FileResource.LICENSE); resource.setContent("I never broke the Law! I am the law!".getBytes()); + resource.setContentType(MediaType.TEXT_PLAIN_VALUE); resource.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(resource)).thenReturn(resource); Mockito.when(repositories.findFileByName(extVersion, "LICENSE")) diff --git a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java index 6d49d0a4d..8192b40cf 100644 --- a/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/adapter/VSCodeAPITest.java @@ -17,7 +17,6 @@ import java.io.IOException; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.*; @@ -55,6 +54,7 @@ import org.springframework.data.elasticsearch.core.SearchHitsImpl; import org.springframework.data.elasticsearch.core.TotalHitsRelation; import org.springframework.data.util.Streamable; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.test.web.servlet.MockMvc; @@ -222,6 +222,7 @@ public void testAsset() throws Exception { mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.Manifest")) .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) .andExpect(content().string("{\"foo\":\"bar\"}")); } @@ -232,6 +233,7 @@ public void testAssetMacOSX() throws Exception { mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}?targetPlatform={target}", "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.Manifest", target)) .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) .andExpect(content().string("{\"foo\":\"bar\",\"target\":\"darwin-arm64\"}")); } @@ -245,6 +247,15 @@ public void testAssetNotFound() throws Exception { .andExpect(status().isNotFound()); } + @Test + public void testAssetVsixPackage() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Services.VSIXPackage")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, "application/zip")); + } + @Test public void testGetItem() throws Exception { var extension = mockExtension(); @@ -256,14 +267,65 @@ public void testGetItem() throws Exception { } @Test - public void testWebResourceAsset() throws Exception { + public void testDefaultWebResourceAsset() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/resources/data.bin")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)) + .andExpect(content().string("data.bin")); + } + + @Test + public void testPngWebResourceAsset() throws Exception { mockExtensionVersion(); mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/img/logo.png")) .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE)) .andExpect(content().string("logo.png")); } + @Test + public void testCssWebResourceAsset() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/public/static/css/main.css")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, "text/css")) + .andExpect(content().string(".main { margin: 0 auto; }")); + } + + @Test + public void testChunkCssWebResourceAsset() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/public/static/css/main.9cab4879.chunk.css")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, "text/css")) + .andExpect(content().string(".root { margin: 0 auto; }")); + } + + @Test + public void testJsWebResourceAsset() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/public/static/js/main.js")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, "application/javascript")) + .andExpect(content().string("() => { console.log('main'); }")); + } + + @Test + public void testChunkJsWebResourceAsset() throws Exception { + mockExtensionVersion(); + mockMvc.perform(get("/vscode/asset/{namespace}/{extensionName}/{version}/{assetType}", + "redhat", "vscode-yaml", "0.5.2", "Microsoft.VisualStudio.Code.WebResources/extension/public/static/js/main.34d01954.chunk.js")) + .andExpect(status().isOk()) + .andExpect(header().string(HttpHeaders.CONTENT_TYPE, "application/javascript")) + .andExpect(content().string("() => { console.log('js'); }")); + } + @Test public void testNotWebResourceAsset() throws Exception { mockExtensionVersion(); @@ -348,12 +410,12 @@ public void testBrowseTopDir() throws Exception { Mockito.when(repositories.findActiveExtensionVersionsByVersion(version, extensionName, namespaceName)) .thenReturn(List.of(extVersion)); - var vsixResource = mockFileResource(15, extVersion, "extension.vsixmanifest", RESOURCE, STORAGE_DB, "".getBytes(StandardCharsets.UTF_8)); - var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, "{\"package\":\"json\"}".getBytes(StandardCharsets.UTF_8)); - var readmeResource = mockFileResource(17, extVersion, "extension/README.md", RESOURCE, STORAGE_DB, "README".getBytes(StandardCharsets.UTF_8)); - var changelogResource = mockFileResource(18, extVersion, "extension/CHANGELOG.md", RESOURCE, STORAGE_DB, "CHANGELOG".getBytes(StandardCharsets.UTF_8)); - var licenseResource = mockFileResource(19, extVersion, "extension/LICENSE.txt", RESOURCE, STORAGE_DB, "LICENSE".getBytes(StandardCharsets.UTF_8)); - var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, "ICON128".getBytes(StandardCharsets.UTF_8)); + var vsixResource = mockFileResource(15, extVersion, "extension.vsixmanifest", RESOURCE, STORAGE_DB, "".getBytes(StandardCharsets.UTF_8), "application/xml"); + var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, "{\"package\":\"json\"}".getBytes(StandardCharsets.UTF_8), "application/json"); + var readmeResource = mockFileResource(17, extVersion, "extension/README.md", RESOURCE, STORAGE_DB, "README".getBytes(StandardCharsets.UTF_8), "text/markdown"); + var changelogResource = mockFileResource(18, extVersion, "extension/CHANGELOG.md", RESOURCE, STORAGE_DB, "CHANGELOG".getBytes(StandardCharsets.UTF_8), "text/markdown"); + var licenseResource = mockFileResource(19, extVersion, "extension/LICENSE.txt", RESOURCE, STORAGE_DB, "LICENSE".getBytes(StandardCharsets.UTF_8), "text/plain"); + var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, "ICON128".getBytes(StandardCharsets.UTF_8), "image/png"); Mockito.when(repositories.findResourceFileResources(1L, "")) .thenReturn(List.of(vsixResource, manifestResource, readmeResource, changelogResource, licenseResource, iconResource)); @@ -385,7 +447,7 @@ public void testBrowseVsixManifest() throws Exception { .thenReturn(List.of(extVersion)); var content = "".getBytes(StandardCharsets.UTF_8); - var vsixResource = mockFileResource(15, extVersion, "extension.vsixmanifest", RESOURCE, STORAGE_DB, content); + var vsixResource = mockFileResource(15, extVersion, "extension.vsixmanifest", RESOURCE, STORAGE_DB, content, "application/xml"); Mockito.when(repositories.findResourceFileResources(1L, "extension.vsixmanifest")) .thenReturn(List.of(vsixResource)); @@ -420,7 +482,7 @@ public void testBrowseVsixManifestUniversal() throws Exception { .thenReturn(extVersions); var content = "".getBytes(StandardCharsets.UTF_8); - var vsixResource = mockFileResource(15, extVersions.get(0), "extension.vsixmanifest", RESOURCE, STORAGE_DB, content); + var vsixResource = mockFileResource(15, extVersions.get(0), "extension.vsixmanifest", RESOURCE, STORAGE_DB, content, "application/xml"); Mockito.when(repositories.findResourceFileResources(1L, "extension.vsixmanifest")) .thenReturn(List.of(vsixResource)); @@ -455,7 +517,7 @@ public void testBrowseVsixManifestWindows() throws Exception { .thenReturn(extVersions); var content = "".getBytes(StandardCharsets.UTF_8); - var vsixResource = mockFileResource(15, extVersions.get(2), "extension.vsixmanifest", RESOURCE, STORAGE_DB, content); + var vsixResource = mockFileResource(15, extVersions.get(2), "extension.vsixmanifest", RESOURCE, STORAGE_DB, content, "application/xml"); Mockito.when(repositories.findResourceFileResources(4L, "extension.vsixmanifest")) .thenReturn(List.of(vsixResource)); @@ -484,11 +546,11 @@ public void testBrowseExtensionDir() throws Exception { Mockito.when(repositories.findActiveExtensionVersionsByVersion(version, extensionName, namespaceName)) .thenReturn(List.of(extVersion)); - var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, "{\"package\":\"json\"}".getBytes(StandardCharsets.UTF_8)); - var readmeResource = mockFileResource(17, extVersion, "extension/README.md", RESOURCE, STORAGE_DB, "README".getBytes(StandardCharsets.UTF_8)); - var changelogResource = mockFileResource(18, extVersion, "extension/CHANGELOG.md", RESOURCE, STORAGE_DB, "CHANGELOG".getBytes(StandardCharsets.UTF_8)); - var licenseResource = mockFileResource(19, extVersion, "extension/LICENSE.txt", RESOURCE, STORAGE_DB, "LICENSE".getBytes(StandardCharsets.UTF_8)); - var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, "ICON128".getBytes(StandardCharsets.UTF_8)); + var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, "{\"package\":\"json\"}".getBytes(StandardCharsets.UTF_8), "application/json"); + var readmeResource = mockFileResource(17, extVersion, "extension/README.md", RESOURCE, STORAGE_DB, "README".getBytes(StandardCharsets.UTF_8), "text/markdown"); + var changelogResource = mockFileResource(18, extVersion, "extension/CHANGELOG.md", RESOURCE, STORAGE_DB, "CHANGELOG".getBytes(StandardCharsets.UTF_8), "text/markdown"); + var licenseResource = mockFileResource(19, extVersion, "extension/LICENSE.txt", RESOURCE, STORAGE_DB, "LICENSE".getBytes(StandardCharsets.UTF_8), "text/plain"); + var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, "ICON128".getBytes(StandardCharsets.UTF_8), "image/png"); Mockito.when(repositories.findResourceFileResources(1L, "extension")) .thenReturn(List.of(manifestResource, readmeResource, changelogResource, licenseResource, iconResource)); @@ -524,7 +586,7 @@ public void testBrowsePackageJson() throws Exception { .thenReturn(List.of(extVersion)); var content = "{\"package\":\"json\"}".getBytes(StandardCharsets.UTF_8); - var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, content); + var manifestResource = mockFileResource(16, extVersion, "extension/package.json", RESOURCE, STORAGE_DB, content, "application/json"); Mockito.when(repositories.findResourceFileResources(1L, "extension/package.json")) .thenReturn(List.of(manifestResource)); @@ -553,7 +615,7 @@ public void testBrowseImagesDir() throws Exception { .thenReturn(List.of(extVersion)); var content = "ICON128".getBytes(StandardCharsets.UTF_8); - var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, content); + var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, content, "image/png"); Mockito.when(repositories.findResourceFileResources(1L, "extension/images")) .thenReturn(List.of(iconResource)); @@ -583,7 +645,7 @@ public void testBrowseIcon() throws Exception { .thenReturn(List.of(extVersion)); var content = "ICON128".getBytes(StandardCharsets.UTF_8); - var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, content); + var iconResource = mockFileResource(20, extVersion, "extension/images/icon128.png", RESOURCE, STORAGE_DB, content, "image/png"); Mockito.when(repositories.findResourceFileResources(1L, "extension/images/icon128.png")) .thenReturn(List.of(iconResource)); @@ -745,10 +807,11 @@ private FileResource mockFileResource(long id, ExtensionVersion extVersion, Stri return resource; } - private FileResource mockFileResource(long id, ExtensionVersion extVersion, String name, String type, String storageType, byte[] content) { + private FileResource mockFileResource(long id, ExtensionVersion extVersion, String name, String type, String storageType, byte[] content, String contentType) { var resource = mockFileResource(id, extVersion, name, type); resource.setStorageType(storageType); resource.setContent(content); + resource.setContentType(contentType); return resource; } @@ -771,6 +834,7 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json extension.setAverageRating(3.0); extension.setNamespace(namespace); var extVersion = new ExtensionVersion(); + extVersion.setExtension(extension); extension.getVersions().add(extVersion); extVersion.setTargetPlatform(targetPlatform); extVersion.setVersion("0.5.2"); @@ -792,13 +856,14 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json Mockito.when(repositories.findVersions(extension)) .thenReturn(Streamable.of(extVersion)); Mockito.when(repositories.countMemberships(namespace, NamespaceMembership.ROLE_OWNER)) - .thenReturn(0l); + .thenReturn(0L); Mockito.when(repositories.countActiveReviews(extension)) - .thenReturn(10l); + .thenReturn(10L); var extensionFile = new FileResource(); extensionFile.setExtension(extVersion); extensionFile.setName("redhat.vscode-yaml-0.5.2.vsix"); extensionFile.setType(FileResource.DOWNLOAD); + extensionFile.setContentType("application/zip"); extensionFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(extensionFile)).thenReturn(extensionFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.DOWNLOAD)) @@ -812,6 +877,7 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json if(!targetPlatform.equals(TargetPlatform.NAME_UNIVERSAL)) manifestContent.put("target", targetPlatform); manifestFile.setContent(new ObjectMapper().writeValueAsBytes(manifestContent)); + manifestFile.setContentType(MediaType.APPLICATION_JSON_VALUE); manifestFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(manifestFile)).thenReturn(manifestFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.MANIFEST)) @@ -820,6 +886,7 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json readmeFile.setExtension(extVersion); readmeFile.setName("README.md"); readmeFile.setType(FileResource.README); + readmeFile.setContentType("text/markdown"); readmeFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(readmeFile)).thenReturn(readmeFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.README)) @@ -828,6 +895,7 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json changelogFile.setExtension(extVersion); changelogFile.setName("CHANGELOG.md"); changelogFile.setType(FileResource.CHANGELOG); + changelogFile.setContentType("text/markdown"); changelogFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(changelogFile)).thenReturn(changelogFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.CHANGELOG)) @@ -836,6 +904,7 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json licenseFile.setExtension(extVersion); licenseFile.setName("LICENSE.txt"); licenseFile.setType(FileResource.LICENSE); + licenseFile.setContentType(MediaType.TEXT_PLAIN_VALUE); licenseFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(licenseFile)).thenReturn(licenseFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.LICENSE)) @@ -844,19 +913,71 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json iconFile.setExtension(extVersion); iconFile.setName("icon128.png"); iconFile.setType(FileResource.ICON); + iconFile.setContentType(MediaType.IMAGE_PNG_VALUE); iconFile.setStorageType(FileResource.STORAGE_DB); Mockito.when(entityManager.merge(iconFile)).thenReturn(iconFile); Mockito.when(repositories.findFileByType(extVersion, FileResource.ICON)) .thenReturn(iconFile); - var webResourceFile = new FileResource(); - webResourceFile.setExtension(extVersion); - webResourceFile.setName("extension/img/logo.png"); - webResourceFile.setType(FileResource.RESOURCE); - webResourceFile.setStorageType(STORAGE_DB); - webResourceFile.setContent("logo.png".getBytes()); - Mockito.when(entityManager.merge(webResourceFile)).thenReturn(webResourceFile); + var binWebResourceFile = new FileResource(); + binWebResourceFile.setExtension(extVersion); + binWebResourceFile.setName("extension/resources/data.bin"); + binWebResourceFile.setType(FileResource.RESOURCE); + binWebResourceFile.setStorageType(STORAGE_DB); + binWebResourceFile.setContent("data.bin".getBytes()); + binWebResourceFile.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + Mockito.when(entityManager.merge(binWebResourceFile)).thenReturn(binWebResourceFile); + Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/resources/data.bin")) + .thenReturn(binWebResourceFile); + var pngWebResourceFile = new FileResource(); + pngWebResourceFile.setExtension(extVersion); + pngWebResourceFile.setName("extension/img/logo.png"); + pngWebResourceFile.setType(FileResource.RESOURCE); + pngWebResourceFile.setStorageType(STORAGE_DB); + pngWebResourceFile.setContent("logo.png".getBytes()); + pngWebResourceFile.setContentType(MediaType.IMAGE_PNG_VALUE); + Mockito.when(entityManager.merge(pngWebResourceFile)).thenReturn(pngWebResourceFile); Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/img/logo.png")) - .thenReturn(webResourceFile); + .thenReturn(pngWebResourceFile); + var jsWebResourceFile = new FileResource(); + jsWebResourceFile.setExtension(extVersion); + jsWebResourceFile.setName("extension/public/static/js/main.js"); + jsWebResourceFile.setType(FileResource.RESOURCE); + jsWebResourceFile.setStorageType(STORAGE_DB); + jsWebResourceFile.setContent("() => { console.log('main'); }".getBytes()); + jsWebResourceFile.setContentType("application/javascript"); + Mockito.when(entityManager.merge(jsWebResourceFile)).thenReturn(jsWebResourceFile); + Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/public/static/js/main.js")) + .thenReturn(jsWebResourceFile); + var jsChunkWebResourceFile = new FileResource(); + jsChunkWebResourceFile.setExtension(extVersion); + jsChunkWebResourceFile.setName("extension/public/static/js/main.34d01954.chunk.js"); + jsChunkWebResourceFile.setType(FileResource.RESOURCE); + jsChunkWebResourceFile.setStorageType(STORAGE_DB); + jsChunkWebResourceFile.setContent("() => { console.log('js'); }".getBytes()); + jsChunkWebResourceFile.setContentType("application/javascript"); + Mockito.when(entityManager.merge(jsChunkWebResourceFile)).thenReturn(jsChunkWebResourceFile); + Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/public/static/js/main.34d01954.chunk.js")) + .thenReturn(jsChunkWebResourceFile); + var cssWebResourceFile = new FileResource(); + cssWebResourceFile.setExtension(extVersion); + cssWebResourceFile.setName("extension/public/static/css/main.css"); + cssWebResourceFile.setType(FileResource.RESOURCE); + cssWebResourceFile.setStorageType(STORAGE_DB); + cssWebResourceFile.setContent(".main { margin: 0 auto; }".getBytes()); + cssWebResourceFile.setContentType("text/css"); + Mockito.when(entityManager.merge(cssWebResourceFile)).thenReturn(cssWebResourceFile); + Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/public/static/css/main.css")) + .thenReturn(cssWebResourceFile); + var cssChunkWebResourceFile = new FileResource(); + cssChunkWebResourceFile.setExtension(extVersion); + cssChunkWebResourceFile.setName("extension/public/static/css/main.9cab4879.chunk.css"); + cssChunkWebResourceFile.setType(FileResource.RESOURCE); + cssChunkWebResourceFile.setStorageType(STORAGE_DB); + cssChunkWebResourceFile.setContent(".root { margin: 0 auto; }".getBytes()); + cssChunkWebResourceFile.setContentType("text/css"); + Mockito.when(entityManager.merge(cssChunkWebResourceFile)).thenReturn(cssChunkWebResourceFile); + Mockito.when(repositories.findFileByTypeAndName(extVersion, FileResource.RESOURCE, "extension/public/static/css/main.9cab4879.chunk.css")) + .thenReturn(cssChunkWebResourceFile); Mockito.when(repositories.findFilesByType(anyCollection(), anyCollection())).thenAnswer(invocation -> { Collection extVersions = invocation.getArgument(0); var types = invocation.getArgument(1); @@ -869,10 +990,8 @@ private ExtensionVersion mockExtensionVersion(String targetPlatform) throws Json return extVersion; } - private String file(String name) throws UnsupportedEncodingException, IOException { - try ( - var stream = getClass().getResourceAsStream(name); - ) { + private String file(String name) throws IOException { + try (var stream = getClass().getResourceAsStream(name)) { return CharStreams.toString(new InputStreamReader(stream, "UTF-8")); } } diff --git a/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java b/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java index 84c693f2e..82808c2b5 100644 --- a/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java +++ b/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java @@ -146,6 +146,7 @@ void testExecuteQueries() { () -> repositories.findNotMigratedResources(), () -> repositories.findNotMigratedPreReleases(), () -> repositories.findNotMigratedRenamedDownloads(), + () -> repositories.findNotMigratedContentTypes(), () -> repositories.topMostActivePublishingUsers(NOW, 1), () -> repositories.topNamespaceExtensions(NOW, 1), () -> repositories.topNamespaceExtensionVersions(NOW, 1),