reformat using google-java-format 2.0

This commit is contained in:
Athou
2026-10-30 19:39:53 +01:00
parent 8f9be28002
commit f979f5426f
23 changed files with 382 additions and 441 deletions

View File

@@ -66,11 +66,10 @@ public class HttpClientFactory {
String userAgent = String userAgent =
config.httpClient() config.httpClient()
.userAgent() .userAgent()
.orElseGet( .orElseGet(() ->
() -> String.format(
String.format( "CommaFeed/%s (https://github.com/Athou/commafeed)",
"CommaFeed/%s (https://github.com/Athou/commafeed)", version.getVersion()));
version.getVersion()));
return newClient(config, connectionManager, userAgent); return newClient(config, connectionManager, userAgent);
} }

View File

@@ -283,9 +283,8 @@ public class HttpGetter {
} }
return CacheBuilder.newBuilder() return CacheBuilder.newBuilder()
.weigher( .weigher((HttpRequest key, HttpResponse value) ->
(HttpRequest key, HttpResponse value) -> value.content() != null ? value.content().length : 0)
value.content() != null ? value.content().length : 0)
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue()) .maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
.expireAfterWrite(cacheConfig.expiration()) .expireAfterWrite(cacheConfig.expiration())
.build(); .build();

View File

@@ -124,10 +124,8 @@ public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
Set<Long> categoryIds = Set<Long> categoryIds =
categories.stream().map(AbstractModel::getId).collect(Collectors.toSet()); categories.stream().map(AbstractModel::getId).collect(Collectors.toSet());
return findAll(user).stream() return findAll(user).stream()
.filter( .filter(s ->
s -> s.getCategory() != null && categoryIds.contains(s.getCategory().getId()))
s.getCategory() != null
&& categoryIds.contains(s.getCategory().getId()))
.toList(); .toList();
} }

View File

