diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java index b774fcc86..dc41ac1b6 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java @@ -93,12 +93,12 @@ private long getMaxContentSize() { public ExtensionVersion mirrorVersion( TempFile extensionFile, String signatureName, - PersonalAccessToken token, + UserData user, String binaryName, String timestamp ) { try (var processor = new ExtensionProcessor(extensionFile)) { - doPublish(processor, binaryName, token, TimeUtil.fromUTCString(timestamp), false); + doPublish(processor, binaryName, user, TimeUtil.fromUTCString(timestamp), false); } publishHandler.mirror(extensionFile, signatureName); return extensionFile.getResource().getExtension(); @@ -128,28 +128,28 @@ public TempFile createExtensionFile(InputStream content) { } } - public ExtensionVersion publishVersion(InputStream inputStream, PersonalAccessToken token) + public ExtensionVersion publishVersion(InputStream inputStream, UserData user) throws ErrorResultException { try ( TempFile tempFile = createExtensionFile(inputStream); ExtensionProcessor processor = new ExtensionProcessor(tempFile) ) { - return publishVersion(processor, token); + return publishVersion(processor, user); } catch (IOException e) { throw new ErrorResultException("Failed to read extension file", e); } } - public ExtensionVersion publishVersion(ExtensionProcessor processor, PersonalAccessToken token) + public ExtensionVersion publishVersion(ExtensionProcessor processor, UserData user) throws ErrorResultException { requireNonNull(processor); - requireNonNull(token); + requireNonNull(user); var content = processor.getExtensionFile(); if (scanService.isEnabled()) { - return publishVersionWithScan(processor, token); + return publishVersionWithScan(processor, user); } else { try { - doPublish(processor, null, token, TimeUtil.getCurrentUTC(), true); + doPublish(processor, null, user, TimeUtil.getCurrentUTC(), true); } catch (ErrorResultException exc) { // In case publication fails early on we need to // delete the temporary extension file, otherwise @@ -164,7 +164,7 @@ public ExtensionVersion publishVersion(ExtensionProcessor processor, PersonalAcc } } - private ExtensionVersion publishVersionWithScan(ExtensionProcessor processor, PersonalAccessToken token) + private ExtensionVersion publishVersionWithScan(ExtensionProcessor processor, UserData user) throws ErrorResultException { var extensionFile = processor.getExtensionFile(); ExtensionScan scan = null; @@ -173,13 +173,13 @@ private ExtensionVersion publishVersionWithScan(ExtensionProcessor processor, Pe // Fail before any validation or scanning happens (and before a scan record is stored) if the // extension version can not be published anyway, e.g. because the publisher lacks the access // rights for the namespace or the version is published already. - publishHandler.checkPublishPreconditions(processor, token); + publishHandler.checkPublishPreconditions(processor, user); - scan = scanService.initializeScan(processor, token.getUser()); + scan = scanService.initializeScan(processor, user); - scanService.runValidation(scan, extensionFile, token.getUser()); + scanService.runValidation(scan, extensionFile, user); - doPublish(processor, null, token, TimeUtil.getCurrentUTC(), true); + doPublish(processor, null, user, TimeUtil.getCurrentUTC(), true); // Publish async handles requesting the long-running scans publishHandler.publishAsync(extensionFile, this, scan); @@ -208,11 +208,12 @@ private ExtensionVersion publishVersionWithScan(ExtensionProcessor processor, Pe private void doPublish( ExtensionProcessor processor, String binaryName, - PersonalAccessToken token, + UserData user, LocalDateTime timestamp, boolean checkDependencies ) { - var extVersion = publishHandler.createExtensionVersion(processor, token, timestamp, checkDependencies); + var extVersion = publishHandler + .createExtensionVersion(processor, user, timestamp, checkDependencies); var download = processor.getBinary(extVersion, binaryName); processor.getExtensionFile().setResource(download); } @@ -383,7 +384,7 @@ private List resolveVersions( var versions = Arrays.stream(targetVersions) .map(target -> { var extVersion = restrictedToUser - ? repositories.findVersionPublishedWithUser( + ? repositories.findVersionPublishedByUser( user, target.version(), target.targetPlatform(), diff --git a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java index 177b2e625..9ac9942ff 100644 --- a/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java +++ b/server/src/main/java/org/eclipse/openvsx/LocalRegistryService.java @@ -721,12 +721,12 @@ private Map> getMemberships(Collection> membershipsByNamespaceId ) { - if (extVersion.getPublishedWith() == null) { + if (extVersion.getPublishedBy() == null) { return false; } - var user = extVersion.getPublishedWith().getUser(); + var user = extVersion.getPublishedBy(); if (UserData.Role.PRIVILEGED.equals(user.getRole())) { return true; } diff --git a/server/src/main/java/org/eclipse/openvsx/accesstoken/AccessTokenService.java b/server/src/main/java/org/eclipse/openvsx/accesstoken/AccessTokenService.java index f6e0091bd..aa4937af9 100644 --- a/server/src/main/java/org/eclipse/openvsx/accesstoken/AccessTokenService.java +++ b/server/src/main/java/org/eclipse/openvsx/accesstoken/AccessTokenService.java @@ -82,18 +82,6 @@ public AccessTokenJson createLongLivedAccessToken(UserData user, String descript return createAccessToken(user, description, expiresTimestamp, null, null, null, PersonalAccessTokenType.LLT); } - /** - * Creates a one-time usable token for user. Depending on configuration, the token expiration may be set as well. - */ - @Transactional - public AccessTokenJson createOneTimeAccessToken(UserData user, String description) { - requireNonNull(user); - final LocalDateTime expiresTimestamp = config.isOttTokenExpiryEnabled() - ? TimeUtil.getCurrentUTC().plus(config.getOttExpiration()) - : null; - return createAccessToken(user, description, expiresTimestamp, null, null, null, PersonalAccessTokenType.OTT); - } - /** * Creates a trusted publishing token for a trusted publisher. The token is scoped to given trusted publisher * associated extension only. Depending on configuration, the token expiration may be set as well. @@ -193,7 +181,7 @@ public ResultJson deactivateAccessToken(UserData user, long id) { // throws once this method returns null - silently discarding the fact that the token was touched // or found expired. @Transactional(TxType.REQUIRES_NEW) - public PersonalAccessToken useAccessToken(String tokenValue, AccessTokenAction accessTokenAction) { + public UserData useAccessToken(String tokenValue, AccessTokenAction accessTokenAction) { var token = repositories.findPersonalAccessToken(hashTokenValue(tokenValue)); if (token == null) { // assume DB contains token v0; fetch and upgrade if found active token @@ -229,9 +217,10 @@ public PersonalAccessToken useAccessToken(String tokenValue, AccessTokenAction a token.setAccessedTimestamp(now); if (token.getType().isOneTime()) { token.setActive(false); + entityManager.remove(token); } } - return token; + return token.getUser(); } private AccessTokenScope getScope(PersonalAccessToken token) { diff --git a/server/src/main/java/org/eclipse/openvsx/admin/AdminService.java b/server/src/main/java/org/eclipse/openvsx/admin/AdminService.java index c3009d683..4bbfc5f32 100644 --- a/server/src/main/java/org/eclipse/openvsx/admin/AdminService.java +++ b/server/src/main/java/org/eclipse/openvsx/admin/AdminService.java @@ -629,30 +629,18 @@ public ResultJson forgetUser(String provider, String username, UserData admin) { removedCustomerMembershipCount++; } - // Personal access tokens. Delete tokens that no retained extension version references; - // scrub and deactivate the rest so retained versions still resolve a publisher. + // Personal access tokens are no longer referenced by extension versions, so they can + // always be deleted outright. var deletedTokenCount = 0; - var scrubbedTokenCount = 0; for (var token : repositories.findPersonalAccessTokens(user)) { - if (repositories.countVersionsByAccessToken(token) == 0) { - entityManager.remove(token); - deletedTokenCount++; - } else { - token.setActive(false); - token.setDescription(null); - // The value is deliberately left in place: AccessTokenService.generateTokenValue() - // checks repositories.hasPersonalAccessToken(value) across all tokens, active or not, to - // avoid ever reissuing a value that was already handed out. Nulling it here would - // let that (astronomically unlikely) collision go undetected. - scrubbedTokenCount++; - } + entityManager.remove(token); + deletedTokenCount++; } // Namespace and customer memberships are already fully removed above. If nothing else in // the database still refers to this user either, delete the row outright instead of // anonymizing it. - var canDeleteUser = scrubbedTokenCount == 0 - && repositories.countReviews(user) == 0 + var canDeleteUser = repositories.countReviews(user) == 0 && repositories.countVersionsRemovedBy(user) == 0 && repositories.countAdminScanDecisions(user) == 0 && repositories.countFileDecisions(user) == 0 @@ -683,7 +671,7 @@ public ResultJson forgetUser(String provider, String username, UserData admin) { + removedExtensionCount + " extensions, removed " + removedMembershipCount + " namespace memberships, removed " + removedCustomerMembershipCount + " customer memberships, deleted " - + deletedTokenCount + " tokens, scrubbed " + scrubbedTokenCount + " tokens."); + + deletedTokenCount + " tokens."); logs.logAction(admin, result); return result; } @@ -695,7 +683,6 @@ public UserData checkAdminUser() { public UserData checkAdminUser(String tokenValue) { var user = Optional.of(tokenValue) .map(tv -> tokens.useAccessToken(tv, new AccessTokenAction.Administration())) - .map(PersonalAccessToken::getUser) .orElse(null); return checkAdminUser(user); diff --git a/server/src/main/java/org/eclipse/openvsx/eclipse/PublisherComplianceChecker.java b/server/src/main/java/org/eclipse/openvsx/eclipse/PublisherComplianceChecker.java index 661235796..68fbba8ac 100644 --- a/server/src/main/java/org/eclipse/openvsx/eclipse/PublisherComplianceChecker.java +++ b/server/src/main/java/org/eclipse/openvsx/eclipse/PublisherComplianceChecker.java @@ -10,9 +10,7 @@ package org.eclipse.openvsx.eclipse; import java.util.LinkedHashSet; -import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import jakarta.persistence.EntityManager; import org.slf4j.Logger; @@ -25,9 +23,7 @@ import org.eclipse.openvsx.ExtensionService; import org.eclipse.openvsx.entities.Extension; -import org.eclipse.openvsx.entities.ExtensionVersionChange; import org.eclipse.openvsx.entities.ExtensionVersionState; -import org.eclipse.openvsx.entities.PersonalAccessToken; import org.eclipse.openvsx.entities.UserData; import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.util.NamingUtil; @@ -67,14 +63,11 @@ public void checkPublishers(ApplicationStartedEvent event) { return; } - var publisherTokens = repositories.findAllPersonalAccessTokens().stream() - .collect(Collectors.groupingBy(PersonalAccessToken::getUser)); - publisherTokens.keySet().forEach(user -> { - var accessTokens = publisherTokens.get(user); - if (!accessTokens.isEmpty() && !isCompliant(user)) { + repositories.findPublishersWithActiveVersions().forEach(user -> { + if (!isCompliant(user)) { // Found a non-compliant publisher: deactivate all extension versions transactions.execute(status -> { - deactivateExtensions(accessTokens); + deactivateExtensions(user); return null; }); } @@ -100,25 +93,23 @@ private boolean isCompliant(UserData user) { .isPresent(); } - private void deactivateExtensions(List accessTokens) { + private void deactivateExtensions(UserData user) { var affectedExtensions = new LinkedHashSet(); var now = TimeUtil.getCurrentUTC(); - for (var accessToken : accessTokens) { - var versions = repositories.findVersionsByAccessToken(accessToken, true); - for (var version : versions) { - version.setActive(false); - // the version stops being publicly visible here, which the changes feed reports at - // this instant rather than at the one it was published at - repositories.recordExtensionVersionChange(version, ExtensionVersionState.INACTIVE, now); - entityManager.merge(version); - var extension = version.getExtension(); - affectedExtensions.add(extension); - logger.atInfo() - .setMessage("Deactivated: {} - {}") - .addArgument(() -> accessToken.getUser().getLoginName()) - .addArgument(() -> NamingUtil.toLogFormat(version)) - .log(); - } + var versions = repositories.findVersionsByUser(user, true); + for (var version : versions) { + version.setActive(false); + // the version stops being publicly visible here, which the changes feed reports at + // this instant rather than at the one it was published at + repositories.recordExtensionVersionChange(version, ExtensionVersionState.INACTIVE, now); + entityManager.merge(version); + var extension = version.getExtension(); + affectedExtensions.add(extension); + logger.atInfo() + .setMessage("Deactivated: {} - {}") + .addArgument(user::getLoginName) + .addArgument(() -> NamingUtil.toLogFormat(version)) + .log(); } // Update affected extensions diff --git a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java index 8a541adca..4e088d5b7 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java @@ -80,8 +80,11 @@ public enum Type { private LocalDateTime timestamp; + /** + * Who published this version. + */ @ManyToOne - private PersonalAccessToken publishedWith; + private UserData publishedBy; private boolean active; @@ -197,9 +200,8 @@ public ExtensionJson toExtensionJson() { json.setGalleryTheme(this.getGalleryTheme()); json.setLocalizedLanguages(this.getLocalizedLanguages()); json.setQna(this.getQna()); - if (this.getPublishedWith() != null) { - json.setPublishedBy(this.getPublishedWith().getUser().toUserJson()); - json.setTrustedPublisher(this.getPublishedWith().getType() == PersonalAccessTokenType.TPT); + if (this.getPublishedBy() != null) { + json.setPublishedBy(this.getPublishedBy().toUserJson()); } if (this.getDependencies() != null) { json.setDependencies(toExtensionReferenceJson(this.getDependencies())); @@ -329,12 +331,12 @@ public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; } - public PersonalAccessToken getPublishedWith() { - return publishedWith; + public UserData getPublishedBy() { + return publishedBy; } - public void setPublishedWith(PersonalAccessToken publishedWith) { - this.publishedWith = publishedWith; + public void setPublishedBy(UserData publishedBy) { + this.publishedBy = publishedBy; } public boolean isActive() { @@ -570,7 +572,8 @@ public boolean equals(Object o) { && Objects.equals(version, that.version) && Objects.equals(targetPlatform, that.targetPlatform) && Objects.equals(timestamp, that.timestamp) - && Objects.equals(getId(publishedWith), getId(that.publishedWith)) // use id to prevent infinite recursion && Objects.equals(displayName, that.displayName) + && Objects.equals(getId(publishedBy), getId(that.publishedBy)) // use id to prevent infinite recursion + && Objects.equals(displayName, that.displayName) && Objects.equals(description, that.description) && Objects.equals(engines, that.engines) && Objects.equals(categories, that.categories) @@ -603,7 +606,7 @@ public int hashCode() { preRelease, preview, timestamp, - getId(publishedWith), + getId(publishedBy), active, potentiallyMalicious, removed, @@ -635,10 +638,6 @@ private Long getId(Extension extension) { return Optional.ofNullable(extension).map(Extension::getId).orElse(null); } - private Long getId(PersonalAccessToken token) { - return Optional.ofNullable(token).map(PersonalAccessToken::getId).orElse(null); - } - private Long getId(UserData user) { return Optional.ofNullable(user).map(UserData::getId).orElse(null); } diff --git a/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessTokenType.java b/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessTokenType.java index cbd9a779f..e412adb05 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessTokenType.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessTokenType.java @@ -17,10 +17,6 @@ public enum PersonalAccessTokenType { * Long-lived personal access token (classic). */ LLT(false, true), - /** - * One time usable general personal access token. - */ - OTT(true, false), /** * One time usable, trusted publishing issued access token. */ diff --git a/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsJobRequestHandler.java b/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsJobRequestHandler.java deleted file mode 100644 index 92652bf45..000000000 --- a/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsJobRequestHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/** ****************************************************************************** - * Copyright (c) 2023 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 java.nio.file.Files; - -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; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; - -import org.eclipse.openvsx.ExtensionProcessor; -import org.eclipse.openvsx.ExtensionService; -import org.eclipse.openvsx.util.NamingUtil; - -@Component -@ConditionalOnProperty(value = "ovsx.data.mirror.enabled", havingValue = "false", matchIfMissing = true) -public class FixTargetPlatformsJobRequestHandler implements JobRequestHandler> { - - protected final Logger logger = new JobRunrDashboardLogger( - LoggerFactory.getLogger(FixTargetPlatformsJobRequestHandler.class)); - - private final ExtensionService extensions; - private final MigrationService migrations; - private final FixTargetPlatformsService service; - - public FixTargetPlatformsJobRequestHandler( - ExtensionService extensions, - MigrationService migrations, - FixTargetPlatformsService service - ) { - this.extensions = extensions; - this.migrations = migrations; - this.service = service; - } - - @Override - @Job(name = "Fix target platform for published extension version", retries = 3) - public void run(MigrationJobRequest jobRequest) throws Exception { - var download = migrations.getResource(jobRequest); - var extVersion = download.getExtension(); - try (var extensionFile = migrations.getExtensionFile(download)) { - if (Files.size(extensionFile.getPath()) == 0) { - return; - } - - boolean fixTargetPlatform; - try (var extProcessor = new ExtensionProcessor(extensionFile)) { - fixTargetPlatform = !extProcessor.getMetadata().getTargetPlatform() - .equals(extVersion.getTargetPlatform()); - } - - if (fixTargetPlatform) { - logger.atInfo() - .setMessage("Fixing target platform for: {}") - .addArgument(() -> NamingUtil.toLogFormat(extVersion)) - .log(); - - // Purge (hard delete) rather than soft-delete: the version is immediately republished - // below with the corrected target platform, so its identity must be freed, not reserved. - extensions.purgeExtensionVersion(service.getUser(), extVersion); - try (var input = Files.newInputStream(extensionFile.getPath())) { - extensions.publishVersion(input, extVersion.getPublishedWith()); - } - } - } - } -} diff --git a/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsService.java b/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsService.java deleted file mode 100644 index 2af74dfe2..000000000 --- a/server/src/main/java/org/eclipse/openvsx/migration/FixTargetPlatformsService.java +++ /dev/null @@ -1,42 +0,0 @@ -/** ****************************************************************************** - * Copyright (c) 2023 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 jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; -import org.springframework.stereotype.Component; - -import org.eclipse.openvsx.entities.UserData; -import org.eclipse.openvsx.repositories.RepositoryService; - -@Component -public class FixTargetPlatformsService { - - private final RepositoryService repositories; - private final EntityManager entityManager; - - public FixTargetPlatformsService(RepositoryService repositories, EntityManager entityManager) { - this.repositories = repositories; - this.entityManager = entityManager; - } - - @Transactional - public UserData getUser() { - var userName = "FixTargetPlatformMigration"; - var user = repositories.findUserByLoginName("system", userName); - if (user == null) { - user = new UserData(); - user.setProvider("system"); - user.setLoginName(userName); - entityManager.persist(user); - } - return user; - } -} 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 d977a1c46..4422221c1 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/MigrationService.java @@ -40,8 +40,6 @@ public class MigrationService { RenameDownloadsJobRequestHandler.class, "ExtractVsixManifestMigration", ExtractVsixManifestsJobRequestHandler.class, - "FixTargetPlatformMigration", - FixTargetPlatformsJobRequestHandler.class, "GenerateSha256ChecksumMigration", GenerateSha256ChecksumJobRequestHandler.class, "CheckPotentiallyMaliciousExtensionVersions", diff --git a/server/src/main/java/org/eclipse/openvsx/migration/OrphanNamespaceMigration.java b/server/src/main/java/org/eclipse/openvsx/migration/OrphanNamespaceMigration.java index be0995991..70f0f61f9 100644 --- a/server/src/main/java/org/eclipse/openvsx/migration/OrphanNamespaceMigration.java +++ b/server/src/main/java/org/eclipse/openvsx/migration/OrphanNamespaceMigration.java @@ -83,8 +83,8 @@ private LinkedHashSet getExtensionPublishers(Streamable ext var publishers = new LinkedHashSet(); for (var extension : extensions) { for (var extVersion : repositories.findActiveVersions(extension)) { - if (extVersion.getPublishedWith() != null) { - publishers.add(extVersion.getPublishedWith().getUser()); + if (extVersion.getPublishedBy() != null) { + publishers.add(extVersion.getPublishedBy()); } } } diff --git a/server/src/main/java/org/eclipse/openvsx/mirror/MirrorExtensionService.java b/server/src/main/java/org/eclipse/openvsx/mirror/MirrorExtensionService.java index 9a9b8c16e..e705d5d8c 100644 --- a/server/src/main/java/org/eclipse/openvsx/mirror/MirrorExtensionService.java +++ b/server/src/main/java/org/eclipse/openvsx/mirror/MirrorExtensionService.java @@ -231,10 +231,10 @@ private void mirrorExtensionVersion(ExtensionJson json) { var description = "MirrorExtensionVersion"; var accessTokenValue = data.getOrAddAccessTokenValue(user, description); - var token = tokens.useAccessToken( + var tokenUser = tokens.useAccessToken( accessTokenValue, new AccessTokenAction.PublishVersion(namespaceName, json.getName())); - extensions.mirrorVersion(extensionFile, signatureName, token, filename, json.getTimestamp()); + extensions.mirrorVersion(extensionFile, signatureName, tokenUser, filename, json.getTimestamp()); logger.atDebug() .setMessage("completed mirroring of extension version: {}") .addArgument(() -> NamingUtil.toLogFormat(json)) diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java index e32354e01..f3a73211e 100644 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java @@ -47,7 +47,6 @@ import org.eclipse.openvsx.entities.ExtensionVersion; import org.eclipse.openvsx.entities.FileResource; import org.eclipse.openvsx.entities.Namespace; -import org.eclipse.openvsx.entities.PersonalAccessToken; import org.eclipse.openvsx.entities.UserData; import org.eclipse.openvsx.extension_control.ExtensionControlService; import org.eclipse.openvsx.repositories.RepositoryService; @@ -133,12 +132,12 @@ public boolean isLicenseRequired() { @Transactional(rollbackOn = ErrorResultException.class) public ExtensionVersion createExtensionVersion( ExtensionProcessor processor, - PersonalAccessToken token, + UserData userData, LocalDateTime timestamp, boolean checkDependencies ) { // Extract extension metadata from its manifest - var extVersion = createExtensionVersion(processor, token.getUser(), token, timestamp); + var extVersion = createExtensionVersion(processor, userData, timestamp); var dependencies = processor.getExtensionDependencies(); var bundledExtensions = processor.getBundledExtensions(); if (checkDependencies) { @@ -168,13 +167,13 @@ public ExtensionVersion createExtensionVersion( *

* Callers publishing with scanning enabled have to invoke this before validating or scanning the * package, as neither is of any use for a package that can not be published in the first place. - * The checks are repeated by {@link #createExtensionVersion(ExtensionProcessor, PersonalAccessToken, + * The checks are repeated by {@link #createExtensionVersion(ExtensionProcessor, UserData, * LocalDateTime, boolean)}, which enforces them while holding the extension lock. * * @throws ErrorResultException if the extension version can not be published */ - public void checkPublishPreconditions(ExtensionProcessor processor, PersonalAccessToken token) { - var namespace = checkPublishPermission(processor, token.getUser()); + public void checkPublishPreconditions(ExtensionProcessor processor, UserData userData) { + var namespace = checkPublishPermission(processor, userData); var extensionName = processor.getExtensionName(); var existingVersion = repositories .findVersion(processor.getVersion(), processor.getTargetPlatform(), extensionName, namespace.getName()); @@ -226,7 +225,6 @@ private String alreadyPublishedMessage( private ExtensionVersion createExtensionVersion( ExtensionProcessor processor, UserData user, - PersonalAccessToken token, LocalDateTime timestamp ) { var namespace = checkPublishPermission(processor, user); @@ -247,7 +245,7 @@ private ExtensionVersion createExtensionVersion( validatePackageMetadata(processor, namespaceName, extensionName, extVersion); extVersion.setTimestamp(timestamp); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(user); extVersion.setActive(false); // Lock the extension row while adding a version so a concurrent delete-all serializes diff --git a/server/src/main/java/org/eclipse/openvsx/ratelimit/IdentityService.java b/server/src/main/java/org/eclipse/openvsx/ratelimit/IdentityService.java index 1b4665b2e..150b56fbb 100644 --- a/server/src/main/java/org/eclipse/openvsx/ratelimit/IdentityService.java +++ b/server/src/main/java/org/eclipse/openvsx/ratelimit/IdentityService.java @@ -82,10 +82,10 @@ public ResolvedIdentity resolveIdentity(HttpServletRequest request) { if (cacheKey == null) { var token = request.getParameter("token"); if (token != null) { - var tokenEntity = tokenService.useAccessToken(token, new AccessTokenAction.Verify()); - if (tokenEntity != null) { + var user = tokenService.useAccessToken(token, new AccessTokenAction.Verify()); + if (user != null) { // if a valid token is present we use it as a cache key - cacheKey = "token_" + tokenEntity.getUser().getId(); + cacheKey = "token_" + user.getId(); } } } diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/AdminStatisticCalculationsRepository.java b/server/src/main/java/org/eclipse/openvsx/repositories/AdminStatisticCalculationsRepository.java index 19a75a4d2..2605bd093 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/AdminStatisticCalculationsRepository.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/AdminStatisticCalculationsRepository.java @@ -48,11 +48,10 @@ public int countActiveExtensions() { } public int countActiveExtensionPublishers() { - var publishers = DSL.countDistinct(PERSONAL_ACCESS_TOKEN.USER_DATA); + var publishers = DSL.countDistinct(EXTENSION_VERSION.PUBLISHED_BY_ID); return dsl.select(publishers) .from(EXTENSION) .join(EXTENSION_VERSION).on(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)) - .join(PERSONAL_ACCESS_TOKEN).on(PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)) .where(EXTENSION.ACTIVE.eq(true)) .and(EXTENSION_VERSION.ACTIVE.eq(true)) .fetchOne(publishers); @@ -62,14 +61,13 @@ public Map countActiveExtensionPublishersGroupedByExtensionsPu var aliasPublisher = "publisher"; var aliasExtensionCount = "extension_count"; var extensionCountsByPublisher = dsl.select( - PERSONAL_ACCESS_TOKEN.USER_DATA.as(aliasPublisher), + EXTENSION_VERSION.PUBLISHED_BY_ID.as(aliasPublisher), DSL.countDistinct(EXTENSION.ID).as(aliasExtensionCount)) .from(EXTENSION) .join(EXTENSION_VERSION).on(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)) - .join(PERSONAL_ACCESS_TOKEN).on(PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)) .where(EXTENSION.ACTIVE.eq(true)) .and(EXTENSION_VERSION.ACTIVE.eq(true)) - .groupBy(PERSONAL_ACCESS_TOKEN.USER_DATA) + .groupBy(EXTENSION_VERSION.PUBLISHED_BY_ID) .asTable("aep"); return dsl.select( @@ -130,10 +128,9 @@ public int countPublishersThatClaimedNamespaceOwnership() { return dsl.select(count) .from(EXTENSION) .join(EXTENSION_VERSION).on(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)) - .join(PERSONAL_ACCESS_TOKEN).on(PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)) .join(NAMESPACE_MEMBERSHIP) .on( - NAMESPACE_MEMBERSHIP.USER_DATA.eq(PERSONAL_ACCESS_TOKEN.USER_DATA) + NAMESPACE_MEMBERSHIP.USER_DATA.eq(EXTENSION_VERSION.PUBLISHED_BY_ID) .and(NAMESPACE_MEMBERSHIP.NAMESPACE.eq(EXTENSION.NAMESPACE_ID))) .where(EXTENSION.ACTIVE.eq(true)) .and(EXTENSION_VERSION.ACTIVE.eq(true)) @@ -145,8 +142,7 @@ public Map topMostActivePublishingUsers(int limit) { var count = DSL.count(EXTENSION_VERSION.ID).as("extension_version_count"); return dsl.select(USER_DATA.ID, USER_DATA.LOGIN_NAME, count) .from(EXTENSION_VERSION) - .join(PERSONAL_ACCESS_TOKEN).on(PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)) - .join(USER_DATA).on(USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)) + .join(USER_DATA).on(USER_DATA.ID.eq(EXTENSION_VERSION.PUBLISHED_BY_ID)) .where(EXTENSION_VERSION.ACTIVE.eq(true)) .groupBy(USER_DATA.ID) .orderBy(count.desc()) diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionRepository.java b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionRepository.java index 02330e495..75eb716d0 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionRepository.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionRepository.java @@ -65,7 +65,7 @@ Extension findByNameIgnoreCaseAndNamespaceNameIgnoreCaseForUpdateNoWait( Streamable findByIdIn(Collection extensionIds); - Streamable findDistinctByVersionsPublishedWithUser(UserData user); + Streamable findDistinctByVersionsPublishedBy(UserData user); long count(); diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepository.java b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepository.java index b74f39885..9f6a0e57d 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepository.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepository.java @@ -466,7 +466,6 @@ private SelectQuery findAllActive() { USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE, EXTENSION_VERSION.ID, EXTENSION_VERSION.VERSION, EXTENSION_VERSION.POTENTIALLY_MALICIOUS, @@ -497,11 +496,7 @@ private SelectQuery findAllActive() { query.addFrom(EXTENSION_VERSION); query.addJoin(EXTENSION, EXTENSION.ID.eq(EXTENSION_VERSION.EXTENSION_ID)); query.addJoin(NAMESPACE, NAMESPACE.ID.eq(EXTENSION.NAMESPACE_ID)); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(EXTENSION_VERSION.PUBLISHED_BY_ID)); query.addJoin( SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, @@ -556,11 +551,7 @@ private ExtensionVersion toExtensionVersionFull( user.setProviderUrl(row.get(USER_DATA.PROVIDER_URL)); user.setProvider(row.get(USER_DATA.PROVIDER)); - var token = new PersonalAccessToken(); - token.setUser(user); - token.setType(PersonalAccessTokenType.valueOf(row.get(PERSONAL_ACCESS_TOKEN.TYPE))); - - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(user); extVersion.setType(ExtensionVersion.Type.REGULAR); return extVersion; } @@ -706,9 +697,8 @@ public List findTargetPlatformsGroupedByVersion(Exte targetPlatformsActive, targetPlatformsRemoved) .from(EXTENSION_VERSION) - .join(PERSONAL_ACCESS_TOKEN).on(PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)) .where(EXTENSION_VERSION.EXTENSION_ID.eq(extension.getId())) - .and(PERSONAL_ACCESS_TOKEN.USER_DATA.eq(user.getId())) + .and(EXTENSION_VERSION.PUBLISHED_BY_ID.eq(user.getId())) .groupBy( EXTENSION_VERSION.SEMVER_MAJOR, EXTENSION_VERSION.SEMVER_MINOR, @@ -828,7 +818,6 @@ public ExtensionVersion findLatest( USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE, EXTENSION_VERSION.ID, EXTENSION_VERSION.VERSION, EXTENSION_VERSION.POTENTIALLY_MALICIOUS, @@ -856,11 +845,7 @@ public ExtensionVersion findLatest( EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, SIGNATURE_KEY_PAIR.PUBLIC_ID); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(EXTENSION_VERSION.PUBLISHED_BY_ID)); query.addJoin( SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, @@ -899,7 +884,6 @@ public ExtensionVersion findLatest( USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE, EXTENSION_VERSION.ID, EXTENSION_VERSION.VERSION, EXTENSION_VERSION.POTENTIALLY_MALICIOUS, @@ -927,11 +911,7 @@ public ExtensionVersion findLatest( EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, SIGNATURE_KEY_PAIR.PUBLIC_ID); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(EXTENSION_VERSION.PUBLISHED_BY_ID)); query.addJoin( SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, @@ -1002,7 +982,7 @@ public List findLatest(Collection extensionIds) { EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID, - EXTENSION_VERSION.PUBLISHED_WITH_ID); + EXTENSION_VERSION.PUBLISHED_BY_ID); latestQuery.addConditions(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)); var latest = latestQuery.asTable(); @@ -1053,8 +1033,7 @@ public List findLatest(Collection extensionIds) { USER_DATA.FULL_NAME, USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, - USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE); + USER_DATA.PROVIDER); query.addFrom(NAMESPACE); query.addJoin(EXTENSION, EXTENSION.NAMESPACE_ID.eq(NAMESPACE.ID)); query.addJoin(latest, JoinType.CROSS_APPLY, DSL.condition(true)); @@ -1062,11 +1041,7 @@ public List findLatest(Collection extensionIds) { SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, SIGNATURE_KEY_PAIR.ID.eq(latest.field(EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID))); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_WITH_ID))); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_BY_ID))); query.addConditions(EXTENSION.ID.in(extensionIds)); return query.fetch(row -> { var extVersion = toExtensionVersionFull(row, null, new TableFieldMapper(latest)); @@ -1170,7 +1145,7 @@ public List findLatest(UserData user) { EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID, - EXTENSION_VERSION.PUBLISHED_WITH_ID); + EXTENSION_VERSION.PUBLISHED_BY_ID); latestQuery.addConditions(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)); var latest = latestQuery.asTable(); @@ -1224,8 +1199,7 @@ public List findLatest(UserData user) { USER_DATA.FULL_NAME, USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, - USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE); + USER_DATA.PROVIDER); query.addFrom(NAMESPACE); query.addJoin(EXTENSION, EXTENSION.NAMESPACE_ID.eq(NAMESPACE.ID)); query.addJoin(latest, JoinType.CROSS_APPLY, DSL.condition(true)); @@ -1233,12 +1207,8 @@ public List findLatest(UserData user) { SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, SIGNATURE_KEY_PAIR.ID.eq(latest.field(EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID))); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_WITH_ID))); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); - query.addConditions(PERSONAL_ACCESS_TOKEN.USER_DATA.eq(user.getId())); + query.addJoin(USER_DATA, USER_DATA.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_BY_ID))); + query.addConditions(USER_DATA.ID.eq(user.getId())); return query.fetch(row -> { var extVersion = toExtensionVersionFull(row, null, new TableFieldMapper(latest)); extVersion.getExtension().getNamespace().setDisplayName(row.get(NAMESPACE.DISPLAY_NAME)); @@ -1279,7 +1249,7 @@ public ExtensionVersion findLatest(UserData user, String namespace, String exten EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID, - EXTENSION_VERSION.PUBLISHED_WITH_ID); + EXTENSION_VERSION.PUBLISHED_BY_ID); latestQuery.addConditions(EXTENSION_VERSION.EXTENSION_ID.eq(EXTENSION.ID)); var latest = latestQuery.asTable(); @@ -1333,8 +1303,7 @@ public ExtensionVersion findLatest(UserData user, String namespace, String exten USER_DATA.FULL_NAME, USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, - USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE); + USER_DATA.PROVIDER); query.addFrom(NAMESPACE); query.addJoin(EXTENSION, EXTENSION.NAMESPACE_ID.eq(NAMESPACE.ID)); query.addJoin(latest, JoinType.CROSS_APPLY, DSL.condition(true)); @@ -1342,13 +1311,9 @@ public ExtensionVersion findLatest(UserData user, String namespace, String exten SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, SIGNATURE_KEY_PAIR.ID.eq(latest.field(EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID))); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_WITH_ID))); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(latest.field(EXTENSION_VERSION.PUBLISHED_BY_ID))); query.addConditions( - PERSONAL_ACCESS_TOKEN.USER_DATA.eq(user.getId()), + USER_DATA.ID.eq(user.getId()), NAMESPACE.NAME.equalIgnoreCase(namespace), EXTENSION.NAME.equalIgnoreCase(extension)); return query.fetchOne(row -> { @@ -1514,7 +1479,6 @@ private ExtensionVersion findInternal( USER_DATA.AVATAR_URL, USER_DATA.PROVIDER_URL, USER_DATA.PROVIDER, - PERSONAL_ACCESS_TOKEN.TYPE, NAMESPACE.ID, NAMESPACE.NAME, NAMESPACE.DISPLAY_NAME, @@ -1557,11 +1521,7 @@ private ExtensionVersion findInternal( EXTENSION_VERSION.DEPENDENCIES, EXTENSION_VERSION.BUNDLED_EXTENSIONS, SIGNATURE_KEY_PAIR.PUBLIC_ID); - query.addJoin( - PERSONAL_ACCESS_TOKEN, - JoinType.LEFT_OUTER_JOIN, - PERSONAL_ACCESS_TOKEN.ID.eq(EXTENSION_VERSION.PUBLISHED_WITH_ID)); - query.addJoin(USER_DATA, USER_DATA.ID.eq(PERSONAL_ACCESS_TOKEN.USER_DATA)); + query.addJoin(USER_DATA, USER_DATA.ID.eq(EXTENSION_VERSION.PUBLISHED_BY_ID)); query.addJoin( SIGNATURE_KEY_PAIR, JoinType.LEFT_OUTER_JOIN, diff --git a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionRepository.java b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionRepository.java index 4d6ad90f8..bb408dbac 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionRepository.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/ExtensionVersionRepository.java @@ -22,6 +22,15 @@ public interface ExtensionVersionRepository extends Repository { + /** + * Finds all distinct publishers who are enlisted as publisher in the extension_version table for active extension. + * In other words, returns distinct {@link UserData} for all users who published a currently active extension. + */ + @Query( + "select distinct ev.publishedBy from ExtensionVersion ev where ev.active = true and ev.publishedBy is not null" + ) + Streamable findPublishersWithActiveVersions(); + Streamable findByExtension(Extension extension); Streamable findByExtensionAndActiveTrue(Extension extension); @@ -39,7 +48,7 @@ ExtensionVersion findByVersionAndTargetPlatformAndExtensionNameIgnoreCaseAndExte String namespace ); - ExtensionVersion findByPublishedWithUserAndVersionAndTargetPlatformAndExtensionNameIgnoreCaseAndExtensionNamespaceNameIgnoreCase( + ExtensionVersion findByPublishedByAndVersionAndTargetPlatformAndExtensionNameIgnoreCaseAndExtensionNamespaceNameIgnoreCase( UserData user, String version, String targetPlatform, @@ -53,11 +62,7 @@ Streamable findByVersionAndExtensionNameIgnoreCaseAndExtension String namespace ); - Streamable findByPublishedWithAndActive(PersonalAccessToken publishedWith, boolean active); - - long countByPublishedWith(PersonalAccessToken publishedWith); - - Streamable findByPublishedWithUserAndActive(UserData user, boolean active); + Streamable findByPublishedByAndActive(UserData user, boolean active); long countByRemovedBy(UserData removedBy); 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 9d7772293..9b748bc52 100644 --- a/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java +++ b/server/src/main/java/org/eclipse/openvsx/repositories/RepositoryService.java @@ -292,7 +292,7 @@ public ExtensionVersion findVersion(String version, String targetPlatform, Strin namespace); } - public ExtensionVersion findVersionPublishedWithUser( + public ExtensionVersion findVersionPublishedByUser( UserData user, String version, String targetPlatform, @@ -300,7 +300,7 @@ public ExtensionVersion findVersionPublishedWithUser( String namespace ) { return extensionVersionRepo - .findByPublishedWithUserAndVersionAndTargetPlatformAndExtensionNameIgnoreCaseAndExtensionNamespaceNameIgnoreCase( + .findByPublishedByAndVersionAndTargetPlatformAndExtensionNameIgnoreCaseAndExtensionNamespaceNameIgnoreCase( user, version, targetPlatform, @@ -371,19 +371,15 @@ public Streamable findDependenciesReference(Extension extensio } public Streamable findExtensions(UserData user) { - return extensionRepo.findDistinctByVersionsPublishedWithUser(user); + return extensionRepo.findDistinctByVersionsPublishedBy(user); } - public Streamable findVersionsByAccessToken(PersonalAccessToken publishedWith, boolean active) { - return extensionVersionRepo.findByPublishedWithAndActive(publishedWith, active); - } - - public long countVersionsByAccessToken(PersonalAccessToken publishedWith) { - return extensionVersionRepo.countByPublishedWith(publishedWith); + public Streamable findVersionsByUser(UserData user, boolean active) { + return extensionVersionRepo.findByPublishedByAndActive(user, active); } - public Streamable findVersionsByUser(UserData user, boolean active) { - return extensionVersionRepo.findByPublishedWithUserAndActive(user, active); + public Streamable findPublishersWithActiveVersions() { + return extensionVersionRepo.findPublishersWithActiveVersions(); } public long countVersionsRemovedBy(UserData user) { diff --git a/server/src/main/java/org/eclipse/openvsx/search/RelevanceService.java b/server/src/main/java/org/eclipse/openvsx/search/RelevanceService.java index ae64203c1..b35358aa9 100644 --- a/server/src/main/java/org/eclipse/openvsx/search/RelevanceService.java +++ b/server/src/main/java/org/eclipse/openvsx/search/RelevanceService.java @@ -136,10 +136,10 @@ private double limit(double value) { } private boolean isVerified(ExtensionVersion extVersion) { - if (extVersion.getPublishedWith() == null) { + if (extVersion.getPublishedBy() == null) { return false; } - var user = extVersion.getPublishedWith().getUser(); + var user = extVersion.getPublishedBy(); var namespace = extVersion.getExtension().getNamespace(); return repositories.isVerified(namespace, user); } 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 7bab676fc..8a80978df 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 @@ -51,7 +51,7 @@ public class Indexes { 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 EXTENSION_VERSION__PUBLISHED_BY_ID__IDX = Internal.createIndex(DSL.name("extension_version__published_by_id__idx"), ExtensionVersion.EXTENSION_VERSION, new OrderField[] { ExtensionVersion.EXTENSION_VERSION.PUBLISHED_BY_ID }, false); public static final Index EXTENSION_VERSION_BY_TARGET_PLATFORM_ORDER_BY_IDX = Internal.createIndex(DSL.name("extension_version_by_target_platform_order_by_idx"), ExtensionVersion.EXTENSION_VERSION, new OrderField[] { ExtensionVersion.EXTENSION_VERSION.EXTENSION_ID, ExtensionVersion.EXTENSION_VERSION.UNIVERSAL_TARGET_PLATFORM.desc(), ExtensionVersion.EXTENSION_VERSION.TARGET_PLATFORM, ExtensionVersion.EXTENSION_VERSION.SEMVER_MAJOR.desc(), ExtensionVersion.EXTENSION_VERSION.SEMVER_MINOR.desc(), ExtensionVersion.EXTENSION_VERSION.SEMVER_PATCH.desc(), ExtensionVersion.EXTENSION_VERSION.SEMVER_IS_PRE_RELEASE, ExtensionVersion.EXTENSION_VERSION.TIMESTAMP.desc() }, false); public static final Index EXTENSION_VERSION_CHANGE_EXTENSION_VERSION_ID_IDX = Internal.createIndex(DSL.name("extension_version_change_extension_version_id_idx"), ExtensionVersionChange.EXTENSION_VERSION_CHANGE, new OrderField[] { ExtensionVersionChange.EXTENSION_VERSION_CHANGE.EXTENSION_VERSION_ID }, false); public static final Index EXTENSION_VERSION_CHANGE_FEED_IDX = Internal.createIndex(DSL.name("extension_version_change_feed_idx"), ExtensionVersionChange.EXTENSION_VERSION_CHANGE, new OrderField[] { ExtensionVersionChange.EXTENSION_VERSION_CHANGE.CHANGED_AT, ExtensionVersionChange.EXTENSION_VERSION_CHANGE.ID }, 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 12b59151c..835e8b2eb 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 @@ -170,9 +170,9 @@ public class Keys { public static final ForeignKey EXTENSION_REVIEW__FKINJBN9GRK135Y6IK0UT4UJP0W = Internal.createForeignKey(ExtensionReview.EXTENSION_REVIEW, DSL.name("fkinjbn9grk135y6ik0ut4ujp0w"), new TableField[] { ExtensionReview.EXTENSION_REVIEW.USER_ID }, Keys.USER_DATA_PKEY, new TableField[] { UserData.USER_DATA.ID }, true); public static final ForeignKey EXTENSION_THREAT__FK_THREAT_SCAN = Internal.createForeignKey(ExtensionThreat.EXTENSION_THREAT, DSL.name("fk_threat_scan"), new TableField[] { ExtensionThreat.EXTENSION_THREAT.SCAN_ID }, Keys.EXTENSION_SCAN_PKEY, new TableField[] { ExtensionScan.EXTENSION_SCAN.ID }, true); public static final ForeignKey EXTENSION_VALIDATION_FAILURE__FK_VALIDATION_FAILURE_SCAN = Internal.createForeignKey(ExtensionValidationFailure.EXTENSION_VALIDATION_FAILURE, DSL.name("fk_validation_failure_scan"), new TableField[] { ExtensionValidationFailure.EXTENSION_VALIDATION_FAILURE.SCAN_ID }, Keys.EXTENSION_SCAN_PKEY, new TableField[] { ExtensionScan.EXTENSION_SCAN.ID }, true); + public static final ForeignKey EXTENSION_VERSION__EXTENSION_VERSION_PUBLISHED_BY_ID_FKEY = Internal.createForeignKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("extension_version_published_by_id_fkey"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.PUBLISHED_BY_ID }, Keys.USER_DATA_PKEY, new TableField[] { UserData.USER_DATA.ID }, true); public static final ForeignKey EXTENSION_VERSION__EXTENSION_VERSION_REMOVED_BY_ID_FKEY = Internal.createForeignKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("extension_version_removed_by_id_fkey"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.REMOVED_BY_ID }, Keys.USER_DATA_PKEY, new TableField[] { UserData.USER_DATA.ID }, true); public static final ForeignKey EXTENSION_VERSION__EXTENSION_VERSION_SIGNATURE_KEY_PAIR_FKEY = Internal.createForeignKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("extension_version_signature_key_pair_fkey"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.SIGNATURE_KEY_PAIR_ID }, Keys.SIGNATURE_KEY_PAIR_PKEY, new TableField[] { SignatureKeyPair.SIGNATURE_KEY_PAIR.ID }, true); - public static final ForeignKey EXTENSION_VERSION__FK70KHJ8PM0VACASUIIAQ0W0R80 = Internal.createForeignKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("fk70khj8pm0vacasuiiaq0w0r80"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.PUBLISHED_WITH_ID }, Keys.PERSONAL_ACCESS_TOKEN_PKEY, new TableField[] { PersonalAccessToken.PERSONAL_ACCESS_TOKEN.ID }, true); public static final ForeignKey EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT = Internal.createForeignKey(ExtensionVersion.EXTENSION_VERSION, DSL.name("fkkhs1ec9s9j08fgicq9pmwu6bt"), new TableField[] { ExtensionVersion.EXTENSION_VERSION.EXTENSION_ID }, Keys.EXTENSION_PKEY, new TableField[] { Extension.EXTENSION.ID }, true); public static final ForeignKey EXTENSION_VERSION_CHANGE__EXTENSION_VERSION_CHANGE_EXTENSION_VERSION_ID_FKEY = Internal.createForeignKey(ExtensionVersionChange.EXTENSION_VERSION_CHANGE, DSL.name("extension_version_change_extension_version_id_fkey"), new TableField[] { ExtensionVersionChange.EXTENSION_VERSION_CHANGE.EXTENSION_VERSION_ID }, Keys.EXTENSION_VERSION_PKEY, new TableField[] { ExtensionVersion.EXTENSION_VERSION.ID }, true); public static final ForeignKey FILE_DECISION__FK_FILE_DECISION_SCAN = Internal.createForeignKey(FileDecision.FILE_DECISION, DSL.name("fk_file_decision_scan"), new TableField[] { FileDecision.FILE_DECISION.SCAN_ID }, Keys.EXTENSION_SCAN_PKEY, new TableField[] { ExtensionScan.EXTENSION_SCAN.ID }, true); 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 a990853ce..8511cb142 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 @@ -129,11 +129,6 @@ public Class getRecordType() { */ public final TableField EXTENSION_ID = createField(DSL.name("extension_id"), SQLDataType.BIGINT, this, ""); - /** - * The column public.extension_version.published_with_id. - */ - public final TableField PUBLISHED_WITH_ID = createField(DSL.name("published_with_id"), SQLDataType.BIGINT, this, ""); - /** * The column public.extension_version.active. */ @@ -250,6 +245,11 @@ public Class getRecordType() { */ public final TableField REMOVED_BY_ID = createField(DSL.name("removed_by_id"), SQLDataType.BIGINT, this, ""); + /** + * The column public.extension_version.published_by_id. + */ + public final TableField PUBLISHED_BY_ID = createField(DSL.name("published_by_id"), SQLDataType.BIGINT, this, ""); + private ExtensionVersion(Name alias, Table aliased) { this(alias, aliased, (Field[]) null, null); } @@ -286,7 +286,7 @@ public Schema getSchema() { @Override public List getIndexes() { - return Arrays.asList(Indexes.EXTENSION_VERSION__EXTENSION_ID__IDX, Indexes.EXTENSION_VERSION__PUBLISHED_WITH_ID__IDX, Indexes.EXTENSION_VERSION_BY_TARGET_PLATFORM_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_LATEST_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_VERSION_LIST_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_VERSION_MAP_ORDER_BY_IDX); + return Arrays.asList(Indexes.EXTENSION_VERSION__EXTENSION_ID__IDX, Indexes.EXTENSION_VERSION__PUBLISHED_BY_ID__IDX, Indexes.EXTENSION_VERSION_BY_TARGET_PLATFORM_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_LATEST_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_VERSION_LIST_ORDER_BY_IDX, Indexes.EXTENSION_VERSION_VERSION_MAP_ORDER_BY_IDX); } @Override @@ -301,7 +301,7 @@ public List> getUniqueKeys() { @Override public List> getReferences() { - return Arrays.asList(Keys.EXTENSION_VERSION__EXTENSION_VERSION_REMOVED_BY_ID_FKEY, Keys.EXTENSION_VERSION__EXTENSION_VERSION_SIGNATURE_KEY_PAIR_FKEY, Keys.EXTENSION_VERSION__FK70KHJ8PM0VACASUIIAQ0W0R80, Keys.EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT); + return Arrays.asList(Keys.EXTENSION_VERSION__EXTENSION_VERSION_PUBLISHED_BY_ID_FKEY, Keys.EXTENSION_VERSION__EXTENSION_VERSION_REMOVED_BY_ID_FKEY, Keys.EXTENSION_VERSION__EXTENSION_VERSION_SIGNATURE_KEY_PAIR_FKEY, Keys.EXTENSION_VERSION__FKKHS1EC9S9J08FGICQ9PMWU6BT); } @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 e26b3d3cf..c2f4ebe77 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 @@ -80,7 +80,7 @@ public Class getRecordType() { /** * The column public.personal_access_token.value. */ - public final TableField VALUE = createField(DSL.name("value"), SQLDataType.VARCHAR(64), this, ""); + public final TableField VALUE = createField(DSL.name("value"), SQLDataType.VARCHAR(128), this, ""); /** * The column public.personal_access_token.user_data. @@ -97,6 +97,11 @@ public Class getRecordType() { */ public final TableField NOTIFIED = createField(DSL.name("notified"), SQLDataType.BOOLEAN, this, ""); + /** + * The column public.personal_access_token.version. + */ + public final TableField VERSION = createField(DSL.name("version"), SQLDataType.SMALLINT.nullable(false), this, ""); + /** * The column public.personal_access_token.type. */ diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtensionVersionRecord.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtensionVersionRecord.java index 68a2c2eaf..6d3a30335 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtensionVersionRecord.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/ExtensionVersionRecord.java @@ -229,270 +229,256 @@ public Long getExtensionId() { return (Long) get(14); } - /** - * Setter for public.extension_version.published_with_id. - */ - public void setPublishedWithId(Long value) { - set(15, value); - } - - /** - * Getter for public.extension_version.published_with_id. - */ - public Long getPublishedWithId() { - return (Long) get(15); - } - /** * Setter for public.extension_version.active. */ public void setActive(Boolean value) { - set(16, value); + set(15, value); } /** * Getter for public.extension_version.active. */ public Boolean getActive() { - return (Boolean) get(16); + return (Boolean) get(15); } /** * Setter for public.extension_version.dependencies. */ public void setDependencies(String value) { - set(17, value); + set(16, value); } /** * Getter for public.extension_version.dependencies. */ public String getDependencies() { - return (String) get(17); + return (String) get(16); } /** * Setter for public.extension_version.bundled_extensions. */ public void setBundledExtensions(String value) { - set(18, value); + set(17, value); } /** * Getter for public.extension_version.bundled_extensions. */ public String getBundledExtensions() { - return (String) get(18); + return (String) get(17); } /** * Setter for public.extension_version.engines. */ public void setEngines(String value) { - set(19, value); + set(18, value); } /** * Getter for public.extension_version.engines. */ public String getEngines() { - return (String) get(19); + return (String) get(18); } /** * Setter for public.extension_version.categories. */ public void setCategories(String value) { - set(20, value); + set(19, value); } /** * Getter for public.extension_version.categories. */ public String getCategories() { - return (String) get(20); + return (String) get(19); } /** * Setter for public.extension_version.tags. */ public void setTags(String value) { - set(21, value); + set(20, value); } /** * Getter for public.extension_version.tags. */ public String getTags() { - return (String) get(21); + return (String) get(20); } /** * Setter for public.extension_version.extension_kind. */ public void setExtensionKind(String value) { - set(22, value); + set(21, value); } /** * Getter for public.extension_version.extension_kind. */ public String getExtensionKind() { - return (String) get(22); + return (String) get(21); } /** * Setter for public.extension_version.pre_release. */ public void setPreRelease(Boolean value) { - set(23, value); + set(22, value); } /** * Getter for public.extension_version.pre_release. */ public Boolean getPreRelease() { - return (Boolean) get(23); + return (Boolean) get(22); } /** * Setter for public.extension_version.target_platform. */ public void setTargetPlatform(String value) { - set(24, value); + set(23, value); } /** * Getter for public.extension_version.target_platform. */ public String getTargetPlatform() { - return (String) get(24); + return (String) get(23); } /** * Setter for public.extension_version.localized_languages. */ public void setLocalizedLanguages(String value) { - set(25, value); + set(24, value); } /** * Getter for public.extension_version.localized_languages. */ public String getLocalizedLanguages() { - return (String) get(25); + return (String) get(24); } /** * Setter for public.extension_version.sponsor_link. */ public void setSponsorLink(String value) { - set(26, value); + set(25, value); } /** * Getter for public.extension_version.sponsor_link. */ public String getSponsorLink() { - return (String) get(26); + return (String) get(25); } /** * Setter for public.extension_version.signature_key_pair_id. */ public void setSignatureKeyPairId(Long value) { - set(27, value); + set(26, value); } /** * Getter for public.extension_version.signature_key_pair_id. */ public Long getSignatureKeyPairId() { - return (Long) get(27); + return (Long) get(26); } /** * Setter for public.extension_version.semver_major. */ public void setSemverMajor(Integer value) { - set(28, value); + set(27, value); } /** * Getter for public.extension_version.semver_major. */ public Integer getSemverMajor() { - return (Integer) get(28); + return (Integer) get(27); } /** * Setter for public.extension_version.semver_minor. */ public void setSemverMinor(Integer value) { - set(29, value); + set(28, value); } /** * Getter for public.extension_version.semver_minor. */ public Integer getSemverMinor() { - return (Integer) get(29); + return (Integer) get(28); } /** * Setter for public.extension_version.semver_patch. */ public void setSemverPatch(Integer value) { - set(30, value); + set(29, value); } /** * Getter for public.extension_version.semver_patch. */ public Integer getSemverPatch() { - return (Integer) get(30); + return (Integer) get(29); } /** * Setter for public.extension_version.semver_pre_release. */ public void setSemverPreRelease(String value) { - set(31, value); + set(30, value); } /** * Getter for public.extension_version.semver_pre_release. */ public String getSemverPreRelease() { - return (String) get(31); + return (String) get(30); } /** * Setter for public.extension_version.semver_is_pre_release. */ public void setSemverIsPreRelease(Boolean value) { - set(32, value); + set(31, value); } /** * Getter for public.extension_version.semver_is_pre_release. */ public Boolean getSemverIsPreRelease() { - return (Boolean) get(32); + return (Boolean) get(31); } /** * Setter for public.extension_version.semver_build_metadata. */ public void setSemverBuildMetadata(String value) { - set(33, value); + set(32, value); } /** * Getter for public.extension_version.semver_build_metadata. */ public String getSemverBuildMetadata() { - return (String) get(33); + return (String) get(32); } /** @@ -500,7 +486,7 @@ public String getSemverBuildMetadata() { * public.extension_version.universal_target_platform. */ public void setUniversalTargetPlatform(Boolean value) { - set(34, value); + set(33, value); } /** @@ -508,62 +494,76 @@ public void setUniversalTargetPlatform(Boolean value) { * public.extension_version.universal_target_platform. */ public Boolean getUniversalTargetPlatform() { - return (Boolean) get(34); + return (Boolean) get(33); } /** * Setter for public.extension_version.potentially_malicious. */ public void setPotentiallyMalicious(Boolean value) { - set(35, value); + set(34, value); } /** * Getter for public.extension_version.potentially_malicious. */ public Boolean getPotentiallyMalicious() { - return (Boolean) get(35); + return (Boolean) get(34); } /** * Setter for public.extension_version.removed. */ public void setRemoved(Boolean value) { - set(36, value); + set(35, value); } /** * Getter for public.extension_version.removed. */ public Boolean getRemoved() { - return (Boolean) get(36); + return (Boolean) get(35); } /** * Setter for public.extension_version.removed_timestamp. */ public void setRemovedTimestamp(LocalDateTime value) { - set(37, value); + set(36, value); } /** * Getter for public.extension_version.removed_timestamp. */ public LocalDateTime getRemovedTimestamp() { - return (LocalDateTime) get(37); + return (LocalDateTime) get(36); } /** * Setter for public.extension_version.removed_by_id. */ public void setRemovedById(Long value) { - set(38, value); + set(37, value); } /** * Getter for public.extension_version.removed_by_id. */ public Long getRemovedById() { + return (Long) get(37); + } + + /** + * Setter for public.extension_version.published_by_id. + */ + public void setPublishedById(Long value) { + set(38, value); + } + + /** + * Getter for public.extension_version.published_by_id. + */ + public Long getPublishedById() { return (Long) get(38); } @@ -590,7 +590,7 @@ public ExtensionVersionRecord() { /** * Create a detached, initialised ExtensionVersionRecord */ - public ExtensionVersionRecord(Long id, String bugs, String description, String displayName, String galleryColor, String galleryTheme, String homepage, String license, String markdown, Boolean preview, String qna, String repository, LocalDateTime timestamp, String version, Long extensionId, Long publishedWithId, Boolean active, String dependencies, String bundledExtensions, String engines, String categories, String tags, String extensionKind, Boolean preRelease, String targetPlatform, String localizedLanguages, String sponsorLink, Long signatureKeyPairId, Integer semverMajor, Integer semverMinor, Integer semverPatch, String semverPreRelease, Boolean semverIsPreRelease, String semverBuildMetadata, Boolean universalTargetPlatform, Boolean potentiallyMalicious, Boolean removed, LocalDateTime removedTimestamp, Long removedById) { + public ExtensionVersionRecord(Long id, String bugs, String description, String displayName, String galleryColor, String galleryTheme, String homepage, String license, String markdown, Boolean preview, String qna, String repository, LocalDateTime timestamp, String version, Long extensionId, Boolean active, String dependencies, String bundledExtensions, String engines, String categories, String tags, String extensionKind, Boolean preRelease, String targetPlatform, String localizedLanguages, String sponsorLink, Long signatureKeyPairId, Integer semverMajor, Integer semverMinor, Integer semverPatch, String semverPreRelease, Boolean semverIsPreRelease, String semverBuildMetadata, Boolean universalTargetPlatform, Boolean potentiallyMalicious, Boolean removed, LocalDateTime removedTimestamp, Long removedById, Long publishedById) { super(ExtensionVersion.EXTENSION_VERSION); setId(id); @@ -608,7 +608,6 @@ public ExtensionVersionRecord(Long id, String bugs, String description, String d setTimestamp(timestamp); setVersion(version); setExtensionId(extensionId); - setPublishedWithId(publishedWithId); setActive(active); setDependencies(dependencies); setBundledExtensions(bundledExtensions); @@ -632,6 +631,7 @@ public ExtensionVersionRecord(Long id, String bugs, String description, String d setRemoved(removed); setRemovedTimestamp(removedTimestamp); setRemovedById(removedById); + setPublishedById(publishedById); resetChangedOnNotNull(); } } diff --git a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/PersonalAccessTokenRecord.java b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/PersonalAccessTokenRecord.java index 1f374f11e..26a342862 100644 --- a/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/PersonalAccessTokenRecord.java +++ b/server/src/main/jooq-gen/org/eclipse/openvsx/jooq/tables/records/PersonalAccessTokenRecord.java @@ -145,46 +145,60 @@ public Boolean getNotified() { return (Boolean) get(8); } + /** + * Setter for public.personal_access_token.version. + */ + public void setVersion(Short value) { + set(9, value); + } + + /** + * Getter for public.personal_access_token.version. + */ + public Short getVersion() { + return (Short) get(9); + } + /** * Setter for public.personal_access_token.type. */ public void setType(String value) { - set(9, value); + set(10, value); } /** * Getter for public.personal_access_token.type. */ public String getType() { - return (String) get(9); + return (String) get(10); } /** * Setter for public.personal_access_token.scope_extension_id. */ public void setScopeExtensionId(Long value) { - set(10, value); + set(11, value); } /** * Getter for public.personal_access_token.scope_extension_id. */ public Long getScopeExtensionId() { - return (Long) get(10); + return (Long) get(11); } /** * Setter for public.personal_access_token.scope_namespace_id. */ public void setScopeNamespaceId(Long value) { - set(11, value); + set(12, value); } /** * Getter for public.personal_access_token.scope_namespace_id. */ public Long getScopeNamespaceId() { - return (Long) get(11); + return (Long) get(12); } /** @@ -192,7 +206,7 @@ public Long getScopeNamespaceId() { * public.personal_access_token.trusted_publisher_id. */ public void setTrustedPublisherId(Long value) { - set(12, value); + set(13, value); } /** @@ -200,7 +214,7 @@ public void setTrustedPublisherId(Long value) { * public.personal_access_token.trusted_publisher_id. */ public Long getTrustedPublisherId() { - return (Long) get(12); + return (Long) get(13); } // ------------------------------------------------------------------------- @@ -226,7 +240,7 @@ public PersonalAccessTokenRecord() { /** * Create a detached, initialised PersonalAccessTokenRecord */ - public PersonalAccessTokenRecord(Long id, LocalDateTime accessedTimestamp, Boolean active, LocalDateTime createdTimestamp, String description, String value, Long userData, LocalDateTime expiresTimestamp, Boolean notified, String type, Long scopeExtensionId, Long scopeNamespaceId, Long trustedPublisherId) { + public PersonalAccessTokenRecord(Long id, LocalDateTime accessedTimestamp, Boolean active, LocalDateTime createdTimestamp, String description, String value, Long userData, LocalDateTime expiresTimestamp, Boolean notified, Short version, String type, Long scopeExtensionId, Long scopeNamespaceId, Long trustedPublisherId) { super(PersonalAccessToken.PERSONAL_ACCESS_TOKEN); setId(id); @@ -238,6 +252,7 @@ public PersonalAccessTokenRecord(Long id, LocalDateTime accessedTimestamp, Boole setUserData(userData); setExpiresTimestamp(expiresTimestamp); setNotified(notified); + setVersion(version); setType(type); setScopeExtensionId(scopeExtensionId); setScopeNamespaceId(scopeNamespaceId); diff --git a/server/src/main/resources/db/migration/V1_73__ExtensionVersion_PublishedBy.sql b/server/src/main/resources/db/migration/V1_73__ExtensionVersion_PublishedBy.sql new file mode 100644 index 000000000..3fa49dd21 --- /dev/null +++ b/server/src/main/resources/db/migration/V1_73__ExtensionVersion_PublishedBy.sql @@ -0,0 +1,32 @@ +-- Who published a version, recorded directly instead of being reached through the token that was used +-- for the upload. A token is a credential with its own lifecycle -- it can be revoked, expire, or (in +-- future) be deleted -- while the authorship of a version is permanent and has to outlive all three. +-- Every read path that asks "who published this?" uses this column from now on. +ALTER TABLE public.extension_version ADD COLUMN published_by_id BIGINT; + +-- Backfill from the only place the answer exists today. Rows whose published_with_id is already NULL +-- have nothing to derive it from and stay NULL, which is why this column is deliberately left nullable: +-- every read path has always had to treat an unknown publisher as "not verified" / omitted from JSON, +-- and they keep doing exactly that. +UPDATE public.extension_version ev +SET published_by_id = pat.user_data +FROM public.personal_access_token pat +WHERE pat.id = ev.published_with_id; + +ALTER TABLE public.extension_version ADD CONSTRAINT extension_version_published_by_id_fkey +FOREIGN KEY (published_by_id) REFERENCES public.user_data(id); + +-- Publisher-keyed lookups (a user's own versions, the publisher compliance check, admin statistics) +-- now filter on this column instead of joining through the token. +CREATE INDEX extension_version__published_by_id__idx ON public.extension_version (published_by_id); + +-- published_with_id keeps recording which credential was used, but as best-effort provenance rather +-- than a hard dependency: deleting a token in future clears the reference instead of being refused by +-- the database. The base migration left this constraint named by Hibernate; drop it by that generated +-- name and recreate under the naming convention used everywhere else on this table. +ALTER TABLE public.extension_version DROP CONSTRAINT fk70khj8pm0vacasuiiaq0w0r80; +ALTER TABLE public.extension_version DROP COLUMN published_with_id; + +-- and now we can delete all inactive one-time-usable personal access tokens +DELETE FROM public.personal_access_token pat +WHERE pat.active = false AND pat.type != 'LLT'; \ No newline at end of file diff --git a/server/src/test/java/org/eclipse/openvsx/ExtensionDeleteTest.java b/server/src/test/java/org/eclipse/openvsx/ExtensionDeleteTest.java index 5c92d6e4c..f78c5e6d1 100644 --- a/server/src/test/java/org/eclipse/openvsx/ExtensionDeleteTest.java +++ b/server/src/test/java/org/eclipse/openvsx/ExtensionDeleteTest.java @@ -113,7 +113,7 @@ void setUp() { em.persist(extension); // The owner is the only publisher of the extension at check time. - em.persist(newVersion("1.0.0", extension, ownerToken)); + em.persist(newVersion("1.0.0", extension, owner)); em.flush(); ownerId = owner.getId(); @@ -169,7 +169,7 @@ void deleteExtension_keepsExtensionAndOtherUsersVersionWhenDeletingOwnVersion() new TransactionTemplate(txManager).executeWithoutResult(status -> { var extension = em.find(Extension.class, extensionId); var token = em.getReference(PersonalAccessToken.class, otherTokenId); - em.persist(newVersion("2.0.0", extension, token)); + em.persist(newVersion("2.0.0", extension, token.getUser())); }); var owner = new UserData(); @@ -250,7 +250,7 @@ private void startConcurrentPublish() { new TransactionTemplate(txManager).executeWithoutResult(status -> { var extension = em.find(Extension.class, extensionId); var token = em.getReference(PersonalAccessToken.class, otherTokenId); - em.persist(newVersion("2.0.0", extension, token)); + em.persist(newVersion("2.0.0", extension, token.getUser())); // Publishing updates the extension row; this write contends with the delete's lock. extension.setLastUpdatedDate(LocalDateTime.now()); em.flush(); @@ -344,12 +344,12 @@ private PersonalAccessToken persistToken(UserData user) { return token; } - private ExtensionVersion newVersion(String version, Extension extension, PersonalAccessToken token) { + private ExtensionVersion newVersion(String version, Extension extension, UserData user) { var extVersion = new ExtensionVersion(); extVersion.setVersion(version); extVersion.setTargetPlatform(TargetPlatform.NAME_UNIVERSAL); extVersion.setExtension(extension); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(user); extVersion.setActive(true); return extVersion; } diff --git a/server/src/test/java/org/eclipse/openvsx/ExtensionServiceTest.java b/server/src/test/java/org/eclipse/openvsx/ExtensionServiceTest.java index eaf3b9052..e56532f55 100644 --- a/server/src/test/java/org/eclipse/openvsx/ExtensionServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/ExtensionServiceTest.java @@ -316,7 +316,7 @@ void shouldNotScanWhenPublishPreconditionsFail() { var token = mockToken(); var content = new ByteArrayInputStream("extension package".getBytes(StandardCharsets.UTF_8)); - assertThatThrownBy(() -> svc.publishVersion(content, token)) + assertThatThrownBy(() -> svc.publishVersion(content, token.getUser())) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Insufficient access rights"); @@ -341,7 +341,7 @@ void shouldRejectAPackageExceedingTheMaxContentSize() { // this code path in production. var content = new DrainOnCloseInputStream(raw, maxContentSize); - assertThatThrownBy(() -> svc.publishVersion(content, token)) + assertThatThrownBy(() -> svc.publishVersion(content, token.getUser())) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("exceeds the size limit") .extracting(exc -> ((ErrorResultException) exc).getStatus()) diff --git a/server/src/test/java/org/eclipse/openvsx/ExtensionSoftDeleteTest.java b/server/src/test/java/org/eclipse/openvsx/ExtensionSoftDeleteTest.java index f6f5ee41e..4abe56102 100644 --- a/server/src/test/java/org/eclipse/openvsx/ExtensionSoftDeleteTest.java +++ b/server/src/test/java/org/eclipse/openvsx/ExtensionSoftDeleteTest.java @@ -476,12 +476,11 @@ private ExtensionVersion dependantReference() { private void persistVersion(String version, String targetPlatform, boolean active, boolean removed) { new TransactionTemplate(txManager).executeWithoutResult(status -> { var extension = em.find(Extension.class, extensionId); - var token = em.getReference(PersonalAccessToken.class, ownerTokenId); var extVersion = new ExtensionVersion(); extVersion.setVersion(version); extVersion.setTargetPlatform(targetPlatform); extVersion.setExtension(extension); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(em.getReference(UserData.class, ownerId)); extVersion.setActive(active); extVersion.setRemoved(removed); if (removed) { diff --git a/server/src/test/java/org/eclipse/openvsx/UserAPITest.java b/server/src/test/java/org/eclipse/openvsx/UserAPITest.java index 064440790..827deb23e 100644 --- a/server/src/test/java/org/eclipse/openvsx/UserAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/UserAPITest.java @@ -994,7 +994,7 @@ private List mockExtension( Mockito.when(repositories.findFiles(extVersion)) .thenReturn(Streamable.empty()); Mockito.when( - repositories.findVersionPublishedWithUser( + repositories.findVersionPublishedByUser( user, extVersion.getVersion(), TargetPlatform.NAME_UNIVERSAL, diff --git a/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java b/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java index 419bcdc1e..027f01515 100644 --- a/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/admin/AdminAPITest.java @@ -915,8 +915,10 @@ void testGetUserPublishInfo() throws Exception { var token = new PersonalAccessToken(); token.setUser(user); token.setActive(true); + versions.forEach(v -> { + v.setPublishedBy(user); + }); token.setType(PersonalAccessTokenType.LLT); - versions.forEach(v -> v.setPublishedWith(token)); when(repositories.findUserByLoginName("github", "test")).thenReturn(user); when(repositories.countActivePersonalAccessTokensAndType(user, PersonalAccessTokenType.LLT)) @@ -975,7 +977,9 @@ void testRevokePublisherAgreement() throws Exception { token.setType(PersonalAccessTokenType.LLT); when(repositories.findPersonalAccessTokens(user)) .thenReturn(Streamable.of(token)); - versions.forEach(v -> v.setPublishedWith(token)); + versions.forEach(v -> { + v.setPublishedBy(user); + }); when(repositories.findVersionsByUser(user, true)) .thenReturn(Streamable.of(versions)); @@ -1104,12 +1108,11 @@ void testForgetUserWithToken() throws Exception { customerMembership.setUser(user); Mockito.when(repositories.findCustomerMemberships(user)).thenReturn(Streamable.of(customerMembership)); - // A token not referenced by any retained version must be deleted outright. + // Personal access tokens are always deleted outright. var unreferenced = new PersonalAccessToken(); unreferenced.setUser(user); unreferenced.setActive(true); Mockito.when(repositories.findPersonalAccessTokens(user)).thenReturn(Streamable.of(unreferenced)); - Mockito.when(repositories.countVersionsByAccessToken(unreferenced)).thenReturn(0L); // The version just removed above still holds a removedBy reference to the user, so the // row must be anonymized rather than deleted. @@ -1125,7 +1128,7 @@ void testForgetUserWithToken() throws Exception { .andExpect( content().json( successJson( - "Forgot user deleted-user-7: deleted 1 extensions, removed 1 namespace memberships, removed 1 customer memberships, deleted 1 tokens, scrubbed 0 tokens."))); + "Forgot user deleted-user-7: deleted 1 extensions, removed 1 namespace memberships, removed 1 customer memberships, deleted 1 tokens."))); // The extension and its version are deactivated but kept in the database. assertThat(version.isActive()).isFalse(); @@ -1133,7 +1136,7 @@ void testForgetUserWithToken() throws Exception { Mockito.verify(entityManager, Mockito.never()).remove(extension); Mockito.verify(entityManager, Mockito.never()).remove(version); - // Memberships, the customer membership, and the unreferenced token are removed. + // Memberships, the customer membership, and the token are removed. Mockito.verify(entityManager).remove(membership); Mockito.verify(entityManager).remove(customerMembership); Mockito.verify(entityManager).remove(unreferenced); @@ -1176,12 +1179,11 @@ void testForgetUserRemovesInactiveExtensionVersions() throws Exception { customerMembership.setUser(user); Mockito.when(repositories.findCustomerMemberships(user)).thenReturn(Streamable.of(customerMembership)); - // A token not referenced by any retained version must be deleted outright. + // Personal access tokens are always deleted outright. var unreferenced = new PersonalAccessToken(); unreferenced.setUser(user); unreferenced.setActive(true); Mockito.when(repositories.findPersonalAccessTokens(user)).thenReturn(Streamable.of(unreferenced)); - Mockito.when(repositories.countVersionsByAccessToken(unreferenced)).thenReturn(0L); // The version just removed above still holds a removedBy reference to the user, so the // row must be anonymized rather than deleted. @@ -1197,7 +1199,7 @@ void testForgetUserRemovesInactiveExtensionVersions() throws Exception { .andExpect( content().json( successJson( - "Forgot user deleted-user-7: deleted 1 extensions, removed 1 namespace memberships, removed 1 customer memberships, deleted 1 tokens, scrubbed 0 tokens."))); + "Forgot user deleted-user-7: deleted 1 extensions, removed 1 namespace memberships, removed 1 customer memberships, deleted 1 tokens."))); // The extension and its version are deactivated but kept in the database. assertThat(version.isActive()).isFalse(); @@ -1205,7 +1207,7 @@ void testForgetUserRemovesInactiveExtensionVersions() throws Exception { Mockito.verify(entityManager, Mockito.never()).remove(extension); Mockito.verify(entityManager, Mockito.never()).remove(version); - // Memberships, the customer membership, and the unreferenced token are removed. + // Memberships, the customer membership, and the token are removed. Mockito.verify(entityManager).remove(membership); Mockito.verify(entityManager).remove(customerMembership); Mockito.verify(entityManager).remove(unreferenced); @@ -1222,7 +1224,7 @@ void testForgetUserRemovesInactiveExtensionVersions() throws Exception { } @Test - void testForgetUserScrubsReferencedToken() throws Exception { + void testForgetUserDeletesTokenAndUser() throws Exception { var token = mockAdminToken(); var user = mockForgettableUser(); Mockito.when(repositories.findMemberships(user)).thenReturn(Streamable.empty()); @@ -1230,14 +1232,14 @@ void testForgetUserScrubsReferencedToken() throws Exception { Mockito.when(repositories.findVersionsByUser(user, false)).thenReturn(Streamable.empty()); Mockito.when(repositories.findVersionsByUser(user, true)).thenReturn(Streamable.empty()); - // A token still referenced by a retained version must be scrubbed and kept, not deleted. - var referenced = new PersonalAccessToken(); - referenced.setUser(user); - referenced.setActive(true); - referenced.setValue("secret-value"); - referenced.setDescription("my token"); - Mockito.when(repositories.findPersonalAccessTokens(user)).thenReturn(Streamable.of(referenced)); - Mockito.when(repositories.countVersionsByAccessToken(referenced)).thenReturn(2L); + // Personal access tokens are no longer referenced by extension versions, so they are + // always deleted outright and never block deletion of the user row itself. + var personalAccessToken = new PersonalAccessToken(); + personalAccessToken.setUser(user); + personalAccessToken.setActive(true); + personalAccessToken.setValue("secret-value"); + personalAccessToken.setDescription("my token"); + Mockito.when(repositories.findPersonalAccessTokens(user)).thenReturn(Streamable.of(personalAccessToken)); mockMvc.perform( post( @@ -1249,11 +1251,10 @@ void testForgetUserScrubsReferencedToken() throws Exception { .andExpect( content().json( successJson( - "Forgot user deleted-user-7: deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 0 tokens, scrubbed 1 tokens."))); + "Forgot user deleted-user-7: deleted user record, deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 1 tokens."))); - Mockito.verify(entityManager, Mockito.never()).remove(referenced); - assertThat(referenced.isActive()).isFalse(); - assertThat(referenced.getDescription()).isNull(); + Mockito.verify(entityManager).remove(personalAccessToken); + Mockito.verify(entityManager).remove(user); } @Test @@ -1283,7 +1284,7 @@ void testForgetUserDeletesUserWithNoRemainingReferences() throws Exception { .andExpect( content().json( successJson( - "Forgot user deleted-user-7: deleted user record, deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 0 tokens, scrubbed 0 tokens."))); + "Forgot user deleted-user-7: deleted user record, deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 0 tokens."))); Mockito.verify(entityManager).remove(user); // The row is gone, so there is nothing left to anonymize. @@ -1313,7 +1314,7 @@ void testForgetUserKeepsAnonymizedUserWhenReviewRemains() throws Exception { .andExpect( content().json( successJson( - "Forgot user deleted-user-7: deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 0 tokens, scrubbed 0 tokens."))); + "Forgot user deleted-user-7: deleted 0 extensions, removed 0 namespace memberships, removed 0 customer memberships, deleted 0 tokens."))); Mockito.verify(entityManager, Mockito.never()).remove(user); assertThat(user.getLoginName()).isEqualTo("deleted-user-7"); @@ -2024,7 +2025,7 @@ void testRevokeBulkPublishers() throws Exception { userToken.setType(PersonalAccessTokenType.LLT); when(repositories.findPersonalAccessTokens(user)) .thenReturn(Streamable.of(userToken)); - versions.getFirst().setPublishedWith(userToken); + versions.getFirst().setPublishedBy(user); when(repositories.findVersionsByUser(user, true)) .thenReturn(Streamable.of(versions.getFirst())); @@ -2042,7 +2043,7 @@ void testRevokeBulkPublishers() throws Exception { user2Token.setType(PersonalAccessTokenType.LLT); when(repositories.findPersonalAccessTokens(user2)) .thenReturn(Streamable.of(user2Token)); - versions.get(1).setPublishedWith(user2Token); + versions.get(1).setPublishedBy(user2); when(repositories.findVersionsByUser(user2, true)) .thenReturn(Streamable.of(versions.get(1))); @@ -2113,7 +2114,7 @@ void testRevokeBulkPublishersSupportsOptionalReason() throws Exception { userToken.setType(PersonalAccessTokenType.LLT); when(repositories.findPersonalAccessTokens(user)) .thenReturn(Streamable.of(userToken)); - versions.getFirst().setPublishedWith(userToken); + versions.getFirst().setPublishedBy(user); when(repositories.findVersionsByUser(user, true)) .thenReturn(Streamable.of(versions.getFirst())); @@ -2162,7 +2163,7 @@ void testRevokeBulkPublishersHandlesMissingUsers() throws Exception { userToken.setType(PersonalAccessTokenType.LLT); when(repositories.findPersonalAccessTokens(user)) .thenReturn(Streamable.of(userToken)); - versions.getFirst().setPublishedWith(userToken); + versions.getFirst().setPublishedBy(user); when(repositories.findVersionsByUser(user, true)) .thenReturn(Streamable.of(versions.getFirst())); diff --git a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java index 0b3cc4ca9..ddd6de3c9 100644 --- a/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/cache/CacheServiceTest.java @@ -313,7 +313,7 @@ void testDeleteExtensionVersion() throws IOException { var newVersion = "0.2.0"; var oldVersion = extVersion.getVersion(); - try (var newTempFile = insertNewVersion(extension, extVersion.getPublishedWith(), newVersion)) { + try (var newTempFile = insertNewVersion(extension, extVersion.getPublishedBy(), newVersion)) { var json = registry.getExtension( namespace.getName(), @@ -368,7 +368,7 @@ void testUpdateExtension() throws IOException { var newVersion = "0.2.0"; var oldVersion = extVersion.getVersion(); - try (var newTempFile = insertNewVersion(extension, extVersion.getPublishedWith(), newVersion)) { + try (var newTempFile = insertNewVersion(extension, extVersion.getPublishedBy(), newVersion)) { newTempFile.getResource().getExtension().setPreRelease(true); extensions.updateExtension(extension); assertNull(getCache(CACHE_EXTENSION_JSON).get(cacheKey, ExtensionJson.class)); @@ -443,7 +443,7 @@ private UserData insertAdmin() { return admin; } - private TempFile insertNewVersion(Extension extension, PersonalAccessToken token, String newVersion) + private TempFile insertNewVersion(Extension extension, UserData user, String newVersion) throws IOException { var extVersion = new ExtensionVersion(); extVersion.setPreview(false); @@ -456,7 +456,7 @@ private TempFile insertNewVersion(Extension extension, PersonalAccessToken token extVersion.setCategories(Collections.emptyList()); extVersion.setTags(Collections.emptyList()); extVersion.setExtension(extension); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(user); entityManager.persist(extVersion); // populate extension versions list @@ -520,7 +520,7 @@ private TempFile insertExtensionVersion() throws IOException { extVersion.setCategories(Collections.emptyList()); extVersion.setTags(Collections.emptyList()); extVersion.setExtension(extension); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(user); entityManager.persist(extVersion); // populate extension versions list diff --git a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionConcurrencyTest.java b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionConcurrencyTest.java index fbe6ec3d5..5a98ed3ca 100644 --- a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionConcurrencyTest.java +++ b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionConcurrencyTest.java @@ -282,7 +282,8 @@ void createExtensionVersion_retriesWhenAnotherWriterCreatedTheExtension() { private ExtensionVersion publish(String targetPlatform) { try (var processor = mockProcessor(targetPlatform)) { - return publishHandler.createExtensionVersion(processor, publishToken(), LocalDateTime.now(), false); + return publishHandler + .createExtensionVersion(processor, publishToken().getUser(), LocalDateTime.now(), false); } } diff --git a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java index 5ad12b67c..5764f0523 100644 --- a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java +++ b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java @@ -124,9 +124,6 @@ void shouldCreateExtensionWhenNamespaceExists() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setType(PersonalAccessTokenType.LLT); - token.setUser(user); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); @@ -137,12 +134,12 @@ void shouldCreateExtensionWhenNamespaceExists() throws IOException { var capturedExtension = ArgumentCaptor.forClass(Extension.class); - var result = handler.createExtensionVersion(processor, token, LocalDateTime.now(), false); + var result = handler.createExtensionVersion(processor, user, LocalDateTime.now(), false); verify(entityManager).persist(capturedExtension.capture()); verify(entityManager).persist(metadata); assertThat(result).isSameAs(metadata); - assertThat(result.getPublishedWith()).isEqualTo(token); + assertThat(result.getPublishedBy()).isEqualTo(user); assertThat(result.getExtension()).isSameAs(capturedExtension.getValue()); assertThat(result.getExtension().getNamespace()).isSameAs(namespace); } @@ -162,8 +159,6 @@ void shouldFailWhenFileResourceCollidesWithDerivedDownloadName() throws IOExcept var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); @@ -186,7 +181,7 @@ void shouldFailWhenFileResourceCollidesWithDerivedDownloadName() throws IOExcept return null; }).when(processor).getFileResources(any(), any()); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining(maliciousName); @@ -206,8 +201,6 @@ void shouldFailWhenTwoFileResourcesHaveTheSameName() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); @@ -234,7 +227,7 @@ void shouldFailWhenTwoFileResourcesHaveTheSameName() throws IOException { return null; }).when(processor).getFileResources(any(), any()); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("CHANGELOG.md"); } @@ -254,8 +247,6 @@ void shouldReportAllFileResourceCollisionsAtOnce() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); @@ -287,7 +278,7 @@ void shouldReportAllFileResourceCollisionsAtOnce() throws IOException { return null; }).when(processor).getFileResources(any(), any()); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Multiple file name collisions") .hasMessageContaining(maliciousName) @@ -302,13 +293,10 @@ void shouldFailWhenNamespaceDoesNotExist() { when(processor.getNamespace()).thenReturn("unknown"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); - token.setType(PersonalAccessTokenType.LLT); when(repositories.findNamespace("unknown")).thenReturn(null); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Unknown publisher"); } @@ -328,16 +316,13 @@ void shouldFailWhenImageFormatIsDisallowed() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); - token.setType(PersonalAccessTokenType.LLT); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); when(validator.validateExtensionVersion("2.0.0")).thenReturn(Optional.empty()); when(validator.validateExtensionName("demo")).thenReturn(Optional.empty()); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("uses an unsupported icon format"); } @@ -360,16 +345,13 @@ void shouldSucceedWhenImageFormatIsAllowed() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); - token.setType(PersonalAccessTokenType.LLT); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); when(validator.validateExtensionVersion(metadata.getVersion())).thenReturn(Optional.empty()); when(validator.validateExtensionName("demo")).thenReturn(Optional.empty()); - var ev = handler.createExtensionVersion(processor, token, LocalDateTime.now(), false); + var ev = handler.createExtensionVersion(processor, user, LocalDateTime.now(), false); assertThat(ev).isNotNull(); } finally { config.setUnsupportedIconFormats(previousUnsupportedIconFormats); @@ -383,9 +365,6 @@ void shouldFailWhenPackageJsonDoesNotMatchManifest() throws IOException { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); - token.setType(PersonalAccessTokenType.LLT); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(true); @@ -399,7 +378,7 @@ void shouldFailWhenPackageJsonDoesNotMatchManifest() throws IOException { "2.0.0", "Demo OK")); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Publisher in extension.vsixmanifest"); @@ -410,7 +389,7 @@ void shouldFailWhenPackageJsonDoesNotMatchManifest() throws IOException { "2.0.0", "Demo OK")); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Extension name in extension.vsixmanifest"); @@ -421,7 +400,7 @@ void shouldFailWhenPackageJsonDoesNotMatchManifest() throws IOException { "9.9.9", "Demo OK")); - assertThatThrownBy(() -> handler.createExtensionVersion(processor, token, LocalDateTime.now(), false)) + assertThatThrownBy(() -> handler.createExtensionVersion(processor, user, LocalDateTime.now(), false)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Extension version in extension.vsixmanifest"); } @@ -432,8 +411,6 @@ void shouldPassPreconditionsForUnpublishedVersion() { try (var processor = org.mockito.Mockito.mock(ExtensionProcessor.class)) { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); when(processor.getNamespace()).thenReturn("publisher"); when(processor.getExtensionName()).thenReturn("demo"); @@ -444,7 +421,7 @@ void shouldPassPreconditionsForUnpublishedVersion() { when(repositories.findVersion("2.0.0", TargetPlatform.NAME_UNIVERSAL, "demo", "publisher")) .thenReturn(null); - assertThatCode(() -> handler.checkPublishPreconditions(processor, token)).doesNotThrowAnyException(); + assertThatCode(() -> handler.checkPublishPreconditions(processor, user)).doesNotThrowAnyException(); } } @@ -453,14 +430,12 @@ void shouldFailPreconditionsWithoutPublishPermission() { try (var processor = org.mockito.Mockito.mock(ExtensionProcessor.class)) { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); when(processor.getNamespace()).thenReturn("publisher"); when(repositories.findNamespace("publisher")).thenReturn(namespace); when(users.hasPublishPermission(user, namespace)).thenReturn(false); - assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, token)) + assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, user)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Insufficient access rights for publisher: publisher"); @@ -472,13 +447,12 @@ void shouldFailPreconditionsWithoutPublishPermission() { @Test void shouldFailPreconditionsWithUnknownNamespace() { try (var processor = org.mockito.Mockito.mock(ExtensionProcessor.class)) { - var token = new PersonalAccessToken(); - token.setUser(new UserData()); + var user = new UserData(); when(processor.getNamespace()).thenReturn("unknown"); when(repositories.findNamespace("unknown")).thenReturn(null); - assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, token)) + assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, user)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("Unknown publisher: unknown"); } @@ -489,8 +463,6 @@ void shouldFailPreconditionsForAlreadyPublishedVersion() { try (var processor = org.mockito.Mockito.mock(ExtensionProcessor.class)) { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); var existing = new ExtensionVersion(); existing.setVersion("2.0.0"); @@ -506,7 +478,7 @@ void shouldFailPreconditionsForAlreadyPublishedVersion() { when(repositories.findVersion("2.0.0", TargetPlatform.NAME_UNIVERSAL, "demo", "publisher")) .thenReturn(existing); - assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, token)) + assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, user)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("is already published."); } @@ -517,8 +489,6 @@ void shouldFailPreconditionsForRemovedVersion() { try (var processor = org.mockito.Mockito.mock(ExtensionProcessor.class)) { var namespace = buildNamespace("publisher"); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); var tombstone = new ExtensionVersion(); tombstone.setVersion("2.0.0"); @@ -535,7 +505,7 @@ void shouldFailPreconditionsForRemovedVersion() { when(repositories.findVersion("2.0.0", TargetPlatform.NAME_UNIVERSAL, "demo", "publisher")) .thenReturn(tombstone); - assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, token)) + assertThatThrownBy(() -> handler.checkPublishPreconditions(processor, user)) .isInstanceOf(ErrorResultException.class) .hasMessageContaining("stays permanently reserved"); } diff --git a/server/src/test/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepositoryTest.java b/server/src/test/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepositoryTest.java index ba217d251..543f50d2a 100644 --- a/server/src/test/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepositoryTest.java +++ b/server/src/test/java/org/eclipse/openvsx/repositories/ExtensionVersionJooqRepositoryTest.java @@ -55,11 +55,13 @@ class ExtensionVersionJooqRepositoryTest extends AbstractPostgresContainerTest { @Autowired EntityManager em; + private UserData owner; + private PersonalAccessToken token; @BeforeEach void setUp() { - var owner = new UserData(); + owner = new UserData(); owner.setLoginName("jooq-repo-test-owner"); em.persist(owner); @@ -320,7 +322,7 @@ private void persistVersion(Extension extension, String version, String targetPl extVersion.setVersion(version); extVersion.setTargetPlatform(targetPlatform); extVersion.setActive(active); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(owner); em.persist(extVersion); // ExtensionVersionJooqRepository queries run over the transaction's raw JDBC connection, @@ -347,7 +349,7 @@ private void persistPreReleaseVersions( extVersion.setTargetPlatform(targetPlatform); extVersion.setActive(true); extVersion.setPreRelease(true); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(owner); em.persist(extVersion); } em.flush(); @@ -370,7 +372,7 @@ private void persistPreReleaseVersion( extVersion.setActive(true); extVersion.setPreRelease(true); extVersion.setTimestamp(timestamp); - extVersion.setPublishedWith(token); + extVersion.setPublishedBy(owner); em.persist(extVersion); } } 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 4dd7c266a..1cbee64d2 100644 --- a/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java +++ b/server/src/test/java/org/eclipse/openvsx/repositories/RepositoryServiceSmokeTest.java @@ -249,8 +249,6 @@ void testExecuteQueries() { () -> repositories.findVersion("version", "targetPlatform", extension), () -> repositories.findVersion("version", "targetPlatform", "extensionName", "namespace"), () -> repositories.findVersions(extension), - () -> repositories.findVersionsByAccessToken(personalAccessToken, true), - () -> repositories.countVersionsByAccessToken(personalAccessToken), () -> repositories.getMaxExtensionDownloadCount(), () -> repositories.getOldestExtensionTimestamp(), () -> repositories.findExtensions(LONG_LIST), @@ -333,6 +331,7 @@ void testExecuteQueries() { () -> repositories .findFileByName("namespaceName", "extensionName", "targetPlatform", "version", "name"), () -> repositories.findVersionsByUser(userData, false), + () -> repositories.findPublishersWithActiveVersions(), () -> repositories.countVersionsRemovedBy(userData), () -> repositories.deleteFiles(extVersion), () -> repositories.findExtensionTargetPlatforms(extension), @@ -363,7 +362,7 @@ void testExecuteQueries() { () -> repositories.findNotMigratedItems(page), () -> repositories.findRemoveFileResourceTypeResourceMigrationItems(0, 1), () -> repositories.findTargetPlatformsGroupedByVersion(extension, userData), - () -> repositories.findVersionPublishedWithUser( + () -> repositories.findVersionPublishedByUser( userData, "version", "targetPlatform", diff --git a/server/src/test/java/org/eclipse/openvsx/search/DatabaseSearchServiceTest.java b/server/src/test/java/org/eclipse/openvsx/search/DatabaseSearchServiceTest.java index 3ea23c438..2739b3e11 100644 --- a/server/src/test/java/org/eclipse/openvsx/search/DatabaseSearchServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/search/DatabaseSearchServiceTest.java @@ -401,9 +401,7 @@ private Extension mockExtension( extVer.setExtension(extension); extension.getVersions().add(extVer); var user = new UserData(); - var token = new PersonalAccessToken(); - token.setUser(user); - extVer.setPublishedWith(token); + extVer.setPublishedBy(user); Mockito.when(repositories.isVerified(namespace, user)).thenReturn(false); Mockito.when(repositories.findLatestVersion(extension, null, false, true)).thenReturn(extVer); return extension; diff --git a/server/src/test/java/org/eclipse/openvsx/search/ElasticSearchServiceTest.java b/server/src/test/java/org/eclipse/openvsx/search/ElasticSearchServiceTest.java index 883c72e5d..61c0abe18 100644 --- a/server/src/test/java/org/eclipse/openvsx/search/ElasticSearchServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/search/ElasticSearchServiceTest.java @@ -265,9 +265,7 @@ private Extension mockExtension( extension.getVersions().add(extVer); var user = new UserData(); user.setLoginName(userName); - var token = new PersonalAccessToken(); - token.setUser(user); - extVer.setPublishedWith(token); + extVer.setPublishedBy(user); Mockito.when(repositories.findLatestVersion(extension, null, false, true)) .thenReturn(extVer); Mockito.when(repositories.isVerified(namespace, user))