mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
exclude terms from search (fix #666)
This commit is contained in:
@@ -7,12 +7,13 @@ import java.util.List;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.FixedSizeSortedSet;
|
import com.commafeed.backend.FixedSizeSortedSet;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
import com.commafeed.backend.model.FeedEntryTag;
|
import com.commafeed.backend.model.FeedEntryTag;
|
||||||
@@ -112,18 +113,21 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
return lazyLoadContent(includeContent, statuses);
|
return lazyLoadContent(includeContent, statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HibernateQuery buildQuery(User user, FeedSubscription sub, boolean unreadOnly, String keywords, Date newerThan, int offset,
|
private HibernateQuery buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords, Date newerThan,
|
||||||
int limit, ReadingOrder order, Date last, String tag) {
|
int offset, int limit, ReadingOrder order, Date last, String tag) {
|
||||||
|
|
||||||
HibernateQuery query = newQuery().from(entry).where(entry.feed.eq(sub.getFeed()));
|
HibernateQuery query = newQuery().from(entry).where(entry.feed.eq(sub.getFeed()));
|
||||||
|
|
||||||
if (keywords != null) {
|
if (keywords != null) {
|
||||||
query.join(entry.content, content);
|
query.join(entry.content, content);
|
||||||
|
|
||||||
for (String keyword : StringUtils.split(keywords)) {
|
for (FeedEntryKeyword keyword : keywords) {
|
||||||
BooleanBuilder or = new BooleanBuilder();
|
BooleanBuilder or = new BooleanBuilder();
|
||||||
or.or(content.content.containsIgnoreCase(keyword));
|
or.or(content.content.containsIgnoreCase(keyword.getKeyword()));
|
||||||
or.or(content.title.containsIgnoreCase(keyword));
|
or.or(content.title.containsIgnoreCase(keyword.getKeyword()));
|
||||||
|
if (keyword.getMode() == Mode.EXCLUDE) {
|
||||||
|
or.not();
|
||||||
|
}
|
||||||
query.where(or);
|
query.where(or);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,8 +184,9 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly, String keywords,
|
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly,
|
||||||
Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent, boolean onlyIds, String tag) {
|
List<FeedEntryKeyword> keywords, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
|
||||||
|
boolean onlyIds, String tag) {
|
||||||
int capacity = offset + limit;
|
int capacity = offset + limit;
|
||||||
Comparator<FeedEntryStatus> comparator = order == ReadingOrder.desc ? STATUS_COMPARATOR_DESC : STATUS_COMPARATOR_ASC;
|
Comparator<FeedEntryStatus> comparator = order == ReadingOrder.desc ? STATUS_COMPARATOR_DESC : STATUS_COMPARATOR_ASC;
|
||||||
FixedSizeSortedSet<FeedEntryStatus> set = new FixedSizeSortedSet<FeedEntryStatus>(capacity, comparator);
|
FixedSizeSortedSet<FeedEntryStatus> set = new FixedSizeSortedSet<FeedEntryStatus>(capacity, comparator);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A keyword used in a search query
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class FeedEntryKeyword {
|
||||||
|
|
||||||
|
public static enum Mode {
|
||||||
|
INCLUDE, EXCLUDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String keyword;
|
||||||
|
private final Mode mode;
|
||||||
|
|
||||||
|
public static List<FeedEntryKeyword> fromQueryString(String keywords) {
|
||||||
|
List<FeedEntryKeyword> list = Lists.newArrayList();
|
||||||
|
if (keywords != null) {
|
||||||
|
for (String keyword : StringUtils.split(keywords)) {
|
||||||
|
boolean not = false;
|
||||||
|
if (keyword.startsWith("-") || keyword.startsWith("!")) {
|
||||||
|
not = true;
|
||||||
|
keyword = keyword.substring(1);
|
||||||
|
}
|
||||||
|
list.add(new FeedEntryKeyword(keyword, not ? Mode.EXCLUDE : Mode.INCLUDE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import org.mozilla.universalchardet.UniversalDetector;
|
|||||||
import org.w3c.css.sac.InputSource;
|
import org.w3c.css.sac.InputSource;
|
||||||
import org.w3c.dom.css.CSSStyleDeclaration;
|
import org.w3c.dom.css.CSSStyleDeclaration;
|
||||||
|
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.commafeed.frontend.model.Entry;
|
import com.commafeed.frontend.model.Entry;
|
||||||
@@ -495,19 +496,20 @@ public class FeedUtils {
|
|||||||
return rot13(new String(Base64.decodeBase64(code)));
|
return rot13(new String(Base64.decodeBase64(code)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeUnwantedFromSearch(List<Entry> entries, String keywords) {
|
public static void removeUnwantedFromSearch(List<Entry> entries, List<FeedEntryKeyword> keywords) {
|
||||||
if (StringUtils.isBlank(keywords)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<Entry> it = entries.iterator();
|
Iterator<Entry> it = entries.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Entry entry = it.next();
|
Entry entry = it.next();
|
||||||
boolean keep = true;
|
boolean keep = true;
|
||||||
for (String keyword : keywords.split(" ")) {
|
for (FeedEntryKeyword keyword : keywords) {
|
||||||
String title = Jsoup.parse(entry.getTitle()).text();
|
String title = Jsoup.parse(entry.getTitle()).text();
|
||||||
String content = Jsoup.parse(entry.getContent()).text();
|
String content = Jsoup.parse(entry.getContent()).text();
|
||||||
if (!StringUtils.containsIgnoreCase(content, keyword) && !StringUtils.containsIgnoreCase(title, keyword)) {
|
boolean condition = !StringUtils.containsIgnoreCase(content, keyword.getKeyword())
|
||||||
|
&& !StringUtils.containsIgnoreCase(title, keyword.getKeyword());
|
||||||
|
if (keyword.getMode() == Mode.EXCLUDE) {
|
||||||
|
condition = !condition;
|
||||||
|
}
|
||||||
|
if (condition) {
|
||||||
keep = false;
|
keep = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -517,5 +519,4 @@ public class FeedUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.commafeed.backend.cache.CacheService;
|
|||||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
@@ -65,9 +66,9 @@ public class FeedEntryService {
|
|||||||
feedEntryStatusDAO.saveOrUpdate(status);
|
feedEntryStatusDAO.saveOrUpdate(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Date olderThan, String keywords) {
|
public void markSubscriptionEntries(User user, List<FeedSubscription> subscriptions, Date olderThan, List<FeedEntryKeyword> keywords) {
|
||||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null, false,
|
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null,
|
||||||
false, null);
|
false, false, null);
|
||||||
markList(statuses, olderThan);
|
markList(statuses, olderThan);
|
||||||
cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
|
cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
|
||||||
cache.invalidateUserRootCategory(user);
|
cache.invalidateUserRootCategory(user);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.commafeed.backend.cache.CacheService;
|
|||||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
import com.commafeed.backend.model.FeedCategory;
|
import com.commafeed.backend.model.FeedCategory;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
@@ -109,6 +110,7 @@ public class CategoryREST {
|
|||||||
|
|
||||||
keywords = StringUtils.trimToNull(keywords);
|
keywords = StringUtils.trimToNull(keywords);
|
||||||
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
||||||
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
limit = Math.min(limit, 1000);
|
limit = Math.min(limit, 1000);
|
||||||
limit = Math.max(0, limit);
|
limit = Math.max(0, limit);
|
||||||
@@ -135,8 +137,8 @@ public class CategoryREST {
|
|||||||
entries.setName(Optional.fromNullable(tag).or("All"));
|
entries.setName(Optional.fromNullable(tag).or("All"));
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||||
removeExcludedSubscriptions(subs, excludedIds);
|
removeExcludedSubscriptions(subs, excludedIds);
|
||||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, subs, unreadOnly, keywords, newerThanDate, offset,
|
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, subs, unreadOnly, entryKeywords, newerThanDate,
|
||||||
limit + 1, order, true, onlyIds, tag);
|
offset, limit + 1, order, true, onlyIds, tag);
|
||||||
|
|
||||||
for (FeedEntryStatus status : list) {
|
for (FeedEntryStatus status : list) {
|
||||||
entries.getEntries().add(
|
entries.getEntries().add(
|
||||||
@@ -158,7 +160,7 @@ public class CategoryREST {
|
|||||||
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
|
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(user, categories);
|
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(user, categories);
|
||||||
removeExcludedSubscriptions(subs, excludedIds);
|
removeExcludedSubscriptions(subs, excludedIds);
|
||||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, subs, unreadOnly, keywords, newerThanDate,
|
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, subs, unreadOnly, entryKeywords, newerThanDate,
|
||||||
offset, limit + 1, order, true, onlyIds, tag);
|
offset, limit + 1, order, true, onlyIds, tag);
|
||||||
|
|
||||||
for (FeedEntryStatus status : list) {
|
for (FeedEntryStatus status : list) {
|
||||||
@@ -180,7 +182,7 @@ public class CategoryREST {
|
|||||||
|
|
||||||
entries.setTimestamp(System.currentTimeMillis());
|
entries.setTimestamp(System.currentTimeMillis());
|
||||||
entries.setIgnoredReadStatus(STARRED.equals(id) || keywords != null || tag != null);
|
entries.setIgnoredReadStatus(STARRED.equals(id) || keywords != null || tag != null);
|
||||||
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), keywords);
|
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), entryKeywords);
|
||||||
return Response.ok(entries).build();
|
return Response.ok(entries).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,11 +247,12 @@ public class CategoryREST {
|
|||||||
|
|
||||||
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
||||||
String keywords = req.getKeywords();
|
String keywords = req.getKeywords();
|
||||||
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
if (ALL.equals(req.getId())) {
|
if (ALL.equals(req.getId())) {
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||||
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
|
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
|
||||||
feedEntryService.markSubscriptionEntries(user, subs, olderThan, keywords);
|
feedEntryService.markSubscriptionEntries(user, subs, olderThan, entryKeywords);
|
||||||
} else if (STARRED.equals(req.getId())) {
|
} else if (STARRED.equals(req.getId())) {
|
||||||
feedEntryService.markStarredEntries(user, olderThan);
|
feedEntryService.markStarredEntries(user, olderThan);
|
||||||
} else {
|
} else {
|
||||||
@@ -257,7 +260,7 @@ public class CategoryREST {
|
|||||||
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
|
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(user, parent);
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(user, categories);
|
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(user, categories);
|
||||||
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
|
removeExcludedSubscriptions(subs, req.getExcludedSubscriptions());
|
||||||
feedEntryService.markSubscriptionEntries(user, subs, olderThan, keywords);
|
feedEntryService.markSubscriptionEntries(user, subs, olderThan, entryKeywords);
|
||||||
}
|
}
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import com.commafeed.backend.cache.CacheService;
|
|||||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
import com.commafeed.backend.feed.FeedFetcher;
|
import com.commafeed.backend.feed.FeedFetcher;
|
||||||
import com.commafeed.backend.feed.FeedQueues;
|
import com.commafeed.backend.feed.FeedQueues;
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
@@ -127,6 +128,7 @@ public class FeedREST {
|
|||||||
|
|
||||||
keywords = StringUtils.trimToNull(keywords);
|
keywords = StringUtils.trimToNull(keywords);
|
||||||
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
||||||
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
limit = Math.min(limit, 1000);
|
limit = Math.min(limit, 1000);
|
||||||
limit = Math.max(0, limit);
|
limit = Math.max(0, limit);
|
||||||
@@ -146,8 +148,8 @@ public class FeedREST {
|
|||||||
entries.setErrorCount(subscription.getFeed().getErrorCount());
|
entries.setErrorCount(subscription.getFeed().getErrorCount());
|
||||||
entries.setFeedLink(subscription.getFeed().getLink());
|
entries.setFeedLink(subscription.getFeed().getLink());
|
||||||
|
|
||||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, Arrays.asList(subscription), unreadOnly, keywords,
|
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(user, Arrays.asList(subscription), unreadOnly,
|
||||||
newerThanDate, offset, limit + 1, order, true, onlyIds, null);
|
entryKeywords, newerThanDate, offset, limit + 1, order, true, onlyIds, null);
|
||||||
|
|
||||||
for (FeedEntryStatus status : list) {
|
for (FeedEntryStatus status : list) {
|
||||||
entries.getEntries().add(
|
entries.getEntries().add(
|
||||||
@@ -166,7 +168,7 @@ public class FeedREST {
|
|||||||
|
|
||||||
entries.setTimestamp(System.currentTimeMillis());
|
entries.setTimestamp(System.currentTimeMillis());
|
||||||
entries.setIgnoredReadStatus(keywords != null);
|
entries.setIgnoredReadStatus(keywords != null);
|
||||||
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), keywords);
|
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), entryKeywords);
|
||||||
return Response.ok(entries).build();
|
return Response.ok(entries).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,10 +291,11 @@ public class FeedREST {
|
|||||||
|
|
||||||
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan());
|
||||||
String keywords = req.getKeywords();
|
String keywords = req.getKeywords();
|
||||||
|
List<FeedEntryKeyword> entryKeywords = FeedEntryKeyword.fromQueryString(keywords);
|
||||||
|
|
||||||
FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(req.getId()));
|
FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(req.getId()));
|
||||||
if (subscription != null) {
|
if (subscription != null) {
|
||||||
feedEntryService.markSubscriptionEntries(user, Arrays.asList(subscription), olderThan, keywords);
|
feedEntryService.markSubscriptionEntries(user, Arrays.asList(subscription), olderThan, entryKeywords);
|
||||||
}
|
}
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user