mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
store entry content externally and load only when needed
This commit is contained in:
@@ -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<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> getStatusesByKeywords(User user,
|
||||
String keywords) {
|
||||
return getStatusesByKeywords(user, keywords, -1, -1);
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> 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<FeedEntryStatus> {
|
||||
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<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> 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<FeedEntryStatus> getStatuses(User user, boolean unreadOnly,
|
||||
int offset, int limit, ReadingOrder order) {
|
||||
int offset, int limit, ReadingOrder order, boolean includeContent) {
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
|
||||
@@ -109,6 +109,11 @@ public class FeedEntryStatusService extends GenericDAO<FeedEntryStatus> {
|
||||
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<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> 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<FeedEntryStatus> getStatuses(Feed feed, User user,
|
||||
boolean unreadOnly, int offset, int limit, ReadingOrder order) {
|
||||
boolean unreadOnly, int offset, int limit, ReadingOrder order,
|
||||
boolean includeContent) {
|
||||
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
@@ -152,6 +159,11 @@ public class FeedEntryStatusService extends GenericDAO<FeedEntryStatus> {
|
||||
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<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> getStatuses(List<FeedCategory> 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<FeedEntryStatus> getStatuses(List<FeedCategory> categories,
|
||||
User user, boolean unreadOnly, int offset, int limit,
|
||||
ReadingOrder order) {
|
||||
ReadingOrder order, boolean includeContent) {
|
||||
|
||||
CriteriaQuery<FeedEntryStatus> query = builder.createQuery(getType());
|
||||
Root<FeedEntryStatus> root = query.from(getType());
|
||||
@@ -181,6 +195,11 @@ public class FeedEntryStatusService extends GenericDAO<FeedEntryStatus> {
|
||||
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<FeedEntryStatus> {
|
||||
|
||||
public void markFeedEntries(User user, Feed feed, Date olderThan) {
|
||||
List<FeedEntryStatus> statuses = getStatuses(feed, user, true,
|
||||
ReadingOrder.desc);
|
||||
ReadingOrder.desc, false);
|
||||
update(markList(statuses, olderThan));
|
||||
}
|
||||
|
||||
public void markCategoryEntries(User user, List<FeedCategory> categories,
|
||||
Date olderThan) {
|
||||
List<FeedEntryStatus> statuses = getStatuses(categories, user, true,
|
||||
ReadingOrder.desc);
|
||||
ReadingOrder.desc, false);
|
||||
update(markList(statuses, olderThan));
|
||||
}
|
||||
|
||||
public void markAllEntries(User user, Date olderThan) {
|
||||
List<FeedEntryStatus> statuses = getStatuses(user, true,
|
||||
ReadingOrder.desc);
|
||||
ReadingOrder.desc, false);
|
||||
update(markList(statuses, olderThan));
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<Feed> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -63,7 +63,7 @@ public class EntriesREST extends AbstractREST {
|
||||
|
||||
List<FeedEntryStatus> 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<FeedEntryStatus> 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<FeedEntryStatus> 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<Entry> list = Lists.newArrayList();
|
||||
List<FeedEntryStatus> entriesStatus = feedEntryStatusService
|
||||
.getStatusesByKeywords(getUser(), keywords);
|
||||
.getStatusesByKeywords(getUser(), keywords, offset, limit, true);
|
||||
for (FeedEntryStatus status : entriesStatus) {
|
||||
list.add(buildEntry(status));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user