diff --git a/vipra-backend/src/main/java/de/vipra/rest/model/ResponseWrapper.java b/vipra-backend/src/main/java/de/vipra/rest/model/ResponseWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c7642be81068e8569301c1e8ba979bf92d765598 --- /dev/null +++ b/vipra-backend/src/main/java/de/vipra/rest/model/ResponseWrapper.java @@ -0,0 +1,102 @@ +package de.vipra.rest.model; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; + +import de.vipra.util.StringUtils; + +public class ResponseWrapper<T> { + + private List<APIError> errors; + private Map<String, Object> headers; + + public List<APIError> getErrors() { + return errors; + } + + public void addError(APIError error) { + if (errors == null) + errors = new ArrayList<>(); + errors.add(error); + } + + public void addHeader(String name, Object value) { + if (headers == null) + headers = new HashMap<>(); + headers.put("V-" + StringUtils.capitalize(name), value); + } + + public boolean hasErrors() { + return errors != null && errors.size() > 0; + } + + private void addHeaders(ResponseBuilder builder) { + if (headers == null || headers.size() == 0) + return; + for (Entry<String, Object> entry : headers.entrySet()) + builder.header(entry.getKey(), entry.getValue()); + } + + /** + * Status 200 + */ + public Response ok(T data) { + ResponseBuilder builder = Response.ok().entity(data); + addHeaders(builder); + return builder.build(); + } + + /** + * Status 201 + */ + public Response created(T data, URI loc) { + ResponseBuilder builder = Response.created(loc).entity(data); + addHeaders(builder); + return builder.build(); + } + + /** + * Status 204 + */ + public Response noContent() { + ResponseBuilder builder = Response.noContent(); + addHeaders(builder); + return builder.build(); + } + + /** + * Status 400 + */ + public Response badRequest() { + ResponseBuilder builder = Response.status(Status.BAD_REQUEST).entity(errors); + addHeaders(builder); + return builder.build(); + } + + /** + * Status 404 + */ + public Response notFound() { + ResponseBuilder builder = Response.status(Status.NOT_FOUND).entity(errors); + addHeaders(builder); + return builder.build(); + } + + /** + * Status 500 + */ + public Response serverError() { + ResponseBuilder builder = Response.serverError().entity(errors); + addHeaders(builder); + return builder.build(); + } + +} diff --git a/vipra-backend/src/main/java/de/vipra/rest/model/Wrapper.java b/vipra-backend/src/main/java/de/vipra/rest/model/Wrapper.java deleted file mode 100644 index d10e083018ab5274770762564c8ba7c8435251c1..0000000000000000000000000000000000000000 --- a/vipra-backend/src/main/java/de/vipra/rest/model/Wrapper.java +++ /dev/null @@ -1,165 +0,0 @@ -package de.vipra.rest.model; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriBuilder; - -import de.vipra.rest.Messages; -import de.vipra.util.NestedMap; - -public class Wrapper<T> { - - private T data; - private List<APIError> errors; - private Map<String, String> links; - private NestedMap meta; - - public Wrapper() {} - - public Wrapper(T data) { - setData(data); - } - - public Wrapper(APIError error) { - addError(error); - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - this.errors = null; - } - - public List<APIError> getErrors() { - return errors; - } - - public void setErrors(List<APIError> errors) { - this.errors = errors; - this.data = null; - } - - public void addError(APIError error) { - if (errors == null) - errors = new ArrayList<>(); - errors.add(error); - } - - public Map<String, String> getLinks() { - return links; - } - - public void setLinks(Map<String, String> links) { - this.links = links; - } - - public void addLink(String key, String link) { - if (links == null) - links = new HashMap<>(); - links.put(key, link); - } - - public NestedMap getMeta() { - return meta; - } - - public void setMeta(NestedMap meta) { - this.meta = meta; - } - - public void addMeta(String key, Object value) { - if (meta == null) - meta = new NestedMap(); - meta.put(key, value); - } - - public void addPaginationLinks(URI base, Integer skip, Integer limit, long count) { - if (skip == null || limit == null || limit == 0) - return; - - if (skip < 0) { - addError(new APIError(Response.Status.BAD_REQUEST, "Wrong skip number", - String.format(Messages.BAD_REQUEST, "skip number must be greater or equal to 0"))); - return; - } - - if (limit < 0) { - addError(new APIError(Response.Status.BAD_REQUEST, "Wrong limit size", - String.format(Messages.BAD_REQUEST, "when using skip, limit size must be greater or equal to 1"))); - return; - } - - addLink("first", UriBuilder.fromUri(base).queryParam("skip", 0).queryParam("limit", limit).build().toString()); - addLink("last", UriBuilder.fromUri(base).queryParam("skip", (count / limit) * limit).queryParam("limit", limit) - .build().toString()); - - if (skip > 0) { - int diff = skip % limit; - if (diff == 0) - diff = limit; - int prevSkip = Math.max(0, skip - diff); - addLink("prev", UriBuilder.fromUri(base).queryParam("skip", prevSkip).queryParam("limit", limit).build() - .toString()); - } - - if (skip + limit < count) { - int diff = limit - skip % limit; - if (diff == 0) - diff = limit; - int nextSkip = skip + diff; - addLink("next", UriBuilder.fromUri(base).queryParam("skip", nextSkip).queryParam("limit", limit).build() - .toString()); - } - } - - public boolean hasErrors() { - return errors != null && errors.size() > 0; - } - - public Response ok() { - return Response.ok().entity(this).build(); - } - - public Response ok(T data) { - this.data = data; - return ok(); - } - - public Response badRequest() { - return Response.status(Status.BAD_REQUEST).entity(this).build(); - } - - public Response serverError() { - return Response.serverError().entity(this).build(); - } - - public Response created(URI loc) { - return Response.created(loc).entity(this).build(); - } - - public Response notFound() { - return Response.status(Status.NOT_FOUND).entity(this).build(); - } - - public Response noContent() { - return Response.noContent().build(); - } - - public Response status(Status status, boolean withEntity) { - ResponseBuilder r = Response.status(status); - if (withEntity) - r.entity(this); - return r.build(); - } - -} diff --git a/vipra-backend/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java b/vipra-backend/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java index 8e65b96201384a46edb7bc358bfe340a579482b2..ac8cc2e9a107af41095a25abf33755b3c04cb7f3 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java +++ b/vipra-backend/src/main/java/de/vipra/rest/provider/CORSResponseFilter.java @@ -22,8 +22,9 @@ public class CORSResponseFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException { response.getHeaders().add("Access-Control-Allow-Origin", "*"); - response.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization"); + response.getHeaders().add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization"); response.getHeaders().add("Access-Control-Allow-Credentials", "true"); response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD"); + response.getHeaders().add("Access-Control-Expose-Headers", "V-Total"); } } \ No newline at end of file diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java index 9c88f448c81d52fafe18fa9ca6ebac11c62cbb9f..d37c7e365ef425c30208a1b1906a85977c34d069 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/ArticleResource.java @@ -27,7 +27,7 @@ import org.bson.types.ObjectId; import de.vipra.rest.Messages; import de.vipra.rest.model.APIError; -import de.vipra.rest.model.Wrapper; +import de.vipra.rest.model.ResponseWrapper; import de.vipra.util.Config; import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; @@ -54,10 +54,7 @@ public class ArticleResource { public Response getArticles(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, @QueryParam("sort") @DefaultValue("date") String sortBy, @QueryParam("fields") String fields, @QueryParam("query") String query) { - Wrapper<List<ArticleFull>> res = new Wrapper<>(); - - if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbArticles.count()); + ResponseWrapper<List<ArticleFull>> res = new ResponseWrapper<>(); if (res.hasErrors()) return res.badRequest(); @@ -66,9 +63,9 @@ public class ArticleResource { List<ArticleFull> articles = dbArticles.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", dbArticles.count()); + res.addHeader("total", dbArticles.count()); else - res.addMeta("total", articles.size()); + res.addHeader("total", articles.size()); return res.ok(articles); } catch (Exception e) { @@ -83,7 +80,7 @@ public class ArticleResource { @Consumes(MediaType.APPLICATION_JSON) @Path("{id}") public Response getArticle(@PathParam("id") String id, @QueryParam("fields") String fields) { - Wrapper<ArticleFull> res = new Wrapper<>(); + ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); if (id == null || id.trim().length() == 0) { res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", String.format(Messages.BAD_REQUEST, "id cannot be empty"))); @@ -112,15 +109,14 @@ public class ArticleResource { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response createArticle(ArticleFull article) { - Wrapper<ArticleFull> res; + ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); try { article = dbArticles.createSingle(article); - res = new Wrapper<>(article); URI newUri = new URL(uri.getAbsolutePath().toURL(), article.getId().toString()).toURI(); - return res.created(newUri); + return res.created(article, newUri); } catch (DatabaseException | MalformedURLException | URISyntaxException e) { e.printStackTrace(); - res = new Wrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be created", + res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be created", "item could not be created due to an internal server error")); return res.serverError(); } @@ -129,13 +125,13 @@ public class ArticleResource { @DELETE @Path("{id}") public Response deleteArticle(@PathParam("id") String id) { - Wrapper<ArticleFull> res = new Wrapper<>(); + ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); long deleted; try { deleted = dbArticles.deleteSingle(MongoUtils.objectId(id)); } catch (DatabaseException e) { e.printStackTrace(); - res = new Wrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be deleted", + res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be deleted", "item could not be created due to an internal server error")); return res.serverError(); } @@ -157,14 +153,14 @@ public class ArticleResource { @Produces(MediaType.APPLICATION_JSON) @Path("{id}") public Response replaceArticle(@PathParam("id") String id, ArticleFull article) { - Wrapper<ArticleFull> res = new Wrapper<>(); + ResponseWrapper<ArticleFull> res = new ResponseWrapper<>(); try { dbArticles.replaceSingle(article); return res.ok(article); } catch (DatabaseException e) { e.printStackTrace(); - res = new Wrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be updated", + res.addError(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be updated", "item could not be updated due to an internal server error")); return res.serverError(); } diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java index 0ea760c5443687d23d77008224153b5dd95797da..9a9aac2ab7b70699c068167edcdc7daace3ada86 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/InfoResource.java @@ -13,7 +13,7 @@ import javax.ws.rs.core.UriInfo; import org.bson.types.ObjectId; -import de.vipra.rest.model.Wrapper; +import de.vipra.rest.model.ResponseWrapper; import de.vipra.util.BuildInfo; import de.vipra.util.Config; import de.vipra.util.NestedMap; @@ -32,7 +32,7 @@ public class InfoResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response getInfo() { - Wrapper<NestedMap> res = new Wrapper<>(); + ResponseWrapper<NestedMap> res = new ResponseWrapper<>(); NestedMap info = new NestedMap(); try { diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/SearchResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/SearchResource.java index 17bd7c1e69d73742b6d57ca3e3275aa2c828ca88..a9600df9df1754c0e9afc2e9f9f9634d97957e6b 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/SearchResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/SearchResource.java @@ -25,7 +25,7 @@ import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import de.vipra.rest.model.APIError; -import de.vipra.rest.model.Wrapper; +import de.vipra.rest.model.ResponseWrapper; import de.vipra.util.Config; import de.vipra.util.Constants; import de.vipra.util.ESClient; @@ -51,7 +51,7 @@ public class SearchResource { @Produces(MediaType.APPLICATION_JSON) public Response doSearch(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, @QueryParam("fields") String fields, @QueryParam("query") String query) { - Wrapper<List<ArticleFull>> res = new Wrapper<>(); + ResponseWrapper<List<ArticleFull>> res = new ResponseWrapper<>(); if (skip == null || skip < 0) skip = 0; @@ -95,7 +95,7 @@ public class SearchResource { articles.add(article); } - res.addMeta("total", articles.size()); + res.addHeader("total", articles.size()); return res.ok(articles); } diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java index 00726deebfd902581cc74d95a6aba8bf5163a41b..6a0d7bde5fdc71e57f17b988124d9865e4e4b0f7 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/TopicResource.java @@ -23,7 +23,7 @@ import org.bson.types.ObjectId; import de.vipra.rest.Messages; import de.vipra.rest.model.APIError; -import de.vipra.rest.model.Wrapper; +import de.vipra.rest.model.ResponseWrapper; import de.vipra.util.Config; import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; @@ -56,10 +56,7 @@ public class TopicResource { @Produces(MediaType.APPLICATION_JSON) public Response getTopics(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, @QueryParam("sort") @DefaultValue("name") String sortBy, @QueryParam("fields") String fields) { - Wrapper<List<TopicFull>> res = new Wrapper<>(); - - if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbTopics.count()); + ResponseWrapper<List<TopicFull>> res = new ResponseWrapper<>(); if (res.hasErrors()) return Response.status(Response.Status.BAD_REQUEST).entity(res).build(); @@ -68,9 +65,9 @@ public class TopicResource { List<TopicFull> topics = dbTopics.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", dbTopics.count()); + res.addHeader("total", dbTopics.count()); else - res.addMeta("total", topics.size()); + res.addHeader("total", topics.size()); return res.ok(topics); } catch (Exception e) { @@ -86,7 +83,7 @@ public class TopicResource { @Path("{id}") public Response getTopic(@PathParam("id") String id, @QueryParam("fields") String fields) throws ConfigException, IOException { - Wrapper<TopicFull> res = new Wrapper<>(); + ResponseWrapper<TopicFull> res = new ResponseWrapper<>(); if (id == null || id.trim().length() == 0) { res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", String.format(Messages.BAD_REQUEST, "id cannot be empty"))); @@ -116,7 +113,7 @@ public class TopicResource { @Consumes(MediaType.APPLICATION_JSON) @Path("{id}/articles") public Response getArticles(@PathParam("id") String id, @QueryParam("fields") String fields) { - Wrapper<List<ArticleFull>> res = new Wrapper<>(); + ResponseWrapper<List<ArticleFull>> res = new ResponseWrapper<>(); try { Topic topic = new Topic(MongoUtils.objectId(id)); QueryBuilder query = QueryBuilder.builder().criteria("topics.topic", topic); @@ -136,7 +133,7 @@ public class TopicResource { @Produces(MediaType.APPLICATION_JSON) @Path("{id}") public Response replaceTopic(@PathParam("id") String id, TopicFull topic) { - Wrapper<TopicFull> res = new Wrapper<>(); + ResponseWrapper<TopicFull> res = new ResponseWrapper<>(); try { dbTopics.replaceSingle(topic); diff --git a/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java b/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java index 6e15887984f366576be421f248b27105b4cd61b2..951e398c4d982968ebfed3aea7fd0b45dd9b173a 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java +++ b/vipra-backend/src/main/java/de/vipra/rest/resource/WordResource.java @@ -20,7 +20,7 @@ import org.bson.types.ObjectId; import de.vipra.rest.Messages; import de.vipra.rest.model.APIError; -import de.vipra.rest.model.Wrapper; +import de.vipra.rest.model.ResponseWrapper; import de.vipra.util.Config; import de.vipra.util.StringUtils; import de.vipra.util.ex.ConfigException; @@ -48,10 +48,7 @@ public class WordResource { @Produces(MediaType.APPLICATION_JSON) public Response getWords(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit, @QueryParam("sort") @DefaultValue("id") String sortBy, @QueryParam("fields") String fields) { - Wrapper<List<Word>> res = new Wrapper<>(); - - if (skip != null && limit != null) - res.addPaginationLinks(uri.getAbsolutePath(), skip, limit, dbWords.count()); + ResponseWrapper<List<Word>> res = new ResponseWrapper<>(); if (res.hasErrors()) return res.badRequest(); @@ -60,9 +57,9 @@ public class WordResource { List<Word> words = dbWords.getMultiple(skip, limit, sortBy, StringUtils.getFields(fields)); if ((skip != null && skip > 0) || (limit != null && limit > 0)) - res.addMeta("total", dbWords.count()); + res.addHeader("total", dbWords.count()); else - res.addMeta("total", words.size()); + res.addHeader("total", words.size()); return res.ok(words); } catch (Exception e) { @@ -77,7 +74,7 @@ public class WordResource { @Consumes(MediaType.APPLICATION_JSON) @Path("{id}") public Response getWord(@PathParam("id") String id, @QueryParam("fields") String fields) { - Wrapper<Word> res = new Wrapper<>(); + ResponseWrapper<Word> res = new ResponseWrapper<>(); if (id == null || id.trim().length() == 0) { res.addError(new APIError(Response.Status.BAD_REQUEST, "ID is empty", String.format(Messages.BAD_REQUEST, "id cannot be empty"))); @@ -107,7 +104,7 @@ public class WordResource { @Consumes(MediaType.APPLICATION_JSON) @Path("{id}/topics") public Response getWordTopics(@PathParam("id") String id, @QueryParam("fields") String fields) { - Wrapper<List<TopicFull>> res = new Wrapper<>(); + ResponseWrapper<List<TopicFull>> res = new ResponseWrapper<>(); try { Word word = new Word(id); QueryBuilder query = QueryBuilder.builder().fields(true, "id", "name").criteria("words.word", word); diff --git a/vipra-ui/app/html/articles/index.html b/vipra-ui/app/html/articles/index.html index 63dfe95c87af1bc81c6f9933fd3068c596b2257d..56c9970a6b708d062c15cb007f736b2d4a00cc4d 100644 --- a/vipra-ui/app/html/articles/index.html +++ b/vipra-ui/app/html/articles/index.html @@ -1,6 +1,6 @@ <div ui-view ng-cloak> <div class="well"> - Found <span ng-bind="articlesMeta.total"></span> articles in the database <query-time/>.<br> + Found <span ng-bind="articlesTotal"></span> articles in the database.<br> </div> <ul class="dashed"> @@ -9,5 +9,5 @@ </li> </ul> - <pagination total="articlesMeta.total" page="page" limit="limit" change="changePage"/> + <pagination total="articlesTotal" page="page" limit="limit" change="changePage"/> </div> \ No newline at end of file diff --git a/vipra-ui/app/html/articles/show.html b/vipra-ui/app/html/articles/show.html index 52c390857ebe7e97d9bce7e419544d894f548156..800544880be9541add49170827bd7b7da20e8b0a 100644 --- a/vipra-ui/app/html/articles/show.html +++ b/vipra-ui/app/html/articles/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1 ng-bind="::article.title"></h1> diff --git a/vipra-ui/app/html/index.html b/vipra-ui/app/html/index.html index b183c4b8a12f8b9b646cab6e3771eace06239405..d6be6e5e35a27c94a48f0215b73a78092d63de2e 100644 --- a/vipra-ui/app/html/index.html +++ b/vipra-ui/app/html/index.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="container"> <div class="row" ng-hide="search"> @@ -37,9 +37,6 @@ <div class="row row-spaced"> <div class="col-md-12"> <input type="text" class="form-control input-lg" placeholder="Search..." ng-model="search" ng-model-options="{debounce:500}"> - <div id="advanced" style="display:none"> - - </div> </div> </div> @@ -48,10 +45,10 @@ Searching... </div> <div class="col-md-12" ng-show="!searching && search && (!searchResults || searchResults.length == 0)"> - <h4>No Results <query-time/></h4> + <h4>No Results</h4> </div> <div class="col-md-12" ng-show="searchResults.length > 0"> - <h4>Results <query-time/></h4> + <h4>Results</h4> <ul class="list-unstyled search-results"> <li class="search-result" ng-repeat="article in searchResults"> <a ui-sref="articles.show({id:article.id})" ng-bind="article.title"></a> diff --git a/vipra-ui/app/html/topics/articles.html b/vipra-ui/app/html/topics/articles.html index 7b188562b7717c706b8fb32c0e04b886e0cd51bd..90d1e2d06a4928dc4ed81347ce5eec03f01acc01 100644 --- a/vipra-ui/app/html/topics/articles.html +++ b/vipra-ui/app/html/topics/articles.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1> <div ng-bind="topic.name" ng-hide="isRename"></div> diff --git a/vipra-ui/app/html/topics/index.html b/vipra-ui/app/html/topics/index.html index 4997b5e93bc2e01e973344282156568378846d43..bf4b95edc2a8b7604134d25116ca2a24c6b7ec91 100644 --- a/vipra-ui/app/html/topics/index.html +++ b/vipra-ui/app/html/topics/index.html @@ -1,6 +1,6 @@ <div ui-view ng-cloak> <div class="well"> - Found <span ng-bind="topicsMeta.total"></span> topics in the database <query-time/>. + Found <span ng-bind="topicsTotal"></span> topics in the database. </div> <ul class="dashed"> @@ -9,5 +9,5 @@ </li> </ul> - <pagination total="topicsMeta.total" page="page" limit="limit" change="changePage"/> + <pagination total="topicsTotal" page="page" limit="limit" change="changePage"/> </div> \ No newline at end of file diff --git a/vipra-ui/app/html/topics/show.html b/vipra-ui/app/html/topics/show.html index 20a53ba7e89f4019bace2f6dffc8245546aa8d1d..964d974382856a7a1d3d1c6d998e644e76daf2ec 100644 --- a/vipra-ui/app/html/topics/show.html +++ b/vipra-ui/app/html/topics/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1> <div ng-bind="topic.name" ng-hide="isRename"></div> diff --git a/vipra-ui/app/html/words/index.html b/vipra-ui/app/html/words/index.html index 4f6df953b5f2487fdbbf93a7dbb54f88b160baa4..7e129d75dd43cde067fc23adfcebc4f7d2db35c8 100644 --- a/vipra-ui/app/html/words/index.html +++ b/vipra-ui/app/html/words/index.html @@ -1,6 +1,6 @@ <div ui-view ng-cloak> <div class="well"> - Found <span ng-bind="wordsMeta.total"></span> words in the database <query-time/>. + Found <span ng-bind="wordsTotal"></span> words in the database. </div> <div class="row"> @@ -27,5 +27,5 @@ </div> </div> - <pagination total="wordsMeta.total" page="page" limit="limit" change="changePage"/> + <pagination total="wordsTotal" page="page" limit="limit" change="changePage"/> </div> \ No newline at end of file diff --git a/vipra-ui/app/html/words/show.html b/vipra-ui/app/html/words/show.html index 6174e8c3554e362f7ed5560f5a9bdf0fb4deef49..445cc90ae99c4df67e0c1c393f39dcbf3ee5298f 100644 --- a/vipra-ui/app/html/words/show.html +++ b/vipra-ui/app/html/words/show.html @@ -1,4 +1,4 @@ -<div ui-view ng-cloak> +<div ng-cloak> <div class="page-header"> <h1 ng-bind="::word.id"></h1> </div> diff --git a/vipra-ui/app/index.html b/vipra-ui/app/index.html index c13bd0d49afcf71e23a482e41d54e28329aef4f7..30b113bd77faf1fbde92cd76043925d347bcc7b3 100644 --- a/vipra-ui/app/index.html +++ b/vipra-ui/app/index.html @@ -59,7 +59,7 @@ <ul class="nav navbar-nav navbar-right"> <li ng-class="{active:$state.includes('about')}"> <a ui-sref="about"> - <span class="glyphicon glyphicon-question-sign"></span> + <span class="glyphicon glyphicon-question-sign"></span> </a> </li> </ul> diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index ec274b7df27d80135b16ae32ceaa85e19e092831..a2d1b64e3e24780e193d14ff686bb8e8699ccd74 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -74,7 +74,7 @@ url: '/articles', templateUrl: Vipra.const.tplBase + '/topics/articles.html', controller: 'TopicsArticlesController' - }) + }); // states: words @@ -120,7 +120,6 @@ return { request: function(config) { requestIncrement(config); - config.$queryTime = performance.now(); return config; }, @@ -131,7 +130,6 @@ response: function(response) { requestDecrement(response.config); - response.data.$queryTime = (performance.now() - response.config.$queryTime).toFixed(2); return response; }, diff --git a/vipra-ui/app/js/config.js b/vipra-ui/app/js/config.js index 67ae35dcc03490f07c31be2baef975e706f60100..50df7e92d2b6b2f912a8aa287bb73a98c83688bd 100644 --- a/vipra-ui/app/js/config.js +++ b/vipra-ui/app/js/config.js @@ -3,8 +3,8 @@ window.Vipra = window.Vipra || {}; Vipra.config = { - restUrl: '//' + location.hostname + ':8000/vipra/rest', - websocketUrl: '//' + location.hostname + ':8000/vipra/ws' + restUrl: '//' + location.hostname + ':8080/vipra/rest', + websocketUrl: '//' + location.hostname + ':8080/vipra/ws' }; })(); \ No newline at end of file diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 739050f1a441182731fc0a676bb83f8fb5bfa5b5..6d3302fc241007aeeffbdf590dcdb0bfeaa95863 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -21,26 +21,25 @@ $scope.search = $location.search().query; - ArticleFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(response) { - $scope.latestArticles = response.data; + ArticleFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(data) { + $scope.latestArticles = data; }); - TopicFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(response) { - $scope.latestTopics = response.data; + TopicFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(data) { + $scope.latestTopics = data; }); - WordFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(response) { - $scope.latestWords = response.data; + WordFactory.query({limit:Vipra.const.latestItems, sort:'-created'}, function(data) { + $scope.latestWords = data; }); $scope.$watch('search', function() { if($scope.search) { $location.search('query', $scope.search); $scope.searching = true; - SearchFactory.query({limit:Vipra.const.searchResults, query:$scope.search}, function(response) { + SearchFactory.query({limit:Vipra.const.searchResults, query:$scope.search}, function(data) { $scope.searching = false; - $scope.searchResults = response.data; - $scope.queryTime = response.$queryTime; + $scope.searchResults = data; }); } else { $location.search('query', null); @@ -56,8 +55,8 @@ app.controller('AboutController', ['$scope', 'InfoFactory', function($scope, InfoFactory) { - InfoFactory.get(function(response) { - $scope.info = response.data; + InfoFactory.get(function(data) { + $scope.info = data; $scope.buildDate = Vipra.formatDateTime(moment($scope.info.app.builddate, 'YYMMDD_HHmm').toDate()); $scope.startTime = Vipra.formatDateTime(moment($scope.info.vm.starttime, 'x').toDate()); $scope.upTime = moment.duration($scope.info.vm.uptime).humanize(); @@ -120,15 +119,15 @@ } // get root node - factory.get({id: $stateParams.id}, function(response) { + factory.get({id: $stateParams.id}, function(data) { // add root node if($stateParams.type === 'articles') - $scope.nodes.add([articleNode(response.data)]); + $scope.nodes.add([articleNode(data)]); else if($stateParams.type === 'topics') - $scope.nodes.add([topicNode(response.data)]); + $scope.nodes.add([topicNode(data)]); else if($stateParams.type === 'words') - $scope.nodes.add([wordNode(response.data)]); - ids[response.data.id] = id; + $scope.nodes.add([wordNode(data)]); + ids[data.id] = id; // create graph $scope.graph = new vis.Network(container, $scope.data, $scope.options); @@ -219,25 +218,25 @@ if(node) { if(node.type === 'article' && $scope.shown.topics) { // node is article, load article to get topics - ArticleFactory.get({id:node.dbid}, function(res) { - for(var i = 0; i < res.data.topics.length; i++) - res.data.topics[i] = res.data.topics[i].topic; - constructor(res, node, 'topics', topicNode); + ArticleFactory.get({id:node.dbid}, function(data) { + for(var i = 0; i < data.topics.length; i++) + data.topics[i] = res.data.topics[i].topic; + constructor(data, node, 'topics', topicNode); }); } else if(node.type === 'topic') { // node is topic, load topic to get words and articles if($scope.shown.words) - TopicFactory.get({id:node.dbid}, function(res) { - constructor(res, node, 'words', wordNode); + TopicFactory.get({id:node.dbid}, function(data) { + constructor(data, node, 'words', wordNode); }); if($scope.shown.articles) - TopicFactory.articles({id:node.dbid}, function(res) { - constructor(res, node, null, articleNode); + TopicFactory.articles({id:node.dbid}, function(data) { + constructor(data, node, null, articleNode); }); } else if(node.type === 'word' && $scope.shown.topics) { // node is word, load word to get topics - WordFactory.get({id:node.dbid}, function(res) { - constructor(res, node, 'topics', topicNode); + WordFactory.get({id:node.dbid}, function(data) { + constructor(data, node, 'topics', topicNode); }); } $scope.nodes.update(node); @@ -274,10 +273,9 @@ skip: ($scope.page-1)*$scope.limit, limit: $scope.limit, sort: $scope.order+$scope.sort - }, function(response) { - $scope.articles = response.data; - $scope.articlesMeta = response.meta; - $scope.queryTime = response.$queryTime; + }, function(data, headers) { + $scope.articles = data; + $scope.articlesTotal = headers("V-Total"); }); }; @@ -299,14 +297,12 @@ $scope.topicSort = $scope.topicSort || 'topic.share'; $scope.topicSortRev = typeof $scope.topicSortRev === 'undefined' ? false : $scope.topicSortRev; - ArticleFactory.get({id: $stateParams.id}, function(response) { - $scope.article = response.data; + ArticleFactory.get({id: $stateParams.id}, function(data) { + $scope.article = data; $scope.article.text = Vipra.createInitial($scope.article.text); $scope.articleDate = Vipra.formatDate($scope.article.date); $scope.articleCreated = Vipra.formatDateTime($scope.article.created); $scope.articleModified = Vipra.formatDateTime($scope.article.modified); - $scope.articleMeta = response.meta; - $scope.queryTime = response.$queryTime; // calculate percentage share var topicShareSeries = [], @@ -358,10 +354,9 @@ skip: ($scope.page-1)*$scope.limit, limit: $scope.limit, sort: $scope.order+$scope.sort - }, function(response) { - $scope.topics = response.data; - $scope.topicsMeta = response.meta; - $scope.queryTime = response.$queryTime; + }, function(data, headers) { + $scope.topics = data; + $scope.topicsTotal = headers("V-Total"); }); }; @@ -383,12 +378,10 @@ $scope.wordSort = $scope.wordSort || 'likeliness'; $scope.wordSortRev = typeof $scope.wordSortRev === 'undefined' ? true : $scope.wordSortRev; - TopicFactory.get({id: $stateParams.id}, function(response) { - $scope.topic = response.data; + TopicFactory.get({id: $stateParams.id}, function(data) { + $scope.topic = data; $scope.topicCreated = Vipra.formatDateTime($scope.topic.created); $scope.topicModified = Vipra.formatDateTime($scope.topic.modified); - $scope.topicMeta = response.meta; - $scope.queryTime = response.$queryTime; }); $scope.startRename = function() { @@ -402,12 +395,11 @@ $scope.endRename = function(save) { delete $scope.renameErrors; if(save) { - TopicFactory.update({id:$scope.topic.id}, $scope.topic, function(response) { - $scope.topic = response.data; + TopicFactory.update({id:$scope.topic.id}, $scope.topic, function(data) { + $scope.topic = data; $scope.isRename = false; - }, function(response) { - if(response.data) - $scope.renameErrors = Vipra.getErrors(response.data.errors); + }, function(errors) { + $scope.renameErrors = Vipra.getErrors(errors); }); } else { $scope.isRename = false; @@ -430,9 +422,8 @@ app.controller('TopicArticlesController', ['$scope', '$stateParams', 'TopicFactory', function($scope, $stateParams, TopicFactory) { - TopicFactory.articles({id: $stateParams.id}, function(response) { - $scope.articles = response.data; - $scope.queryTime = response.$queryTime; + TopicFactory.articles({id: $stateParams.id}, function(data) { + $scope.articles = data; }); }]); @@ -458,10 +449,9 @@ limit: $scope.limit, sort: $scope.sort, sort: $scope.order+$scope.sort - }, function(response) { - $scope.words = response.data; - $scope.wordsMeta = response.meta; - $scope.queryTime = response.$queryTime; + }, function(data, headers) { + $scope.words = data; + $scope.wordsTotal = headers("V-Total"); }); }; @@ -480,15 +470,13 @@ app.controller('WordsShowController', ['$scope', '$stateParams', 'WordFactory', function($scope, $stateParams, WordFactory) { - WordFactory.get({id: $stateParams.id}, function(response) { - $scope.word = response.data; + WordFactory.get({id: $stateParams.id}, function(data) { + $scope.word = data; $scope.wordCreated = Vipra.formatDateTime($scope.word.created); - $scope.wordMeta = response.meta; - $scope.queryTime = response.$queryTime; }); - WordFactory.topics({id: $stateParams.id}, function(response) { - $scope.topics = response.data; + WordFactory.topics({id: $stateParams.id}, function(data) { + $scope.topics = data; }); }]); diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js index 48364ce22994f8a1cb73e01273289a21a1fe96ef..49bb69f92f8f138db052bec2937f57b052cb6aaf 100644 --- a/vipra-ui/app/js/directives.js +++ b/vipra-ui/app/js/directives.js @@ -32,14 +32,6 @@ } }); - app.directive('queryTime', function() { - return { - restrict: 'E', - replace: true, - template: '<small class="text-muted">(took <span ng-bind-template="{{queryTime}}ms"></span>)</small>' - }; - }); - app.directive('pagination', function() { return { restrict: 'E', diff --git a/vipra-ui/app/js/factories.js b/vipra-ui/app/js/factories.js index b6f203282cd302538815b4920e0740dd4790222f..54b50fe55f4b5681cc1e7e35444216ab9acd54f4 100644 --- a/vipra-ui/app/js/factories.js +++ b/vipra-ui/app/js/factories.js @@ -7,30 +7,24 @@ var app = angular.module('vipra.factories', []); app.factory('ArticleFactory', ['$resource', function($resource) { - return $resource(Vipra.config.restUrl + '/articles/:id', {}, { - query: { isArray: false } - }); + return $resource(Vipra.config.restUrl + '/articles/:id'); }]); app.factory('TopicFactory', ['$resource', function($resource) { return $resource(Vipra.config.restUrl + '/topics/:id', {}, { - query: { isArray: false }, update: { method: 'PUT' }, - articles: { url: Vipra.config.restUrl + '/topics/:id/articles' } + articles: { isArray: true, url: Vipra.config.restUrl + '/topics/:id/articles' } }); }]); app.factory('WordFactory', ['$resource', function($resource) { return $resource(Vipra.config.restUrl + '/words/:id', {}, { - query: { isArray: false }, - topics: { url: Vipra.config.restUrl + '/words/:id/topics' } + topics: { isArray: true, url: Vipra.config.restUrl + '/words/:id/topics' } }); }]); app.factory('SearchFactory', ['$resource', function($resource) { - return $resource(Vipra.config.restUrl + '/search', {}, { - query: { isArray: false } - }); + return $resource(Vipra.config.restUrl + '/search'); }]); app.factory('InfoFactory', ['$resource', function($resource) {