@@ -104,56 +104,52 @@ public class FeedRefreshEngine {
private void startFeedProcessingLoop() { private void startFeedProcessingLoop() {
// take a feed from the queue, process it, rince, repeat // take a feed from the queue, process it, rince, repeat
feedProcessingLoopExecutor.submit( feedProcessingLoopExecutor.submit(() -> {
() -> { while (!feedProcessingLoopExecutor.isShutdown()) {
while (!feedProcessingLoopExecutor.isShutdown()) { try {
try { // take() is blocking until a feed is available from the queue
// take() is blocking until a feed is available from the queue Feed feed = queue.take();
Feed feed = queue.take();
// send the feed to be processed // send the feed to be processed
log.debug( log.debug("got feed {} from the queue, send it for processing", feed.getId());
"got feed {} from the queue, send it for processing", processFeedAsync(feed);
feed.getId());
processFeedAsync(feed);
// we removed a feed from the queue, try to refill it as it may now be // we removed a feed from the queue, try to refill it as it may now be
// empty // empty
if (queue.isEmpty()) { if (queue.isEmpty()) {
log.debug("took the last feed from the queue, try to refill"); log.debug("took the last feed from the queue, try to refill");
refillQueueAsync(); refillQueueAsync();
}
} catch (InterruptedException e) {
log.debug("interrupted while waiting for a feed in the queue");
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} }
}); } catch (InterruptedException e) {
log.debug("interrupted while waiting for a feed in the queue");
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
});
} }
private void startRefillLoop() { private void startRefillLoop() {
// refill the queue at regular intervals if it's empty // refill the queue at regular intervals if it's empty
refillLoopExecutor.submit( refillLoopExecutor.submit(() -> {
() -> { while (!refillLoopExecutor.isShutdown()) {
while (!refillLoopExecutor.isShutdown()) { try {
try { if (queue.isEmpty()) {
if (queue.isEmpty()) { log.debug("refilling queue");
log.debug("refilling queue"); refillQueueAsync();
refillQueueAsync();
}
log.debug("sleeping for 15s");
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
log.debug("interrupted while sleeping");
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} }
});
log.debug("sleeping for 15s");
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
log.debug("interrupted while sleeping");
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
});
} }
public void refreshImmediately(Feed feed) { public void refreshImmediately(Feed feed) {
@@ -184,65 +180,53 @@ public class FeedRefreshEngine {
} }
}, },
refillExecutor) refillExecutor)
.whenComplete( .whenComplete((data, ex) -> {
(data, ex) -> { if (ex != null) {
if (ex != null) { log.error("error while refilling the queue", ex);
log.error("error while refilling the queue", ex); }
} });
});
} }
private void processFeedAsync(Feed feed) { private void processFeedAsync(Feed feed) {
CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor) CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor)
.thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor) .thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor)
.thenCompose( .thenCompose(r -> {
r -> { List<CompletableFuture<Void>> futures =
List<CompletableFuture<Void>> futures = r.insertedUnreadEntriesBySubscription().entrySet().stream()
r.insertedUnreadEntriesBySubscription().entrySet().stream() .map(e -> {
.map( FeedSubscription sub = e.getKey();
e -> { List<FeedEntry> entries = e.getValue();
FeedSubscription sub = e.getKey();
List<FeedEntry> entries = e.getValue();
notifier.notifyOverWebsocket(sub, entries); notifier.notifyOverWebsocket(sub, entries);
return CompletableFuture.runAsync( return CompletableFuture.runAsync(
() -> () -> notifier.sendPushNotifications(sub, entries),
notifier notifierExecutor);
.sendPushNotifications( })
sub, .toList();
entries), return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
notifierExecutor); })
}) .exceptionally(ex -> {
.toList(); log.error("error while processing feed {}", feed.getUrl(), ex);
return CompletableFuture.allOf( return null;
futures.toArray(CompletableFuture[]::new)); });
})
.exceptionally(
ex -> {
log.error("error while processing feed {}", feed.getUrl(), ex);
return null;
});
} }
private List<Feed> getNextUpdatableFeeds(int max) { private List<Feed> getNextUpdatableFeeds(int max) {
return unitOfWork.call( return unitOfWork.call(() -> {
() -> { Instant lastLoginThreshold =
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero()
config.feedRefresh().userInactivityPeriod().isZero() ? null
? null : Instant.now().minus(config.feedRefresh().userInactivityPeriod());
: Instant.now() List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
.minus(config.feedRefresh().userInactivityPeriod()); if (!feeds.isEmpty()) {
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold); // update disabledUntil to prevent feeds from being returned again by
if (!feeds.isEmpty()) { // feedDAO.findNextUpdatable()
// update disabledUntil to prevent feeds from being returned again by Instant nextUpdateDate = Instant.now().plus(config.feedRefresh().interval());
// feedDAO.findNextUpdatable() feedDAO.setDisabledUntil(
Instant nextUpdateDate = feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
Instant.now().plus(config.feedRefresh().interval()); }
feedDAO.setDisabledUntil( return feeds;
feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate); });
}
return feeds;
});
} }
private int getBatchSize() { private int getBatchSize() {
@@ -292,19 +276,18 @@ public class FeedRefreshEngine {
ThreadPoolExecutor pool = ThreadPoolExecutor pool =
new ThreadPoolExecutor( new ThreadPoolExecutor(
threads, threads, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>()); threads, threads, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
pool.setRejectedExecutionHandler( pool.setRejectedExecutionHandler((r, e) -> {
(r, e) -> { if (e.isShutdown()) {
if (e.isShutdown()) { return;
return; }
}
try { try {
e.getQueue().put(r); e.getQueue().put(r);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
log.debug("interrupted while waiting for a slot in the queue.", ex); log.debug("interrupted while waiting for a slot in the queue.", ex);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
}); });
return pool; return pool;
} }
} }

View File

@@ -91,24 +91,22 @@ public class FeedRefreshUpdater {
if (locked1 && locked2) { if (locked1 && locked2) {
processed = true; processed = true;
insertedEntry = insertedEntry =
unitOfWork.call( unitOfWork.call(() -> {
() -> { if (feedEntryService.find(feed, entry) != null) {
if (feedEntryService.find(feed, entry) != null) { // entry already exists, nothing to do
// entry already exists, nothing to do return null;
return null; }
}
FeedEntry feedEntry = feedEntryService.create(feed, entry); FeedEntry feedEntry = feedEntryService.create(feed, entry);
entryInserted.mark(); entryInserted.mark();
for (FeedSubscription sub : subscriptions) { for (FeedSubscription sub : subscriptions) {
boolean unread = boolean unread = feedEntryService.applyFilter(sub, feedEntry);
feedEntryService.applyFilter(sub, feedEntry); if (unread) {
if (unread) { subscriptionsForWhichEntryIsUnread.add(sub);
subscriptionsForWhichEntryIsUnread.add(sub); }
} }
} return feedEntry;
return feedEntry; });
});
} else { } else {
log.error("lock timeout for {} - {}", feed.getUrl(), key1); log.error("lock timeout for {} - {}", feed.getUrl(), key1);
} }
@@ -147,14 +145,13 @@ public class FeedRefreshUpdater {
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions); AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
processed &= addEntryResult.processed; processed &= addEntryResult.processed;
inserted += addEntryResult.insertedEntry != null ? 1 : 0; inserted += addEntryResult.insertedEntry != null ? 1 : 0;
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach( addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> {
sub -> { if (addEntryResult.insertedEntry != null) {
if (addEntryResult.insertedEntry != null) { insertedUnreadEntriesBySubscription
insertedUnreadEntriesBySubscription .computeIfAbsent(sub, k -> new ArrayList<>())
.computeIfAbsent(sub, k -> new ArrayList<>()) .add(addEntryResult.insertedEntry);
.add(addEntryResult.insertedEntry); }
} });
});
} }
if (inserted == 0) { if (inserted == 0) {

View File

@@ -65,20 +65,17 @@ public class OPMLExporter {
for (FeedCategory child : for (FeedCategory child :
categories.stream() categories.stream()
.filter( .filter(c ->
c -> c.getParent() != null && c.getParent().getId().equals(cat.getId()))
c.getParent() != null
&& c.getParent().getId().equals(cat.getId()))
.toList()) { .toList()) {
outline.getChildren().add(buildCategoryOutline(child, categories, subscriptions)); outline.getChildren().add(buildCategoryOutline(child, categories, subscriptions));
} }
for (FeedSubscription sub : for (FeedSubscription sub :
subscriptions.stream() subscriptions.stream()
.filter( .filter(s ->
s -> s.getCategory() != null
s.getCategory() != null && s.getCategory().getId().equals(cat.getId()))
&& s.getCategory().getId().equals(cat.getId()))
.toList()) { .toList()) {
outline.getChildren().add(buildSubscriptionOutline(sub)); outline.getChildren().add(buildSubscriptionOutline(sub));
} }

View File

@@ -148,26 +148,23 @@ public class FeedEntryService {
List<FeedEntryStatus> statusesToMark = List<FeedEntryStatus> statusesToMark =
statuses.stream() statuses.stream()
.filter(FeedEntryStatus::isMarkable) .filter(FeedEntryStatus::isMarkable)
.filter( .filter(s -> {
s -> { Instant entryDate = s.getEntry().getPublished();
Instant entryDate = s.getEntry().getPublished(); return olderThan == null
return olderThan == null || entryDate == null
|| entryDate == null || entryDate.isBefore(olderThan);
|| entryDate.isBefore(olderThan); })
}) .filter(s -> {
.filter( Instant insertedDate = s.getEntry().getInserted();
s -> { return insertedBefore == null
Instant insertedDate = s.getEntry().getInserted(); || insertedDate == null
return insertedBefore == null || insertedDate.isBefore(insertedBefore);
|| insertedDate == null })
|| insertedDate.isBefore(insertedBefore);
})
.toList(); .toList();
statusesToMark.forEach( statusesToMark.forEach(s -> {
s -> { s.setRead(true);
s.setRead(true); feedEntryStatusDAO.merge(s);
feedEntryStatusDAO.merge(s); });
});
} }
} }

