diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace index bd0a79efd0dac011c7b923562854f37b2b355aed..776533a41752c0b806d9d859a69c0ae06499a1b7 100644 --- a/ma-impl.sublime-workspace +++ b/ma-impl.sublime-workspace @@ -287,14 +287,6 @@ }, "buffers": [ - { - "file": "vipra-ui/css/app.less", - "settings": - { - "buffer_size": 1761, - "line_ending": "Unix" - } - } ], "build_system": "", "build_system_choices": @@ -478,31 +470,42 @@ "/home/eike/repos/master/ma-impl/vipra-ui/css", "/home/eike/repos/master/ma-impl/vipra-ui/html", "/home/eike/repos/master/ma-impl/vipra-ui/html/articles", + "/home/eike/repos/master/ma-impl/vipra-ui/html/directives", "/home/eike/repos/master/ma-impl/vipra-ui/html/topics", "/home/eike/repos/master/ma-impl/vipra-ui/html/words", - "/home/eike/repos/master/ma-impl/vipra-ui/js" + "/home/eike/repos/master/ma-impl/vipra-ui/js", + "/home/eike/repos/master/ma-impl/vm/data" ], "file_history": [ - "/home/eike/repos/master/ma-impl/vipra-ui/html/index.html", - "/home/eike/repos/master/ma-impl/vipra-ui/html/words/index.html", - "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/index.html", - "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/js/controllers.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/words/show.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/show.html", "/home/eike/repos/master/ma-impl/vipra-ui/js/directives.js", "/home/eike/repos/master/ma-impl/vipra-ui/js/app.js", - "/home/eike/repos/master/ma-impl/vipra-ui/js/controllers.js", - "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/show.html", - "/home/eike/repos/master/ma-impl/vipra-ui/css/app.less", - "/home/eike/repos/master/ma-impl/vipra-ui/js/filters.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/index.html", "/home/eike/repos/master/ma-impl/vipra-ui/index.html", "/home/eike/repos/master/ma-impl/vm/data/data.json", + "/home/eike/repos/master/ma-impl/vm/test/2011-q3/4.txt", + "/home/eike/repos/master/ma-impl/vm/test/2011-q4/5.txt", + "/home/eike/repos/master/ma-impl/vm/test/2011-q1/6.txt", + "/home/eike/repos/master/ma-impl/vm/data/test-10.json", + "/home/eike/repos/master/ma-impl/vm/test/2011-q1/3.txt", + "/home/eike/repos/master/ma-impl/vm/test/2011-q2/2.txt", + "/home/eike/repos/master/ma-impl/vm/test/2011-q3/1.txt", + "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/js/helpers.js", + "/home/eike/repos/master/ma-impl/vipra-ui/js/filters.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/articles/show.html", + "/home/eike/repos/master/ma-impl/vipra-ui/css/app.less", + "/home/eike/repos/master/ma-impl/vipra-ui/js/services.js", + "/home/eike/repos/master/ma-impl/vipra-ui/html/directives/pagination.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/words/index.html", + "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/index.html", "/home/eike/repos/master/ma-impl/vm/data/test-1.json", "/home/eike/repos/master/ma-impl/vm/data/test-2.json", - "/home/eike/repos/master/ma-impl/vm/data/test-10.json", "/home/eike/repos/master/ma-impl/vipra-ui/js/factories.js", "/run/user/1000/gvfs/smb-share:server=eike-ain,share=share/interceptors.js", - "/home/eike/repos/master/ma-impl/vipra-ui/html/topics/show.html", - "/home/eike/repos/master/ma-impl/vipra-ui/html/words/show.html", "/home/eike/repos/master/ma-impl/vipra-ui/gulpfile.js", "/home/eike/repos/master/ma-impl/vipra-ui/css/footer.less", "/home/eike/repos/master/ma-impl/vipra-ui/less/vendor.less", @@ -511,7 +514,6 @@ "/home/eike/repos/master/ma-impl/vipra-ui/public/index.html", "/home/eike/repos/master/ma-impl/vipra-ui/js/vendor.js", "/home/eike/repos/master/ma-impl/vipra-ui/less/main.less", - "/home/eike/repos/master/ma-impl/vipra-ui/js/services.js", "/home/eike/repos/master/ma-impl/vipra-ui/css/main.less", "/home/eike/.config/sublime-text-3/Packages/User/Preferences.sublime-settings", "/home/eike/repos/master/ma-impl/vipra-ui/app/adapters/application.js", @@ -603,15 +605,7 @@ "/home/eike/repos/master/ma-impl/vipra-cmd/build2.xml", "/home/eike/repos/master/ma-impl/vipra-ui/README.md", "/home/eike/repos/testasd/bower.json", - "/home/eike/repos/master/ma-impl/vipra-ui2/package.json", - "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles/list.js", - "/home/eike/repos/master/ma-impl/vipra-ui/package.json", - "/home/eike/repos/master/ma-impl/vipra-ui/node_modules/ember-highcharts/package.json", - "/home/eike/repos/master/ma-impl/vm/config/initd-mongod", - "/home/eike/repos/master/ma-impl/vm/webapps/vipra-rest/WEB-INF/web.xml", - "/core", - "/home/eike/repos/master/ma-impl/vm/config/environment", - "/home/eike/repos/master/ma-impl/vm/config/initd-tomcat" + "/home/eike/repos/master/ma-impl/vipra-ui2/package.json" ], "find": { @@ -935,39 +929,8 @@ "groups": [ { - "selected": 0, "sheets": [ - { - "buffer": 0, - "file": "vipra-ui/css/app.less", - "semi_transient": false, - "settings": - { - "buffer_size": 1761, - "regions": - { - }, - "selection": - [ - [ - 492, - 492 - ] - ], - "settings": - { - "syntax": "Packages/LESS/LESS.tmLanguage", - "tab_size": 2, - "translate_tabs_to_spaces": true - }, - "translation.x": -0.0, - "translation.y": 102.0, - "zoom_level": 1.0 - }, - "stack_index": 0, - "type": "text" - } ] } ], @@ -1122,7 +1085,7 @@ "selected_items": [ ], - "width": 378.0 + "width": 604.0 }, "selected_group": 0, "settings": diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java index 490abad971e2c113513275372512a5e8580eeab5..e78b661e6c1c1a1faa024e7d7f865cfa45f31d28 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java +++ b/vipra-rest/src/main/java/de/vipra/rest/provider/ObjectMapperProvider.java @@ -42,7 +42,7 @@ public class ObjectMapperProvider implements ContextResolver<ObjectMapper> { final ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); - mapper.setSerializationInclusion(Include.NON_NULL); + mapper.setSerializationInclusion(Include.NON_EMPTY); mapper.setDateFormat(new SimpleDateFormat(Constants.DATETIME_FORMAT)); mapper.registerModule(module); return mapper; diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java index a919f92ab5273cf3cad2d0c12783f89bef1724d1..bbea795e308fc7401c946512250caa89a9635944 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ArticleResource.java @@ -46,11 +46,11 @@ public class ArticleResource { UriInfo uri; final Cache<String, ArticleFull> cache; - final DatabaseService<ArticleFull, ObjectId> service; + final DatabaseService<ArticleFull, ObjectId> dbArticles; public ArticleResource(@Context ServletContext servletContext) throws ConfigException, IOException { Config config = Config.getConfig(); - service = DatabaseService.getDatabaseService(config, ArticleFull.class); + dbArticles = DatabaseService.getDatabaseService(config, ArticleFull.class); CacheManager manager = (CacheManager) servletContext.getAttribute("cachemanager"); Cache<String, ArticleFull> articleCache = manager.getCache("articlecache", String.class, ArticleFull.class); @@ -68,16 +68,16 @@ public class ArticleResource { Wrapper<List<ArticleFull>> res = new Wrapper<>(); if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, service.count()); + res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbArticles.count()); if (res.hasErrors()) return res.badRequest(); try { - List<ArticleFull> articles = service.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); + List<ArticleFull> articles = dbArticles.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", service.count()); + res.addMeta("total", dbArticles.count()); else res.addMeta("total", articles.size()); @@ -123,7 +123,7 @@ public class ArticleResource { public Response createArticle(ArticleFull article) { Wrapper<ArticleFull> res; try { - article = service.createSingle(article); + article = dbArticles.createSingle(article); res = new Wrapper<>(article); URI newUri = new URL(uri.getAbsolutePath().toURL(), article.getId().toString()).toURI(); return res.created(newUri); @@ -140,7 +140,7 @@ public class ArticleResource { Wrapper<ArticleFull> res = new Wrapper<>(); long deleted; try { - deleted = service.deleteSingle(MongoUtils.objectId(id)); + deleted = dbArticles.deleteSingle(MongoUtils.objectId(id)); } catch (DatabaseException e) { res = new Wrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be deleted", "item could not be created due to an internal server error")); @@ -168,7 +168,7 @@ public class ArticleResource { ArticleFull article = wrapper.getData(); Wrapper<ArticleFull> res = new Wrapper<>(); try { - service.updateSingle(article); + dbArticles.updateSingle(article); cache.put(id, article); return res.ok(article); } catch (DatabaseException e) { @@ -182,13 +182,13 @@ public class ArticleResource { if (fields == null || fields.length == 0) { ArticleFull article = cache.get(id); if (article == null) { - article = service.getSingle(MongoUtils.objectId(id)); + article = dbArticles.getSingle(MongoUtils.objectId(id)); if (article != null) cache.put(id, article); } return article; } else - return service.getSingle(MongoUtils.objectId(id), fields); + return dbArticles.getSingle(MongoUtils.objectId(id), fields); } } diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/ImportResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/ImportResource.java index f67a0b495ad04cc5da865321ec2c8975ff11f90c..a28863956774110a9d55ead6b0496455d4ba4d17 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/ImportResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/ImportResource.java @@ -38,11 +38,11 @@ public class ImportResource { UriInfo uri; final Cache<String, Import> cache; - final DatabaseService<Import, ObjectId> service; + final DatabaseService<Import, ObjectId> dbImports; public ImportResource(@Context ServletContext servletContext) throws ConfigException, IOException { Config config = Config.getConfig(); - service = DatabaseService.getDatabaseService(config, Import.class); + dbImports = DatabaseService.getDatabaseService(config, Import.class); CacheManager manager = (CacheManager) servletContext.getAttribute("cachemanager"); Cache<String, Import> importCache = manager.getCache("importcache", String.class, Import.class); @@ -59,16 +59,16 @@ public class ImportResource { Wrapper<List<Import>> res = new Wrapper<>(); if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, service.count()); + res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbImports.count()); if (res.hasErrors()) return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); try { - List<Import> imports = service.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); + List<Import> imports = dbImports.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", service.count()); + res.addMeta("total", dbImports.count()); else res.addMeta("total", imports.size()); @@ -85,7 +85,7 @@ public class ImportResource { @Path("latest") public Response getLatestImport(@QueryParam("fields") String fields) { Wrapper<Import> res = new Wrapper<>(); - List<Import> latestImport = service.getMultiple(0, 1, "date", false, StringUtils.getFields(fields)); + List<Import> latestImport = dbImports.getMultiple(0, 1, "date", null, false, StringUtils.getFields(fields)); if (latestImport == null || latestImport.size() != 1) { return res.noContent(); @@ -127,13 +127,13 @@ public class ImportResource { if (fields == null || fields.length == 0) { Import importOp = cache.get(id); if (importOp == null) { - importOp = service.getSingle(MongoUtils.objectId(id)); + importOp = dbImports.getSingle(MongoUtils.objectId(id)); if (importOp != null) cache.put(id, importOp); } return importOp; } else - return service.getSingle(MongoUtils.objectId(id), fields); + return dbImports.getSingle(MongoUtils.objectId(id), fields); } } diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/TopicResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/TopicResource.java index 7675508c2462bfd6061c38b1aa99fd891c7b266d..f158154c670a87ff1bdc6154c405d39c8b1a3436 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/TopicResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/TopicResource.java @@ -17,6 +17,8 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.bson.types.ObjectId; import org.ehcache.Cache; import org.ehcache.CacheManager; @@ -30,8 +32,10 @@ import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; import de.vipra.util.ex.DatabaseException; +import de.vipra.util.model.ArticleFull; import de.vipra.util.model.TopicFull; import de.vipra.util.service.DatabaseService; +import de.vipra.util.service.Service.QueryBuilder; @Path("topics") public class TopicResource { @@ -40,11 +44,15 @@ public class TopicResource { UriInfo uri; final Cache<String, TopicFull> cache; - final DatabaseService<TopicFull, ObjectId> service; + final DatabaseService<TopicFull, ObjectId> dbTopics; + final DatabaseService<ArticleFull, ObjectId> dbArticles; + + public static final Logger log = LogManager.getLogger(TopicResource.class); public TopicResource(@Context ServletContext servletContext) throws ConfigException, IOException { Config config = Config.getConfig(); - service = DatabaseService.getDatabaseService(config, TopicFull.class); + dbTopics = DatabaseService.getDatabaseService(config, TopicFull.class); + dbArticles = DatabaseService.getDatabaseService(config, ArticleFull.class); CacheManager manager = (CacheManager) servletContext.getAttribute("cachemanager"); Cache<String, TopicFull> topicCache = manager.getCache("topiccache", String.class, TopicFull.class); @@ -61,16 +69,16 @@ public class TopicResource { Wrapper<List<TopicFull>> res = new Wrapper<>(); if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, service.count()); + res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbTopics.count()); if (res.hasErrors()) return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); try { - List<TopicFull> topics = service.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); + List<TopicFull> topics = dbTopics.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", service.count()); + res.addMeta("total", dbTopics.count()); else res.addMeta("total", topics.size()); @@ -85,7 +93,8 @@ public class TopicResource { @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Path("{id}") - public Response getTopic(@PathParam("id") String id, @QueryParam("fields") String fields) { + public Response getTopic(@PathParam("id") String id, @QueryParam("fields") String fields) + throws ConfigException, IOException { Wrapper<TopicFull> res = new Wrapper<>(); if (id == null || id.trim().length() == 0) { res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", @@ -101,9 +110,12 @@ public class TopicResource { return res.badRequest(); } - if (topic != null) + if (topic != null) { + List<ArticleFull> articles = dbArticles.getMultiple(QueryBuilder.builder().criteria("topics.topic", topic)); + topic.setArticles(articles); + return res.ok(topic); - else { + } else { res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found", String.format(Messages.NOT_FOUND, "topic", id))); return res.notFound(); @@ -118,7 +130,7 @@ public class TopicResource { TopicFull topic = wrapper.getData(); Wrapper<TopicFull> res = new Wrapper<>(); try { - service.updateSingle(topic); + dbTopics.updateSingle(topic); cache.put(id, topic); return res.ok(topic); } catch (DatabaseException e) { @@ -132,13 +144,13 @@ public class TopicResource { if (fields == null || fields.length == 0) { TopicFull topic = cache.get(id); if (topic == null) { - topic = service.getSingle(MongoUtils.objectId(id)); + topic = dbTopics.getSingle(MongoUtils.objectId(id)); if (topic != null) cache.put(id, topic); } return topic; } else - return service.getSingle(MongoUtils.objectId(id), fields); + return dbTopics.getSingle(MongoUtils.objectId(id), fields); } } diff --git a/vipra-rest/src/main/java/de/vipra/rest/resource/WordResource.java b/vipra-rest/src/main/java/de/vipra/rest/resource/WordResource.java index b05dbef57884ca03b6ffefb71d4e366303f959cb..c8cb5df41e92327400966cac2deab1f838545f2c 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/resource/WordResource.java +++ b/vipra-rest/src/main/java/de/vipra/rest/resource/WordResource.java @@ -16,6 +16,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.bson.types.ObjectId; import org.ehcache.Cache; import org.ehcache.CacheManager; import org.ehcache.config.CacheConfigurationBuilder; @@ -26,8 +27,10 @@ import de.vipra.rest.model.Wrapper; import de.vipra.util.Config; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; +import de.vipra.util.model.TopicFull; import de.vipra.util.model.Word; import de.vipra.util.service.DatabaseService; +import de.vipra.util.service.Service.QueryBuilder; @Path("words") public class WordResource { @@ -36,11 +39,13 @@ public class WordResource { UriInfo uri; final Cache<String, Word> cache; - final DatabaseService<Word, String> service; + final DatabaseService<Word, String> dbWords; + final DatabaseService<TopicFull, ObjectId> dbTopics; public WordResource(@Context ServletContext servletContext) throws ConfigException, IOException { Config config = Config.getConfig(); - service = DatabaseService.getDatabaseService(config, Word.class); + dbWords = DatabaseService.getDatabaseService(config, Word.class); + dbTopics = DatabaseService.getDatabaseService(config, TopicFull.class); CacheManager manager = (CacheManager) servletContext.getAttribute("cachemanager"); Cache<String, Word> wordCache = manager.getCache("wordcache", String.class, Word.class); @@ -57,16 +62,16 @@ public class WordResource { Wrapper<List<Word>> res = new Wrapper<>(); if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, service.count()); + res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbWords.count()); if (res.hasErrors()) return res.badRequest(); try { - List<Word> words = service.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); + List<Word> words = dbWords.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", service.count()); + res.addMeta("total", dbWords.count()); else res.addMeta("total", words.size()); @@ -97,9 +102,13 @@ public class WordResource { return res.badRequest(); } - if (word != null) + if (word != null) { + List<TopicFull> topics = dbTopics.getMultiple( + QueryBuilder.builder().fields(false, "index", "created", "modified").criteria("words.word", word)); + word.setTopics(topics); + return res.ok(word); - else { + } else { String msg = String.format(Messages.NOT_FOUND, "word", id); res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found", msg)); return res.notFound(); @@ -110,13 +119,13 @@ public class WordResource { if (fields == null || fields.length == 0) { Word word = cache.get(id); if (word == null) { - word = service.getSingle(id); + word = dbWords.getSingle(id); if (word != null) cache.put(id, word); } return word; } else - return service.getSingle(id, fields); + return dbWords.getSingle(id, fields); } } diff --git a/vipra-ui/html/topics/show.html b/vipra-ui/html/topics/show.html index 45b6595814b7f04d7ce8788b4e79e849f4e983c8..38d1648ede547bad61d2c42d76e7ef2003194cba 100644 --- a/vipra-ui/html/topics/show.html +++ b/vipra-ui/html/topics/show.html @@ -21,7 +21,15 @@ </tbody> </table> -<h4>Words</h4> +<h3>Articles</h3> + +<ul class="list-unstyled"> + <li ng-repeat="article in ::topic.articles"> + <article-link article="article"/> + </li> +</ul> + +<h3>Words</h3> <table class="table table-bordered table-condensed"> <thead> diff --git a/vipra-ui/html/words/show.html b/vipra-ui/html/words/show.html index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1ab0373b9d80526fe1895bf5c55481f6a77c62a6 100644 --- a/vipra-ui/html/words/show.html +++ b/vipra-ui/html/words/show.html @@ -0,0 +1,18 @@ +<h1 ng-bind="::word.id"></h1> + +<table class="table table-bordered table-condensed"> + <tbody> + <tr> + <th>Created</th> + <td ng-bind="::word.created"></td> + </tr> + </tbody> +</table> + +<h3>Topics</h3> + +<ul class="list-unstyled"> + <li ng-repeat="topic in ::word.topics"> + <topic-link topic="topic"/> + </li> +</ul> \ No newline at end of file diff --git a/vipra-ui/js/controllers.js b/vipra-ui/js/controllers.js index fe19b5f01344aa6aba4bba10ac6baa50582a5655..0eabe9f4852207196d67f05fdef03aa232bcf04f 100644 --- a/vipra-ui/js/controllers.js +++ b/vipra-ui/js/controllers.js @@ -127,6 +127,7 @@ WordFactory.get({id: $stateParams.id}, function(response) { $scope.word = response.data; + $scope.word.created = formatDateTime($scope.word.created); $scope.wordMeta = response.meta; $scope.queryTime = response.$queryTime; }); diff --git a/vipra-ui/js/directives.js b/vipra-ui/js/directives.js index a5681be6b7a90c2135129d2b1d5feec91e8b17d0..46bff5302cc34918a871bd9d4d50eeb470944c62 100644 --- a/vipra-ui/js/directives.js +++ b/vipra-ui/js/directives.js @@ -18,6 +18,18 @@ } }); + app.directive('articleLink', function() { + return { + scope: { + article: '=' + }, + restrict: 'E', + replace: true, + transclude: true, + template: '<a class="article-link" ui-sref="articles.show({id:article.id})"><span ng-bind="article.title"></span><ng-transclude/></a>' + } + }); + app.directive('queryTime', function() { return { restrict: 'E', diff --git a/vipra-util/src/main/java/de/vipra/util/Pair.java b/vipra-util/src/main/java/de/vipra/util/Pair.java new file mode 100644 index 0000000000000000000000000000000000000000..23c2e378094845c731aa2a7bbf90b1caa50ac8eb --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/Pair.java @@ -0,0 +1,35 @@ +package de.vipra.util; + +public class Pair<X, Y> { + + private X x; + private Y y; + + public Pair() {} + + public Pair(X x, Y y) { + this.x = x; + this.y = y; + } + + public X x() { + return x; + } + + public void setX(X x) { + this.x = x; + } + + public Y y() { + return y; + } + + public void setY(Y y) { + this.y = y; + } + + public static <X, Y> Pair<X, Y> pair(X x, Y y) { + return new Pair<>(x, y); + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java index 4449f5b26eeceabe4d2aec28c13d85b039f8148e..afa7d461397c8343837b55604b91988cf2cb3475 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java @@ -11,20 +11,20 @@ public class ArticleStats implements Serializable { private static final long serialVersionUID = -4712841724990200627L; - private long wordCount; + private Long wordCount; - public long getWordCount() { + public Long getWordCount() { return wordCount; } - public void setWordCount(long wordCount) { + public void setWordCount(Long wordCount) { this.wordCount = wordCount; } public static ArticleStats generateFromText(final String text, final WordMap wordMap) { ArticleStats stats = new ArticleStats(); String[] words = text.split("\\s+"); - stats.setWordCount(words.length); + stats.setWordCount((long) words.length); return stats; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/Import.java b/vipra-util/src/main/java/de/vipra/util/model/Import.java index a89697388f89d02f78b042d0dfa14e795ad6d4ff..4ed9ce315b851c43465e814fa534c59c0bc51488 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Import.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Import.java @@ -24,25 +24,25 @@ public class Import implements Model<ObjectId>, Serializable { private Date date; - private long duration; + private Long duration; @QueryIgnore(multi = true) @Reference(ignoreMissing = true) private List<Article> articles; - private int articlesCount; + private Integer articlesCount; @QueryIgnore(multi = true) @Reference(ignoreMissing = true) private List<Topic> topics; - private int topicsCount; + private Integer topicsCount; @QueryIgnore(multi = true) @Reference(ignoreMissing = true) private List<Word> words; - private int wordsCount; + private Integer wordsCount; @Override public ObjectId getId() { @@ -62,11 +62,11 @@ public class Import implements Model<ObjectId>, Serializable { this.date = date; } - public long getDuration() { + public Long getDuration() { return duration; } - public void setDuration(long duration) { + public void setDuration(Long duration) { this.duration = duration; } @@ -80,7 +80,7 @@ public class Import implements Model<ObjectId>, Serializable { articlesCount = articles.size(); } - public int getArticlesCount() { + public Integer getArticlesCount() { return articlesCount; } @@ -94,7 +94,7 @@ public class Import implements Model<ObjectId>, Serializable { topicsCount = topics.size(); } - public int getTopicsCount() { + public Integer getTopicsCount() { return topicsCount; } @@ -108,7 +108,7 @@ public class Import implements Model<ObjectId>, Serializable { wordsCount = words.size(); } - public int getWordsCount() { + public Integer getWordsCount() { return wordsCount; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java index 63750c08c94d55f69d34bd5bdc893da663359fbd..f004d83788a70049a290eb3049588d1d8346d6c0 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java @@ -10,6 +10,7 @@ import org.mongodb.morphia.annotations.Embedded; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; import org.mongodb.morphia.annotations.PrePersist; +import org.mongodb.morphia.annotations.Transient; import de.vipra.util.Constants; import de.vipra.util.MongoUtils; @@ -25,12 +26,15 @@ public class TopicFull implements Model<ObjectId>, Serializable { private String name; - private int index; + private Integer index; @Embedded @QueryIgnore(multi = true) private List<TopicWord> words; + @Transient + private List<ArticleFull> articles; + private Date created; private Date modified; @@ -57,11 +61,11 @@ public class TopicFull implements Model<ObjectId>, Serializable { this.name = name; } - public int getIndex() { + public Integer getIndex() { return index; } - public void setIndex(int index) { + public void setIndex(Integer index) { this.index = index; } @@ -73,6 +77,14 @@ public class TopicFull implements Model<ObjectId>, Serializable { this.words = topicWords; } + public List<ArticleFull> getArticles() { + return articles; + } + + public void setArticles(List<ArticleFull> articles) { + this.articles = articles; + } + public Date getCreated() { return created; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicRef.java b/vipra-util/src/main/java/de/vipra/util/model/TopicRef.java index 920abdce7074e73c8c4dd3e99cd33087e5a8ee17..c5de02e6b750df507e7d8d0f9b15bc2eed307f21 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicRef.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicRef.java @@ -14,7 +14,7 @@ public class TopicRef implements Comparable<TopicRef>, Serializable { private String topicIndex; @Reference(ignoreMissing = true) private Topic topic; - private int count; + private Integer count; public String getTopicIndex() { return topicIndex; @@ -24,11 +24,11 @@ public class TopicRef implements Comparable<TopicRef>, Serializable { this.topicIndex = index; } - public int getCount() { + public Integer getCount() { return count; } - public void setCount(int count) { + public void setCount(Integer count) { this.count = count; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java index abed0a8abfbf7641b852e6ae2a0f9728354b6e32..bd79ed2b418461b4f33432d7537c765e479e80a1 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicWord.java @@ -20,11 +20,11 @@ public class TopicWord implements Comparable<TopicWord>, Serializable { @JsonProperty("word") private String wordString; - private double likeliness; + private Double likeliness; public TopicWord() {} - public TopicWord(Word word, double likeliness) { + public TopicWord(Word word, Double likeliness) { this.word = word; this.likeliness = likeliness; } @@ -41,11 +41,11 @@ public class TopicWord implements Comparable<TopicWord>, Serializable { return wordString; } - public double getLikeliness() { + public Double getLikeliness() { return likeliness; } - public void setLikeliness(double likeliness) { + public void setLikeliness(Double likeliness) { this.likeliness = likeliness; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/Word.java b/vipra-util/src/main/java/de/vipra/util/model/Word.java index 06758a80987ac6a13e99019ea9846a74aa57e24c..7b5c4ed688ebfd12b1facebe2d666648cdfed9c6 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Word.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Word.java @@ -2,6 +2,7 @@ package de.vipra.util.model; import java.io.Serializable; import java.util.Date; +import java.util.List; import org.mongodb.morphia.annotations.Entity; import org.mongodb.morphia.annotations.Id; @@ -36,6 +37,9 @@ public class Word implements Model<String>, Serializable { @JsonIgnore private String word; + @Transient + private List<TopicFull> topics; + @QueryIgnore(multi = true) private Date created; @@ -73,6 +77,14 @@ public class Word implements Model<String>, Serializable { this.id = word; } + public List<TopicFull> getTopics() { + return topics; + } + + public void setTopics(List<TopicFull> topics) { + this.topics = topics; + } + public boolean isCreated() { return isCreated; } diff --git a/vipra-util/src/main/java/de/vipra/util/service/DatabaseService.java b/vipra-util/src/main/java/de/vipra/util/service/DatabaseService.java index da1e780a62b2f21dece1eecce1d3c999c842639a..692dc93efe156cde80e707079e73bf05a4614aab 100644 --- a/vipra-util/src/main/java/de/vipra/util/service/DatabaseService.java +++ b/vipra-util/src/main/java/de/vipra/util/service/DatabaseService.java @@ -13,6 +13,7 @@ import org.mongodb.morphia.query.Query; import de.vipra.util.Config; import de.vipra.util.ListUtils; import de.vipra.util.Mongo; +import de.vipra.util.Pair; import de.vipra.util.an.QueryIgnore; import de.vipra.util.ex.ConfigException; import de.vipra.util.ex.DatabaseException; @@ -57,29 +58,56 @@ public class DatabaseService<Type extends Model<IdType>, IdType> implements Serv @Override public List<Type> getMultiple(Integer skip, Integer limit, String sortBy, String... fields) { - return getMultiple(skip, limit, sortBy, true, fields); + return getMultiple(QueryBuilder.builder().skip(skip).limit(limit).sortBy(sortBy).fields(true, fields)); } @Override - public List<Type> getMultiple(Integer skip, Integer limit, String sortBy, boolean defaultIgnore, String... fields) { + public List<Type> getMultiple(Integer skip, Integer limit, String sortBy, Pair<String, Object> criteria, + String... fields) { + return getMultiple( + QueryBuilder.builder().skip(skip).limit(limit).sortBy(sortBy).criteria(criteria).fields(true, fields)); + } + + @Override + public List<Type> getMultiple(Integer skip, Integer limit, String sortBy, Pair<String, Object> criteria, + boolean defaultIgnore, String... fields) { + return getMultiple(QueryBuilder.builder().skip(skip).limit(limit).sortBy(sortBy).fields(true, fields) + .criteria(criteria).defaultIgnore(defaultIgnore)); + } + + @Override + public List<Type> getMultiple(QueryBuilder builder) { Query<Type> q = datastore.createQuery(clazz); - if (skip != null && skip > 0) - q.offset(skip); - if (limit != null && limit > 0) - q.limit(limit); - if (sortBy != null) - q.order(sortBy); - if (fields != null && fields.length > 0) - q.retrievedFields(true, setMinus(fields, ignoredFieldsMulti)); - else if (defaultIgnore && ignoredFieldsMulti.length > 0) + if (builder.getSkip() != null && builder.getSkip() > 0) + q.offset(builder.getSkip()); + if (builder.getLimit() != null && builder.getLimit() > 0) + q.limit(builder.getLimit()); + if (builder.getSortBy() != null) + q.order(builder.getSortBy()); + if (builder.getCriteria() != null) + for (Pair<String, Object> criteria : builder.getCriteria()) + q.field(criteria.x()).equal(criteria.y()); + if (builder.getFields() != null) { + String[] fields = builder.getFields(); + if (builder.isInclude()) { + if (builder.isDefaultIgnore() && ignoredFieldsMulti.length > 0) + fields = setMinus(fields, ignoredFieldsMulti); + q.retrievedFields(true, fields); + } else { + if (builder.isDefaultIgnore() && ignoredFieldsMulti.length > 0) + fields = setPlus(fields, ignoredFieldsMulti); + q.retrievedFields(false, fields); + } + } else if (ignoredFieldsMulti.length > 0) { q.retrievedFields(false, ignoredFieldsMulti); + } List<Type> list = q.asList(); return list; } @Override public List<Type> getAll(String... fields) { - return getMultiple(null, null, null, fields); + return getMultiple(null, null, null, null, fields); } @Override @@ -131,4 +159,14 @@ public class DatabaseService<Type extends Model<IdType>, IdType> implements Serv return a; } + private String[] setPlus(String[] a, String[] b) { + if (a != null && b != null) { + Set<String> sa = new HashSet<>(Arrays.asList(a)); + Set<String> sb = new HashSet<>(Arrays.asList(b)); + sa.addAll(sb); + return sa.toArray(new String[sa.size()]); + } + return a; + } + } diff --git a/vipra-util/src/main/java/de/vipra/util/service/Service.java b/vipra-util/src/main/java/de/vipra/util/service/Service.java index 3282b1728c499bd70178ff7326d073fe8ecf1ed6..dbdc07eedbdeb76c438f80f6a6a0977eaa86da70 100644 --- a/vipra-util/src/main/java/de/vipra/util/service/Service.java +++ b/vipra-util/src/main/java/de/vipra/util/service/Service.java @@ -1,7 +1,9 @@ package de.vipra.util.service; +import java.util.ArrayList; import java.util.List; +import de.vipra.util.Pair; import de.vipra.util.model.Model; public interface Service<Type extends Model<IdType>, IdType, E extends Exception> { @@ -10,9 +12,14 @@ public interface Service<Type extends Model<IdType>, IdType, E extends Exception List<Type> getMultiple(Integer skip, Integer limit, String sortBy, String... fields) throws E; - List<Type> getMultiple(Integer skip, Integer limit, String sortBy, boolean noDefaultIgnore, String... fields) + List<Type> getMultiple(Integer skip, Integer limit, String sortBy, Pair<String, Object> criteria, String... fields) throws E; + List<Type> getMultiple(Integer skip, Integer limit, String sortBy, Pair<String, Object> criteria, + boolean noDefaultIgnore, String... fields) throws E; + + List<Type> getMultiple(QueryBuilder builder) throws E; + List<Type> getAll(String... fields) throws E; Type createSingle(Type t) throws E; @@ -27,4 +34,88 @@ public interface Service<Type extends Model<IdType>, IdType, E extends Exception long count() throws E; + public static class QueryBuilder { + + private Integer skip; + private Integer limit; + private String sortBy; + private List<Pair<String, Object>> criteria; + private String[] fields; + private boolean include; + private boolean defaultIgnore = true; + + private QueryBuilder() {} + + public static QueryBuilder builder() { + return new QueryBuilder(); + } + + public QueryBuilder skip(Integer skip) { + this.skip = skip; + return this; + } + + public QueryBuilder limit(Integer limit) { + this.limit = limit; + return this; + } + + public QueryBuilder sortBy(String sortBy) { + this.sortBy = sortBy; + return this; + } + + public QueryBuilder criteria(String field, Object value) { + return criteria(Pair.pair(field, value)); + } + + public QueryBuilder criteria(Pair<String, Object> pair) { + if (criteria == null) { + criteria = new ArrayList<>(); + } + criteria.add(pair); + return this; + } + + public QueryBuilder fields(boolean include, String... strings) { + this.include = include; + this.fields = strings; + return this; + } + + public QueryBuilder defaultIgnore(boolean defaultIgnore) { + this.defaultIgnore = defaultIgnore; + return this; + } + + public Integer getSkip() { + return skip; + } + + public Integer getLimit() { + return limit; + } + + public String getSortBy() { + return sortBy; + } + + public List<Pair<String, Object>> getCriteria() { + return criteria; + } + + public boolean isInclude() { + return include; + } + + public String[] getFields() { + return fields; + } + + public boolean isDefaultIgnore() { + return defaultIgnore; + } + + } + }