add a "insertedBefore" field to mark as read requests to make sure the user does not mark entries that were fetched but never seen before (fixes a regression from #1007)

This commit is contained in:
Athou
2023-12-29 13:30:14 +01:00
parent 39ba4a1c97
commit f845f225cf
8 changed files with 41 additions and 32 deletions

View File

@@ -113,6 +113,7 @@ export interface MarkRequest {
id: string
read: boolean
olderThan?: number
insertedBefore?: number
keywords?: string
excludedSubscriptions?: number[]
}

View File

@@ -279,7 +279,8 @@ export function FeedEntries() {
req: {
id: source.id,
read: true,
olderThan: entriesTimestamp,
olderThan: Date.now(),
insertedBefore: entriesTimestamp,
},
})
)

View File

@@ -27,7 +27,8 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
req: {
id: source.id,
read: true,
olderThan: entriesTimestamp,
olderThan: Date.now(),
insertedBefore: entriesTimestamp,
},
})
)
@@ -78,7 +79,8 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
req: {
id: source.id,
read: true,
olderThan: entriesTimestamp - threshold * 24 * 60 * 60 * 1000,
olderThan: Date.now() - threshold * 24 * 60 * 60 * 1000,
insertedBefore: entriesTimestamp,
},
})
)

View File

@@ -1,6 +1,5 @@
package com.commafeed.backend.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -108,30 +107,30 @@ public class FeedEntryService {
feedEntryStatusDAO.saveOrUpdate(status);
}
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Date olderThan, List<FeedEntryKeyword> keywords) {
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Date olderThan, Date insertedBefore,
List<FeedEntryKeyword> keywords) {
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null,
false, false, null, null, null);
markList(statuses, olderThan);
markList(statuses, olderThan, insertedBefore);
cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
cache.invalidateUserRootCategory(user);
}
public void markStarredEntries(User user, Date olderThan) {
public void markStarredEntries(User user, Date olderThan, Date insertedBefore) {
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findStarred(user, null, -1, -1, null, false);
markList(statuses, olderThan);
markList(statuses, olderThan, insertedBefore);
}
private void markList(List<FeedEntryStatus> statuses, Date olderThan) {
List<FeedEntryStatus> list = new ArrayList<>();
for (FeedEntryStatus status : statuses) {
if (!status.isRead()) {
Date entryDate = status.getEntry().getUpdated();
if (olderThan == null || entryDate == null || olderThan.after(entryDate)) {
status.setRead(true);
list.add(status);
}
}
}
feedEntryStatusDAO.saveOrUpdate(list);
private void markList(List<FeedEntryStatus> statuses, Date olderThan, Date insertedBefore) {
List<FeedEntryStatus> statusesToMark = statuses.stream().filter(s -> {
Date entryDate = s.getEntry().getUpdated();
return olderThan == null || entryDate == null || entryDate.before(olderThan);
}).filter(s -> {
Date insertedDate = s.getEntry().getInserted();
return insertedBefore == null || insertedDate == null || insertedDate.before(insertedBefore);
}).toList();
statusesToMark.forEach(s -> s.setRead(true));
feedEntryStatusDAO.saveOrUpdate(statusesToMark);
}
}

View File

@@ -22,11 +22,14 @@ public class MarkRequest implements Serializable {
@Schema(description = "mark as read or unread", requiredMode = RequiredMode.REQUIRED)
private boolean read;
@Schema(
description = "only entries older than this, pass the timestamp you got from the entry list to prevent marking an entry that was not retrieved",
requiredMode = RequiredMode.NOT_REQUIRED)
@Schema(description = "mark only entries older than this", requiredMode = RequiredMode.NOT_REQUIRED)
private Long olderThan;
@Schema(
description = "pass the timestamp you got from the entry list to avoid marking entries that may have been fetched in the mean time and never displayed",
requiredMode = RequiredMode.NOT_REQUIRED)
private Long insertedBefore;
@Schema(
description = "only mark read if a feed has these keywords in the title or rss content",
requiredMode = RequiredMode.NOT_REQUIRED)

View File

@@ -243,21 +243,22 @@ public class CategoryREST {
Preconditions.checkNotNull(req.getId());
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore());
String keywords = req.getKeywords();
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
if (ALL.equals(req.getId())) {
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
feedEntryService.markSubscriptionEntries(user, subs, olderThan, entryKeywords);
feedEntryService.markSubscriptionEntries(user, subs, olderThan, insertedBefore, entryKeywords);
} else if (STARRED.equals(req.getId())) {
feedEntryService.markStarredEntries(user, olderThan);
feedEntryService.markStarredEntries(user, olderThan, insertedBefore);
} else {
FeedCategory parent = feedCategoryDAO.findById(user, Long.valueOf(req.getId()));
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(user, categories);
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
feedEntryService.markSubscriptionEntries(user, subs, olderThan, entryKeywords);
feedEntryService.markSubscriptionEntries(user, subs, olderThan, insertedBefore, entryKeywords);
}
return Response.ok().build();
}

View File

@@ -322,12 +322,14 @@ public class FeedREST {
Preconditions.checkNotNull(req.getId());
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore());
String keywords = req.getKeywords();
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(req.getId()));
if (subscription != null) {
feedEntryService.markSubscriptionEntries(user, Collections.singletonList(subscription), olderThan, entryKeywords);
feedEntryService.markSubscriptionEntries(user, Collections.singletonList(subscription), olderThan, insertedBefore,
entryKeywords);
}
return Response.ok().build();
}

View File

@@ -189,8 +189,8 @@ public class FeverREST {
if (params.containsKey("mark") && params.containsKey("id") && params.containsKey("as")) {
long id = Long.parseLong(params.get("id"));
String before = params.get("before");
Date olderThan = before == null ? null : Date.from(Instant.ofEpochSecond(Long.parseLong(before)));
mark(user, params.get("mark"), id, params.get("as"), olderThan);
Date insertedBefore = before == null ? null : Date.from(Instant.ofEpochSecond(Long.parseLong(before)));
mark(user, params.get("mark"), id, params.get("as"), insertedBefore);
}
return resp;
@@ -306,7 +306,7 @@ public class FeverREST {
}).toList();
}
private void mark(User user, String source, long id, String action, Date olderThan) {
private void mark(User user, String source, long id, String action, Date insertedBefore) {
if ("item".equals(source)) {
if ("read".equals(action) || "unread".equals(action)) {
feedEntryService.markEntry(user, id, "read".equals(action));
@@ -317,12 +317,12 @@ public class FeverREST {
}
} else if ("feed".equals(source)) {
FeedSubscription subscription = feedSubscriptionDAO.findById(user, id);
feedEntryService.markSubscriptionEntries(user, Collections.singletonList(subscription), olderThan, null);
feedEntryService.markSubscriptionEntries(user, Collections.singletonList(subscription), null, insertedBefore, null);
} else if ("group".equals(source)) {
FeedCategory parent = feedCategoryDAO.findById(user, id);
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user, categories);
feedEntryService.markSubscriptionEntries(user, subscriptions, olderThan, null);
feedEntryService.markSubscriptionEntries(user, subscriptions, null, insertedBefore, null);
}
}