View File

@@ -47,14 +47,13 @@ public class FeedSubscriptionService {
// we need to use this hook because the feed needs to have been persisted before being // we need to use this hook because the feed needs to have been persisted before being
// processed // processed
// by the feed engine // by the feed engine
feedSubscriptionDAO.onPostCommitInsert( feedSubscriptionDAO.onPostCommitInsert(sub -> {
sub -> { Feed feed = sub.getFeed();
Feed feed = sub.getFeed(); if (feed.getDisabledUntil() == null
if (feed.getDisabledUntil() == null || feed.getDisabledUntil().isBefore(Instant.now())) {
|| feed.getDisabledUntil().isBefore(Instant.now())) { feedRefreshEngine.refreshImmediately(feed);
feedRefreshEngine.refreshImmediately(feed); }
} });
});
} }
public long subscribe( public long subscribe(

View File

@@ -79,13 +79,10 @@ public class DatabaseCleaningService {
} while (entriesDeleted > 0); } while (entriesDeleted > 0);
} }
deleted = deleted =
unitOfWork.call( unitOfWork.call(() ->
() -> feedDAO.delete(
feedDAO.delete( feedDAO.findByIds(
feedDAO.findByIds( feeds.stream().map(AbstractModel::getId).toList())));
feeds.stream()
.map(AbstractModel::getId)
.toList())));
total += deleted; total += deleted;
log.debug("removed {} feeds without subscriptions", total); log.debug("removed {} feeds without subscriptions", total);
} while (deleted != 0); } while (deleted != 0);
@@ -119,10 +116,9 @@ public class DatabaseCleaningService {
} }
List<FeedCapacity> feeds = List<FeedCapacity> feeds =
unitOfWork.call( unitOfWork.call(() ->
() -> feedEntryDAO.findFeedsExceedingCapacity(
feedEntryDAO.findFeedsExceedingCapacity( maxFeedCapacity, batchSize, keepStarredEntries));
maxFeedCapacity, batchSize, keepStarredEntries));
if (feeds.isEmpty()) { if (feeds.isEmpty()) {
break; break;
} }
@@ -139,12 +135,11 @@ public class DatabaseCleaningService {
final long rem = remaining; final long rem = remaining;
deleted = deleted =
unitOfWork.call( unitOfWork.call(() ->
() -> feedEntryDAO.deleteOldEntries(
feedEntryDAO.deleteOldEntries( feed.id(),
feed.id(), Math.min(batchSize, rem),
Math.min(batchSize, rem), keepStarredEntries));
keepStarredEntries));
entriesDeletedMeter.mark(deleted); entriesDeletedMeter.mark(deleted);
total += deleted; total += deleted;
remaining -= deleted; remaining -= deleted;
@@ -166,10 +161,9 @@ public class DatabaseCleaningService {
} }
deleted = deleted =
unitOfWork.call( unitOfWork.call(() ->
() -> feedEntryDAO.deleteEntriesOlderThan(
feedEntryDAO.deleteEntriesOlderThan( olderThan, batchSize, keepStarredEntries));
olderThan, batchSize, keepStarredEntries));
entriesDeletedMeter.mark(deleted); entriesDeletedMeter.mark(deleted);
total += deleted; total += deleted;
log.debug("removed {} old entries", total); log.debug("removed {} old entries", total);

