diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java index 7dea7478..a4026bf8 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java @@ -163,7 +163,6 @@ public class FeedEntryStatusDAO extends GenericDAO { public List findAll(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) { - log.info("new findAll"); CriteriaQuery query = builder.createTupleQuery(); Root root = query.from(FeedEntry.class); @@ -203,6 +202,7 @@ public class FeedEntryStatusDAO extends GenericDAO { if (status == null) { status = new FeedEntryStatus(); status.setEntry(entry); + status.setRead(true); status.setSubscription(subscription); } results.add(status); @@ -247,16 +247,61 @@ public class FeedEntryStatusDAO extends GenericDAO { } public List findBySubscription( - FeedSubscription subscription, boolean unreadOnly, - ReadingOrder order, boolean includeContent) { - return findBySubscription(subscription, unreadOnly, null, -1, -1, - order, includeContent); + FeedSubscription subscription, Date newerThan, int offset, + int limit, ReadingOrder order, boolean includeContent) { + + CriteriaQuery query = builder.createQuery(FeedEntry.class); + Root root = query.from(FeedEntry.class); + + SetJoin feedJoin = root.join(FeedEntry_.feeds); + SetJoin subJoin = feedJoin + .join(Feed_.subscriptions); + + List predicates = Lists.newArrayList(); + + predicates.add(builder.equal(subJoin.get(FeedSubscription_.id), + subscription.getId())); + + if (newerThan != null) { + predicates.add(builder.greaterThanOrEqualTo( + root.get(FeedEntry_.inserted), newerThan)); + } + + query.where(predicates.toArray(new Predicate[0])); + orderBy(query, root, order); + + TypedQuery q = em.createQuery(query); + limit(q, offset, limit); + setTimeout(q); + + List list = q.getResultList(); + List results = Lists.newArrayList(); + for (FeedEntry entry : list) { + FeedEntryStatus status = findByEntry(entry, subscription); + if (status == null) { + status = new FeedEntryStatus(); + status.setEntry(entry); + status.setSubscription(subscription); + status.setRead(true); + } + results.add(status); + } + + return lazyLoadContent(includeContent, results); } - public List findBySubscription( - FeedSubscription subscription, boolean unreadOnly, Date newerThan, - int offset, int limit, ReadingOrder order, boolean includeContent) { + public List findUnreadBySubscription( + FeedSubscription subscription, ReadingOrder order, + boolean includeContent) { + return findUnreadBySubscription(subscription, null, -1, -1, order, + includeContent); + } + public List findUnreadBySubscription( + FeedSubscription subscription, Date newerThan, int offset, + int limit, ReadingOrder order, boolean includeContent) { + + log.info("findUnreadBySubscription"); CriteriaQuery query = builder.createQuery(getType()); Root root = query.from(getType()); @@ -267,9 +312,7 @@ public class FeedEntryStatusDAO extends GenericDAO { predicates.add(builder.equal(root.get(FeedEntryStatus_.subscription), subscription)); - if (unreadOnly) { - predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); - } + predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); if (newerThan != null) { predicates.add(builder.greaterThanOrEqualTo( @@ -287,16 +330,73 @@ public class FeedEntryStatusDAO extends GenericDAO { } public List findByCategories( - List categories, User user, boolean unreadOnly, - ReadingOrder order, boolean includeContent) { - return findByCategories(categories, user, unreadOnly, null, -1, -1, - order, includeContent); + List categories, Date newerThan, int offset, + int limit, ReadingOrder order, boolean includeContent) { + + CriteriaQuery query = builder.createTupleQuery(); + Root root = query.from(FeedEntry.class); + + SetJoin feedJoin = root.join(FeedEntry_.feeds); + SetJoin subJoin = feedJoin + .join(Feed_.subscriptions); + + Selection entryAlias = root.alias("entry"); + Selection subAlias = subJoin.alias("subscription"); + query.multiselect(entryAlias, subAlias); + + List predicates = Lists.newArrayList(); + + if (categories.size() == 1) { + predicates.add(builder.equal(subJoin + .get(FeedSubscription_.category), categories.iterator() + .next())); + } else { + predicates.add(subJoin.get(FeedSubscription_.category).in( + categories)); + } + + if (newerThan != null) { + predicates.add(builder.greaterThanOrEqualTo( + root.get(FeedEntry_.inserted), newerThan)); + } + + query.where(predicates.toArray(new Predicate[0])); + orderBy(query, root, order); + + TypedQuery q = em.createQuery(query); + limit(q, offset, limit); + setTimeout(q); + + List list = q.getResultList(); + List results = Lists.newArrayList(); + for (Tuple tuple : list) { + FeedEntry entry = tuple.get(entryAlias); + FeedSubscription subscription = tuple.get(subAlias); + + FeedEntryStatus status = findByEntry(entry, subscription); + if (status == null) { + status = new FeedEntryStatus(); + status.setEntry(entry); + status.setSubscription(subscription); + status.setRead(true); + } + results.add(status); + } + + return lazyLoadContent(includeContent, results); + } - public List findByCategories( - List categories, User user, boolean unreadOnly, - Date newerThan, int offset, int limit, ReadingOrder order, + public List findUnreadByCategories( + List categories, ReadingOrder order, boolean includeContent) { + return findUnreadByCategories(categories, null, -1, -1, order, + includeContent); + } + + public List findUnreadByCategories( + List categories, Date newerThan, int offset, + int limit, ReadingOrder order, boolean includeContent) { CriteriaQuery query = builder.createQuery(getType()); Root root = query.from(getType()); @@ -308,9 +408,6 @@ public class FeedEntryStatusDAO extends GenericDAO { Join subJoin = root .join(FeedEntryStatus_.subscription); - predicates - .add(builder.equal(subJoin.get(FeedSubscription_.user), user)); - if (categories.size() == 1) { predicates.add(builder.equal(subJoin .get(FeedSubscription_.category), categories.iterator() @@ -320,9 +417,7 @@ public class FeedEntryStatusDAO extends GenericDAO { categories)); } - if (unreadOnly) { - predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); - } + predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); if (newerThan != null) { predicates.add(builder.greaterThanOrEqualTo( @@ -384,41 +479,46 @@ public class FeedEntryStatusDAO extends GenericDAO { public void markSubscriptionEntries(FeedSubscription subscription, Date olderThan) { - List statuses = findBySubscription(subscription, true, + List statuses = findUnreadBySubscription(subscription, null, false); - saveOrUpdate(markList(statuses, olderThan)); + markList(statuses, olderThan); } public void markCategoryEntries(User user, List categories, Date olderThan) { - List statuses = findByCategories(categories, user, - true, null, false); - saveOrUpdate(markList(statuses, olderThan)); + List statuses = findUnreadByCategories(categories, + null, false); + markList(statuses, olderThan); } public void markStarredEntries(User user, Date olderThan) { List statuses = findStarred(user, null, false); - saveOrUpdate(markList(statuses, olderThan)); + markList(statuses, olderThan); } public void markAllEntries(User user, Date olderThan) { List statuses = findAllUnread(user, null, false); - saveOrUpdate(markList(statuses, olderThan)); + markList(statuses, olderThan); } - private List markList(List statuses, - Date olderThan) { + private void markList(List statuses, Date olderThan) { List list = Lists.newArrayList(); for (FeedEntryStatus status : statuses) { if (!status.isRead()) { Date inserted = status.getEntry().getInserted(); if (olderThan == null || inserted == null || olderThan.after(inserted)) { - status.setRead(true); - list.add(status); + if (status.isStarred()) { + status.setRead(true); + list.add(status); + } else { + delete(status); + } + } } } - return list; + saveOrUpdate(list); } + } diff --git a/src/main/java/com/commafeed/backend/services/FeedEntryService.java b/src/main/java/com/commafeed/backend/services/FeedEntryService.java index f09f9c10..20aa0aed 100644 --- a/src/main/java/com/commafeed/backend/services/FeedEntryService.java +++ b/src/main/java/com/commafeed/backend/services/FeedEntryService.java @@ -4,7 +4,10 @@ import javax.ejb.Stateless; import javax.inject.Inject; import com.commafeed.backend.dao.FeedEntryStatusDAO; +import com.commafeed.backend.dao.FeedSubscriptionDAO; +import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntryStatus; +import com.commafeed.backend.model.FeedSubscription; import com.commafeed.backend.model.User; @Stateless @@ -13,18 +16,74 @@ public class FeedEntryService { @Inject FeedEntryStatusDAO feedEntryStatusDAO; - public void markEntry(User user, Long entryId, boolean read) { - FeedEntryStatus status = feedEntryStatusDAO.findById(user, entryId); - if (status != null) { - status.setRead(read); + @Inject + FeedSubscriptionDAO feedSubscriptionDAO; + + public void markEntry(User user, Long entryId, Long subscriptionId, + boolean read) { + FeedSubscription sub = feedSubscriptionDAO.findById(user, + subscriptionId); + if (sub == null) { + return; + } + + FeedEntry entry = new FeedEntry(); + entry.setId(entryId); + + FeedEntryStatus status = feedEntryStatusDAO.findByEntry(entry, sub); + + if (read) { + if (status != null) { + if (status.isStarred()) { + status.setRead(true); + feedEntryStatusDAO.saveOrUpdate(status); + } else { + feedEntryStatusDAO.delete(status); + } + } + } else { + if (status == null) { + status = new FeedEntryStatus(); + status.setEntry(entry); + status.setSubscription(sub); + } + status.setRead(false); feedEntryStatusDAO.saveOrUpdate(status); } + } - public void starEntry(User user, Long entryId, boolean starred) { - FeedEntryStatus status = feedEntryStatusDAO.findById(user, entryId); - if (status != null) { - status.setStarred(starred); + public void starEntry(User user, Long entryId, Long subscriptionId, + boolean starred) { + + FeedSubscription sub = feedSubscriptionDAO.findById(user, + subscriptionId); + if (sub == null) { + return; + } + + FeedEntry entry = new FeedEntry(); + entry.setId(entryId); + + FeedEntryStatus status = feedEntryStatusDAO.findByEntry(entry, sub); + + if (!starred) { + if (status != null) { + if (!status.isRead()) { + status.setStarred(false); + feedEntryStatusDAO.saveOrUpdate(status); + } else { + feedEntryStatusDAO.delete(status); + } + } + } else { + if (status == null) { + status = new FeedEntryStatus(); + status.setEntry(entry); + status.setSubscription(sub); + status.setRead(true); + } + status.setStarred(true); feedEntryStatusDAO.saveOrUpdate(status); } } diff --git a/src/main/java/com/commafeed/frontend/model/Entry.java b/src/main/java/com/commafeed/frontend/model/Entry.java index 945a84a9..dbb4264d 100644 --- a/src/main/java/com/commafeed/frontend/model/Entry.java +++ b/src/main/java/com/commafeed/frontend/model/Entry.java @@ -11,6 +11,7 @@ import javax.xml.bind.annotation.XmlRootElement; import com.commafeed.backend.feeds.FeedUtils; import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntryStatus; +import com.commafeed.backend.model.FeedSubscription; import com.sun.syndication.feed.synd.SyndContentImpl; import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.feed.synd.SyndEntryImpl; @@ -27,28 +28,28 @@ public class Entry implements Serializable { Entry entry = new Entry(); FeedEntry feedEntry = status.getEntry(); - entry.setId(String.valueOf(status.getId())); + FeedSubscription sub = status.getSubscription(); + + entry.setRead(status.isRead()); + entry.setStarred(status.isStarred()); + + entry.setId(String.valueOf(feedEntry.getId())); entry.setGuid(feedEntry.getGuid()); entry.setTitle(feedEntry.getContent().getTitle()); entry.setContent(feedEntry.getContent().getContent()); entry.setRtl(FeedUtils.isRTL(feedEntry)); entry.setAuthor(feedEntry.getAuthor()); - entry.setEnclosureUrl(status.getEntry().getContent().getEnclosureUrl()); - entry.setEnclosureType(status.getEntry().getContent() - .getEnclosureType()); + entry.setEnclosureUrl(feedEntry.getContent().getEnclosureUrl()); + entry.setEnclosureType(feedEntry.getContent().getEnclosureType()); entry.setDate(feedEntry.getUpdated()); entry.setInsertedDate(feedEntry.getInserted()); entry.setUrl(feedEntry.getUrl()); - entry.setRead(status.isRead()); - entry.setStarred(status.isStarred()); - - entry.setFeedName(status.getSubscription().getTitle()); - entry.setFeedId(String.valueOf(status.getSubscription().getId())); - entry.setFeedUrl(status.getSubscription().getFeed().getUrl()); - entry.setFeedLink(status.getSubscription().getFeed().getLink()); - entry.setIconUrl(FeedUtils.getFaviconUrl(status.getSubscription(), - publicUrl)); + entry.setFeedName(sub.getTitle()); + entry.setFeedId(String.valueOf(sub.getId())); + entry.setFeedUrl(sub.getFeed().getUrl()); + entry.setFeedLink(sub.getFeed().getLink()); + entry.setIconUrl(FeedUtils.getFaviconUrl(sub, publicUrl)); return entry; } diff --git a/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java b/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java index 28600eca..03891204 100644 --- a/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/MarkRequest.java @@ -15,9 +15,12 @@ import com.wordnik.swagger.annotations.ApiProperty; @ApiClass("Mark Request") public class MarkRequest implements Serializable { - @ApiProperty(value = "id", required = true) + @ApiProperty(value = "entry id, category id, 'all' or 'starred'", required = true) private String id; + @ApiProperty(value = "feed id, only required when marking an entry") + private Long feedId; + @ApiProperty(value = "mark as read or unread") private boolean read; @@ -48,4 +51,12 @@ public class MarkRequest implements Serializable { this.olderThan = olderThan; } + public Long getFeedId() { + return feedId; + } + + public void setFeedId(Long feedId) { + this.feedId = feedId; + } + } diff --git a/src/main/java/com/commafeed/frontend/model/request/StarRequest.java b/src/main/java/com/commafeed/frontend/model/request/StarRequest.java index b46865b9..76816aed 100644 --- a/src/main/java/com/commafeed/frontend/model/request/StarRequest.java +++ b/src/main/java/com/commafeed/frontend/model/request/StarRequest.java @@ -18,6 +18,9 @@ public class StarRequest implements Serializable { @ApiProperty(value = "id", required = true) private String id; + @ApiProperty(value = "feed id", required = true) + private Long feedId; + @ApiProperty(value = "starred or not") private boolean starred; @@ -37,4 +40,12 @@ public class StarRequest implements Serializable { this.starred = starred; } + public Long getFeedId() { + return feedId; + } + + public void setFeedId(Long feedId) { + this.feedId = feedId; + } + } diff --git a/src/main/java/com/commafeed/frontend/pages/NextUnreadRedirectPage.java b/src/main/java/com/commafeed/frontend/pages/NextUnreadRedirectPage.java index 32feae81..21c7f64e 100644 --- a/src/main/java/com/commafeed/frontend/pages/NextUnreadRedirectPage.java +++ b/src/main/java/com/commafeed/frontend/pages/NextUnreadRedirectPage.java @@ -49,8 +49,8 @@ public class NextUnreadRedirectPage extends WebPage { if (category != null) { List children = feedCategoryDAO .findAllChildrenCategories(user, category); - statuses = feedEntryStatusDAO.findByCategories(children, user, - true, null, 0, 1, ReadingOrder.desc, false); + statuses = feedEntryStatusDAO.findUnreadByCategories(children, + null, 0, 1, ReadingOrder.desc, false); } } diff --git a/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java b/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java index 0e144723..9a874e97 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/CategoryREST.java @@ -114,11 +114,17 @@ public class CategoryREST extends AbstractResourceREST { if (feedCategory != null) { List childrenCategories = feedCategoryDAO .findAllChildrenCategories(getUser(), feedCategory); - List unreadEntries = feedEntryStatusDAO - .findByCategories(childrenCategories, getUser(), - unreadOnly, newerThanDate, offset, limit + 1, - order, true); - for (FeedEntryStatus status : unreadEntries) { + List list = null; + if (unreadOnly) { + list = feedEntryStatusDAO.findUnreadByCategories( + childrenCategories, newerThanDate, offset, + limit + 1, order, true); + } else { + list = feedEntryStatusDAO.findByCategories( + childrenCategories, newerThanDate, offset, + limit + 1, order, true); + } + for (FeedEntryStatus status : list) { entries.getEntries().add( Entry.build(status, applicationSettingsService .get().getPublicUrl())); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java b/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java index adaaace9..dd42a988 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/EntryREST.java @@ -34,9 +34,10 @@ public class EntryREST extends AbstractResourceREST { @ApiParam(value = "Mark Request", required = true) MarkRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); + Preconditions.checkNotNull(req.getFeedId()); feedEntryService.markEntry(getUser(), Long.valueOf(req.getId()), - req.isRead()); + req.getFeedId(), req.isRead()); return Response.ok(Status.OK).build(); } @@ -48,9 +49,10 @@ public class EntryREST extends AbstractResourceREST { @ApiParam(value = "Star Request", required = true) StarRequest req) { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); + Preconditions.checkNotNull(req.getFeedId()); feedEntryService.starEntry(getUser(), Long.valueOf(req.getId()), - req.isStarred()); + req.getFeedId(), req.isStarred()); return Response.ok(Status.OK).build(); } diff --git a/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java b/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java index 687abc61..f9ae3809 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/FeedREST.java @@ -100,10 +100,17 @@ public class FeedREST extends AbstractResourceREST { entries.setMessage(subscription.getFeed().getMessage()); entries.setErrorCount(subscription.getFeed().getErrorCount()); - List unreadEntries = feedEntryStatusDAO - .findBySubscription(subscription, unreadOnly, - newerThanDate, offset, limit + 1, order, true); - for (FeedEntryStatus status : unreadEntries) { + List list = null; + if (unreadOnly) { + list = feedEntryStatusDAO.findUnreadBySubscription( + subscription, newerThanDate, offset, limit + 1, order, + true); + } else { + list = feedEntryStatusDAO.findBySubscription(subscription, + newerThanDate, offset, limit + 1, order, true); + } + + for (FeedEntryStatus status : list) { entries.getEntries().add( Entry.build(status, applicationSettingsService.get() .getPublicUrl())); @@ -202,16 +209,20 @@ public class FeedREST extends AbstractResourceREST { @POST @ApiOperation(value = "Queue a feed for refresh", notes = "Manually add a feed to the refresh queue") public Response queueForRefresh(@ApiParam(value = "Feed id") IDRequest req) { - Preconditions.checkNotNull(req); - Preconditions.checkNotNull(req.getId()); + // TODO evaluate if this is needed + + // Preconditions.checkNotNull(req); + // Preconditions.checkNotNull(req.getId()); + // + // FeedSubscription sub = feedSubscriptionDAO.findById(getUser(), + // req.getId()); + // if (sub != null) { + // taskGiver.add(sub.getFeed()); + // return Response.ok(Status.OK).build(); + // } + // return Response.ok(Status.NOT_FOUND).build(); - FeedSubscription sub = feedSubscriptionDAO.findById(getUser(), - req.getId()); - if (sub != null) { - taskGiver.add(sub.getFeed()); - return Response.ok(Status.OK).build(); - } - return Response.ok(Status.NOT_FOUND).build(); + return Response.ok("Disabled for now").build(); } @Path("/mark") diff --git a/src/main/webapp/js/controllers.js b/src/main/webapp/js/controllers.js index a5b70bfb..a8cda482 100644 --- a/src/main/webapp/js/controllers.js +++ b/src/main/webapp/js/controllers.js @@ -731,6 +731,7 @@ function($scope, $stateParams, $http, $route, $window, EntryService, SettingsSer }); EntryService.mark({ id : entry.id, + feedId : entry.feedId, read : read }); } @@ -759,6 +760,7 @@ function($scope, $stateParams, $http, $route, $window, EntryService, SettingsSer entry.starred = star; EntryService.star({ id : entry.id, + feedId : entry.feedId, starred : star }); }