mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
migrate from java.util.Date to java.time
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@@ -42,8 +42,10 @@ import com.commafeed.frontend.servlet.RobotsTxtDisallowAllServlet;
|
|||||||
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
||||||
import com.commafeed.frontend.ws.WebSocketConfigurator;
|
import com.commafeed.frontend.ws.WebSocketConfigurator;
|
||||||
import com.commafeed.frontend.ws.WebSocketEndpoint;
|
import com.commafeed.frontend.ws.WebSocketEndpoint;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.MapperFeature;
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Key;
|
import com.google.inject.Key;
|
||||||
@@ -76,7 +78,7 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
|||||||
public static final String USERNAME_ADMIN = "admin";
|
public static final String USERNAME_ADMIN = "admin";
|
||||||
public static final String USERNAME_DEMO = "demo";
|
public static final String USERNAME_DEMO = "demo";
|
||||||
|
|
||||||
public static final Date STARTUP_TIME = new Date();
|
public static final Instant STARTUP_TIME = Instant.now();
|
||||||
|
|
||||||
private HibernateBundle<CommaFeedConfiguration> hibernateBundle;
|
private HibernateBundle<CommaFeedConfiguration> hibernateBundle;
|
||||||
private WebsocketBundle<CommaFeedConfiguration> websocketBundle;
|
private WebsocketBundle<CommaFeedConfiguration> websocketBundle;
|
||||||
@@ -89,8 +91,7 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
|||||||
@Override
|
@Override
|
||||||
public void initialize(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
public void initialize(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
||||||
configureEnvironmentSubstitutor(bootstrap);
|
configureEnvironmentSubstitutor(bootstrap);
|
||||||
|
configureObjectMapper(bootstrap.getObjectMapper());
|
||||||
bootstrap.getObjectMapper().registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false));
|
|
||||||
|
|
||||||
bootstrap.addBundle(websocketBundle = new WebsocketBundle<>());
|
bootstrap.addBundle(websocketBundle = new WebsocketBundle<>());
|
||||||
bootstrap.addBundle(hibernateBundle = new HibernateBundle<>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
|
bootstrap.addBundle(hibernateBundle = new HibernateBundle<>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class,
|
||||||
@@ -134,6 +135,15 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
|||||||
bootstrap.setConfigurationSourceProvider(buildEnvironmentSubstitutor(bootstrap));
|
bootstrap.setConfigurationSourceProvider(buildEnvironmentSubstitutor(bootstrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void configureObjectMapper(ObjectMapper objectMapper) {
|
||||||
|
// read and write instants as milliseconds instead of nanoseconds
|
||||||
|
objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
|
||||||
|
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
|
||||||
|
|
||||||
|
// add support for serializing metrics
|
||||||
|
objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false));
|
||||||
|
}
|
||||||
|
|
||||||
private static EnvironmentSubstitutor buildEnvironmentSubstitutor(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
private static EnvironmentSubstitutor buildEnvironmentSubstitutor(Bootstrap<CommaFeedConfiguration> bootstrap) {
|
||||||
// enable config.yml string substitution
|
// enable config.yml string substitution
|
||||||
// e.g. having a custom config.yml file with app.session.path=${SOME_ENV_VAR} will substitute SOME_ENV_VAR
|
// e.g. having a custom config.yml file with app.session.path=${SOME_ENV_VAR} will substitute SOME_ENV_VAR
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import com.commafeed.backend.cache.RedisPoolFactory;
|
import com.commafeed.backend.cache.RedisPoolFactory;
|
||||||
import com.commafeed.frontend.session.SessionHandlerFactory;
|
import com.commafeed.frontend.session.SessionHandlerFactory;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
@@ -175,9 +174,8 @@ public class CommaFeedConfiguration extends Configuration implements WebsocketBu
|
|||||||
|
|
||||||
private Duration treeReloadInterval = Duration.seconds(30);
|
private Duration treeReloadInterval = Duration.seconds(30);
|
||||||
|
|
||||||
public Date getUnreadThreshold() {
|
public Instant getUnreadThreshold() {
|
||||||
int keepStatusDays = getKeepStatusDays();
|
return getKeepStatusDays() > 0 ? Instant.now().minus(getKeepStatusDays(), ChronoUnit.DAYS) : null;
|
||||||
return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -26,8 +26,8 @@ public class FeedDAO extends GenericDAO<Feed> {
|
|||||||
super(sessionFactory);
|
super(sessionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
|
public List<Feed> findNextUpdatable(int count, Instant lastLoginThreshold) {
|
||||||
JPAQuery<Feed> query = query().selectFrom(feed).where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date())));
|
JPAQuery<Feed> query = query().selectFrom(feed).where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(Instant.now())));
|
||||||
if (lastLoginThreshold != null) {
|
if (lastLoginThreshold != null) {
|
||||||
query.where(JPAExpressions.selectOne()
|
query.where(JPAExpressions.selectOne()
|
||||||
.from(subscription)
|
.from(subscription)
|
||||||
@@ -39,7 +39,7 @@ public class FeedDAO extends GenericDAO<Feed> {
|
|||||||
return query.orderBy(feed.disabledUntil.asc()).limit(count).fetch();
|
return query.orderBy(feed.disabledUntil.asc()).limit(count).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisabledUntil(List<Long> feedIds, Date date) {
|
public void setDisabledUntil(List<Long> feedIds, Instant date) {
|
||||||
updateQuery(feed).set(feed.disabledUntil, date).where(feed.id.in(feedIds)).execute();
|
updateQuery(feed).set(feed.disabledUntil, date).where(feed.id.in(feedIds)).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
@@ -49,7 +49,7 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
|||||||
/**
|
/**
|
||||||
* Delete entries older than a certain date
|
* Delete entries older than a certain date
|
||||||
*/
|
*/
|
||||||
public int deleteEntriesOlderThan(Date olderThan, long max) {
|
public int deleteEntriesOlderThan(Instant olderThan, long max) {
|
||||||
List<FeedEntry> list = query().selectFrom(entry).where(entry.updated.lt(olderThan)).orderBy(entry.updated.asc()).limit(max).fetch();
|
List<FeedEntry> list = query().selectFrom(entry).where(entry.updated.lt(olderThan)).orderBy(entry.updated.asc()).limit(max).fetch();
|
||||||
return delete(list);
|
return delete(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
@@ -73,8 +73,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
|
|
||||||
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
|
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
Instant unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
||||||
boolean read = unreadThreshold != null && entry.getUpdated().before(unreadThreshold);
|
boolean read = unreadThreshold != null && entry.getUpdated().isBefore(unreadThreshold);
|
||||||
status = new FeedEntryStatus(user, sub, entry);
|
status = new FeedEntryStatus(user, sub, entry);
|
||||||
status.setRead(read);
|
status.setRead(read);
|
||||||
status.setMarkable(!read);
|
status.setMarkable(!read);
|
||||||
@@ -90,7 +90,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryStatus> findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) {
|
public List<FeedEntryStatus> findStarred(User user, Instant newerThan, int offset, int limit, ReadingOrder order,
|
||||||
|
boolean includeContent) {
|
||||||
JPAQuery<FeedEntryStatus> query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue());
|
JPAQuery<FeedEntryStatus> query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue());
|
||||||
if (newerThan != null) {
|
if (newerThan != null) {
|
||||||
query.where(status.entryInserted.gt(newerThan));
|
query.where(status.entryInserted.gt(newerThan));
|
||||||
@@ -114,7 +115,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JPAQuery<FeedEntry> buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords,
|
private JPAQuery<FeedEntry> buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords,
|
||||||
Date newerThan, int offset, int limit, ReadingOrder order, FeedEntryStatus last, String tag, Long minEntryId, Long maxEntryId) {
|
Instant newerThan, int offset, int limit, ReadingOrder order, FeedEntryStatus last, String tag, Long minEntryId,
|
||||||
|
Long maxEntryId) {
|
||||||
|
|
||||||
JPAQuery<FeedEntry> query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed()));
|
JPAQuery<FeedEntry> query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed()));
|
||||||
|
|
||||||
@@ -139,7 +141,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
or.or(status.read.isFalse());
|
or.or(status.read.isFalse());
|
||||||
query.where(or);
|
query.where(or);
|
||||||
|
|
||||||
Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
Instant unreadThreshold = config.getApplicationSettings().getUnreadThreshold();
|
||||||
if (unreadThreshold != null) {
|
if (unreadThreshold != null) {
|
||||||
query.where(entry.updated.goe(unreadThreshold));
|
query.where(entry.updated.goe(unreadThreshold));
|
||||||
}
|
}
|
||||||
@@ -193,7 +195,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly,
|
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly,
|
||||||
List<FeedEntryKeyword> keywords, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
|
List<FeedEntryKeyword> keywords, Instant newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
|
||||||
boolean onlyIds, String tag, Long minEntryId, Long maxEntryId) {
|
boolean onlyIds, String tag, Long minEntryId, Long maxEntryId) {
|
||||||
int capacity = offset + limit;
|
int capacity = offset + limit;
|
||||||
|
|
||||||
@@ -208,7 +210,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
|
|
||||||
for (Tuple tuple : tuples) {
|
for (Tuple tuple : tuples) {
|
||||||
Long id = tuple.get(entry.id);
|
Long id = tuple.get(entry.id);
|
||||||
Date updated = tuple.get(entry.updated);
|
Instant updated = tuple.get(entry.updated);
|
||||||
Long statusId = tuple.get(status.id);
|
Long statusId = tuple.get(status.id);
|
||||||
|
|
||||||
FeedEntryContent content = new FeedEntryContent();
|
FeedEntryContent content = new FeedEntryContent();
|
||||||
@@ -260,7 +262,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
List<Tuple> tuples = query.select(entry.count(), entry.updated.max()).fetch();
|
List<Tuple> tuples = query.select(entry.count(), entry.updated.max()).fetch();
|
||||||
for (Tuple tuple : tuples) {
|
for (Tuple tuple : tuples) {
|
||||||
Long count = tuple.get(entry.count());
|
Long count = tuple.get(entry.count());
|
||||||
Date updated = tuple.get(entry.updated.max());
|
Instant updated = tuple.get(entry.updated.max());
|
||||||
uc = new UnreadCount(subscription.getId(), count == null ? 0 : count, updated);
|
uc = new UnreadCount(subscription.getId(), count == null ? 0 : count, updated);
|
||||||
}
|
}
|
||||||
return uc;
|
return uc;
|
||||||
@@ -276,7 +278,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long deleteOldStatuses(Date olderThan, int limit) {
|
public long deleteOldStatuses(Instant olderThan, int limit) {
|
||||||
List<Long> ids = query().select(status.id)
|
List<Long> ids = query().select(status.id)
|
||||||
.from(status)
|
.from(status)
|
||||||
.where(status.entryInserted.lt(olderThan), status.starred.isFalse())
|
.where(status.entryInserted.lt(olderThan), status.starred.isFalse())
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.StringUtils;
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
@@ -32,8 +32,8 @@ public class FeedFetcher {
|
|||||||
private final HttpGetter getter;
|
private final HttpGetter getter;
|
||||||
private final Set<FeedURLProvider> urlProviders;
|
private final Set<FeedURLProvider> urlProviders;
|
||||||
|
|
||||||
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag, Date lastPublishedDate,
|
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag,
|
||||||
String lastContentHash) throws FeedException, IOException, NotModifiedException {
|
Instant lastPublishedDate, String lastContentHash) throws FeedException, IOException, NotModifiedException {
|
||||||
log.debug("Fetching feed {}", feedUrl);
|
log.debug("Fetching feed {}", feedUrl);
|
||||||
|
|
||||||
int timeout = 20000;
|
int timeout = 20000;
|
||||||
@@ -76,8 +76,7 @@ public class FeedFetcher {
|
|||||||
etagHeaderValueChanged ? result.getETag() : null);
|
etagHeaderValueChanged ? result.getETag() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastPublishedDate != null && parserResult.lastPublishedDate() != null
|
if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) {
|
||||||
&& lastPublishedDate.getTime() == parserResult.lastPublishedDate().getTime()) {
|
|
||||||
log.debug("publishedDate not modified: {}", feedUrl);
|
log.debug("publishedDate not modified: {}", feedUrl);
|
||||||
throw new NotModifiedException("publishedDate not modified",
|
throw new NotModifiedException("publishedDate not modified",
|
||||||
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingDeque;
|
import java.util.concurrent.BlockingDeque;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -11,8 +12,6 @@ import java.util.concurrent.SynchronousQueue;
|
|||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import com.codahale.metrics.Gauge;
|
import com.codahale.metrics.Gauge;
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
@@ -166,12 +165,12 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
|
|
||||||
private List<Feed> getNextUpdatableFeeds(int max) {
|
private List<Feed> getNextUpdatableFeeds(int max) {
|
||||||
return unitOfWork.call(() -> {
|
return unitOfWork.call(() -> {
|
||||||
Date lastLoginThreshold = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad())
|
Instant lastLoginThreshold = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad())
|
||||||
? DateUtils.addDays(new Date(), -30)
|
? Instant.now().minus(Duration.ofDays(30))
|
||||||
: null;
|
: null;
|
||||||
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
||||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
||||||
Date nextUpdateDate = DateUtils.addMinutes(new Date(), config.getApplicationSettings().getRefreshIntervalMinutes());
|
Instant nextUpdateDate = Instant.now().plus(Duration.ofMinutes(config.getApplicationSettings().getRefreshIntervalMinutes()));
|
||||||
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
||||||
return feeds;
|
return feeds;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
|
|
||||||
@@ -21,61 +21,59 @@ public class FeedRefreshIntervalCalculator {
|
|||||||
this.refreshIntervalMinutes = config.getApplicationSettings().getRefreshIntervalMinutes();
|
this.refreshIntervalMinutes = config.getApplicationSettings().getRefreshIntervalMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date onFetchSuccess(Date publishedDate, Long averageEntryInterval) {
|
public Instant onFetchSuccess(Instant publishedDate, Long averageEntryInterval) {
|
||||||
Date defaultRefreshInterval = getDefaultRefreshInterval();
|
Instant defaultRefreshInterval = getDefaultRefreshInterval();
|
||||||
return heavyLoad ? computeRefreshIntervalForHeavyLoad(publishedDate, averageEntryInterval, defaultRefreshInterval)
|
return heavyLoad ? computeRefreshIntervalForHeavyLoad(publishedDate, averageEntryInterval, defaultRefreshInterval)
|
||||||
: defaultRefreshInterval;
|
: defaultRefreshInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date onFeedNotModified(Date publishedDate, Long averageEntryInterval) {
|
public Instant onFeedNotModified(Instant publishedDate, Long averageEntryInterval) {
|
||||||
Date defaultRefreshInterval = getDefaultRefreshInterval();
|
return onFetchSuccess(publishedDate, averageEntryInterval);
|
||||||
return heavyLoad ? computeRefreshIntervalForHeavyLoad(publishedDate, averageEntryInterval, defaultRefreshInterval)
|
|
||||||
: defaultRefreshInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date onFetchError(int errorCount) {
|
public Instant onFetchError(int errorCount) {
|
||||||
int retriesBeforeDisable = 3;
|
int retriesBeforeDisable = 3;
|
||||||
if (errorCount < retriesBeforeDisable || !heavyLoad) {
|
if (errorCount < retriesBeforeDisable || !heavyLoad) {
|
||||||
return getDefaultRefreshInterval();
|
return getDefaultRefreshInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
int disabledHours = Math.min(24 * 7, errorCount - retriesBeforeDisable + 1);
|
int disabledHours = Math.min(24 * 7, errorCount - retriesBeforeDisable + 1);
|
||||||
return DateUtils.addHours(new Date(), disabledHours);
|
return Instant.now().plus(Duration.ofHours(disabledHours));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date getDefaultRefreshInterval() {
|
private Instant getDefaultRefreshInterval() {
|
||||||
return DateUtils.addMinutes(new Date(), refreshIntervalMinutes);
|
return Instant.now().plus(Duration.ofMinutes(refreshIntervalMinutes));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date computeRefreshIntervalForHeavyLoad(Date publishedDate, Long averageEntryInterval, Date defaultRefreshInterval) {
|
private Instant computeRefreshIntervalForHeavyLoad(Instant publishedDate, Long averageEntryInterval, Instant defaultRefreshInterval) {
|
||||||
Date now = new Date();
|
Instant now = Instant.now();
|
||||||
|
|
||||||
if (publishedDate == null) {
|
if (publishedDate == null) {
|
||||||
// feed with no entries, recheck in 24 hours
|
// feed with no entries, recheck in 24 hours
|
||||||
return DateUtils.addHours(now, 24);
|
return now.plus(Duration.ofHours(24));
|
||||||
} else if (publishedDate.before(DateUtils.addMonths(now, -1))) {
|
} else if (ChronoUnit.DAYS.between(publishedDate, now) >= 30) {
|
||||||
// older than a month, recheck in 24 hours
|
// older than a month, recheck in 24 hours
|
||||||
return DateUtils.addHours(now, 24);
|
return now.plus(Duration.ofHours(24));
|
||||||
} else if (publishedDate.before(DateUtils.addDays(now, -14))) {
|
} else if (ChronoUnit.DAYS.between(publishedDate, now) >= 14) {
|
||||||
// older than two weeks, recheck in 12 hours
|
// older than two weeks, recheck in 12 hours
|
||||||
return DateUtils.addHours(now, 12);
|
return now.plus(Duration.ofHours(12));
|
||||||
} else if (publishedDate.before(DateUtils.addDays(now, -7))) {
|
} else if (ChronoUnit.DAYS.between(publishedDate, now) >= 7) {
|
||||||
// older than a week, recheck in 6 hours
|
// older than a week, recheck in 6 hours
|
||||||
return DateUtils.addHours(now, 6);
|
return now.plus(Duration.ofHours(6));
|
||||||
} else if (averageEntryInterval != null) {
|
} else if (averageEntryInterval != null) {
|
||||||
// use average time between entries to decide when to refresh next, divided by factor
|
// use average time between entries to decide when to refresh next, divided by factor
|
||||||
int factor = 2;
|
int factor = 2;
|
||||||
|
|
||||||
// not more than 6 hours
|
// not more than 6 hours
|
||||||
long date = Math.min(DateUtils.addHours(now, 6).getTime(), now.getTime() + averageEntryInterval / factor);
|
long date = Math.min(now.plus(Duration.ofHours(6)).toEpochMilli(), now.toEpochMilli() + averageEntryInterval / factor);
|
||||||
|
|
||||||
// not less than default refresh interval
|
// not less than default refresh interval
|
||||||
date = Math.max(defaultRefreshInterval.getTime(), date);
|
date = Math.max(defaultRefreshInterval.toEpochMilli(), date);
|
||||||
|
|
||||||
return new Date(date);
|
return Instant.ofEpochMilli(date);
|
||||||
} else {
|
} else {
|
||||||
// unknown case, recheck in 24 hours
|
// unknown case, recheck in 24 hours
|
||||||
return DateUtils.addHours(now, 24);
|
return now.plus(Duration.ofHours(24));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -161,7 +161,7 @@ public class FeedRefreshUpdater implements Managed {
|
|||||||
|
|
||||||
if (!processed) {
|
if (!processed) {
|
||||||
// requeue asap
|
// requeue asap
|
||||||
feed.setDisabledUntil(new Date(0));
|
feed.setDisabledUntil(Instant.EPOCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insertedAtLeastOneEntry) {
|
if (insertedAtLeastOneEntry) {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
@@ -58,8 +58,8 @@ public class FeedRefreshWorker {
|
|||||||
|
|
||||||
Integer maxEntriesAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays();
|
Integer maxEntriesAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays();
|
||||||
if (maxEntriesAgeDays > 0) {
|
if (maxEntriesAgeDays > 0) {
|
||||||
Date threshold = DateUtils.addDays(new Date(), -1 * maxEntriesAgeDays);
|
Instant threshold = Instant.now().minus(Duration.ofDays(maxEntriesAgeDays));
|
||||||
entries = entries.stream().filter(entry -> entry.updated().after(threshold)).toList();
|
entries = entries.stream().filter(entry -> entry.updated().isAfter(threshold)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
String urlAfterRedirect = result.urlAfterRedirect();
|
String urlAfterRedirect = result.urlAfterRedirect();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.commafeed.backend.feed.parser;
|
|||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -50,8 +51,8 @@ public class FeedParser {
|
|||||||
|
|
||||||
private static final Namespace ATOM_10_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom");
|
private static final Namespace ATOM_10_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom");
|
||||||
|
|
||||||
private static final Date START = new Date(86400000);
|
private static final Instant START = Instant.ofEpochMilli(86400000);
|
||||||
private static final Date END = new Date(1000L * Integer.MAX_VALUE - 86400000);
|
private static final Instant END = Instant.ofEpochMilli(1000L * Integer.MAX_VALUE - 86400000);
|
||||||
|
|
||||||
private final EncodingDetector encodingDetector;
|
private final EncodingDetector encodingDetector;
|
||||||
private final FeedCleaner feedCleaner;
|
private final FeedCleaner feedCleaner;
|
||||||
@@ -72,9 +73,9 @@ public class FeedParser {
|
|||||||
String title = feed.getTitle();
|
String title = feed.getTitle();
|
||||||
String link = feed.getLink();
|
String link = feed.getLink();
|
||||||
List<Entry> entries = buildEntries(feed, feedUrl);
|
List<Entry> entries = buildEntries(feed, feedUrl);
|
||||||
Date lastEntryDate = entries.stream().findFirst().map(Entry::updated).orElse(null);
|
Instant lastEntryDate = entries.stream().findFirst().map(Entry::updated).orElse(null);
|
||||||
Date lastPublishedDate = validateDate(feed.getPublishedDate(), false);
|
Instant lastPublishedDate = toValidInstant(feed.getPublishedDate(), false);
|
||||||
if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.before(lastEntryDate)) {
|
if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.isBefore(lastEntryDate)) {
|
||||||
lastPublishedDate = lastEntryDate;
|
lastPublishedDate = lastEntryDate;
|
||||||
}
|
}
|
||||||
Long averageEntryInterval = averageTimeBetweenEntries(entries);
|
Long averageEntryInterval = averageTimeBetweenEntries(entries);
|
||||||
@@ -122,7 +123,7 @@ public class FeedParser {
|
|||||||
url = guid;
|
url = guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date updated = buildEntryUpdateDate(item);
|
Instant updated = buildEntryUpdateDate(item);
|
||||||
Content content = buildContent(item);
|
Content content = buildContent(item);
|
||||||
|
|
||||||
entries.add(new Entry(guid, url, updated, content));
|
entries.add(new Entry(guid, url, updated, content));
|
||||||
@@ -153,15 +154,12 @@ public class FeedParser {
|
|||||||
return new Enclosure(enclosure.getUrl(), enclosure.getType());
|
return new Enclosure(enclosure.getUrl(), enclosure.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date buildEntryUpdateDate(SyndEntry item) {
|
private Instant buildEntryUpdateDate(SyndEntry item) {
|
||||||
Date date = item.getUpdatedDate();
|
Date date = item.getUpdatedDate();
|
||||||
if (date == null) {
|
if (date == null) {
|
||||||
date = item.getPublishedDate();
|
date = item.getPublishedDate();
|
||||||
}
|
}
|
||||||
if (date == null) {
|
return toValidInstant(date, true);
|
||||||
date = new Date();
|
|
||||||
}
|
|
||||||
return validateDate(date, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildEntryUrl(SyndFeed feed, String feedUrl, SyndEntry item) {
|
private String buildEntryUrl(SyndFeed feed, String feedUrl, SyndEntry item) {
|
||||||
@@ -176,19 +174,21 @@ public class FeedParser {
|
|||||||
return FeedUtils.toAbsoluteUrl(url, feedLink, feedUrl);
|
return FeedUtils.toAbsoluteUrl(url, feedLink, feedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date validateDate(Date date, boolean nullToNow) {
|
private Instant toValidInstant(Date date, boolean nullToNow) {
|
||||||
Date now = new Date();
|
Instant now = Instant.now();
|
||||||
if (date == null) {
|
if (date == null) {
|
||||||
return nullToNow ? now : null;
|
return nullToNow ? now : null;
|
||||||
}
|
}
|
||||||
if (date.before(START) || date.after(END)) {
|
|
||||||
|
Instant instant = date.toInstant();
|
||||||
|
if (instant.isBefore(START) || instant.isAfter(END)) {
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (date.after(now)) {
|
if (instant.isAfter(now)) {
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
return date;
|
return instant;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getContent(SyndEntry item) {
|
private String getContent(SyndEntry item) {
|
||||||
@@ -262,7 +262,7 @@ public class FeedParser {
|
|||||||
|
|
||||||
SummaryStatistics stats = new SummaryStatistics();
|
SummaryStatistics stats = new SummaryStatistics();
|
||||||
for (int i = 0; i < entries.size() - 1; i++) {
|
for (int i = 0; i < entries.size() - 1; i++) {
|
||||||
long diff = Math.abs(entries.get(i).updated().getTime() - entries.get(i + 1).updated().getTime());
|
long diff = Math.abs(entries.get(i).updated().toEpochMilli() - entries.get(i + 1).updated().toEpochMilli());
|
||||||
stats.addValue(diff);
|
stats.addValue(diff);
|
||||||
}
|
}
|
||||||
return (long) stats.getMean();
|
return (long) stats.getMean();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.commafeed.backend.feed.parser;
|
package com.commafeed.backend.feed.parser;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record FeedParserResult(String title, String link, Date lastPublishedDate, Long averageEntryInterval, Date lastEntryDate,
|
public record FeedParserResult(String title, String link, Instant lastPublishedDate, Long averageEntryInterval, Instant lastEntryDate,
|
||||||
List<Entry> entries) {
|
List<Entry> entries) {
|
||||||
public record Entry(String guid, String url, Date updated, Content content) {
|
public record Entry(String guid, String url, Instant updated, Content content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Content(String title, String content, String author, String categories, Enclosure enclosure, Media media) {
|
public record Content(String title, String content, String author, String categories, Enclosure enclosure, Media media) {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package com.commafeed.backend.model;
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -44,20 +42,20 @@ public class Feed extends AbstractModel {
|
|||||||
/**
|
/**
|
||||||
* Last time we tried to fetch the feed
|
* Last time we tried to fetch the feed
|
||||||
*/
|
*/
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date lastUpdated;
|
private Instant lastUpdated;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last publishedDate value in the feed
|
* Last publishedDate value in the feed
|
||||||
*/
|
*/
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date lastPublishedDate;
|
private Instant lastPublishedDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* date of the last entry of the feed
|
* date of the last entry of the feed
|
||||||
*/
|
*/
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date lastEntryDate;
|
private Instant lastEntryDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* error message while retrieving the feed
|
* error message while retrieving the feed
|
||||||
@@ -73,8 +71,8 @@ public class Feed extends AbstractModel {
|
|||||||
/**
|
/**
|
||||||
* feed refresh is disabled until this date
|
* feed refresh is disabled until this date
|
||||||
*/
|
*/
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date disabledUntil;
|
private Instant disabledUntil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* http header returned by the feed
|
* http header returned by the feed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.model;
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
@@ -11,8 +11,6 @@ import jakarta.persistence.JoinColumn;
|
|||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -39,11 +37,11 @@ public class FeedEntry extends AbstractModel {
|
|||||||
@Column(length = 2048)
|
@Column(length = 2048)
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date inserted;
|
private Instant inserted;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date updated;
|
private Instant updated;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "entry", cascade = CascadeType.REMOVE)
|
@OneToMany(mappedBy = "entry", cascade = CascadeType.REMOVE)
|
||||||
private Set<FeedEntryStatus> statuses;
|
private Set<FeedEntryStatus> statuses;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.backend.model;
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
@@ -10,8 +10,6 @@ import jakarta.persistence.FetchType;
|
|||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
import jakarta.persistence.Transient;
|
import jakarta.persistence.Transient;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -49,11 +47,11 @@ public class FeedEntryStatus extends AbstractModel {
|
|||||||
@JoinColumn(nullable = false)
|
@JoinColumn(nullable = false)
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date entryInserted;
|
private Instant entryInserted;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date entryUpdated;
|
private Instant entryUpdated;
|
||||||
|
|
||||||
public FeedEntryStatus() {
|
public FeedEntryStatus() {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package com.commafeed.backend.model;
|
package com.commafeed.backend.model;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Temporal;
|
|
||||||
import jakarta.persistence.TemporalType;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -35,15 +33,15 @@ public class User extends AbstractModel {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private boolean disabled;
|
private boolean disabled;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date lastLogin;
|
private Instant lastLogin;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date created;
|
private Instant created;
|
||||||
|
|
||||||
@Column(length = 40)
|
@Column(length = 40)
|
||||||
private String recoverPasswordToken;
|
private String recoverPasswordToken;
|
||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Column
|
||||||
private Date recoverPasswordTokenDate;
|
private Instant recoverPasswordTokenDate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
@@ -106,7 +106,7 @@ public class DatabaseCleaningService {
|
|||||||
log.info("cleanup done: {} entries for feeds exceeding capacity deleted", total);
|
log.info("cleanup done: {} entries for feeds exceeding capacity deleted", total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanEntriesOlderThan(final Date olderThan) {
|
public void cleanEntriesOlderThan(final Instant olderThan) {
|
||||||
log.info("cleaning old entries");
|
log.info("cleaning old entries");
|
||||||
long total = 0;
|
long total = 0;
|
||||||
long deleted;
|
long deleted;
|
||||||
@@ -119,7 +119,7 @@ public class DatabaseCleaningService {
|
|||||||
log.info("cleanup done: {} old entries deleted", total);
|
log.info("cleanup done: {} old entries deleted", total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanStatusesOlderThan(final Date olderThan) {
|
public void cleanStatusesOlderThan(final Instant olderThan) {
|
||||||
log.info("cleaning old read statuses");
|
log.info("cleaning old read statuses");
|
||||||
long total = 0;
|
long total = 0;
|
||||||
long deleted;
|
long deleted;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
@@ -73,7 +73,7 @@ public class FeedEntryService {
|
|||||||
entry.setGuidHash(guidHash);
|
entry.setGuidHash(guidHash);
|
||||||
entry.setUrl(FeedUtils.truncate(e.url(), 2048));
|
entry.setUrl(FeedUtils.truncate(e.url(), 2048));
|
||||||
entry.setUpdated(e.updated());
|
entry.setUpdated(e.updated());
|
||||||
entry.setInserted(new Date());
|
entry.setInserted(Instant.now());
|
||||||
entry.setFeed(feed);
|
entry.setFeed(feed);
|
||||||
|
|
||||||
entry.setContent(feedEntryContentService.findOrCreate(e.content(), feed.getLink()));
|
entry.setContent(feedEntryContentService.findOrCreate(e.content(), feed.getLink()));
|
||||||
@@ -117,7 +117,7 @@ public class FeedEntryService {
|
|||||||
feedEntryStatusDAO.saveOrUpdate(status);
|
feedEntryStatusDAO.saveOrUpdate(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Date olderThan, Date insertedBefore,
|
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Instant olderThan, Instant insertedBefore,
|
||||||
List<FeedEntryKeyword> keywords) {
|
List<FeedEntryKeyword> keywords) {
|
||||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null,
|
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null,
|
||||||
false, false, null, null, null);
|
false, false, null, null, null);
|
||||||
@@ -126,18 +126,18 @@ public class FeedEntryService {
|
|||||||
cache.invalidateUserRootCategory(user);
|
cache.invalidateUserRootCategory(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markStarredEntries(User user, Date olderThan, Date insertedBefore) {
|
public void markStarredEntries(User user, Instant olderThan, Instant insertedBefore) {
|
||||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findStarred(user, null, -1, -1, null, false);
|
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findStarred(user, null, -1, -1, null, false);
|
||||||
markList(statuses, olderThan, insertedBefore);
|
markList(statuses, olderThan, insertedBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markList(List<FeedEntryStatus> statuses, Date olderThan, Date insertedBefore) {
|
private void markList(List<FeedEntryStatus> statuses, Instant olderThan, Instant insertedBefore) {
|
||||||
List<FeedEntryStatus> statusesToMark = statuses.stream().filter(s -> {
|
List<FeedEntryStatus> statusesToMark = statuses.stream().filter(s -> {
|
||||||
Date entryDate = s.getEntry().getUpdated();
|
Instant entryDate = s.getEntry().getUpdated();
|
||||||
return olderThan == null || entryDate == null || entryDate.before(olderThan);
|
return olderThan == null || entryDate == null || entryDate.isBefore(olderThan);
|
||||||
}).filter(s -> {
|
}).filter(s -> {
|
||||||
Date insertedDate = s.getEntry().getInserted();
|
Instant insertedDate = s.getEntry().getInserted();
|
||||||
return insertedBefore == null || insertedDate == null || insertedDate.before(insertedBefore);
|
return insertedBefore == null || insertedDate == null || insertedDate.isBefore(insertedBefore);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
statusesToMark.forEach(s -> s.setRead(true));
|
statusesToMark.forEach(s -> s.setRead(true));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
@@ -45,7 +45,7 @@ public class FeedService {
|
|||||||
feed.setUrl(url);
|
feed.setUrl(url);
|
||||||
feed.setNormalizedUrl(normalizedUrl);
|
feed.setNormalizedUrl(normalizedUrl);
|
||||||
feed.setNormalizedUrlHash(normalizedUrlHash);
|
feed.setNormalizedUrlHash(normalizedUrlHash);
|
||||||
feed.setDisabledUntil(new Date(0));
|
feed.setDisabledUntil(Instant.EPOCH);
|
||||||
feedDAO.saveOrUpdate(feed);
|
feedDAO.saveOrUpdate(feed);
|
||||||
}
|
}
|
||||||
return feed;
|
return feed;
|
||||||
@@ -55,7 +55,7 @@ public class FeedService {
|
|||||||
String normalized = FeedUtils.normalizeURL(feed.getUrl());
|
String normalized = FeedUtils.normalizeURL(feed.getUrl());
|
||||||
feed.setNormalizedUrl(normalized);
|
feed.setNormalizedUrl(normalized);
|
||||||
feed.setNormalizedUrlHash(DigestUtils.sha1Hex(normalized));
|
feed.setNormalizedUrlHash(DigestUtils.sha1Hex(normalized));
|
||||||
feed.setLastUpdated(new Date());
|
feed.setLastUpdated(Instant.now());
|
||||||
feed.setEtagHeader(FeedUtils.truncate(feed.getEtagHeader(), 255));
|
feed.setEtagHeader(FeedUtils.truncate(feed.getEtagHeader(), 255));
|
||||||
feedDAO.saveOrUpdate(feed);
|
feedDAO.saveOrUpdate(feed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -110,8 +110,8 @@ public class FeedSubscriptionService {
|
|||||||
public void refreshAllUpForRefresh(User user) {
|
public void refreshAllUpForRefresh(User user) {
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||||
for (FeedSubscription sub : subs) {
|
for (FeedSubscription sub : subs) {
|
||||||
Date disabledUntil = sub.getFeed().getDisabledUntil();
|
Instant disabledUntil = sub.getFeed().getDisabledUntil();
|
||||||
if (disabledUntil == null || disabledUntil.before(new Date())) {
|
if (disabledUntil == null || disabledUntil.isBefore(Instant.now())) {
|
||||||
Feed feed = sub.getFeed();
|
Feed feed = sub.getFeed();
|
||||||
feedRefreshEngine.refreshImmediately(feed);
|
feedRefreshEngine.refreshImmediately(feed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -130,7 +130,7 @@ public class UserService {
|
|||||||
byte[] salt = encryptionService.generateSalt();
|
byte[] salt = encryptionService.generateSalt();
|
||||||
user.setName(name);
|
user.setName(name);
|
||||||
user.setEmail(email);
|
user.setEmail(email);
|
||||||
user.setCreated(new Date());
|
user.setCreated(Instant.now());
|
||||||
user.setSalt(salt);
|
user.setSalt(salt);
|
||||||
user.setPassword(encryptionService.getEncryptedPassword(password, salt));
|
user.setPassword(encryptionService.getEncryptedPassword(password, salt));
|
||||||
userDAO.saveOrUpdate(user);
|
userDAO.saveOrUpdate(user);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.commafeed.backend.service.internal;
|
package com.commafeed.backend.service.internal;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.dao.UnitOfWork;
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
@@ -25,9 +24,9 @@ public class PostLoginActivities {
|
|||||||
|
|
||||||
public void executeFor(User user) {
|
public void executeFor(User user) {
|
||||||
// only update lastLogin every once in a while in order to avoid invalidating the cache every time someone logs in
|
// only update lastLogin every once in a while in order to avoid invalidating the cache every time someone logs in
|
||||||
Date now = new Date();
|
Instant now = Instant.now();
|
||||||
Date lastLogin = user.getLastLogin();
|
Instant lastLogin = user.getLastLogin();
|
||||||
if (lastLogin == null || lastLogin.before(DateUtils.addMinutes(now, -30))) {
|
if (lastLogin == null || ChronoUnit.MINUTES.between(lastLogin, now) >= 30) {
|
||||||
user.setLastLogin(now);
|
user.setLastLogin(now);
|
||||||
|
|
||||||
boolean heavyLoad = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad());
|
boolean heavyLoad = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad());
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.commafeed.backend.task;
|
package com.commafeed.backend.task;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.service.DatabaseCleaningService;
|
import com.commafeed.backend.service.DatabaseCleaningService;
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ public class OldEntriesCleanupTask extends ScheduledTask {
|
|||||||
public void run() {
|
public void run() {
|
||||||
int maxAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays();
|
int maxAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays();
|
||||||
if (maxAgeDays > 0) {
|
if (maxAgeDays > 0) {
|
||||||
Date threshold = DateUtils.addDays(new Date(), -1 * maxAgeDays);
|
Instant threshold = Instant.now().minus(Duration.ofDays(maxAgeDays));
|
||||||
cleaner.cleanEntriesOlderThan(threshold);
|
cleaner.cleanEntriesOlderThan(threshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.task;
|
package com.commafeed.backend.task;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
@@ -19,7 +19,7 @@ public class OldStatusesCleanupTask extends ScheduledTask {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Date threshold = config.getApplicationSettings().getUnreadThreshold();
|
Instant threshold = config.getApplicationSettings().getUnreadThreshold();
|
||||||
if (threshold != null) {
|
if (threshold != null) {
|
||||||
cleaner.cleanStatusesOlderThan(threshold);
|
cleaner.cleanStatusesOlderThan(threshold);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.commafeed.frontend.model;
|
package com.commafeed.frontend.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -67,10 +68,10 @@ public class Entry implements Serializable {
|
|||||||
private Integer mediaThumbnailHeight;
|
private Integer mediaThumbnailHeight;
|
||||||
|
|
||||||
@Schema(description = "entry publication date", type = "number", requiredMode = RequiredMode.REQUIRED)
|
@Schema(description = "entry publication date", type = "number", requiredMode = RequiredMode.REQUIRED)
|
||||||
private Date date;
|
private Instant date;
|
||||||
|
|
||||||
@Schema(description = "entry insertion date in the database", type = "number", requiredMode = RequiredMode.REQUIRED)
|
@Schema(description = "entry insertion date in the database", type = "number", requiredMode = RequiredMode.REQUIRED)
|
||||||
private Date insertedDate;
|
private Instant insertedDate;
|
||||||
|
|
||||||
@Schema(description = "feed id", requiredMode = RequiredMode.REQUIRED)
|
@Schema(description = "feed id", requiredMode = RequiredMode.REQUIRED)
|
||||||
private String feedId;
|
private String feedId;
|
||||||
@@ -165,7 +166,7 @@ public class Entry implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry.setLink(getUrl());
|
entry.setLink(getUrl());
|
||||||
entry.setPublishedDate(getDate());
|
entry.setPublishedDate(getDate() == null ? null : Date.from(getDate()));
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.frontend.model;
|
package com.commafeed.frontend.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.model.Feed;
|
||||||
@@ -30,10 +30,10 @@ public class Subscription implements Serializable {
|
|||||||
private int errorCount;
|
private int errorCount;
|
||||||
|
|
||||||
@Schema(description = "last time the feed was refreshed", type = "number")
|
@Schema(description = "last time the feed was refreshed", type = "number")
|
||||||
private Date lastRefresh;
|
private Instant lastRefresh;
|
||||||
|
|
||||||
@Schema(description = "next time the feed refresh is planned, null if refresh is already queued", type = "number")
|
@Schema(description = "next time the feed refresh is planned, null if refresh is already queued", type = "number")
|
||||||
private Date nextRefresh;
|
private Instant nextRefresh;
|
||||||
|
|
||||||
@Schema(description = "this subscription's feed url", requiredMode = RequiredMode.REQUIRED)
|
@Schema(description = "this subscription's feed url", requiredMode = RequiredMode.REQUIRED)
|
||||||
private String feedUrl;
|
private String feedUrl;
|
||||||
@@ -54,13 +54,12 @@ public class Subscription implements Serializable {
|
|||||||
private int position;
|
private int position;
|
||||||
|
|
||||||
@Schema(description = "date of the newest item", type = "number")
|
@Schema(description = "date of the newest item", type = "number")
|
||||||
private Date newestItemTime;
|
private Instant newestItemTime;
|
||||||
|
|
||||||
@Schema(description = "JEXL string evaluated on new entries to mark them as read if they do not match")
|
@Schema(description = "JEXL string evaluated on new entries to mark them as read if they do not match")
|
||||||
private String filter;
|
private String filter;
|
||||||
|
|
||||||
public static Subscription build(FeedSubscription subscription, UnreadCount unreadCount) {
|
public static Subscription build(FeedSubscription subscription, UnreadCount unreadCount) {
|
||||||
Date now = new Date();
|
|
||||||
FeedCategory category = subscription.getCategory();
|
FeedCategory category = subscription.getCategory();
|
||||||
Feed feed = subscription.getFeed();
|
Feed feed = subscription.getFeed();
|
||||||
Subscription sub = new Subscription();
|
Subscription sub = new Subscription();
|
||||||
@@ -73,7 +72,8 @@ public class Subscription implements Serializable {
|
|||||||
sub.setFeedLink(feed.getLink());
|
sub.setFeedLink(feed.getLink());
|
||||||
sub.setIconUrl(FeedUtils.getFaviconUrl(subscription));
|
sub.setIconUrl(FeedUtils.getFaviconUrl(subscription));
|
||||||
sub.setLastRefresh(feed.getLastUpdated());
|
sub.setLastRefresh(feed.getLastUpdated());
|
||||||
sub.setNextRefresh((feed.getDisabledUntil() != null && feed.getDisabledUntil().before(now)) ? null : feed.getDisabledUntil());
|
sub.setNextRefresh(
|
||||||
|
(feed.getDisabledUntil() != null && feed.getDisabledUntil().isBefore(Instant.now())) ? null : feed.getDisabledUntil());
|
||||||
sub.setUnread(unreadCount.getUnreadCount());
|
sub.setUnread(unreadCount.getUnreadCount());
|
||||||
sub.setNewestItemTime(unreadCount.getNewestItemTime());
|
sub.setNewestItemTime(unreadCount.getNewestItemTime());
|
||||||
sub.setCategoryId(category == null ? null : String.valueOf(category.getId()));
|
sub.setCategoryId(category == null ? null : String.valueOf(category.getId()));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.frontend.model;
|
package com.commafeed.frontend.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -18,12 +18,12 @@ public class UnreadCount implements Serializable {
|
|||||||
private long unreadCount;
|
private long unreadCount;
|
||||||
|
|
||||||
@Schema(type = "number")
|
@Schema(type = "number")
|
||||||
private Date newestItemTime;
|
private Instant newestItemTime;
|
||||||
|
|
||||||
public UnreadCount() {
|
public UnreadCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnreadCount(long feedId, long unreadCount, Date newestItemTime) {
|
public UnreadCount(long feedId, long unreadCount, Instant newestItemTime) {
|
||||||
this.feedId = feedId;
|
this.feedId = feedId;
|
||||||
this.unreadCount = unreadCount;
|
this.unreadCount = unreadCount;
|
||||||
this.newestItemTime = newestItemTime;
|
this.newestItemTime = newestItemTime;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.commafeed.frontend.model;
|
package com.commafeed.frontend.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||||
@@ -31,10 +31,10 @@ public class UserModel implements Serializable {
|
|||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
|
|
||||||
@Schema(description = "account creation date", type = "number")
|
@Schema(description = "account creation date", type = "number")
|
||||||
private Date created;
|
private Instant created;
|
||||||
|
|
||||||
@Schema(description = "last login date", type = "number")
|
@Schema(description = "last login date", type = "number")
|
||||||
private Date lastLogin;
|
private Instant lastLogin;
|
||||||
|
|
||||||
@Schema(description = "user is admin", requiredMode = RequiredMode.REQUIRED)
|
@Schema(description = "user is admin", requiredMode = RequiredMode.REQUIRED)
|
||||||
private boolean admin;
|
private boolean admin;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.commafeed.frontend.resource;
|
package com.commafeed.frontend.resource;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -131,7 +131,7 @@ public class CategoryREST {
|
|||||||
id = ALL;
|
id = ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date newerThanDate = newerThan == null ? null : new Date(newerThan);
|
Instant newerThanDate = newerThan == null ? null : Instant.ofEpochMilli(newerThan);
|
||||||
|
|
||||||
List<Long> excludedIds = null;
|
List<Long> excludedIds = null;
|
||||||
if (StringUtils.isNotEmpty(excludedSubscriptionIds)) {
|
if (StringUtils.isNotEmpty(excludedSubscriptionIds)) {
|
||||||
@@ -242,8 +242,8 @@ public class CategoryREST {
|
|||||||
Preconditions.checkNotNull(req);
|
Preconditions.checkNotNull(req);
|
||||||
Preconditions.checkNotNull(req.getId());
|
Preconditions.checkNotNull(req.getId());
|
||||||
|
|
||||||
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
Instant olderThan = req.getOlderThan() == null ? null : Instant.ofEpochMilli(req.getOlderThan());
|
||||||
Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore());
|
Instant insertedBefore = req.getInsertedBefore() == null ? null : Instant.ofEpochMilli(req.getInsertedBefore());
|
||||||
String keywords = req.getKeywords();
|
String keywords = req.getKeywords();
|
||||||
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.io.InputStream;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -164,7 +165,7 @@ public class FeedREST {
|
|||||||
|
|
||||||
boolean unreadOnly = readType == ReadingMode.unread;
|
boolean unreadOnly = readType == ReadingMode.unread;
|
||||||
|
|
||||||
Date newerThanDate = newerThan == null ? null : new Date(newerThan);
|
Instant newerThanDate = newerThan == null ? null : Instant.ofEpochMilli(newerThan);
|
||||||
|
|
||||||
FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(id));
|
FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(id));
|
||||||
if (subscription != null) {
|
if (subscription != null) {
|
||||||
@@ -321,8 +322,8 @@ public class FeedREST {
|
|||||||
Preconditions.checkNotNull(req);
|
Preconditions.checkNotNull(req);
|
||||||
Preconditions.checkNotNull(req.getId());
|
Preconditions.checkNotNull(req.getId());
|
||||||
|
|
||||||
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
Instant olderThan = req.getOlderThan() == null ? null : Instant.ofEpochMilli(req.getOlderThan());
|
||||||
Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore());
|
Instant insertedBefore = req.getInsertedBefore() == null ? null : Instant.ofEpochMilli(req.getInsertedBefore());
|
||||||
String keywords = req.getKeywords();
|
String keywords = req.getKeywords();
|
||||||
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
@@ -379,7 +380,7 @@ public class FeedREST {
|
|||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.add(Calendar.MONTH, 1);
|
calendar.add(Calendar.MONTH, 1);
|
||||||
builder.expires(calendar.getTime());
|
builder.expires(calendar.getTime());
|
||||||
builder.lastModified(CommaFeedApplication.STARTUP_TIME);
|
builder.lastModified(Date.from(CommaFeedApplication.STARTUP_TIME));
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.commafeed.frontend.resource;
|
package com.commafeed.frontend.resource;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
import org.apache.hc.core5.net.URIBuilder;
|
import org.apache.hc.core5.net.URIBuilder;
|
||||||
|
|
||||||
import com.codahale.metrics.annotation.Timed;
|
import com.codahale.metrics.annotation.Timed;
|
||||||
@@ -282,7 +282,7 @@ public class UserREST {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
user.setRecoverPasswordToken(DigestUtils.sha1Hex(UUID.randomUUID().toString()));
|
user.setRecoverPasswordToken(DigestUtils.sha1Hex(UUID.randomUUID().toString()));
|
||||||
user.setRecoverPasswordTokenDate(new Date());
|
user.setRecoverPasswordTokenDate(Instant.now());
|
||||||
userDAO.saveOrUpdate(user);
|
userDAO.saveOrUpdate(user);
|
||||||
mailService.sendMail(user, "Password recovery", buildEmailContent(user));
|
mailService.sendMail(user, "Password recovery", buildEmailContent(user));
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
@@ -325,7 +325,7 @@ public class UserREST {
|
|||||||
if (user.getRecoverPasswordToken() == null || !user.getRecoverPasswordToken().equals(token)) {
|
if (user.getRecoverPasswordToken() == null || !user.getRecoverPasswordToken().equals(token)) {
|
||||||
return Response.status(Status.UNAUTHORIZED).entity("Invalid token.").build();
|
return Response.status(Status.UNAUTHORIZED).entity("Invalid token.").build();
|
||||||
}
|
}
|
||||||
if (user.getRecoverPasswordTokenDate().before(DateUtils.addDays(new Date(), -2))) {
|
if (ChronoUnit.DAYS.between(user.getRecoverPasswordTokenDate(), Instant.now()) >= 2) {
|
||||||
return Response.status(Status.UNAUTHORIZED).entity("token expired.").build();
|
return Response.status(Status.UNAUTHORIZED).entity("token expired.").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -189,7 +188,7 @@ public class FeverREST {
|
|||||||
if (params.containsKey("mark") && params.containsKey("id") && params.containsKey("as")) {
|
if (params.containsKey("mark") && params.containsKey("id") && params.containsKey("as")) {
|
||||||
long id = Long.parseLong(params.get("id"));
|
long id = Long.parseLong(params.get("id"));
|
||||||
String before = params.get("before");
|
String before = params.get("before");
|
||||||
Date insertedBefore = before == null ? null : Date.from(Instant.ofEpochSecond(Long.parseLong(before)));
|
Instant insertedBefore = before == null ? null : Instant.ofEpochSecond(Long.parseLong(before));
|
||||||
mark(user, params.get("mark"), id, params.get("as"), insertedBefore);
|
mark(user, params.get("mark"), id, params.get("as"), insertedBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +205,7 @@ public class FeverREST {
|
|||||||
.map(Feed::getLastUpdated)
|
.map(Feed::getLastUpdated)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.max(Comparator.naturalOrder())
|
.max(Comparator.naturalOrder())
|
||||||
.map(d -> d.toInstant().getEpochSecond())
|
.map(d -> d.getEpochSecond())
|
||||||
.orElse(0L);
|
.orElse(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +241,7 @@ public class FeverREST {
|
|||||||
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(s.getFeed().getLastUpdated() == null ? 0 : s.getFeed().getLastUpdated().toInstant().getEpochSecond());
|
f.setLastUpdatedOnTime(s.getFeed().getLastUpdated() == null ? 0 : s.getFeed().getLastUpdated().getEpochSecond());
|
||||||
return f;
|
return f;
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
@@ -291,7 +290,7 @@ public class FeverREST {
|
|||||||
i.setUrl(s.getEntry().getUrl());
|
i.setUrl(s.getEntry().getUrl());
|
||||||
i.setSaved(s.isStarred());
|
i.setSaved(s.isStarred());
|
||||||
i.setRead(s.isRead());
|
i.setRead(s.isRead());
|
||||||
i.setCreatedOnTime(s.getEntryUpdated().toInstant().getEpochSecond());
|
i.setCreatedOnTime(s.getEntryUpdated().getEpochSecond());
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +305,7 @@ public class FeverREST {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mark(User user, String source, long id, String action, Date insertedBefore) {
|
private void mark(User user, String source, long id, String action, Instant insertedBefore) {
|
||||||
if ("item".equals(source)) {
|
if ("item".equals(source)) {
|
||||||
if ("read".equals(action) || "unread".equals(action)) {
|
if ("read".equals(action) || "unread".equals(action)) {
|
||||||
feedEntryService.markEntry(user, id, "read".equals(action));
|
feedEntryService.markEntry(user, id, "read".equals(action));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
@@ -49,7 +49,7 @@ class FeedFetcherTest {
|
|||||||
.thenReturn(new HttpResult(content, "content-type", "last-modified-2", "etag-2", 20, null));
|
.thenReturn(new HttpResult(content, "content-type", "last-modified-2", "etag-2", 20, null));
|
||||||
|
|
||||||
NotModifiedException e = Assertions.assertThrows(NotModifiedException.class,
|
NotModifiedException e = Assertions.assertThrows(NotModifiedException.class,
|
||||||
() -> fetcher.fetch(url, false, lastModified, etag, new Date(), lastContentHash));
|
() -> fetcher.fetch(url, false, lastModified, etag, Instant.now(), lastContentHash));
|
||||||
|
|
||||||
Assertions.assertEquals("last-modified-2", e.getNewLastModifiedHeader());
|
Assertions.assertEquals("last-modified-2", e.getNewLastModifiedHeader());
|
||||||
Assertions.assertEquals("etag-2", e.getNewEtagHeader());
|
Assertions.assertEquals("etag-2", e.getNewEtagHeader());
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package com.commafeed.e2e;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.text.SimpleDateFormat;
|
import java.time.Instant;
|
||||||
import java.util.Date;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
@@ -115,7 +115,7 @@ public class PlaywrightTestBase {
|
|||||||
|
|
||||||
private String getFileName(ExtensionContext context) {
|
private String getFileName(ExtensionContext context) {
|
||||||
return String.format("%s.%s-%s", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(),
|
return String.format("%s.%s-%s", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(),
|
||||||
new SimpleDateFormat("yyyy-MM-dd--HH-mm-ss").format(new Date()));
|
DateTimeFormatter.ofPattern("yyyy-MM-dd--HH-mm-ss").format(Instant.now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveScreenshot(PlaywrightTestBase testInstance, String fileName) {
|
private void saveScreenshot(PlaywrightTestBase testInstance, String fileName) {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package com.commafeed.integration.rest;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Calendar;
|
import java.time.Instant;
|
||||||
import java.util.Date;
|
import java.time.LocalDate;
|
||||||
import java.util.GregorianCalendar;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
@@ -99,13 +99,13 @@ class FeedIT extends BaseIT {
|
|||||||
@Test
|
@Test
|
||||||
void markOlderThan() {
|
void markOlderThan() {
|
||||||
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
||||||
markFeedEntries(subscriptionId, new GregorianCalendar(2023, Calendar.DECEMBER, 28).getTime(), null);
|
markFeedEntries(subscriptionId, LocalDate.of(2023, 12, 28).atStartOfDay().toInstant(ZoneOffset.UTC), null);
|
||||||
Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
|
Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void markInsertedBeforeBeforeSubscription() {
|
void markInsertedBeforeBeforeSubscription() {
|
||||||
Date insertedBefore = new Date();
|
Instant insertedBefore = Instant.now();
|
||||||
|
|
||||||
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
||||||
markFeedEntries(subscriptionId, null, insertedBefore);
|
markFeedEntries(subscriptionId, null, insertedBefore);
|
||||||
@@ -116,17 +116,17 @@ class FeedIT extends BaseIT {
|
|||||||
void markInsertedBeforeAfterSubscription() {
|
void markInsertedBeforeAfterSubscription() {
|
||||||
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
||||||
|
|
||||||
Date insertedBefore = new Date();
|
Instant insertedBefore = Instant.now();
|
||||||
|
|
||||||
markFeedEntries(subscriptionId, null, insertedBefore);
|
markFeedEntries(subscriptionId, null, insertedBefore);
|
||||||
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
|
Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markFeedEntries(long subscriptionId, Date olderThan, Date insertedBefore) {
|
private void markFeedEntries(long subscriptionId, Instant olderThan, Instant insertedBefore) {
|
||||||
MarkRequest request = new MarkRequest();
|
MarkRequest request = new MarkRequest();
|
||||||
request.setId(String.valueOf(subscriptionId));
|
request.setId(String.valueOf(subscriptionId));
|
||||||
request.setOlderThan(olderThan == null ? null : olderThan.getTime());
|
request.setOlderThan(olderThan == null ? null : olderThan.toEpochMilli());
|
||||||
request.setInsertedBefore(insertedBefore == null ? null : insertedBefore.getTime());
|
request.setInsertedBefore(insertedBefore == null ? null : insertedBefore.toEpochMilli());
|
||||||
getClient().target(getApiBaseUrl() + "feed/mark").request().post(Entity.json(request), Void.TYPE);
|
getClient().target(getApiBaseUrl() + "feed/mark").request().post(Entity.json(request), Void.TYPE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,26 +137,26 @@ class FeedIT extends BaseIT {
|
|||||||
void refresh() {
|
void refresh() {
|
||||||
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
||||||
|
|
||||||
Date now = new Date();
|
Instant now = Instant.now();
|
||||||
IDRequest request = new IDRequest();
|
IDRequest request = new IDRequest();
|
||||||
request.setId(subscriptionId);
|
request.setId(subscriptionId);
|
||||||
getClient().target(getApiBaseUrl() + "feed/refresh").request().post(Entity.json(request), Void.TYPE);
|
getClient().target(getApiBaseUrl() + "feed/refresh").request().post(Entity.json(request), Void.TYPE);
|
||||||
|
|
||||||
Awaitility.await()
|
Awaitility.await()
|
||||||
.atMost(Duration.ofSeconds(15))
|
.atMost(Duration.ofSeconds(15))
|
||||||
.until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().after(now));
|
.until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().isAfter(now));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void refreshAll() {
|
void refreshAll() {
|
||||||
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl());
|
||||||
|
|
||||||
Date now = new Date();
|
Instant now = Instant.now();
|
||||||
getClient().target(getApiBaseUrl() + "feed/refreshAll").request().get(Void.TYPE);
|
getClient().target(getApiBaseUrl() + "feed/refreshAll").request().get(Void.TYPE);
|
||||||
|
|
||||||
Awaitility.await()
|
Awaitility.await()
|
||||||
.atMost(Duration.ofSeconds(15))
|
.atMost(Duration.ofSeconds(15))
|
||||||
.until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().after(now));
|
.until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().isAfter(now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user