diff --git a/pom.xml b/pom.xml index 4db521a4..ea2b1dfd 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ UTF-8 java:openejb/Resource/My DataSource - false + true diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java index bdb08797..4eb762cc 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java @@ -18,6 +18,7 @@ import org.apache.commons.lang.StringUtils; import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.FeedCategory; +import com.commafeed.backend.model.FeedEntryContent_; import com.commafeed.backend.model.FeedEntryStatus; import com.commafeed.backend.model.FeedEntryStatus_; import com.commafeed.backend.model.FeedEntry_; @@ -58,12 +59,7 @@ public class FeedEntryStatusService extends GenericDAO { } public List getStatusesByKeywords(User user, - String keywords) { - return getStatusesByKeywords(user, keywords, -1, -1); - } - - public List getStatusesByKeywords(User user, - String keywords, int offset, int limit) { + String keywords, int offset, int limit, boolean includeContent) { String joinedKeywords = StringUtils.join( keywords.toLowerCase().split(" "), "%"); @@ -76,13 +72,17 @@ public class FeedEntryStatusService extends GenericDAO { predicates.add(builder.equal(root.get(FeedEntryStatus_.subscription) .get(FeedSubscription_.user), user)); - Predicate content = builder.like( - builder.lower(root.get(FeedEntryStatus_.entry).get( - FeedEntry_.content)), joinedKeywords); + Predicate content = builder.like(builder.lower(root + .get(FeedEntryStatus_.entry).get(FeedEntry_.content) + .get(FeedEntryContent_.content)), joinedKeywords); Predicate title = builder.like( - builder.lower(root.get(FeedEntryStatus_.entry).get( - FeedEntry_.title)), joinedKeywords); + builder.lower(root.get(FeedEntryStatus_.entry) + .get(FeedEntry_.content).get(FeedEntryContent_.title)), + joinedKeywords); predicates.add(builder.or(content, title)); + if (includeContent) { + root.fetch(FeedEntryStatus_.entry).fetch(FeedEntry_.content); + } query.where(predicates.toArray(new Predicate[0])); @@ -94,12 +94,12 @@ public class FeedEntryStatusService extends GenericDAO { } public List getStatuses(User user, boolean unreadOnly, - ReadingOrder order) { - return getStatuses(user, unreadOnly, -1, -1, order); + ReadingOrder order, boolean includeContent) { + return getStatuses(user, unreadOnly, -1, -1, order, includeContent); } public List getStatuses(User user, boolean unreadOnly, - int offset, int limit, ReadingOrder order) { + int offset, int limit, ReadingOrder order, boolean includeContent) { CriteriaQuery query = builder.createQuery(getType()); Root root = query.from(getType()); @@ -109,6 +109,11 @@ public class FeedEntryStatusService extends GenericDAO { if (unreadOnly) { predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); } + + if (includeContent) { + root.fetch(FeedEntryStatus_.entry).fetch(FeedEntry_.content); + } + query.where(predicates.toArray(new Predicate[0])); orderBy(query, root, order); @@ -134,12 +139,14 @@ public class FeedEntryStatusService extends GenericDAO { } public List getStatuses(Feed feed, User user, - boolean unreadOnly, ReadingOrder order) { - return getStatuses(feed, user, unreadOnly, -1, -1, order); + boolean unreadOnly, ReadingOrder order, boolean includeContent) { + return getStatuses(feed, user, unreadOnly, -1, -1, order, + includeContent); } public List getStatuses(Feed feed, User user, - boolean unreadOnly, int offset, int limit, ReadingOrder order) { + boolean unreadOnly, int offset, int limit, ReadingOrder order, + boolean includeContent) { CriteriaQuery query = builder.createQuery(getType()); Root root = query.from(getType()); @@ -152,6 +159,11 @@ public class FeedEntryStatusService extends GenericDAO { if (unreadOnly) { predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); } + + if (includeContent) { + root.fetch(FeedEntryStatus_.entry).fetch(FeedEntry_.content); + } + query.where(predicates.toArray(new Predicate[0])); orderBy(query, root, order); @@ -162,13 +174,15 @@ public class FeedEntryStatusService extends GenericDAO { } public List getStatuses(List categories, - User user, boolean unreadOnly, ReadingOrder order) { - return getStatuses(categories, user, unreadOnly, -1, -1, order); + User user, boolean unreadOnly, ReadingOrder order, + boolean includeContent) { + return getStatuses(categories, user, unreadOnly, -1, -1, order, + includeContent); } public List getStatuses(List categories, User user, boolean unreadOnly, int offset, int limit, - ReadingOrder order) { + ReadingOrder order, boolean includeContent) { CriteriaQuery query = builder.createQuery(getType()); Root root = query.from(getType()); @@ -181,6 +195,11 @@ public class FeedEntryStatusService extends GenericDAO { if (unreadOnly) { predicates.add(builder.isFalse(root.get(FeedEntryStatus_.read))); } + + if (includeContent) { + root.fetch(FeedEntryStatus_.entry).fetch(FeedEntry_.content); + } + query.where(predicates.toArray(new Predicate[0])); orderBy(query, root, order); @@ -213,20 +232,20 @@ public class FeedEntryStatusService extends GenericDAO { public void markFeedEntries(User user, Feed feed, Date olderThan) { List statuses = getStatuses(feed, user, true, - ReadingOrder.desc); + ReadingOrder.desc, false); update(markList(statuses, olderThan)); } public void markCategoryEntries(User user, List categories, Date olderThan) { List statuses = getStatuses(categories, user, true, - ReadingOrder.desc); + ReadingOrder.desc, false); update(markList(statuses, olderThan)); } public void markAllEntries(User user, Date olderThan) { List statuses = getStatuses(user, true, - ReadingOrder.desc); + ReadingOrder.desc, false); update(markList(statuses, olderThan)); } diff --git a/src/main/java/com/commafeed/backend/feeds/FeedParser.java b/src/main/java/com/commafeed/backend/feeds/FeedParser.java index 50edb523..0a1345b6 100644 --- a/src/main/java/com/commafeed/backend/feeds/FeedParser.java +++ b/src/main/java/com/commafeed/backend/feeds/FeedParser.java @@ -15,6 +15,7 @@ import org.xml.sax.InputSource; import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.FeedEntry; +import com.commafeed.backend.model.FeedEntryContent; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; @@ -48,17 +49,19 @@ public class FeedParser { for (SyndEntry item : items) { FeedEntry entry = new FeedEntry(); entry.setGuid(item.getUri()); - entry.setTitle(handleContent(item.getTitle())); - entry.setContent(handleContent(getContent(item))); entry.setUrl(item.getLink()); entry.setUpdated(getUpdateDate(item)); + FeedEntryContent content = new FeedEntryContent(); + content.setContent(handleContent(getContent(item))); + content.setTitle(handleContent(item.getTitle())); SyndEnclosure enclosure = (SyndEnclosure) Iterables.getFirst( item.getEnclosures(), null); if (enclosure != null) { - entry.setEnclosureUrl(enclosure.getUrl()); - entry.setEnclosureType(enclosure.getType()); + content.setEnclosureUrl(enclosure.getUrl()); + content.setEnclosureType(enclosure.getType()); } + entry.setContent(content); feed.getEntries().add(entry); } @@ -103,7 +106,6 @@ public class FeedParser { Whitelist whitelist = Whitelist.relaxed(); whitelist.addEnforcedAttribute("a", "target", "_blank"); - // TODO evaluate potential security issues whitelist.addTags("iframe"); whitelist.addAttributes("iframe", "src", "height", "width", "allowfullscreen", "frameborder"); diff --git a/src/main/java/com/commafeed/backend/model/FeedEntry.java b/src/main/java/com/commafeed/backend/model/FeedEntry.java index 8aea117b..01f221ac 100644 --- a/src/main/java/com/commafeed/backend/model/FeedEntry.java +++ b/src/main/java/com/commafeed/backend/model/FeedEntry.java @@ -3,13 +3,15 @@ package com.commafeed.backend.model; import java.util.Date; import java.util.Set; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; -import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.OneToMany; +import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -30,18 +32,9 @@ public class FeedEntry extends AbstractModel { @JoinTable(name = "FEED_FEEDENTRIES", joinColumns = { @JoinColumn(name = "FEED_ID", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "FEEDENTRY_ID", nullable = false, updatable = false) }) private Set feeds = Sets.newHashSet(); - @Column(length = 2048) - private String title; - - @Lob - @Column(length = Integer.MAX_VALUE) - private String content; - - @Column(length = 2048) - private String enclosureUrl; - - @Column(length = 255) - private String enclosureType; + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false) + @JoinColumn(nullable = false, updatable = false) + private FeedEntryContent content; @Column(length = 2048) private String url; @@ -65,22 +58,6 @@ public class FeedEntry extends AbstractModel { this.guid = guid; } - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - public String getUrl() { return url; } @@ -121,20 +98,12 @@ public class FeedEntry extends AbstractModel { this.inserted = inserted; } - public String getEnclosureUrl() { - return enclosureUrl; + public FeedEntryContent getContent() { + return content; } - public void setEnclosureUrl(String enclosureUrl) { - this.enclosureUrl = enclosureUrl; - } - - public String getEnclosureType() { - return enclosureType; - } - - public void setEnclosureType(String enclosureType) { - this.enclosureType = enclosureType; + public void setContent(FeedEntryContent content) { + this.content = content; } } diff --git a/src/main/java/com/commafeed/backend/model/FeedEntryContent.java b/src/main/java/com/commafeed/backend/model/FeedEntryContent.java new file mode 100644 index 00000000..119b7204 --- /dev/null +++ b/src/main/java/com/commafeed/backend/model/FeedEntryContent.java @@ -0,0 +1,58 @@ +package com.commafeed.backend.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Lob; +import javax.persistence.Table; + +@Entity +@Table(name = "FEEDENTRYCONTENTS") +@SuppressWarnings("serial") +public class FeedEntryContent extends AbstractModel { + + @Column(length = 2048) + private String title; + + @Lob + @Column(length = Integer.MAX_VALUE) + private String content; + + @Column(length = 2048) + private String enclosureUrl; + + @Column(length = 255) + private String enclosureType; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getEnclosureUrl() { + return enclosureUrl; + } + + public void setEnclosureUrl(String enclosureUrl) { + this.enclosureUrl = enclosureUrl; + } + + public String getEnclosureType() { + return enclosureType; + } + + public void setEnclosureType(String enclosureType) { + this.enclosureType = enclosureType; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + +} diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java index dc56f006..b1bc8ef4 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java @@ -136,7 +136,7 @@ public class AdminUsersREST extends AbstractREST { .entity("You cannot delete the admin user.").build(); } feedEntryStatusService.delete(feedEntryStatusService.getStatuses(user, - false, ReadingOrder.desc)); + false, ReadingOrder.desc, false)); feedSubscriptionService.delete(feedSubscriptionService.findAll(user)); feedCategoryService.delete(feedCategoryService.findAll(user)); userSettingsService.delete(userSettingsService.findByUser(user)); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java index f7832441..8f3bd7e0 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java @@ -63,7 +63,7 @@ public class EntriesREST extends AbstractREST { List unreadEntries = feedEntryStatusService .getStatuses(subscription.getFeed(), getUser(), - unreadOnly, offset, limit, order); + unreadOnly, offset, limit, order, true); for (FeedEntryStatus status : unreadEntries) { entries.getEntries().add(buildEntry(status)); } @@ -75,7 +75,7 @@ public class EntriesREST extends AbstractREST { entries.setName("All"); List unreadEntries = feedEntryStatusService .getStatuses(getUser(), unreadOnly, offset, limit, - order); + order, true); for (FeedEntryStatus status : unreadEntries) { entries.getEntries().add(buildEntry(status)); } @@ -88,7 +88,7 @@ public class EntriesREST extends AbstractREST { .findAllChildrenCategories(getUser(), feedCategory); List unreadEntries = feedEntryStatusService .getStatuses(childrenCategories, getUser(), - unreadOnly, offset, limit, order); + unreadOnly, offset, limit, order, true); for (FeedEntryStatus status : unreadEntries) { entries.getEntries().add(buildEntry(status)); } @@ -106,10 +106,11 @@ public class EntriesREST extends AbstractREST { FeedEntry feedEntry = status.getEntry(); entry.setId(String.valueOf(status.getId())); - entry.setTitle(feedEntry.getTitle()); - entry.setContent(feedEntry.getContent()); - entry.setEnclosureUrl(status.getEntry().getEnclosureUrl()); - entry.setEnclosureType(status.getEntry().getEnclosureType()); + entry.setTitle(feedEntry.getContent().getTitle()); + entry.setContent(feedEntry.getContent().getContent()); + entry.setEnclosureUrl(status.getEntry().getContent().getEnclosureUrl()); + entry.setEnclosureType(status.getEntry().getContent() + .getEnclosureType()); entry.setDate(feedEntry.getUpdated()); entry.setUrl(feedEntry.getUrl()); @@ -171,14 +172,16 @@ public class EntriesREST extends AbstractREST { @Path("search") @GET - public Entries searchEntries(@QueryParam("keywords") String keywords) { + public Entries searchEntries(@QueryParam("keywords") String keywords, + @DefaultValue("0") @QueryParam("offset") int offset, + @DefaultValue("-1") @QueryParam("limit") int limit) { Preconditions.checkArgument(StringUtils.length(keywords) >= 3); Entries entries = new Entries(); List list = Lists.newArrayList(); List entriesStatus = feedEntryStatusService - .getStatusesByKeywords(getUser(), keywords); + .getStatusesByKeywords(getUser(), keywords, offset, limit, true); for (FeedEntryStatus status : entriesStatus) { list.add(buildEntry(status)); }