diff --git a/ma-impl.sublime-workspace b/ma-impl.sublime-workspace index eac89659bc2779cbc08064ded16afa2761036267..5297a4a50b886f76788c2b79ea89629489267106 100644 --- a/ma-impl.sublime-workspace +++ b/ma-impl.sublime-workspace @@ -275,6 +275,38 @@ }, "buffers": [ + { + "file": "vipra-ui/app/templates/topics/show.hbs", + "settings": + { + "buffer_size": 196, + "line_ending": "Unix" + } + }, + { + "file": "vipra-ui/app/routes/articles/show.js", + "settings": + { + "buffer_size": 646, + "line_ending": "Unix" + } + }, + { + "file": "vipra-ui/app/styles/app.css", + "settings": + { + "buffer_size": 81, + "line_ending": "Unix" + } + }, + { + "file": "vipra-ui/app/models/topic.js", + "settings": + { + "buffer_size": 244, + "line_ending": "Unix" + } + } ], "build_system": "", "build_system_choices": @@ -461,22 +493,17 @@ "/home/eike/repos/master/ma-impl/vipra-ui/app/routes", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics", + "/home/eike/repos/master/ma-impl/vipra-ui/app/styles", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components", - "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/helpers", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/integration", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/integration/components", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/adapters", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/controllers", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/helpers", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/models", - "/home/eike/repos/master/ma-impl/vipra-ui/tests/unit/routes" + "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics" ], "file_history": [ + "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/show.js", + "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/list.js", + "/home/eike/repos/master/ma-impl/vipra-ui/app/components/topic-link.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/components/topics-list.js", @@ -487,10 +514,8 @@ "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/topics-list.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/models/article.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/models/topic.js", - "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/list.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/components/filter-list.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/show.hbs", - "/home/eike/repos/master/ma-impl/vipra-ui/app/components/topic-link.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/helpers/topic-numi.js", "/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/topic-link.hbs", "/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles/show.js", @@ -603,8 +628,7 @@ "/home/eike/Repositories/niels_website/web/src/index.html", "/home/eike/Repositories/niels_website/web/src/intergeo-2015.html", "/home/eike/Repositories/niels_website/web/src/less/main.less", - "/home/eike/Downloads/intellij/idea-IU-141.2735.5/Install-Linux-tar.txt", - "/home/eike/Downloads/JetBrains.IntelliJ.IDEA.Ultimate.v14.1.5.141.2735.5.Linux.Incl.KeyMaker-DVT/dvt.nfo" + "/home/eike/Downloads/intellij/idea-IU-141.2735.5/Install-Linux-tar.txt" ], "find": { @@ -926,8 +950,123 @@ "groups": [ { + "selected": 1, "sheets": [ + { + "buffer": 0, + "file": "vipra-ui/app/templates/topics/show.hbs", + "semi_transient": false, + "settings": + { + "buffer_size": 196, + "regions": + { + }, + "selection": + [ + [ + 196, + 196 + ] + ], + "settings": + { + "syntax": "Packages/Handlebars/grammars/Handlebars.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 1, + "type": "text" + }, + { + "buffer": 1, + "file": "vipra-ui/app/routes/articles/show.js", + "semi_transient": false, + "settings": + { + "buffer_size": 646, + "regions": + { + }, + "selection": + [ + [ + 395, + 395 + ] + ], + "settings": + { + "syntax": "Packages/JavaScript/JavaScript.tmLanguage", + "tab_size": 2, + "translate_tabs_to_spaces": true + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 0, + "type": "text" + }, + { + "buffer": 2, + "file": "vipra-ui/app/styles/app.css", + "semi_transient": false, + "settings": + { + "buffer_size": 81, + "regions": + { + }, + "selection": + [ + [ + 79, + 79 + ] + ], + "settings": + { + "syntax": "Packages/CSS/CSS.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 2, + "type": "text" + }, + { + "buffer": 3, + "file": "vipra-ui/app/models/topic.js", + "semi_transient": false, + "settings": + { + "buffer_size": 244, + "regions": + { + }, + "selection": + [ + [ + 121, + 121 + ] + ], + "settings": + { + "syntax": "Packages/JavaScript/JavaScript.tmLanguage" + }, + "translation.x": 0.0, + "translation.y": 0.0, + "zoom_level": 1.0 + }, + "stack_index": 3, + "type": "text" + } ] } ], diff --git a/vipra-rest/src/main/java/de/vipra/rest/Application.java b/vipra-rest/src/main/java/de/vipra/rest/Application.java index 56342a6905c4a1f3da978137ceab64283ca9b441..3a5aa15bb2b98c6013e4ec810a64acddb1018561 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/Application.java +++ b/vipra-rest/src/main/java/de/vipra/rest/Application.java @@ -8,7 +8,6 @@ import org.glassfish.jersey.server.filter.EncodingFilter; import de.vipra.rest.provider.APIRequestFilter; import de.vipra.rest.provider.CORSResponseFilter; import de.vipra.rest.provider.ObjectMapperProvider; -import de.vipra.rest.provider.PatchReaderInterceptor; public class Application extends ResourceConfig { @@ -18,7 +17,6 @@ public class Application extends ResourceConfig { register(CORSResponseFilter.class); register(ObjectMapperProvider.class); register(APIRequestFilter.class); - register(PatchReaderInterceptor.class); EncodingFilter.enableFor(this, GZipEncoder.class); } diff --git a/vipra-rest/src/main/java/de/vipra/rest/PATCH.java b/vipra-rest/src/main/java/de/vipra/rest/PATCH.java deleted file mode 100644 index 78b80504335a3d1dd80a1e8f17f8680477dc984f..0000000000000000000000000000000000000000 --- a/vipra-rest/src/main/java/de/vipra/rest/PATCH.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.vipra.rest; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.ws.rs.HttpMethod; -import javax.ws.rs.NameBinding; - -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@HttpMethod("PATCH") -@Documented -@NameBinding -public @interface PATCH {} \ No newline at end of file diff --git a/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java b/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java index 82ab23749b15f219866af7961b5849002f2fff7a..8b0e5a3280006cc41b2762379a56bad76c4f8604 100644 --- a/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java +++ b/vipra-rest/src/main/java/de/vipra/rest/model/ResponseWrapper.java @@ -1,13 +1,10 @@ package de.vipra.rest.model; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class ResponseWrapper<T> { - private Map<String, String> links; private T data; private List<APIError> errors; private final APIVersion jsonapi = new APIVersion(); @@ -22,21 +19,6 @@ public class ResponseWrapper<T> { addError(error); } - public Map<String, String> getLinks() { - return links; - } - - public void setLinks(Map<String, String> links) { - this.links = links; - } - - public void addLink(String name, String link) { - if (links == null) { - links = new HashMap<>(); - } - links.put(name, link); - } - public T getData() { return data; } @@ -66,4 +48,8 @@ public class ResponseWrapper<T> { return jsonapi; } + public String tag() { + return data != null ? Integer.toString(data.hashCode()) : null; + } + } diff --git a/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java b/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java deleted file mode 100644 index ac4c7179e7ccf844824b72a4c713495cb2849010..0000000000000000000000000000000000000000 --- a/vipra-rest/src/main/java/de/vipra/rest/provider/PatchReaderInterceptor.java +++ /dev/null @@ -1,111 +0,0 @@ -package de.vipra.rest.provider; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; - -import javax.ws.rs.GET; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; -import javax.ws.rs.ext.ReaderInterceptor; -import javax.ws.rs.ext.ReaderInterceptorContext; - -import org.glassfish.jersey.message.MessageBodyWorkers; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.fge.jsonpatch.JsonPatch; -import com.github.fge.jsonpatch.JsonPatchException; - -import de.vipra.rest.PATCH; - -@Provider -@PATCH -public class PatchReaderInterceptor implements ReaderInterceptor { - private UriInfo info; - private MessageBodyWorkers workers; - - @Context - public void setInfo(UriInfo info) { - this.info = info; - } - - @Context - public void setWorkers(MessageBodyWorkers workers) { - this.workers = workers; - } - - @Override - public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) - throws IOException, WebApplicationException { - - // Get the resource we are being called on, - // and find the GET method - Object resource = info.getMatchedResources().get(0); - - Method found = null; - for (Method next : resource.getClass().getMethods()) { - if (next.getAnnotation(GET.class) != null) { - found = next; - break; - } - } - - if (found != null) { - - // Invoke the get method to get the state we are trying to patch - // - Object bean; - try { - bean = found.invoke(resource); - } catch (Exception e) { - throw new WebApplicationException(e); - } - - // Convert this object to a an aray of bytes - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - MessageBodyWriter<? super Object> bodyWriter = workers.getMessageBodyWriter(Object.class, bean.getClass(), - new Annotation[0], MediaType.APPLICATION_JSON_TYPE); - - bodyWriter.writeTo(bean, bean.getClass(), bean.getClass(), new Annotation[0], - MediaType.APPLICATION_JSON_TYPE, new MultivaluedHashMap<String, Object>(), baos); - - // Use the Jackson 2.x classes to convert both the incoming patch - // and the current state of the object into a JsonNode / JsonPatch - ObjectMapper mapper = new ObjectMapper(); - JsonNode serverState = mapper.readValue(baos.toByteArray(), JsonNode.class); - JsonNode patchAsNode = mapper.readValue(readerInterceptorContext.getInputStream(), JsonNode.class); - JsonPatch patch = JsonPatch.fromJson(patchAsNode); - - try { - // Apply the patch - JsonNode result = patch.apply(serverState); - - // Stream the result & modify the stream on the - // readerInterceptor - ByteArrayOutputStream resultAsByteArray = new ByteArrayOutputStream(); - mapper.writeValue(resultAsByteArray, result); - readerInterceptorContext.setInputStream(new ByteArrayInputStream(resultAsByteArray.toByteArray())); - - // Pass control back to the Jersey code - return readerInterceptorContext.proceed(); - - } catch (JsonPatchException e) { - throw new WebApplicationException( - Response.serverError().type("text/plain").entity(e.getMessage()).build()); - } - - } else { - throw new IllegalArgumentException("No matching GET method on resource"); - } - - } -} 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 4e0b483dce84e4df8524febca574b6679c5855f4..be869472cbee97ae09b610466ac1c18e69e68a41 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 @@ -50,8 +50,7 @@ public class ArticleResource { @QueryParam("sort") @DefaultValue("date") String sortBy) { List<Article> articles = service.getMultiple(uri.getAbsolutePath(), skip, limit, sortBy); ResponseWrapper<List<Article>> res = new ResponseWrapper<>(articles); - res.addLink("self", uri.getAbsolutePath().toString()); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); } @GET @@ -68,7 +67,7 @@ public class ArticleResource { Article article = service.getSingle(id); if (article != null) { res.setData(article); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); } else { String msg = String.format(Messages.NOT_FOUND, "article", id); res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found", msg)); @@ -84,7 +83,7 @@ public class ArticleResource { try { article = service.createSingle(article); res = new ResponseWrapper<>(article); - return Response.created(article.uri(uri.getAbsolutePath())).entity(res).build(); + return Response.created(article.uri(uri.getAbsolutePath())).entity(res).tag(res.tag()).build(); } catch (DatabaseException e) { res = new ResponseWrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be created", "item could not be created due to an internal server error")); @@ -133,7 +132,7 @@ public class ArticleResource { return Response.status(Response.Status.NOT_FOUND).entity(res).build(); case 1: res.setData(article); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); default: return Response.serverError().build(); } 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 c3c09269d48cb131b18976e965a6e3a8546ea45f..028116570f891b4cf103987fb30699eaa770da44 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 @@ -47,8 +47,7 @@ public class TopicResource { @QueryParam("limit") @DefaultValue("0") int limit) { List<Topic> topics = service.getMultiple(uri.getAbsolutePath(), skip, limit, null); ResponseWrapper<List<Topic>> res = new ResponseWrapper<>(topics); - res.addLink("self", uri.getAbsolutePath().toString()); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); } @GET @@ -65,7 +64,7 @@ public class TopicResource { Topic topic = service.getSingle(id); if (topic != null) { res.setData(topic); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); } else { res.addError(new APIError(Response.Status.NOT_FOUND, "Resource not found", String.format(Messages.NOT_FOUND, "topic", id))); @@ -89,7 +88,7 @@ public class TopicResource { return Response.status(Response.Status.NOT_FOUND).entity(res).build(); case 1: res.setData(topic); - return Response.ok().entity(res).build(); + return Response.ok().entity(res).tag(res.tag()).build(); default: return Response.serverError().build(); } diff --git a/vipra-ui/app/models/topic.js b/vipra-ui/app/models/topic.js index 34cf33dc7693478ef9064a94e43a52fca97db0bd..73627bf94ab0d0825e7b906e3dd8c1cd792a5ed5 100644 --- a/vipra-ui/app/models/topic.js +++ b/vipra-ui/app/models/topic.js @@ -3,6 +3,7 @@ import DS from 'ember-data'; export default DS.Model.extend({ name: DS.attr(), index: DS.attr(), + words: DS.attr(), _name: function() { var name = this.get('name'); diff --git a/vipra-ui/app/routes/articles/show.js b/vipra-ui/app/routes/articles/show.js index 84617d83dc3806727e3fd1330daeb6df0bb4b163..f825a14d961dea9a0dc15397b32bc1913ff02020 100644 --- a/vipra-ui/app/routes/articles/show.js +++ b/vipra-ui/app/routes/articles/show.js @@ -11,13 +11,15 @@ export default Ember.Route.extend({ afterModel(model) { var words = [], stats = model.article.get('stats'); - for(var word in stats.uniqueWords) { - var o = stats.uniqueWords[word]; - words.push({word: word, count: o.termFrequency, norm: o.normalizedTermFrequency}); + if(stats && stats.uniqueWords) { + for(var word in stats.uniqueWords) { + var o = stats.uniqueWords[word]; + words.push({word: word, count: o.termFrequency, norm: o.normalizedTermFrequency}); + } + words.sort(function(a,b) { + return b.count - a.count; + }); + model.statsData = words.slice(0,20); } - words.sort(function(a,b) { - return b.count - a.count; - }); - model.statsData = words.slice(0,20); } }); \ No newline at end of file diff --git a/vipra-ui/app/routes/topics/show.js b/vipra-ui/app/routes/topics/show.js index 10a179b7826929b9dd5597de3b8624d9a23c20cc..2f0623aa8c5458105139dacd5a0434fd0c991aa7 100644 --- a/vipra-ui/app/routes/topics/show.js +++ b/vipra-ui/app/routes/topics/show.js @@ -3,7 +3,7 @@ import Ember from 'ember'; export default Ember.Route.extend({ model(params) { return Ember.RSVP.hash({ - article: this.store.find('topic', params.topic_id) + topic: this.store.find('topic', params.topic_id) }); } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/vipra-ui/app/styles/app.css b/vipra-ui/app/styles/app.css index 9e0888e722f60a03fe2bd782526109adf61fba18..f48d3e041c4d050ee17a9cab265e35a3bff1d2a2 100644 --- a/vipra-ui/app/styles/app.css +++ b/vipra-ui/app/styles/app.css @@ -1,3 +1,8 @@ td { vertical-align: top; +} + +.word { + cursor: pointer; + padding-right: 5px; } \ No newline at end of file diff --git a/vipra-ui/app/templates/topics/show.hbs b/vipra-ui/app/templates/topics/show.hbs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d36b7e1b2ef6a4d2b4679188e761124afe016754 100644 --- a/vipra-ui/app/templates/topics/show.hbs +++ b/vipra-ui/app/templates/topics/show.hbs @@ -0,0 +1,9 @@ +<h2>{{model.topic._name}}</h2> + +<h3>Words</h3> + +{{#each model.topic.words as |word|}} + <span class="word" title="Likeliness: {{word.likeliness}}">{{word.word}}</span> +{{/each}} + +<h3>Articles</h3> \ No newline at end of file