From ed189c1c31948c60e91730fd3d87c0b3d9cd063f Mon Sep 17 00:00:00 2001 From: Athou Date: Wed, 3 Apr 2013 13:33:33 +0200 Subject: [PATCH] search for entries --- .../backend/dao/FeedEntryService.java | 23 ++++++++++ .../commafeed/backend/model/FeedEntry.java | 8 ++-- .../frontend/rest/resources/EntriesREST.java | 31 ++++++++++++++ src/main/resources/META-INF/orm.xml | 4 ++ src/main/webapp/directives/toolbar.html | 42 ++++++++++--------- src/main/webapp/js/controllers.js | 31 +++++++++----- src/main/webapp/js/directives.js | 17 +++++++- src/main/webapp/js/main.js | 5 +++ src/main/webapp/js/services.js | 6 +++ src/main/webapp/templates/feeds.view.html | 4 +- 10 files changed, 135 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryService.java b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java index b146b5a8..3ff9122c 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedEntryService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java @@ -65,6 +65,29 @@ public class FeedEntryService extends GenericDAO { return query.getResultList(); } + public List getEntriesByKeywords(User user, + String keywords) { + return getEntriesByKeywords(user, keywords, -1, -1); + } + + public List getEntriesByKeywords(User user, + String keywords, int offset, int limit) { + Query query = em.createNamedQuery("Entry.allByKeywords"); + query.setParameter("userId", user.getId()); + query.setParameter("user", user); + + String joinedKeywords = StringUtils.join( + keywords.toLowerCase().split(" "), "%"); + query.setParameter("keywords", "%" + joinedKeywords + "%"); + if (offset > -1) { + query.setFirstResult(offset); + } + if (limit > -1) { + query.setMaxResults(limit); + } + return buildList(query.getResultList()); + } + public List getEntries(User user, boolean unreadOnly) { return getEntries(user, unreadOnly, -1, -1); } diff --git a/src/main/java/com/commafeed/backend/model/FeedEntry.java b/src/main/java/com/commafeed/backend/model/FeedEntry.java index 9a8fef79..372f5b9c 100644 --- a/src/main/java/com/commafeed/backend/model/FeedEntry.java +++ b/src/main/java/com/commafeed/backend/model/FeedEntry.java @@ -13,7 +13,6 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import org.apache.commons.codec.binary.StringUtils; import org.hibernate.annotations.Index; @Entity @@ -32,7 +31,8 @@ public class FeedEntry extends AbstractModel { private String title; @Lob - private byte[] content; + @Column(length = Integer.MAX_VALUE) + private String content; @Column(length = 2048) private String url; @@ -61,11 +61,11 @@ public class FeedEntry extends AbstractModel { } public String getContent() { - return StringUtils.newStringUtf8(content); + return content; } public void setContent(String content) { - this.content = StringUtils.getBytesUtf8(content); + this.content = content; } public String getUrl() { 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 84a6524a..e0941f3b 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java @@ -10,6 +10,8 @@ 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 com.commafeed.backend.model.Feed; import com.commafeed.backend.model.FeedCategory; import com.commafeed.backend.model.FeedEntry; @@ -223,4 +225,33 @@ public class EntriesREST extends AbstractREST { feedEntryStatusService.saveOrUpdate(status); } + @Path("search") + @GET + public Entries searchEntries(@QueryParam("keywords") String keywords) { + Preconditions.checkArgument(StringUtils.length(keywords) >= 3); + + Entries entries = new Entries(); + + List subs = feedSubscriptionService + .findAll(getUser()); + Map subMapping = Maps.uniqueIndex(subs, + new Function() { + public Long apply(FeedSubscription sub) { + return sub.getFeed().getId(); + } + }); + + List list = Lists.newArrayList(); + List entriesWithStatus = feedEntryService + .getEntriesByKeywords(getUser(), keywords); + for (FeedEntryWithStatus feedEntry : entriesWithStatus) { + Long id = feedEntry.getEntry().getFeed().getId(); + list.add(populateEntry(buildEntry(feedEntry), subMapping.get(id))); + } + + entries.setName("Search for : " + keywords); + entries.getEntries().addAll(list); + return entries; + } + } diff --git a/src/main/resources/META-INF/orm.xml b/src/main/resources/META-INF/orm.xml index 9eb7e8be..d7a96c5d 100644 --- a/src/main/resources/META-INF/orm.xml +++ b/src/main/resources/META-INF/orm.xml @@ -29,4 +29,8 @@ select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed = e.feed and s2.category in (:categories) ) order by e.updated desc + + + select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed = e.feed) and lower(e.content) like :keywords order by e.updated desc + \ No newline at end of file diff --git a/src/main/webapp/directives/toolbar.html b/src/main/webapp/directives/toolbar.html index 638126a4..f234ce9b 100644 --- a/src/main/webapp/directives/toolbar.html +++ b/src/main/webapp/directives/toolbar.html @@ -1,24 +1,28 @@
- -
-
- - -
+
+ +
+ + +
+ + + - - - - + +
+
+ + +
-
\ No newline at end of file diff --git a/src/main/webapp/js/controllers.js b/src/main/webapp/js/controllers.js index 796fefd9..0219fa35 100644 --- a/src/main/webapp/js/controllers.js +++ b/src/main/webapp/js/controllers.js @@ -110,6 +110,7 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, $scope.selectedType = $stateParams._type; $scope.selectedId = $stateParams._id; + $scope.keywords = $stateParams._keywords; $scope.name = null; $scope.message = null; @@ -140,13 +141,8 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, limit = $window.height() / 33; limit = parseInt(limit, 10) + 5; } - EntryService.get({ - type : $scope.selectedType, - id : $scope.selectedId, - readType : $scope.settingsService.settings.readingMode, - offset : $scope.entries.length, - limit : limit - }, function(data) { + + var callback = function(data) { for ( var i = 0; i < data.entries.length; i++) { $scope.entries.push(data.entries[i]); } @@ -154,7 +150,22 @@ module.controller('FeedListCtrl', function($scope, $stateParams, $http, $route, $scope.message = data.message; $scope.busy = false; $scope.hasMore = data.entries.length == limit; - }); + }; + if (!$scope.keywords) { + EntryService.get({ + type : $scope.selectedType, + id : $scope.selectedId, + readType : $scope.settingsService.settings.readingMode, + offset : $scope.entries.length, + limit : limit + }, callback); + } else { + EntryService.search({ + keywords : $scope.keywords, + offset : $scope.entries.length, + limit : limit + }, callback); + } }; $scope.mark = function(entry, read) { @@ -282,8 +293,8 @@ module.controller('ManageUsersCtrl', function($scope, $state, $location, }; }); -module.controller('ManageUserCtrl', function($scope, $state, $stateParams, $dialog, - AdminUsersService) { +module.controller('ManageUserCtrl', function($scope, $state, $stateParams, + $dialog, AdminUsersService) { $scope.user = $stateParams._id ? AdminUsersService.get({ id : $stateParams._id }) : { diff --git a/src/main/webapp/js/directives.js b/src/main/webapp/js/directives.js index 0ebae414..7e3a382a 100644 --- a/src/main/webapp/js/directives.js +++ b/src/main/webapp/js/directives.js @@ -173,7 +173,7 @@ module.directive('category', function($compile) { }; }); -module.directive('toolbar', function($stateParams, $route, $location, +module.directive('toolbar', function($state, $stateParams, $route, $location, SettingsService, EntryService, SubscriptionService, SessionService) { return { scope : {}, @@ -208,6 +208,21 @@ module.directive('toolbar', function($stateParams, $route, $location, }); }); }; + + $scope.keywords = $stateParams._keywords; + $scope.search = function() { + if ($scope.keywords == $stateParams._keywords) { + $scope.refresh(); + } else { + $state.transitionTo('feeds.search', { + _keywords : $scope.keywords + }); + } + }; + $scope.showButtons = function() { + return !$stateParams._keywords; + } + $scope.toAdmin = function() { $location.path('admin'); }; diff --git a/src/main/webapp/js/main.js b/src/main/webapp/js/main.js index b191cd95..438fcfac 100644 --- a/src/main/webapp/js/main.js +++ b/src/main/webapp/js/main.js @@ -13,6 +13,11 @@ app.config(function($routeProvider, $stateProvider, $urlRouterProvider) { templateUrl : 'templates/feeds.view.html', controller : 'FeedListCtrl' }); + $stateProvider.state('feeds.search', { + url : '/search/:_keywords', + templateUrl : 'templates/feeds.view.html', + controller : 'FeedListCtrl' + }); $stateProvider.state('admin', { abstract : true, diff --git a/src/main/webapp/js/services.js b/src/main/webapp/js/services.js index 4e738784..cc7c76da 100644 --- a/src/main/webapp/js/services.js +++ b/src/main/webapp/js/services.js @@ -147,6 +147,12 @@ module.factory('EntryService', function($resource, $http) { params : { _method : 'mark' } + }, + search : { + method : 'GET', + params : { + _method : 'search' + } } }; var res = $resource('rest/entries/:_method', {}, actions); diff --git a/src/main/webapp/templates/feeds.view.html b/src/main/webapp/templates/feeds.view.html index 94a0633e..c9844f70 100644 --- a/src/main/webapp/templates/feeds.view.html +++ b/src/main/webapp/templates/feeds.view.html @@ -8,9 +8,9 @@
- {{entry.feedName}} + {{entry.feedName}} - +