Skip to content

Commit 92fdd64

Browse files
authored
Log if a user deletes an extension (eclipse-openvsx#1616)
* add general LogService and log if a user deletes an extension * add Nonnull annotations
1 parent ffd91be commit 92fdd64

10 files changed

Lines changed: 110 additions & 37 deletions

File tree

server/src/main/java/org/eclipse/openvsx/ExtensionService.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@
2525
import org.eclipse.openvsx.scanning.ExtensionScanPersistenceService;
2626
import org.eclipse.openvsx.scanning.ExtensionScanService;
2727
import org.eclipse.openvsx.search.SearchUtilService;
28-
import org.eclipse.openvsx.util.ErrorResultException;
29-
import org.eclipse.openvsx.util.NamingUtil;
30-
import org.eclipse.openvsx.util.TempFile;
31-
import org.eclipse.openvsx.util.TimeUtil;
28+
import org.eclipse.openvsx.util.*;
3229
import org.jobrunr.scheduling.JobRequestScheduler;
3330
import org.springframework.beans.factory.annotation.Value;
3431
import org.springframework.http.HttpStatus;
@@ -54,6 +51,7 @@ public class ExtensionService {
5451
private final RepositoryService repositories;
5552
private final SearchUtilService search;
5653
private final CacheService cache;
54+
private final LogService logs;
5755
private final PublishExtensionVersionHandler publishHandler;
5856
private final JobRequestScheduler scheduler;
5957
private final ExtensionScanService scanService;
@@ -70,6 +68,7 @@ public ExtensionService(
7068
RepositoryService repositories,
7169
SearchUtilService search,
7270
CacheService cache,
71+
LogService logs,
7372
PublishExtensionVersionHandler publishHandler,
7473
JobRequestScheduler scheduler,
7574
ExtensionScanService scanService,
@@ -79,6 +78,7 @@ public ExtensionService(
7978
this.repositories = repositories;
8079
this.search = search;
8180
this.cache = cache;
81+
this.logs = logs;
8282
this.publishHandler = publishHandler;
8383
this.scheduler = scheduler;
8484
this.scanService = scanService;
@@ -227,7 +227,7 @@ public ResultJson deleteExtension(
227227
var results = new ArrayList<ResultJson>();
228228
if(repositories.isDeleteAllVersions(namespaceName, extensionName, targetVersions, user)) {
229229
var extension = repositories.findExtension(extensionName, namespaceName);
230-
results.add(deleteExtension(extension));
230+
results.add(deleteExtension(user, extension));
231231
} else {
232232
for (var targetVersion : targetVersions) {
233233
var extVersion = repositories.findVersion(user, targetVersion.version(), targetVersion.targetPlatform(), extensionName, namespaceName);
@@ -236,7 +236,7 @@ public ResultJson deleteExtension(
236236
throw new ErrorResultException(message, HttpStatus.NOT_FOUND);
237237
}
238238

239-
results.add(deleteExtension(extVersion));
239+
results.add(deleteExtension(user, extVersion));
240240
}
241241
}
242242

@@ -246,7 +246,7 @@ public ResultJson deleteExtension(
246246
return result;
247247
}
248248

249-
protected ResultJson deleteExtension(Extension extension) throws ErrorResultException {
249+
protected ResultJson deleteExtension(UserData user, Extension extension) throws ErrorResultException {
250250
var bundledRefs = repositories.findBundledExtensionsReference(extension);
251251
if (!bundledRefs.isEmpty()) {
252252
throw new ErrorResultException("Extension " + NamingUtil.toExtensionId(extension)
@@ -280,16 +280,20 @@ protected ResultJson deleteExtension(Extension extension) throws ErrorResultExce
280280
entityManager.remove(extension);
281281
search.removeSearchEntry(extension);
282282

283-
return ResultJson.success("Deleted " + NamingUtil.toExtensionId(extension));
283+
var result = ResultJson.success("Deleted " + NamingUtil.toExtensionId(extension));
284+
logs.logAction(user, result);
285+
return result;
284286
}
285287

286-
protected ResultJson deleteExtension(ExtensionVersion extVersion) {
288+
protected ResultJson deleteExtension(UserData user, ExtensionVersion extVersion) {
287289
var extension = extVersion.getExtension();
288290
removeExtensionVersion(extVersion);
289291
extension.getVersions().remove(extVersion);
290292
updateExtension(extension);
291293

292-
return ResultJson.success("Deleted " + NamingUtil.toLogFormat(extVersion));
294+
var result = ResultJson.success("Deleted " + NamingUtil.toLogFormat(extVersion));
295+
logs.logAction(user, result);
296+
return result;
293297
}
294298

295299
private void removeExtensionVersion(ExtensionVersion extVersion) {

server/src/main/java/org/eclipse/openvsx/admin/AdminAPI.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,20 @@ public class AdminAPI {
4747

4848
private final RepositoryService repositories;
4949
private final AdminService admins;
50+
private final LogService logs;
5051
private final LocalRegistryService local;
5152
private final SearchUtilService search;
5253

5354
public AdminAPI(
5455
RepositoryService repositories,
5556
AdminService admins,
57+
LogService logs,
5658
LocalRegistryService local,
5759
SearchUtilService search
5860
) {
5961
this.repositories = repositories;
6062
this.admins = admins;
63+
this.logs = logs;
6164
this.local = local;
6265
this.search = search;
6366
}
@@ -181,7 +184,7 @@ public ResponseEntity<ResultJson> updateSearchIndex() {
181184
search.updateSearchIndex(true);
182185

183186
var result = ResultJson.success("Updated search index");
184-
admins.logAdminAction(adminUser, result);
187+
logs.logAction(adminUser, result);
185188
return ResponseEntity.ok(result);
186189
} catch (ErrorResultException exc) {
187190
return exc.toResponseEntity();
@@ -307,7 +310,7 @@ public ResponseEntity<ResultJson> deleteReview(
307310
try {
308311
var adminUser = admins.checkAdminUser();
309312
var result = admins.deleteReview(namespace, extension, loginName, provider);
310-
admins.logAdminAction(adminUser, result);
313+
logs.logAction(adminUser, result);
311314
return ResponseEntity.ok(result);
312315
} catch (ErrorResultException exc) {
313316
return exc.toResponseEntity();

server/src/main/java/org/eclipse/openvsx/admin/AdminService.java

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class AdminService {
5353
private final CacheService cache;
5454
private final JobRequestScheduler scheduler;
5555
private final MailService mail;
56+
private final LogService logs;
5657
private final ExtensionScanPersistenceService scanPersistenceService;
5758

5859
public AdminService(
@@ -67,6 +68,7 @@ public AdminService(
6768
CacheService cache,
6869
JobRequestScheduler scheduler,
6970
MailService mail,
71+
LogService logs,
7072
ExtensionScanPersistenceService scanPersistenceService
7173
) {
7274
this.repositories = repositories;
@@ -80,6 +82,7 @@ public AdminService(
8082
this.cache = cache;
8183
this.scheduler = scheduler;
8284
this.mail = mail;
85+
this.logs = logs;
8386
this.scanPersistenceService = scanPersistenceService;
8487
}
8588

@@ -131,7 +134,7 @@ public void deleteExtensionAndDependencies(Extension extension, UserData admin,
131134

132135
entityManager.remove(extension);
133136
search.removeSearchEntry(extension);
134-
logAdminAction(admin, ResultJson.success("Deleted " + NamingUtil.toExtensionId(extension)));
137+
logs.logAction(admin, ResultJson.success("Deleted " + NamingUtil.toExtensionId(extension)));
135138
}
136139

137140
protected void deleteExtensionAndDependencies(ExtensionVersion extVersion, UserData admin, int depth) {
@@ -144,7 +147,7 @@ protected void deleteExtensionAndDependencies(ExtensionVersion extVersion, UserD
144147
removeExtensionVersion(extVersion);
145148
extension.getVersions().remove(extVersion);
146149
extensions.updateExtension(extension);
147-
logAdminAction(admin, ResultJson.success("Deleted " + NamingUtil.toLogFormat(extVersion)));
150+
logs.logAction(admin, ResultJson.success("Deleted " + NamingUtil.toLogFormat(extVersion)));
148151
}
149152

150153
@Transactional(rollbackOn = ErrorResultException.class)
@@ -228,7 +231,7 @@ protected ResultJson deleteExtension(Extension extension, UserData admin) throws
228231
search.removeSearchEntry(extension);
229232

230233
var result = ResultJson.success("Deleted " + NamingUtil.toExtensionId(extension));
231-
logAdminAction(admin, result);
234+
logs.logAction(admin, result);
232235
return result;
233236
}
234237

@@ -239,7 +242,7 @@ protected ResultJson deleteExtension(ExtensionVersion extVersion, UserData admin
239242
extensions.updateExtension(extension);
240243

241244
var result = ResultJson.success("Deleted " + NamingUtil.toLogFormat(extVersion));
242-
logAdminAction(admin, result);
245+
logs.logAction(admin, result);
243246
return result;
244247
}
245248

@@ -311,7 +314,7 @@ public ResultJson editNamespaceMember(String namespaceName, String userName, Str
311314
: users.addNamespaceMember(namespace, user, role);
312315

313316
search.updateSearchEntries(repositories.findActiveExtensions(namespace).toList());
314-
logAdminAction(admin, result);
317+
logs.logAction(admin, result);
315318
return result;
316319
}
317320

@@ -449,7 +452,7 @@ public ResultJson revokePublisherContributions(String provider, String loginName
449452
var result = ResultJson.success("Deactivated " + deactivatedTokenCount
450453
+ " tokens, deactivated " + deactivatedExtensionCount + " extensions of user "
451454
+ provider + "/" + loginName + ".");
452-
logAdminAction(admin, result);
455+
logs.logAction(admin, result);
453456
return result;
454457
}
455458

@@ -462,7 +465,7 @@ public ResultJson revokePublisherTokens(String provider, String loginName, UserD
462465

463466
var deactivatedTokenCount = repositories.deactivateAccessTokens(user);
464467
var result = ResultJson.success("Deactivated " + deactivatedTokenCount + " tokens of user " + provider + "/" + loginName + ".");
465-
logAdminAction(admin, result);
468+
logs.logAction(admin, result);
466469
mail.scheduleRevokedAccessTokensMail(user);
467470
return result;
468471
}
@@ -487,17 +490,6 @@ private UserData checkAdminUser(UserData user) {
487490
return user;
488491
}
489492

490-
@Transactional
491-
public void logAdminAction(UserData admin, ResultJson result) {
492-
if (result.getSuccess() != null) {
493-
var log = new PersistedLog();
494-
log.setUser(admin);
495-
log.setTimestamp(TimeUtil.getCurrentUTC());
496-
log.setMessage(result.getSuccess());
497-
entityManager.persist(log);
498-
}
499-
}
500-
501493
public AdminStatistics getAdminStatistics(int year, int month) throws ErrorResultException {
502494
validateYearAndMonth(year, month);
503495
var statistics = repositories.findAdminStatisticsByYearAndMonth(year, month);

server/src/main/java/org/eclipse/openvsx/admin/ScanAPI.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.eclipse.openvsx.repositories.RepositoryService;
2626
import org.eclipse.openvsx.storage.StorageUtilService;
2727
import org.eclipse.openvsx.util.ErrorResultException;
28+
import org.eclipse.openvsx.util.LogService;
2829
import org.eclipse.openvsx.util.TimeUtil;
2930
import org.eclipse.openvsx.util.UrlUtil;
3031
import org.springframework.http.HttpStatus;
@@ -57,17 +58,20 @@ public class ScanAPI {
5758

5859
private final RepositoryService repositories;
5960
private final AdminService admins;
61+
private final LogService logs;
6062
private final StorageUtilService storageUtil;
6163
private final org.eclipse.openvsx.scanning.ExtensionScanCompletionService completionService;
6264

6365
public ScanAPI(
6466
RepositoryService repositories,
6567
AdminService admins,
68+
LogService logs,
6669
StorageUtilService storageUtil,
6770
org.eclipse.openvsx.scanning.ExtensionScanCompletionService completionService
6871
) {
6972
this.repositories = repositories;
7073
this.admins = admins;
74+
this.logs = logs;
7175
this.storageUtil = storageUtil;
7276
this.completionService = completionService;
7377
}
@@ -661,7 +665,7 @@ public ResponseEntity<ScanDecisionResponseJson> makeScanDecisions(
661665

662666
// Log the admin decision to /admin/log
663667
var logMessage = formatDecisionLogMessage(scan, decisionValue, threats.size(), activated);
664-
admins.logAdminAction(adminUser, ResultJson.success(logMessage));
668+
logs.logAction(adminUser, ResultJson.success(logMessage));
665669

666670
results.add(ScanDecisionResultJson.success(scanIdStr));
667671
successful++;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/******************************************************************************
2+
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information regarding copyright ownership.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* https://www.eclipse.org/legal/epl-2.0.
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*****************************************************************************/
13+
package org.eclipse.openvsx.util;
14+
15+
import jakarta.annotation.Nonnull;
16+
import jakarta.persistence.EntityManager;
17+
import jakarta.transaction.Transactional;
18+
import org.eclipse.openvsx.entities.PersistedLog;
19+
import org.eclipse.openvsx.entities.UserData;
20+
import org.eclipse.openvsx.json.ResultJson;
21+
import org.springframework.stereotype.Service;
22+
23+
import java.util.Objects;
24+
25+
@Service
26+
public class LogService {
27+
28+
private final EntityManager entityManager;
29+
30+
public LogService(EntityManager entityManager) {
31+
this.entityManager = entityManager;
32+
}
33+
34+
@Transactional
35+
public void logAction(@Nonnull UserData user, @Nonnull ResultJson result) {
36+
Objects.requireNonNull(user);
37+
Objects.requireNonNull(result);
38+
39+
if (result.getSuccess() != null) {
40+
var log = new PersistedLog();
41+
log.setUser(user);
42+
log.setTimestamp(TimeUtil.getCurrentUTC());
43+
log.setMessage(result.getSuccess());
44+
entityManager.persist(log);
45+
}
46+
}
47+
}

server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.eclipse.openvsx.storage.*;
3737
import org.eclipse.openvsx.metrics.ExtensionDownloadMetrics;
3838
import org.eclipse.openvsx.storage.log.DownloadCountService;
39+
import org.eclipse.openvsx.util.LogService;
3940
import org.eclipse.openvsx.util.TargetPlatform;
4041
import org.eclipse.openvsx.util.VersionAlias;
4142
import org.eclipse.openvsx.util.VersionService;
@@ -46,6 +47,7 @@
4647
import org.mockito.Mockito;
4748
import org.mockito.stubbing.Answer;
4849
import org.springframework.beans.factory.annotation.Autowired;
50+
import org.springframework.beans.factory.annotation.Qualifier;
4951
import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient;
5052
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
5153
import org.springframework.boot.test.context.TestConfiguration;
@@ -91,7 +93,7 @@
9193
AzureBlobStorageService.class, AwsStorageService.class, VSCodeIdService.class, DownloadCountService.class, ExtensionDownloadMetrics.class,
9294
CacheService.class, EclipseService.class, PublishExtensionVersionService.class, SimpleMeterRegistry.class,
9395
JobRequestScheduler.class, ExtensionControlService.class, FileCacheDurationConfig.class, CdnServiceConfig.class,
94-
ExtensionScanPersistenceService.class
96+
ExtensionScanPersistenceService.class, LogService.class
9597
})
9698
class RegistryAPITest {
9799

@@ -2576,7 +2578,7 @@ LocalRegistryService localRegistryService(
25762578
EntityManager entityManager,
25772579
RepositoryService repositories,
25782580
ExtensionService extensions,
2579-
VersionService versions,
2581+
@Qualifier("registryTest") VersionService versions,
25802582
UserService users,
25812583
SearchUtilService search,
25822584
ExtensionValidator validator,
@@ -2608,6 +2610,7 @@ ExtensionService extensionService(
26082610
RepositoryService repositories,
26092611
SearchUtilService search,
26102612
CacheService cache,
2613+
LogService logs,
26112614
PublishExtensionVersionHandler publishHandler,
26122615
JobRequestScheduler scheduler,
26132616
ExtensionScanService extensionScanService,
@@ -2618,6 +2621,7 @@ ExtensionService extensionService(
26182621
repositories,
26192622
search,
26202623
cache,
2624+
logs,
26212625
publishHandler,
26222626
scheduler,
26232627
extensionScanService,
@@ -2670,6 +2674,7 @@ LocalStorageService localStorageService() {
26702674
ExtensionJsonCacheKeyGenerator extensionJsonCacheKeyGenerator() { return new ExtensionJsonCacheKeyGenerator(); }
26712675

26722676
@Bean
2677+
@Qualifier("registryTest")
26732678
VersionService versionService() {
26742679
return new VersionService();
26752680
}

0 commit comments

Comments
 (0)