View File

@@ -31,16 +31,15 @@ public class DemoAccountCleanupTask extends ScheduledTask {
} }
log.info("recreating demo user account"); log.info("recreating demo user account");
unitOfWork.run( unitOfWork.run(() -> {
() -> { User demoUser = userDAO.findByName(CommaFeedConstants.USERNAME_DEMO);
User demoUser = userDAO.findByName(CommaFeedConstants.USERNAME_DEMO); if (demoUser == null) {
if (demoUser == null) { return;
return; }
}
userService.unregister(demoUser); userService.unregister(demoUser);
userService.createDemoUser(); userService.createDemoUser();
}); });
} }
@Override @Override

View File

@@ -140,14 +140,9 @@ public class FeverREST {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst())); uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst()));
form.getValues() form.getValues()
.forEach( .forEach((k, v) ->
(k, v) -> params.put(
params.put( k, v.stream().map(FormValue::getValue).findFirst().orElse(null)));
k,
v.stream()
.map(FormValue::getValue)
.findFirst()
.orElse(null)));
return handle(userId, params); return handle(userId, params);
} }
@@ -246,46 +241,42 @@ public class FeverREST {
s -> s.getCategory() == null ? 0 : s.getCategory().getId())) s -> s.getCategory() == null ? 0 : s.getCategory().getId()))
.entrySet() .entrySet()
.stream() .stream()
.map( .map(e -> {
e -> { FeverFeedGroup fg = new FeverFeedGroup();
FeverFeedGroup fg = new FeverFeedGroup(); fg.setGroupId(e.getKey());
fg.setGroupId(e.getKey()); fg.setFeedIds(e.getValue().stream().map(FeedSubscription::getId).toList());
fg.setFeedIds( return fg;
e.getValue().stream().map(FeedSubscription::getId).toList()); })
return fg;
})
.toList(); .toList();
} }
private List<FeverGroup> buildGroups(List<FeedCategory> categories) { private List<FeverGroup> buildGroups(List<FeedCategory> categories) {
return categories.stream() return categories.stream()
.map( .map(c -> {
c -> { FeverGroup g = new FeverGroup();
FeverGroup g = new FeverGroup(); g.setId(c.getId());
g.setId(c.getId()); g.setTitle(c.getName());
g.setTitle(c.getName()); return g;
return g; })
})
.toList(); .toList();
} }
private List<FeverFeed> buildFeeds(List<FeedSubscription> subscriptions) { private List<FeverFeed> buildFeeds(List<FeedSubscription> subscriptions) {
return subscriptions.stream() return subscriptions.stream()
.map( .map(s -> {
s -> { FeverFeed f = new FeverFeed();
FeverFeed f = new FeverFeed(); f.setId(s.getId());
f.setId(s.getId()); f.setFaviconId(s.getId());
f.setFaviconId(s.getId()); f.setTitle(s.getTitle());
f.setTitle(s.getTitle()); f.setUrl(s.getFeed().getUrl());
f.setUrl(s.getFeed().getUrl()); f.setSiteUrl(s.getFeed().getLink());
f.setSiteUrl(s.getFeed().getLink()); f.setSpark(false);
f.setSpark(false); f.setLastUpdatedOnTime(
f.setLastUpdatedOnTime( s.getFeed().getLastUpdated() == null
s.getFeed().getLastUpdated() == null ? 0
? 0 : s.getFeed().getLastUpdated().getEpochSecond());
: s.getFeed().getLastUpdated().getEpochSecond()); return f;
return f; })
})
.toList(); .toList();
} }
@@ -367,19 +358,18 @@ public class FeverREST {
private List<FeverFavicon> buildFavicons(List<FeedSubscription> subscriptions) { private List<FeverFavicon> buildFavicons(List<FeedSubscription> subscriptions) {
return subscriptions.stream() return subscriptions.stream()
.map( .map(s -> {
s -> { Favicon favicon = feedFaviconService.fetchFavicon(s.getFeed());
Favicon favicon = feedFaviconService.fetchFavicon(s.getFeed());
FeverFavicon f = new FeverFavicon(); FeverFavicon f = new FeverFavicon();
f.setId(s.getFeed().getId()); f.setId(s.getFeed().getId());
f.setData( f.setData(
String.format( String.format(
"data:%s;base64,%s", "data:%s;base64,%s",
favicon.mediaType(), favicon.mediaType(),
Base64.getEncoder().encodeToString(favicon.icon()))); Base64.getEncoder().encodeToString(favicon.icon())));
return f; return f;
}) })
.toList(); .toList();
} }

View File

@@ -216,11 +216,10 @@ public class GoogleReaderREST {
List<GoogleReaderModel.Tag> tags = new ArrayList<>(); List<GoogleReaderModel.Tag> tags = new ArrayList<>();
feedCategoryDAO feedCategoryDAO
.findAll(user) .findAll(user)
.forEach( .forEach(c ->
c -> tags.add(
tags.add( new GoogleReaderModel.Tag(
new GoogleReaderModel.Tag( GoogleReaderStreamId.label(c.getName()))));
GoogleReaderStreamId.label(c.getName()))));
tags.add(new GoogleReaderModel.Tag(GoogleReaderStreamId.STARRED)); tags.add(new GoogleReaderModel.Tag(GoogleReaderStreamId.STARRED));
GoogleReaderModel.TagList resp = new GoogleReaderModel.TagList(); GoogleReaderModel.TagList resp = new GoogleReaderModel.TagList();
@@ -259,21 +258,19 @@ public class GoogleReaderREST {
Map<Long, FeedCategory> categoriesById = Map<Long, FeedCategory> categoriesById =
feedCategoryDAO.findAll(user).stream() feedCategoryDAO.findAll(user).stream()
.collect(Collectors.toMap(FeedCategory::getId, c -> c)); .collect(Collectors.toMap(FeedCategory::getId, c -> c));
unreadByCategory.forEach( unreadByCategory.forEach((categoryId, count) -> {
(categoryId, count) -> { if (categoryId == 0) {
if (categoryId == 0) { return;
return; }
} FeedCategory category = categoriesById.get(categoryId);
FeedCategory category = categoriesById.get(categoryId); if (category == null) {
if (category == null) { return;
return; }
} GoogleReaderModel.UnreadCountEntry entry = new GoogleReaderModel.UnreadCountEntry();
GoogleReaderModel.UnreadCountEntry entry = entry.setId(GoogleReaderStreamId.label(category.getName()));
new GoogleReaderModel.UnreadCountEntry(); entry.setCount(count);
entry.setId(GoogleReaderStreamId.label(category.getName())); entries.add(entry);
entry.setCount(count); });
entries.add(entry);
});
GoogleReaderModel.UnreadCountEntry readingList = new GoogleReaderModel.UnreadCountEntry(); GoogleReaderModel.UnreadCountEntry readingList = new GoogleReaderModel.UnreadCountEntry();
readingList.setId(GoogleReaderStreamId.READING_LIST); readingList.setId(GoogleReaderStreamId.READING_LIST);
@@ -334,10 +331,8 @@ public class GoogleReaderREST {
GoogleReaderModel.ItemRefs resp = new GoogleReaderModel.ItemRefs(); GoogleReaderModel.ItemRefs resp = new GoogleReaderModel.ItemRefs();
resp.setItemRefs( resp.setItemRefs(
paged.statuses().stream() paged.statuses().stream()
.map( .map(s ->
s -> new GoogleReaderModel.ItemRef(String.valueOf(s.getEntry().getId())))
new GoogleReaderModel.ItemRef(
String.valueOf(s.getEntry().getId())))
.toList()); .toList());
resp.setContinuation(paged.continuation()); resp.setContinuation(paged.continuation());
return resp; return resp;

View File

@@ -38,20 +38,18 @@ public class DatabaseApiKeyIdentityProvider
@Override @Override
public Uni<SecurityIdentity> authenticate( public Uni<SecurityIdentity> authenticate(
TokenAuthenticationRequest request, AuthenticationRequestContext context) { TokenAuthenticationRequest request, AuthenticationRequestContext context) {
return context.runBlocking( return context.runBlocking(() -> {
() -> { Optional<User> user =
Optional<User> user = unitOfWork.call(() -> userService.login(request.getToken().getToken()));
unitOfWork.call(() -> userService.login(request.getToken().getToken())); if (user.isEmpty()) {
if (user.isEmpty()) { throw new AuthenticationFailedException("could not find a user with this api key");
throw new AuthenticationFailedException( }
"could not find a user with this api key");
}
Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get())); Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get()));
return QuarkusSecurityIdentity.builder() return QuarkusSecurityIdentity.builder()
.setPrincipal(new QuarkusPrincipal(String.valueOf(user.get().getId()))) .setPrincipal(new QuarkusPrincipal(String.valueOf(user.get().getId())))
.addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet())) .addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet()))
.build(); .build();
}); });
} }
} }

View File

@@ -39,25 +39,22 @@ public class DatabaseUsernamePasswordIdentityProvider
@Override @Override
public Uni<SecurityIdentity> authenticate( public Uni<SecurityIdentity> authenticate(
UsernamePasswordAuthenticationRequest request, AuthenticationRequestContext context) { UsernamePasswordAuthenticationRequest request, AuthenticationRequestContext context) {
return context.runBlocking( return context.runBlocking(() -> {
() -> { Optional<User> user =
Optional<User> user = unitOfWork.call(() ->
unitOfWork.call( userService.login(
() -> request.getUsername(),
userService.login( new String(request.getPassword().getPassword())));
request.getUsername(), if (user.isEmpty()) {
new String( throw new CommaFeedApplicationException(
request.getPassword().getPassword()))); CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD);
if (user.isEmpty()) { }
throw new CommaFeedApplicationException(
CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD);
}
Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get())); Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get()));
return QuarkusSecurityIdentity.builder() return QuarkusSecurityIdentity.builder()
.setPrincipal(new QuarkusPrincipal(String.valueOf(user.get().getId()))) .setPrincipal(new QuarkusPrincipal(String.valueOf(user.get().getId())))
.addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet())) .addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet()))
.build(); .build();
}); });
} }
} }

View File

@@ -40,24 +40,23 @@ public class TrustedIdentityProvider implements IdentityProvider<TrustedAuthenti
@Override @Override
public Uni<SecurityIdentity> authenticate( public Uni<SecurityIdentity> authenticate(
TrustedAuthenticationRequest request, AuthenticationRequestContext context) { TrustedAuthenticationRequest request, AuthenticationRequestContext context) {
return context.runBlocking( return context.runBlocking(() -> {
() -> { Long userId = Long.valueOf(request.getPrincipal());
Long userId = Long.valueOf(request.getPrincipal()); User user = unitOfWork.call(() -> userDAO.findById(userId));
User user = unitOfWork.call(() -> userDAO.findById(userId)); if (user == null) {
if (user == null) { throw new AuthenticationFailedException("user not found");
throw new AuthenticationFailedException("user not found"); }
}
// execute post login activities manually because we didn't call login() since // execute post login activities manually because we didn't call login() since
// we received // we received
// a trusted authentication request // a trusted authentication request
unitOfWork.run(() -> postLoginActivities.executeFor(user)); unitOfWork.run(() -> postLoginActivities.executeFor(user));
Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user)); Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user));
return QuarkusSecurityIdentity.builder() return QuarkusSecurityIdentity.builder()
.setPrincipal(new QuarkusPrincipal(String.valueOf(userId))) .setPrincipal(new QuarkusPrincipal(String.valueOf(userId)))
.addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet())) .addRoles(roles.stream().map(Enum::name).collect(Collectors.toSet()))
.build(); .build();
}); });
} }
} }

