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),