Skip to content
Snippets Groups Projects
Commit 1fd2ba42 authored by Eike Cochu's avatar Eike Cochu
Browse files

added simple search

parent c4731520
Branches ember-ui
No related tags found
No related merge requests found
Showing
with 288 additions and 110 deletions
......@@ -279,6 +279,30 @@
},
"buffers":
[
{
"file": "vipra-ui/app/templates/index.hbs",
"settings":
{
"buffer_size": 1530,
"line_ending": "Unix"
}
},
{
"file": "vipra-ui/app/styles/app.scss",
"settings":
{
"buffer_size": 914,
"line_ending": "Unix"
}
},
{
"file": "vipra-ui/app/adapters/application.js",
"settings":
{
"buffer_size": 506,
"line_ending": "Unix"
}
}
],
"build_system": "",
"build_system_choices":
......@@ -462,33 +486,48 @@
"/home/eike/repos/master/ma-impl/vipra-ui/app",
"/home/eike/repos/master/ma-impl/vipra-ui/app/adapters",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components",
"/home/eike/repos/master/ma-impl/vipra-ui/app/helpers",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/articles",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/topics",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/words",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates"
"/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/routes/words",
"/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/words"
],
"file_history":
[
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/search.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/debounced-input.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/articles/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/application.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/words/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/words/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/index.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/word.js",
"/home/eike/Downloads/files.txt",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/application.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/pagination-bar.js",
"/home/eike/.cache/.fr-kZOCSD/META-INF/MANIFEST.MF",
"/home/eike/repos/master/ma-impl/Vagrantfile",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/topics/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/words/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/articles/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/articles/index.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/topics/index.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/components/items-list.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/items-list.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/words/index.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/components/pagination-bar.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/words/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/controllers/words.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/adapters/application.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/styles/app.scss",
"/home/eike/repos/master/ma-impl/vipra-ui/app/helpers/is-empty.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/index.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/import.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/router.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/styles/sticky-footer.scss",
......@@ -515,7 +554,6 @@
"/home/eike/repos/master/ma-impl/vipra-ui/app/index.html",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/words/show.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/templates/words/show.hbs",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/word.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/routes/words",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/topic.js",
"/home/eike/repos/master/ma-impl/vipra-ui/app/models/article.js",
......@@ -591,11 +629,7 @@
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/list.hbs",
"/home/eike/Repositories/fu/ss15/ma/impl/vm/bootstrap.sh",
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/adapters/application.js",
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles/list.js",
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/templates/articles/show.hbs",
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/components/filter-text.js",
"/home/eike/Repositories/fu/ss15/ma/impl/vm/webapps/test/index.html",
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/controllers/articles/list.js"
"/home/eike/Repositories/fu/ss15/ma/impl/vipra-ui/app/routes/articles/list.js"
],
"find":
{
......@@ -919,8 +953,99 @@
"groups":
[
{
"selected": 1,
"sheets":
[
{
"buffer": 0,
"file": "vipra-ui/app/templates/index.hbs",
"semi_transient": false,
"settings":
{
"buffer_size": 1530,
"regions":
{
},
"selection":
[
[
1352,
1352
]
],
"settings":
{
"syntax": "Packages/Handlebars/grammars/Handlebars.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 1,
"type": "text"
},
{
"buffer": 1,
"file": "vipra-ui/app/styles/app.scss",
"semi_transient": false,
"settings":
{
"buffer_size": 914,
"regions":
{
},
"selection":
[
[
681,
681
]
],
"settings":
{
"syntax": "Packages/SCSS/SCSS.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/adapters/application.js",
"semi_transient": false,
"settings":
{
"buffer_size": 506,
"regions":
{
},
"selection":
[
[
119,
119
]
],
"settings":
{
"syntax": "Packages/JavaScriptNext - ES6 Syntax/JavaScriptNext.tmLanguage",
"tab_size": 2,
"translate_tabs_to_spaces": true
},
"translation.x": 0.0,
"translation.y": 0.0,
"zoom_level": 1.0
},
"stack_index": 2,
"type": "text"
}
]
}
],
......
File moved
package de.vipra.cmd;
public class Options {
}
......@@ -5,7 +5,10 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
......@@ -26,12 +29,18 @@ import org.bson.types.ObjectId;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.CacheConfigurationBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import de.vipra.rest.APIMediaType;
import de.vipra.rest.Messages;
import de.vipra.rest.model.APIError;
import de.vipra.rest.model.Wrapper;
import de.vipra.util.Config;
import de.vipra.util.ESClient;
import de.vipra.util.MongoUtils;
import de.vipra.util.StringUtils;
import de.vipra.util.ex.ConfigException;
......@@ -47,6 +56,7 @@ public class ArticleResource {
final Cache<String, ArticleFull> cache;
final DatabaseService<ArticleFull, ObjectId> service;
final TransportClient client;
public ArticleResource(@Context ServletContext servletContext) throws ConfigException, IOException {
Config config = Config.getConfig();
......@@ -58,12 +68,22 @@ public class ArticleResource {
articleCache = manager.createCache("articlecache", CacheConfigurationBuilder.newCacheConfigurationBuilder()
.buildConfig(String.class, ArticleFull.class));
this.cache = articleCache;
client = ESClient.getClient(config);
}
@GET
@Produces(APIMediaType.APPLICATION_JSONAPI)
public Response getArticles(@QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit,
@QueryParam("sort") @DefaultValue("date") String sortBy, @QueryParam("fields") String fields) {
@QueryParam("sort") @DefaultValue("date") String sortBy, @QueryParam("fields") String fields,
@QueryParam("query") String query) {
if (query == null)
return getArticlesFromDb(skip, limit, sortBy, fields);
else
return getArticlesFromIndex(skip, limit, query);
}
private Response getArticlesFromDb(Integer skip, Integer limit, String sortBy, String fields) {
Wrapper<List<ArticleFull>> res = new Wrapper<>();
if (skip != null && limit != null)
......@@ -87,6 +107,40 @@ public class ArticleResource {
}
}
private Response getArticlesFromIndex(Integer skip, Integer limit, String query) {
Wrapper<List<ArticleFull>> res = new Wrapper<>();
if (skip == null || skip < 0)
skip = 0;
if (limit == null || limit < 0)
limit = 20;
SearchResponse response = null;
try {
response = client.prepareSearch("articles").setQuery(QueryBuilders.multiMatchQuery(query, "_all"))
.setFrom(skip).setSize(limit).execute().actionGet();
} catch (Exception e) {
res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage()));
return res.badRequest();
}
SearchHits hits = response.getHits();
List<ArticleFull> articles = new ArrayList<>(10);
for (SearchHit hit : hits) {
Map<String, Object> source = hit.getSource();
ArticleFull article = new ArticleFull();
article.setId(MongoUtils.objectId(hit.getId()));
article.setTitle(source.get("title").toString());
article.setText(StringUtils.ellipsize(source.get("text").toString(), 150));
articles.add(article);
}
res.addMeta("total", articles.size());
return res.ok(articles);
}
@GET
@Produces(APIMediaType.APPLICATION_JSONAPI)
@Consumes(APIMediaType.APPLICATION_JSONAPI)
......
package de.vipra.rest.resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import de.vipra.rest.APIMediaType;
import de.vipra.rest.model.APIError;
import de.vipra.rest.model.Wrapper;
import de.vipra.util.Config;
import de.vipra.util.ESClient;
import de.vipra.util.MongoUtils;
import de.vipra.util.StringUtils;
import de.vipra.util.ex.ConfigException;
import de.vipra.util.model.ArticleFull;
@Path("search")
public class SearchResource {
@Context
UriInfo uri;
final TransportClient client;
public SearchResource(@Context ServletContext servletContext) throws IOException, ConfigException {
Config config = Config.getConfig();
client = ESClient.getClient(config);
}
@GET
@Produces(APIMediaType.APPLICATION_JSONAPI)
public Response search(@QueryParam("query") String query, @QueryParam("skip") Integer skip,
@QueryParam("limit") Integer limit, @QueryParam("excerpt") Integer excerpt) {
Wrapper<List<ArticleFull>> res = new Wrapper<>();
if (skip == null || skip < 0)
skip = 0;
if (limit == null || limit < 0)
limit = 20;
SearchResponse response = null;
try {
response = client.prepareSearch("articles").setSearchType(SearchType.QUERY_AND_FETCH)
.setQuery(QueryBuilders.multiMatchQuery(query, "_all")).setFrom(skip).setSize(limit).execute()
.actionGet();
} catch (Exception e) {
res.addError(new APIError(Response.Status.BAD_REQUEST, "Error", e.getMessage()));
return res.badRequest();
}
SearchHits hits = response.getHits();
List<ArticleFull> articles = new ArrayList<>(10);
for (SearchHit hit : hits) {
Map<String, Object> source = hit.getSource();
ArticleFull article = new ArticleFull();
article.setId(MongoUtils.objectId(hit.getId()));
article.setTitle(source.get("title").toString());
if (excerpt != null && excerpt > 0)
article.setText(StringUtils.ellipsize(source.get("text").toString(), excerpt));
articles.add(article);
}
res.addMeta("total", articles.size());
return res.ok(articles);
}
}
......@@ -6,9 +6,8 @@
</Console>
</Appenders>
<Loggers>
<Root level="ALL">
<Root level="DEBUG">
<AppenderRef ref="Console" />
</Root>
<Logger name="org.mongodb" level="INFO"/>
</Loggers>
</Configuration>
\ No newline at end of file
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host: `http://${window.location.hostname}:8000`,
host: `http://${window.location.hostname}:8080`,
namespace: 'vipra-rest',
updateRecord(store, type, snapshot) {
var data = {};
......
......@@ -5,7 +5,12 @@ export default Ember.TextField.extend({
fireAtStart: false,
_elementValueDidChange() {
Ember.run.debounce(this, this._setValue, this.debounce, this.fireAtStart);
let val = this.$().val();
if(val) {
Ember.run.debounce(this, this._setValue, this.debounce, this.fireAtStart);
} else {
this._setValue();
}
},
_setValue() {
......
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: 'page',
page: 1
});
export default Ember.Controller.extend({
queryParams: 'q',
q: '',
search: Ember.computed('q', function() {
let query = this.get('q');
if(query) {
return this.store.query('article', {
query: query,
limit: 10
});
}
})
});
\ No newline at end of file
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: 'page',
page: 1
});
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: 'page',
page: 1
});
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr(),
text: DS.attr(),
url: DS.attr(),
date: DS.attr('date'),
stats: DS.attr(),
topics: DS.attr(),
created: DS.attr('date'),
modified: DS.attr('date'),
_name: function() {
var title = this.get('title');
return title ? title : this.get('id');
}.property('title')
});
import DS from 'ember-data';
export default DS.Model.extend({
word: DS.attr(),
_name: function() {
return this.get('id');
}.property('id')
......
......@@ -76,6 +76,12 @@ export default Ember.Route.extend({
name: 'Articles',
data: data
}];
},
resetController(controller, isExiting, transition) {
if(isExiting) {
controller.set('page', 1);
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return {
latestarticles: this.store.query('article', {limit: 5, sort: '-created'}),
......@@ -8,4 +9,5 @@ export default Ember.Route.extend({
latestwords: this.store.query('word', {limit: 5, sort: '-created'}),
};
}
});
\ No newline at end of file
......@@ -26,6 +26,12 @@ export default Ember.Route.extend({
limit: limit,
topics: this.store.query('topic', query)
});
},
resetController(controller, isExiting, transition) {
if(isExiting) {
controller.set('page', 1);
}
}
});
\ No newline at end of file
......@@ -27,6 +27,12 @@ export default Ember.Route.extend({
limit: limit,
words: this.store.query('word', query)
});
},
resetController(controller, isExiting, transition) {
if(isExiting) {
controller.set('page', 1);
}
}
});
\ No newline at end of file
......@@ -41,6 +41,11 @@ body {
text-overflow: ellipsis;
}
.search-result {
padding: 5px;
margin-bottom: 5px;
}
.navbar-default {
.collapse:not(.in) {
.navbar-nav > .active {
......
......@@ -14,9 +14,9 @@
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="vipra-navbar-collapse-1">
<ul class="nav navbar-nav">
{{#link-to 'articles' tagName='li'}}{{link-to 'Articles' 'articles'}}{{/link-to}}
{{#link-to 'topics' tagName='li'}}{{link-to 'Topics' 'topics'}}{{/link-to}}
{{#link-to 'words' tagName='li'}}{{link-to 'Words' 'words'}}{{/link-to}}
{{#link-to 'articles' tagName='li'}}{{link-to 'Articles' 'articles' (query-params page=1)}}{{/link-to}}
{{#link-to 'topics' tagName='li'}}{{link-to 'Topics' 'topics' (query-params page=1)}}{{/link-to}}
{{#link-to 'words' tagName='li'}}{{link-to 'Words' 'words' (query-params page=1)}}{{/link-to}}
{{outlet 'menu-left'}}
<div id="testi"></div>
</ul>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment