diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java index 2b27faa8..944592e1 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java @@ -154,9 +154,9 @@ public class DocumentDao { criteriaList.add("d.DOC_IDUSER_C = :userId"); parameterMap.put("userId", criteria.getUserId()); } - if (!Strings.isNullOrEmpty(criteria.getSearch())) { + if (!Strings.isNullOrEmpty(criteria.getSearch()) || !Strings.isNullOrEmpty(criteria.getFullSearch())) { LuceneDao luceneDao = new LuceneDao(); - Set documentIdList = luceneDao.search(criteria.getUserId(), criteria.getSearch()); + Set documentIdList = luceneDao.search(criteria.getUserId(), criteria.getSearch(), criteria.getFullSearch()); if (documentIdList.size() == 0) { // If the search doesn't find any document, the request should return nothing documentIdList.add(UUID.randomUUID().toString()); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java index 2b61b339..a3c26997 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/criteria/DocumentCriteria.java @@ -20,6 +20,11 @@ public class DocumentCriteria { */ private String search; + /** + * Full content search query. + */ + private String fullSearch; + /** * Minimum creation date. */ @@ -81,6 +86,24 @@ public class DocumentCriteria { this.search = search; } + /** + * Getter of fullSearch. + * + * @return the fullSearch + */ + public String getFullSearch() { + return fullSearch; + } + + /** + * Setter of fullSearch. + * + * @param fullSearch fullSearch + */ + public void setFullSearch(String fullSearch) { + this.fullSearch = fullSearch; + } + /** * Getter of createDateMin. * diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java index e5a12b5f..6856e166 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/lucene/LuceneDao.java @@ -143,13 +143,15 @@ public class LuceneDao { * Search files. * * @param userId User ID to filter on - * @param searchQuery Search query + * @param searchQuery Search query on title and description + * @param fullSearchQuery Search query on all fields * @return List of document IDs * @throws Exception */ - public Set search(String userId, String searchQuery) throws Exception { + public Set search(String userId, String searchQuery, String fullSearchQuery) throws Exception { // Escape query and add quotes so QueryParser generate a PhraseQuery - searchQuery = "\"" + QueryParserUtil.escape(searchQuery) + "\""; + searchQuery = "\"" + QueryParserUtil.escape(searchQuery + " " + fullSearchQuery) + "\""; + fullSearchQuery = "\"" + QueryParserUtil.escape(fullSearchQuery) + "\""; // Build search query StandardQueryParser qpHelper = new StandardQueryParser(new DocsStandardAnalyzer(Version.LUCENE_42)); @@ -157,9 +159,9 @@ public class LuceneDao { // Search on documents and files BooleanQuery query = new BooleanQuery(); - query.add(qpHelper.parse(searchQuery, "content"), Occur.SHOULD); query.add(qpHelper.parse(searchQuery, "title"), Occur.SHOULD); query.add(qpHelper.parse(searchQuery, "description"), Occur.SHOULD); + query.add(qpHelper.parse(fullSearchQuery, "content"), Occur.SHOULD); // Filter on provided user ID List terms = new ArrayList(); diff --git a/docs-parent/TODO b/docs-parent/TODO index d57cb696..a0c153ff 100644 --- a/docs-parent/TODO +++ b/docs-parent/TODO @@ -1,8 +1,2 @@ -- New image rescale between thumbnail and original (client) -- Criteria to search inside OCR-ed content (eg. full:uranium) (server) -- Criteria to search on a specific time span (eg. at:2013-06) (server) -- Show help on special criterias (client) -- Disable Add/Edit button while uploading (client) - - Extract text from PDF for indexing, see PDFBox (server) - Make thumbnail of the first page of PDF, see PDFBox (server) \ No newline at end of file diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java index 4985bf95..533d314b 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/DocumentResource.java @@ -207,10 +207,14 @@ public class DocumentResource extends BaseResource { DateTimeFormat.forPattern("yyyy").getParser(), DateTimeFormat.forPattern("yyyy-MM").getParser(), DateTimeFormat.forPattern("yyyy-MM-dd").getParser() }; + DateTimeFormatter yearFormatter = new DateTimeFormatter(null, parsers[0]); + DateTimeFormatter monthFormatter = new DateTimeFormatter(null, parsers[1]); + DateTimeFormatter dayFormatter = new DateTimeFormatter(null, parsers[2]); DateTimeFormatter formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter(); String[] criteriaList = search.split(" *"); List query = new ArrayList<>(); + List fullQuery = new ArrayList<>(); for (String criteria : criteriaList) { String[] params = criteria.split(":"); if (params.length != 2 || Strings.isNullOrEmpty(params[0]) || Strings.isNullOrEmpty(params[1])) { @@ -233,7 +237,7 @@ public class DocumentResource extends BaseResource { documentCriteria.getTagIdList().add(tag.getId()); } } else if (params[0].equals("after") || params[0].equals("before")) { - // New date criteria + // New date span criteria try { DateTime date = formatter.parseDateTime(params[1]); if (params[0].equals("before")) documentCriteria.setCreateDateMax(date.toDate()); @@ -241,22 +245,45 @@ public class DocumentResource extends BaseResource { } catch (IllegalArgumentException e) { // NOP } + } else if (params[0].equals("at")) { + // New specific date criteria + try { + if (params[1].length() == 10) { + DateTime date = dayFormatter.parseDateTime(params[1]); + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusDays(1).toDate()); + } else if (params[1].length() == 7) { + DateTime date = monthFormatter.parseDateTime(params[1]); + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusMonths(1).toDate()); + } else if (params[1].length() == 4) { + DateTime date = yearFormatter.parseDateTime(params[1]); + documentCriteria.setCreateDateMin(date.toDate()); + documentCriteria.setCreateDateMax(date.plusYears(1).toDate()); + } + } catch (IllegalArgumentException e) { + // NOP + } } else if (params[0].equals("shared")) { // New shared state criteria if (params[1].equals("yes")) { documentCriteria.setShared(true); } } else if (params[0].equals("lang")) { - // New shared state criteria + // New language criteria if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) { documentCriteria.setLanguage(params[1]); } + } else if (params[0].equals("full")) { + // New full content search criteria + fullQuery.add(params[1]); } else { query.add(criteria); } } documentCriteria.setSearch(Joiner.on(" ").join(query)); + documentCriteria.setFullSearch(Joiner.on(" ").join(fullQuery)); return documentCriteria; } diff --git a/docs-web/src/main/webapp/partial/docs/document.edit.html b/docs-web/src/main/webapp/partial/docs/document.edit.html index 2077ac42..c2fb318e 100644 --- a/docs-web/src/main/webapp/partial/docs/document.edit.html +++ b/docs-web/src/main/webapp/partial/docs/document.edit.html @@ -43,7 +43,7 @@
- +
diff --git a/docs-web/src/main/webapp/partial/docs/document.html b/docs-web/src/main/webapp/partial/docs/document.html index 0b2e0a67..0b23b2c0 100644 --- a/docs-web/src/main/webapp/partial/docs/document.html +++ b/docs-web/src/main/webapp/partial/docs/document.html @@ -7,7 +7,16 @@

- +

diff --git a/docs-web/src/main/webapp/partial/docs/document.view.html b/docs-web/src/main/webapp/partial/docs/document.view.html index b26c3dee..df5f8716 100644 --- a/docs-web/src/main/webapp/partial/docs/document.view.html +++ b/docs-web/src/main/webapp/partial/docs/document.view.html @@ -25,7 +25,7 @@
  • - +
    diff --git a/docs-web/src/main/webapp/partial/docs/file.view.html b/docs-web/src/main/webapp/partial/docs/file.view.html index b99973a2..11cd52ea 100644 --- a/docs-web/src/main/webapp/partial/docs/file.view.html +++ b/docs-web/src/main/webapp/partial/docs/file.view.html @@ -9,13 +9,13 @@
    - +
    - +
    - +
    diff --git a/docs-web/src/main/webapp/partial/share/file.view.html b/docs-web/src/main/webapp/partial/share/file.view.html index bd345ebf..0fbb368e 100644 --- a/docs-web/src/main/webapp/partial/share/file.view.html +++ b/docs-web/src/main/webapp/partial/share/file.view.html @@ -9,13 +9,13 @@
    - +
    - +
    - +
    diff --git a/docs-web/src/main/webapp/partial/share/share.html b/docs-web/src/main/webapp/partial/share/share.html index b47e649a..e2a1bb37 100644 --- a/docs-web/src/main/webapp/partial/share/share.html +++ b/docs-web/src/main/webapp/partial/share/share.html @@ -13,7 +13,7 @@
  • diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java index 7c75eff3..b4e38286 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java @@ -1,6 +1,20 @@ package com.sismics.docs.rest; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.Date; + +import javax.ws.rs.core.MediaType; + +import junit.framework.Assert; + +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.joda.time.format.DateTimeFormat; +import org.junit.Test; + import com.sismics.docs.rest.filter.CookieAuthenticationFilter; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; @@ -9,18 +23,6 @@ import com.sun.jersey.core.util.MultivaluedMapImpl; import com.sun.jersey.multipart.FormDataBodyPart; import com.sun.jersey.multipart.FormDataMultiPart; -import junit.framework.Assert; -import org.codehaus.jettison.json.JSONArray; -import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; -import org.junit.Test; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.Date; - -import javax.ws.rs.core.MediaType; - /** * Exhaustive test of the document resource. * @@ -108,20 +110,29 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertEquals("SuperTag", tags.getJSONObject(0).getString("name")); Assert.assertEquals("#ffff00", tags.getJSONObject(0).getString("color")); - // Search documents by query + // Search documents by query in full content documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); getParams = new MultivaluedMapImpl(); - getParams.putSingle("search", "uranium"); + getParams.putSingle("search", "full:uranium"); response = documentResource.queryParams(getParams).get(ClientResponse.class); json = response.getEntity(JSONObject.class); Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); documents = json.getJSONArray("documents"); Assert.assertTrue(documents.length() == 1); - Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id")); - Assert.assertEquals(create1Date, documents.getJSONObject(0).getLong("create_date")); - // Search documents by query + // Search documents by query in full content + documentResource = resource().path("/document/list"); + documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("search", "full:title"); + response = documentResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + documents = json.getJSONArray("documents"); + Assert.assertTrue(documents.length() == 1); + + // Search documents by query in title/description documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); getParams = new MultivaluedMapImpl(); @@ -132,7 +143,7 @@ public class TestDocumentResource extends BaseJerseyTest { documents = json.getJSONArray("documents"); Assert.assertTrue(documents.length() == 1); - // Search documents by query + // Search documents by query in title/description documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); getParams = new MultivaluedMapImpl(); @@ -143,7 +154,19 @@ public class TestDocumentResource extends BaseJerseyTest { documents = json.getJSONArray("documents"); Assert.assertTrue(documents.length() == 1); - // Search documents by date + // Search documents by specific date + documentResource = resource().path("/document/list"); + documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("search", "at:" + DateTimeFormat.forPattern("yyyy-MM").print(new Date().getTime())); + response = documentResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + documents = json.getJSONArray("documents"); + Assert.assertTrue(documents.length() == 1); + Assert.assertEquals(document1Id, documents.getJSONObject(0).getString("id")); + + // Search documents by date span documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); getParams = new MultivaluedMapImpl(); @@ -197,7 +220,7 @@ public class TestDocumentResource extends BaseJerseyTest { documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); getParams = new MultivaluedMapImpl(); - getParams.putSingle("search", "after:2010 before:2040-08 tag:super shared:yes lang:eng uranium"); + getParams.putSingle("search", "after:2010 before:2040-08 tag:super shared:yes lang:eng title description full:uranium"); response = documentResource.queryParams(getParams).get(ClientResponse.class); json = response.getEntity(JSONObject.class); Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); @@ -216,6 +239,17 @@ public class TestDocumentResource extends BaseJerseyTest { documents = json.getJSONArray("documents"); Assert.assertTrue(documents.length() == 0); + // Search documents (nothing) + documentResource = resource().path("/document/list"); + documentResource.addFilter(new CookieAuthenticationFilter(document1Token)); + getParams = new MultivaluedMapImpl(); + getParams.putSingle("search", "full:random"); + response = documentResource.queryParams(getParams).get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus())); + documents = json.getJSONArray("documents"); + Assert.assertTrue(documents.length() == 0); + // Search documents (nothing) documentResource = resource().path("/document/list"); documentResource.addFilter(new CookieAuthenticationFilter(document1Token));