forked from Archives/Athou_commafeed
search is now context aware (will only search in selected category or feed)
This commit is contained in:
@@ -14,6 +14,7 @@ import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Disjunction;
|
||||
@@ -131,7 +132,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
if (keywords != null) {
|
||||
Criteria contentJoin = criteria.createCriteria(FeedEntry_.content.getName(), "content", JoinType.INNER_JOIN);
|
||||
|
||||
for (String keyword : keywords.split(" ")) {
|
||||
for (String keyword : StringUtils.split(keywords)) {
|
||||
Disjunction or = Restrictions.disjunction();
|
||||
or.add(Restrictions.ilike(FeedEntryContent_.content.getName(), keyword, MatchMode.ANYWHERE));
|
||||
or.add(Restrictions.ilike(FeedEntryContent_.title.getName(), keyword, MatchMode.ANYWHERE));
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.StringReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -29,6 +30,7 @@ import org.w3c.dom.css.CSSStyleDeclaration;
|
||||
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.frontend.model.Entry;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gwt.i18n.client.HasDirection.Direction;
|
||||
import com.google.gwt.i18n.shared.BidiUtils;
|
||||
@@ -447,4 +449,27 @@ public class FeedUtils {
|
||||
return rot13(new String(Base64.decodeBase64(code)));
|
||||
}
|
||||
|
||||
public static void removeUnwantedFromSearch(List<Entry> entries, String keywords) {
|
||||
if (StringUtils.isBlank(keywords)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Iterator<Entry> it = entries.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry entry = it.next();
|
||||
boolean keep = true;
|
||||
for (String keyword : keywords.split(" ")) {
|
||||
String title = Jsoup.parse(entry.getTitle()).text();
|
||||
String content = Jsoup.parse(entry.getContent()).text();
|
||||
if (!StringUtils.containsIgnoreCase(content, keyword) && !StringUtils.containsIgnoreCase(title, keyword)) {
|
||||
keep = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!keep) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.feeds.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
@@ -84,7 +85,7 @@ public class CategoryREST extends AbstractREST {
|
||||
|
||||
@Inject
|
||||
CacheService cache;
|
||||
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@@ -103,9 +104,15 @@ public class CategoryREST extends AbstractREST {
|
||||
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(
|
||||
value = "limit for paging, default 20, maximum 50") @DefaultValue("20") @QueryParam("limit") int limit, @ApiParam(
|
||||
value = "date ordering",
|
||||
allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
|
||||
allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order, @ApiParam(
|
||||
value = "keywords separated by spaces, 3 characters minimum",
|
||||
required = true) @QueryParam("keywords") String keywords) {
|
||||
|
||||
Preconditions.checkNotNull(readType);
|
||||
|
||||
keywords = StringUtils.trimToNull(keywords);
|
||||
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
||||
|
||||
limit = Math.min(limit, 50);
|
||||
limit = Math.max(0, limit);
|
||||
|
||||
@@ -122,7 +129,7 @@ public class CategoryREST extends AbstractREST {
|
||||
if (ALL.equals(id)) {
|
||||
entries.setName("All");
|
||||
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findAll(getUser());
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(subscriptions, unreadOnly, null, newerThanDate, offset,
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(subscriptions, unreadOnly, keywords, newerThanDate, offset,
|
||||
limit + 1, order, true);
|
||||
for (FeedEntryStatus status : list) {
|
||||
entries.getEntries().add(
|
||||
@@ -143,7 +150,7 @@ public class CategoryREST extends AbstractREST {
|
||||
if (parent != null) {
|
||||
List<FeedCategory> categories = feedCategoryDAO.findAllChildrenCategories(getUser(), parent);
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findByCategories(getUser(), categories);
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(subs, unreadOnly, null, newerThanDate, offset,
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(subs, unreadOnly, keywords, newerThanDate, offset,
|
||||
limit + 1, order, true);
|
||||
for (FeedEntryStatus status : list) {
|
||||
entries.getEntries().add(
|
||||
@@ -162,6 +169,7 @@ public class CategoryREST extends AbstractREST {
|
||||
}
|
||||
|
||||
entries.setTimestamp(System.currentTimeMillis());
|
||||
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), keywords);
|
||||
return Response.ok(entries).build();
|
||||
}
|
||||
|
||||
@@ -180,7 +188,7 @@ public class CategoryREST extends AbstractREST {
|
||||
int offset = 0;
|
||||
int limit = 20;
|
||||
|
||||
Entries entries = (Entries) getCategoryEntries(id, readType, null, offset, limit, order).getEntity();
|
||||
Entries entries = (Entries) getCategoryEntries(id, readType, null, offset, limit, order, null).getEntity();
|
||||
|
||||
SyndFeed feed = new SyndFeedImpl();
|
||||
feed.setFeedType("rss_2.0");
|
||||
|
||||
@@ -1,29 +1,15 @@
|
||||
package com.commafeed.frontend.rest.resources;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.model.FeedEntryStatus;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||
import com.commafeed.backend.services.ApplicationSettingsService;
|
||||
import com.commafeed.backend.services.FeedEntryService;
|
||||
import com.commafeed.frontend.model.Entries;
|
||||
import com.commafeed.frontend.model.Entry;
|
||||
import com.commafeed.frontend.model.request.MarkRequest;
|
||||
import com.commafeed.frontend.model.request.MultipleMarkRequest;
|
||||
import com.commafeed.frontend.model.request.StarRequest;
|
||||
@@ -87,63 +73,6 @@ public class EntryREST extends AbstractREST {
|
||||
return Response.ok(Status.OK).build();
|
||||
}
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@ApiOperation(
|
||||
value = "Search for entries",
|
||||
notes = "Look through title and content of entries by keywords",
|
||||
responseClass = "com.commafeed.frontend.model.Entries")
|
||||
public Response searchEntries(
|
||||
@ApiParam(value = "keywords separated by spaces, 3 characters minimum", required = true) @QueryParam("keywords") String keywords,
|
||||
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(
|
||||
value = "limit for paging") @DefaultValue("-1") @QueryParam("limit") int limit) {
|
||||
keywords = StringUtils.trimToEmpty(keywords);
|
||||
limit = Math.min(limit, 50);
|
||||
Preconditions.checkArgument(StringUtils.length(keywords) >= 3);
|
||||
|
||||
Entries entries = new Entries();
|
||||
entries.setOffset(offset);
|
||||
entries.setLimit(limit);
|
||||
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(getUser());
|
||||
List<FeedEntryStatus> entriesStatus = feedEntryStatusDAO.findBySubscriptions(subs, false, keywords, null, offset, limit + 1,
|
||||
ReadingOrder.desc, true);
|
||||
for (FeedEntryStatus status : entriesStatus) {
|
||||
entries.getEntries().add(
|
||||
Entry.build(status, applicationSettingsService.get().getPublicUrl(), applicationSettingsService.get()
|
||||
.isImageProxyEnabled()));
|
||||
}
|
||||
|
||||
boolean hasMore = entries.getEntries().size() > limit;
|
||||
if (hasMore) {
|
||||
entries.setHasMore(true);
|
||||
entries.getEntries().remove(entries.getEntries().size() - 1);
|
||||
}
|
||||
|
||||
removeUnwanted(entries.getEntries(), keywords);
|
||||
|
||||
entries.setName("Search for : " + keywords);
|
||||
entries.setTimestamp(System.currentTimeMillis());
|
||||
return Response.ok(entries).build();
|
||||
}
|
||||
|
||||
private void removeUnwanted(List<Entry> entries, String keywords) {
|
||||
Iterator<Entry> it = entries.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry entry = it.next();
|
||||
boolean keep = true;
|
||||
for (String keyword : keywords.split(" ")) {
|
||||
String title = Jsoup.parse(entry.getTitle()).text();
|
||||
String content = Jsoup.parse(entry.getContent()).text();
|
||||
if (!StringUtils.containsIgnoreCase(content, keyword) && !StringUtils.containsIgnoreCase(title, keyword)) {
|
||||
keep = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!keep) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class FeedREST extends AbstractREST {
|
||||
|
||||
@Context
|
||||
private HttpServletRequest request;
|
||||
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@@ -140,10 +140,15 @@ public class FeedREST extends AbstractREST {
|
||||
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset, @ApiParam(
|
||||
value = "limit for paging, default 20, maximum 50") @DefaultValue("20") @QueryParam("limit") int limit, @ApiParam(
|
||||
value = "date ordering",
|
||||
allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order) {
|
||||
allowableValues = "asc,desc") @QueryParam("order") @DefaultValue("desc") ReadingOrder order, @ApiParam(
|
||||
value = "keywords separated by spaces, 3 characters minimum",
|
||||
required = true) @QueryParam("keywords") String keywords) {
|
||||
|
||||
Preconditions.checkNotNull(id);
|
||||
Preconditions.checkNotNull(readType);
|
||||
|
||||
keywords = StringUtils.trimToNull(keywords);
|
||||
Preconditions.checkArgument(keywords == null || StringUtils.length(keywords) >= 3);
|
||||
|
||||
limit = Math.min(limit, 50);
|
||||
limit = Math.max(0, limit);
|
||||
@@ -163,7 +168,7 @@ public class FeedREST extends AbstractREST {
|
||||
entries.setErrorCount(subscription.getFeed().getErrorCount());
|
||||
entries.setFeedLink(subscription.getFeed().getLink());
|
||||
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(Arrays.asList(subscription), unreadOnly, null,
|
||||
List<FeedEntryStatus> list = feedEntryStatusDAO.findBySubscriptions(Arrays.asList(subscription), unreadOnly, keywords,
|
||||
newerThanDate, offset, limit + 1, order, true);
|
||||
|
||||
for (FeedEntryStatus status : list) {
|
||||
@@ -180,6 +185,7 @@ public class FeedREST extends AbstractREST {
|
||||
}
|
||||
|
||||
entries.setTimestamp(System.currentTimeMillis());
|
||||
FeedUtils.removeUnwantedFromSearch(entries.getEntries(), keywords);
|
||||
return Response.ok(entries).build();
|
||||
}
|
||||
|
||||
@@ -197,7 +203,7 @@ public class FeedREST extends AbstractREST {
|
||||
int offset = 0;
|
||||
int limit = 20;
|
||||
|
||||
Entries entries = (Entries) getFeedEntries(id, readType, null, offset, limit, order).getEntity();
|
||||
Entries entries = (Entries) getFeedEntries(id, readType, null, offset, limit, order, null).getEntity();
|
||||
|
||||
SyndFeed feed = new SyndFeedImpl();
|
||||
feed.setFeedType("rss_2.0");
|
||||
|
||||
@@ -21,6 +21,10 @@ module.run(['$rootScope', function($rootScope) {
|
||||
// args.all
|
||||
$rootScope.$broadcast('reload', args || {});
|
||||
});
|
||||
$rootScope.$on('emitEntrySearch', function(event, args) {
|
||||
// args.keywords
|
||||
$rootScope.$broadcast('entrySearch', args);
|
||||
});
|
||||
$rootScope.$on('emitFeedSearch', function(event, args) {
|
||||
$rootScope.$broadcast('feedSearch');
|
||||
});
|
||||
@@ -440,6 +444,7 @@ module.controller('ToolbarCtrl', [
|
||||
return ($http.pendingRequests.length + $.active);
|
||||
}
|
||||
|
||||
$scope.keywords = $location.search().q;
|
||||
$scope.session = ProfileService.get();
|
||||
$scope.ServerService = ServerService.get();
|
||||
$scope.settingsService = SettingsService;
|
||||
@@ -509,15 +514,11 @@ module.controller('ToolbarCtrl', [
|
||||
markAll(new Date().getTime() - 1209600000);
|
||||
};
|
||||
|
||||
$scope.keywords = $stateParams._keywords;
|
||||
$scope.search = function() {
|
||||
if ($scope.keywords == $stateParams._keywords) {
|
||||
$scope.refresh();
|
||||
} else {
|
||||
$state.transitionTo('feeds.search', {
|
||||
_keywords : $scope.keywords
|
||||
});
|
||||
}
|
||||
$location.search('q', $scope.keywords);
|
||||
$scope.$emit('emitEntrySearch', {
|
||||
keywords : $scope.keywords
|
||||
});
|
||||
};
|
||||
$scope.showButtons = function() {
|
||||
return !$stateParams._keywords;
|
||||
@@ -664,19 +665,21 @@ module.controller('FeedListCtrl', [
|
||||
'$route',
|
||||
'$state',
|
||||
'$window',
|
||||
'$location',
|
||||
'EntryService',
|
||||
'SettingsService',
|
||||
'FeedService',
|
||||
'CategoryService',
|
||||
'AnalyticsService',
|
||||
function($scope, $stateParams, $http, $route, $state, $window, EntryService, SettingsService, FeedService, CategoryService,
|
||||
function($scope, $stateParams, $http, $route, $state, $window, $location, EntryService, SettingsService, FeedService, CategoryService,
|
||||
AnalyticsService) {
|
||||
|
||||
AnalyticsService.track();
|
||||
|
||||
$scope.keywords = $location.search().q;
|
||||
|
||||
$scope.selectedType = $stateParams._type;
|
||||
$scope.selectedId = $stateParams._id;
|
||||
$scope.keywords = $stateParams._keywords;
|
||||
|
||||
$scope.name = null;
|
||||
$scope.message = null;
|
||||
@@ -738,22 +741,16 @@ module.controller('FeedListCtrl', [
|
||||
$scope.hasMore = data.hasMore;
|
||||
$scope.feedLink = data.feedLink;
|
||||
};
|
||||
if (!$scope.keywords) {
|
||||
var service = $scope.selectedType == 'feed' ? FeedService : CategoryService;
|
||||
service.entries({
|
||||
id : $scope.selectedId,
|
||||
readType : $scope.settingsService.settings.readingMode,
|
||||
order : $scope.settingsService.settings.readingOrder,
|
||||
offset : offset,
|
||||
limit : limit
|
||||
}, callback);
|
||||
} else {
|
||||
EntryService.search({
|
||||
keywords : $scope.keywords,
|
||||
offset : $scope.entries.length,
|
||||
limit : limit
|
||||
}, callback);
|
||||
}
|
||||
|
||||
var service = $scope.selectedType == 'feed' ? FeedService : CategoryService;
|
||||
service.entries({
|
||||
id : $scope.selectedId,
|
||||
readType : $scope.keywords ? 'all' : $scope.settingsService.settings.readingMode,
|
||||
order : $scope.settingsService.settings.readingOrder,
|
||||
offset : offset,
|
||||
limit : limit,
|
||||
keywords : $scope.keywords
|
||||
}, callback);
|
||||
};
|
||||
|
||||
$scope.goToFeed = function(id) {
|
||||
@@ -1152,7 +1149,9 @@ module.controller('FeedListCtrl', [
|
||||
$scope.markAll(args.olderThan);
|
||||
});
|
||||
|
||||
$scope.$on('reload', function(event, args) {
|
||||
var reload = function(all, keywords) {
|
||||
$scope.keywords = keywords;
|
||||
$location.search('q', keywords);
|
||||
delete $scope.current;
|
||||
$scope.name = null;
|
||||
$scope.entries = [];
|
||||
@@ -1163,13 +1162,21 @@ module.controller('FeedListCtrl', [
|
||||
$scope.hasMore = true;
|
||||
$scope.loadMoreEntries();
|
||||
|
||||
if (args.all) {
|
||||
if (all) {
|
||||
FeedService.refreshAll();
|
||||
} else if ($scope.selectedType == 'feed') {
|
||||
FeedService.refresh({
|
||||
id : $stateParams._id
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on('entrySearch', function(event, args) {
|
||||
reload(null, args.keywords);
|
||||
});
|
||||
|
||||
$scope.$on('reload', function(event, args) {
|
||||
reload(args.all, null);
|
||||
});
|
||||
}]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user