View File

@@ -41,11 +41,10 @@ class NativeImageClassesTest {
WireFeedGenerator.class)) { WireFeedGenerator.class)) {
Set<Class<?>> moduleClasses = Set<Class<?>> moduleClasses =
new HashSet<>(reflections.get(Scanners.SubTypes.of(clazz).asClass())); new HashSet<>(reflections.get(Scanners.SubTypes.of(clazz).asClass()));
moduleClasses.removeIf( moduleClasses.removeIf(c ->
c -> c.isInterface()
c.isInterface() || Modifier.isAbstract(c.getModifiers())
|| Modifier.isAbstract(c.getModifiers()) || !Modifier.isPublic(c.getModifiers()));
|| !Modifier.isPublic(c.getModifiers()));
moduleClasses.removeAll(classesInAnnotation); moduleClasses.removeAll(classesInAnnotation);
missingClasses.addAll(moduleClasses); missingClasses.addAll(moduleClasses);
} }

View File

@@ -317,18 +317,17 @@ class HttpGetterTest {
this.mockServerClient this.mockServerClient
.when(HttpRequest.request().withMethod("GET")) .when(HttpRequest.request().withMethod("GET"))
.respond( .respond(req -> {
req -> { calls.incrementAndGet();
calls.incrementAndGet();
if (req.containsHeader(HttpHeaders.COOKIE)) { if (req.containsHeader(HttpHeaders.COOKIE)) {
throw new Exception("cookie should not be sent by the client"); throw new Exception("cookie should not be sent by the client");
} }
return HttpResponse.response() return HttpResponse.response()
.withBody("ok") .withBody("ok")
.withHeader(HttpHeaders.SET_COOKIE, "foo=bar"); .withHeader(HttpHeaders.SET_COOKIE, "foo=bar");
}); });
Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl)); Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl));
Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl + "?foo=bar")); Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl + "?foo=bar"));
@@ -341,11 +340,10 @@ class HttpGetterTest {
this.mockServerClient this.mockServerClient
.when(HttpRequest.request().withMethod("GET")) .when(HttpRequest.request().withMethod("GET"))
.respond( .respond(req -> {
req -> { calls.incrementAndGet();
calls.incrementAndGet(); return HttpResponse.response().withBody("ok");
return HttpResponse.response().withBody("ok"); });
});
HttpResult result = getter.get(this.feedUrl); HttpResult result = getter.get(this.feedUrl);
Assertions.assertEquals(result, getter.get(this.feedUrl)); Assertions.assertEquals(result, getter.get(this.feedUrl));
@@ -400,17 +398,15 @@ class HttpGetterTest {
this.mockServerClient this.mockServerClient
.when(HttpRequest.request().withMethod("GET")) .when(HttpRequest.request().withMethod("GET"))
.respond( .respond(req -> {
req -> { calls.incrementAndGet();
calls.incrementAndGet();
if (req.containsHeader(HttpHeaders.UPGRADE)) { if (req.containsHeader(HttpHeaders.UPGRADE)) {
throw new Exception( throw new Exception("upgrade header should not be sent by the client");
"upgrade header should not be sent by the client"); }
}
return HttpResponse.response().withBody("ok"); return HttpResponse.response().withBody("ok");
}); });
Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl)); Assertions.assertDoesNotThrow(() -> getter.get(this.feedUrl));
Assertions.assertEquals(1, calls.get()); Assertions.assertEquals(1, calls.get());
@@ -438,33 +434,30 @@ class HttpGetterTest {
HttpGetterTest.this HttpGetterTest.this
.mockServerClient .mockServerClient
.when(HttpRequest.request().withMethod("GET")) .when(HttpRequest.request().withMethod("GET"))
.respond( .respond(req -> {
req -> { try {
try { String acceptEncodingHeader =
String acceptEncodingHeader = req.getFirstHeader(HttpHeaders.ACCEPT_ENCODING);
req.getFirstHeader(HttpHeaders.ACCEPT_ENCODING); if (!ACCEPT_ENCODING.equals(acceptEncodingHeader)) {
if (!ACCEPT_ENCODING.equals(acceptEncodingHeader)) { throw new Exception(
throw new Exception( "Wrong value in the Accept-Encoding header, should be '%s' but was '%s'"
"Wrong value in the Accept-Encoding header, should be '%s' but was '%s'" .formatted(ACCEPT_ENCODING, acceptEncodingHeader));
.formatted( }
ACCEPT_ENCODING,
acceptEncodingHeader));
}
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
try (OutputStream compressionOutputStream = try (OutputStream compressionOutputStream =
compressionFunction.apply(output)) { compressionFunction.apply(output)) {
compressionOutputStream.write(body.getBytes()); compressionOutputStream.write(body.getBytes());
} }
return HttpResponse.response() return HttpResponse.response()
.withBody(output.toByteArray()) .withBody(output.toByteArray())
.withHeader(HttpHeaders.CONTENT_ENCODING, encoding); .withHeader(HttpHeaders.CONTENT_ENCODING, encoding);
} catch (Exception e) { } catch (Exception e) {
log.error("Error in compression callback", e); log.error("Error in compression callback", e);
throw e; throw e;
} }
}); });
HttpResult result = getter.get(HttpGetterTest.this.feedUrl); HttpResult result = getter.get(HttpGetterTest.this.feedUrl);
Assertions.assertEquals(body, new String(result.content())); Assertions.assertEquals(body, new String(result.content()));

View File

@@ -68,7 +68,8 @@ class YoutubeFaviconFetcherTest {
byte[] apiResponse = byte[] apiResponse =
""" """
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}""" {"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}\
"""
.getBytes(); .getBytes();
HttpResult apiHttpResult = HttpResult apiHttpResult =
new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO); new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
@@ -102,7 +103,8 @@ class YoutubeFaviconFetcherTest {
byte[] apiResponse = byte[] apiResponse =
""" """
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}""" {"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}\
"""
.getBytes(); .getBytes();
HttpResult apiHttpResult = HttpResult apiHttpResult =
new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO); new HttpResult(apiResponse, "application/json", null, null, null, Duration.ZERO);
@@ -136,7 +138,8 @@ class YoutubeFaviconFetcherTest {
byte[] playlistResponse = byte[] playlistResponse =
""" """
{"items":[{"snippet":{"channelId":"testChannelId"}}]}""" {"items":[{"snippet":{"channelId":"testChannelId"}}]}\
"""
.getBytes(); .getBytes();
HttpResult playlistHttpResult = HttpResult playlistHttpResult =
new HttpResult( new HttpResult(
@@ -151,7 +154,8 @@ class YoutubeFaviconFetcherTest {
byte[] channelResponse = byte[] channelResponse =
""" """
{"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}""" {"items":[{"snippet":{"thumbnails":{"default":{"url":"https://example.com/icon.png"}}}}]}\
"""
.getBytes(); .getBytes();
HttpResult channelHttpResult = HttpResult channelHttpResult =
new HttpResult( new HttpResult(

View File

@@ -226,14 +226,16 @@ class XMLCleanerTest {
void testRemoveMultilineDoctype() { void testRemoveMultilineDoctype() {
String source = String source =
""" """
<!DOCTYPE <!DOCTYPE
html html
> >
<html><head></head><body></body></html>"""; <html><head></head><body></body></html>\
""";
Assertions.assertEquals( Assertions.assertEquals(
""" """
<html><head></head><body></body></html>""", <html><head></head><body></body></html>\
""",
xmlCleaner.removeDoctypeDeclarations(source)); xmlCleaner.removeDoctypeDeclarations(source));
} }

View File

@@ -12,23 +12,23 @@ class FeedEntryContentCleaningServiceTest {
void testClean() { void testClean() {
String content = String content =
""" """
<p> <p>
Some text Some text
<img width="965" height="320" src="https://localhost/an-image.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="alt-desc" decoding="async" sizes="(max-width: 965px) 100vw, 965px" style="width: 100%; opacity: 0"> <img width="965" height="320" src="https://localhost/an-image.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="alt-desc" decoding="async" sizes="(max-width: 965px) 100vw, 965px" style="width: 100%; opacity: 0">
<iframe src="https://localhost/an-iframe" style="width: 100%; opacity: 0"></iframe> <iframe src="https://localhost/an-iframe" style="width: 100%; opacity: 0"></iframe>
<forbidden-element>aaa</forbidden-element> <forbidden-element>aaa</forbidden-element>
"""; """;
String result = feedEntryContentCleaningService.clean(content, "baseUri", false); String result = feedEntryContentCleaningService.clean(content, "baseUri", false);
Assertions.assertLinesMatch( Assertions.assertLinesMatch(
""" """
<p> <p>
Some text Some text
<img width="965" height="320" src="https://localhost/an-image.png" alt="alt-desc" style="width:100%;"> <img width="965" height="320" src="https://localhost/an-image.png" alt="alt-desc" style="width:100%;">
<iframe src="https://localhost/an-iframe" style="width:100%;"></iframe> <iframe src="https://localhost/an-iframe" style="width:100%;"></iframe>
aaa aaa
</p> </p>
""" """
.lines(), .lines(),
result.lines()); result.lines());
} }

View File

@@ -98,19 +98,19 @@ class PushNotificationServiceTest {
.withBody( .withBody(
JsonBody.json( JsonBody.json(
""" """
{ {
"title": "Test Feed", "title": "Test Feed",
"message": "Test Entry", "message": "Test Entry",
"priority": 5, "priority": 5,
"extras": { "extras": {
"client::notification": { "client::notification": {
"click": { "click": {
"url": "http://example.com/entry" "url": "http://example.com/entry"
} }
} }
} }
} }
"""))) """)))
.respond(HttpResponse.response().withStatusCode(200)); .respond(HttpResponse.response().withStatusCode(200));
Assertions.assertDoesNotThrow( Assertions.assertDoesNotThrow(

View File

@@ -14,14 +14,15 @@ class InPageReferenceFeedURLProviderTest {
String url = "http://example.com"; String url = "http://example.com";
String html = String html =
""" """
<html> <html>
<head> <head>
<link type="application/atom+xml" href="/feed.atom"> <link type="application/atom+xml" href="/feed.atom">
<link type="application/rss+xml" href="/feed.rss"> <link type="application/rss+xml" href="/feed.rss">
</head> </head>
<body> <body>
</body> </body>
</html>"""; </html>\
""";
Assertions.assertIterableEquals( Assertions.assertIterableEquals(
List.of("http://example.com/feed.atom", "http://example.com/feed.rss"), List.of("http://example.com/feed.atom", "http://example.com/feed.rss"),
@@ -33,9 +34,10 @@ class InPageReferenceFeedURLProviderTest {
String url = "http://example.com"; String url = "http://example.com";
String html = String html =
""" """
<?xml version="1.0"?> <?xml version="1.0"?>
<feed></feed> <feed></feed>
</xml>"""; </xml>\
""";
Assertions.assertTrue(provider.get(url, html).isEmpty()); Assertions.assertTrue(provider.get(url, html).isEmpty());
} }
@@ -45,13 +47,14 @@ class InPageReferenceFeedURLProviderTest {
String url = "http://example.com"; String url = "http://example.com";
String html = String html =
""" """
<html> <html>
<head> <head>
<link type="text/css" href="/style.css"> <link type="text/css" href="/style.css">
</head> </head>
<body> <body>
</body> </body>
</html>"""; </html>\
""";
Assertions.assertTrue(provider.get(url, html).isEmpty()); Assertions.assertTrue(provider.get(url, html).isEmpty());
} }

View File

@@ -170,10 +170,9 @@ class GoogleReaderIT extends BaseIT {
client.get(BASE + "/reader/api/0/unread-count").as(UnreadCounts.class); client.get(BASE + "/reader/api/0/unread-count").as(UnreadCounts.class);
Assertions.assertTrue( Assertions.assertTrue(
counts.getUnreadCounts().stream() counts.getUnreadCounts().stream()
.anyMatch( .anyMatch(c ->
c -> c.getId().equals("user/-/state/com.google/reading-list")
c.getId().equals("user/-/state/com.google/reading-list") && c.getCount() == 2));
&& c.getCount() == 2));
} }
@Test @Test