Add doc for search syntax (#634)

This commit is contained in:
Julien Kirch 2022-04-17 13:10:01 +02:00 committed by GitHub
parent 46f6b9e537
commit bd23f14792
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 144 additions and 122 deletions

View File

@ -14,8 +14,7 @@ Teedy is an open source, lightweight document management system for individuals
![New!](https://teedy.io/img/laptop-demo.png?20180301) ![New!](https://teedy.io/img/laptop-demo.png?20180301)
Demo # Demo
----
A demo is available at [demo.teedy.io](https://demo.teedy.io) A demo is available at [demo.teedy.io](https://demo.teedy.io)
@ -23,8 +22,7 @@ A demo is available at [demo.teedy.io](https://demo.teedy.io)
- "admin" login with "admin" password - "admin" login with "admin" password
- "demo" login with "password" password - "demo" login with "password" password
Features # Features
--------
- Responsive user interface - Responsive user interface
- Optical character recognition - Optical character recognition
@ -54,8 +52,7 @@ Features
- [Bulk files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode) - [Bulk files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode)
- Tested to one million documents - Tested to one million documents
Install with Docker # Install with Docker
-------------------
A preconfigured Docker image is available, including OCR and media conversion tools, listening on port 8080. The database is an embedded H2 database but PostgreSQL is also supported for more performance. A preconfigured Docker image is available, including OCR and media conversion tools, listening on port 8080. The database is an embedded H2 database but PostgreSQL is also supported for more performance.
@ -68,7 +65,7 @@ The data directory is `/data`. Don't forget to mount a volume on it.
To build external URL, the server is expecting a `DOCS_BASE_URL` environment variable (for example https://teedy.mycompany.com) To build external URL, the server is expecting a `DOCS_BASE_URL` environment variable (for example https://teedy.mycompany.com)
### Available environment variables ## Available environment variables
- General - General
- `DOCS_BASE_URL`: The base url used by the application. Generated url's will be using this as base. - `DOCS_BASE_URL`: The base url used by the application. Generated url's will be using this as base.
@ -94,11 +91,11 @@ To build external URL, the server is expecting a `DOCS_BASE_URL` environment var
- `DOCS_SMTP_USERNAME`: The username to be used. - `DOCS_SMTP_USERNAME`: The username to be used.
- `DOCS_SMTP_PASSWORD`: The password to be used. - `DOCS_SMTP_PASSWORD`: The password to be used.
### Examples ## Examples
In the following examples some passwords are exposed in cleartext. This was done in order to keep the examples simple. We strongly encourage you to use variables with an `.env` file or other means to securely store your passwords. In the following examples some passwords are exposed in cleartext. This was done in order to keep the examples simple. We strongly encourage you to use variables with an `.env` file or other means to securely store your passwords.
#### Using the internal database ### Using the internal database
```yaml ```yaml
version: '3' version: '3'
@ -121,7 +118,7 @@ services:
- ./docs/data:/data - ./docs/data:/data
``` ```
#### Using PostgreSQL ### Using PostgreSQL
```yaml ```yaml
version: '3' version: '3'
@ -179,10 +176,9 @@ networks:
driver: bridge driver: bridge
``` ```
Manual installation # Manual installation
-------------------
#### Requirements ## Requirements
- Java 11 - Java 11
- Tesseract 4 for OCR - Tesseract 4 for OCR
@ -190,13 +186,12 @@ Manual installation
- mediainfo for video metadata extraction - mediainfo for video metadata extraction
- A webapp server like [Jetty](http://eclipse.org/jetty/) or [Tomcat](http://tomcat.apache.org/) - A webapp server like [Jetty](http://eclipse.org/jetty/) or [Tomcat](http://tomcat.apache.org/)
#### Download ## Download
The latest release is downloadable here: <https://github.com/sismics/docs/releases> in WAR format. The latest release is downloadable here: <https://github.com/sismics/docs/releases> in WAR format.
**The default admin password is "admin". Don't forget to change it before going to production.** **The default admin password is "admin". Don't forget to change it before going to production.**
How to build Teedy from the sources ## How to build Teedy from the sources
----------------------------------
Prerequisites: JDK 11, Maven 3, NPM, Grunt, Tesseract 4 Prerequisites: JDK 11, Maven 3, NPM, Grunt, Tesseract 4
@ -209,35 +204,39 @@ Teedy is organized in several Maven modules:
First off, clone the repository: `git clone git://github.com/sismics/docs.git` First off, clone the repository: `git clone git://github.com/sismics/docs.git`
or download the sources from GitHub. or download the sources from GitHub.
#### Launch the build ### Launch the build
From the root directory: From the root directory:
mvn clean -DskipTests install ```console
mvn clean -DskipTests install
```
#### Run a stand-alone version ### Run a stand-alone version
From the `docs-web` directory: From the `docs-web` directory:
mvn jetty:run ```console
mvn jetty:run
```
#### Build a .war to deploy to your servlet container ### Build a .war to deploy to your servlet container
From the `docs-web` directory: From the `docs-web` directory:
mvn -Pprod -DskipTests clean install ```console
mvn -Pprod -DskipTests clean install
```
You will get your deployable WAR in the `docs-web/target` directory. You will get your deployable WAR in the `docs-web/target` directory.
Contributing # Contributing
------------
All contributions are more than welcomed. Contributions may close an issue, fix a bug (reported or not reported), improve the existing code, add new feature, and so on. All contributions are more than welcomed. Contributions may close an issue, fix a bug (reported or not reported), improve the existing code, add new feature, and so on.
The `master` branch is the default and base branch for the project. It is used for development and all Pull Requests should go there. The `master` branch is the default and base branch for the project. It is used for development and all Pull Requests should go there.
License # License
-------
Teedy is released under the terms of the GPL license. See `COPYING` for more Teedy is released under the terms of the GPL license. See `COPYING` for more
information or see <http://opensource.org/licenses/GPL-2.0>. information or see <http://opensource.org/licenses/GPL-2.0>.

View File

@ -183,12 +183,10 @@ public class GroupDao {
} }
criteriaList.add("g.GRP_DELETEDATE_D is null"); criteriaList.add("g.GRP_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -123,10 +123,8 @@ public class MetadataDao {
criteriaList.add("m.MET_DELETEDATE_D is null"); criteriaList.add("m.MET_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);

View File

@ -64,10 +64,8 @@ public class RouteDao {
} }
criteriaList.add("r.RTE_DELETEDATE_D is null"); criteriaList.add("r.RTE_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);

View File

@ -145,10 +145,8 @@ public class RouteModelDao {
criteriaList.add("rm.RTM_DELETEDATE_D is null"); criteriaList.add("rm.RTM_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);

View File

@ -90,10 +90,8 @@ public class RouteStepDao {
} }
criteriaList.add("rs.RTP_DELETEDATE_D is null"); criteriaList.add("rs.RTP_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);

View File

@ -19,7 +19,6 @@ public class ShareDao {
* *
* @param share Share * @param share Share
* @return New ID * @return New ID
* @throws Exception
*/ */
public String create(Share share) { public String create(Share share) {
// Create the UUID // Create the UUID

View File

@ -199,10 +199,8 @@ public class TagDao {
criteriaList.add("t.TAG_DELETEDATE_D is null"); criteriaList.add("t.TAG_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);

View File

@ -20,7 +20,6 @@ public class VocabularyDao {
* *
* @param vocabulary Vocabulary * @param vocabulary Vocabulary
* @return New ID * @return New ID
* @throws Exception
*/ */
public String create(Vocabulary vocabulary) { public String create(Vocabulary vocabulary) {
// Create the UUID // Create the UUID

View File

@ -42,11 +42,9 @@ public class WebhookDao {
} }
criteriaList.add("w.WHK_DELETEDATE_D is null"); criteriaList.add("w.WHK_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) { sb.append(" where ");
sb.append(" where "); sb.append(Joiner.on(" and ").join(criteriaList));
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search // Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria); QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -1,5 +1,6 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.criteria;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -49,13 +50,13 @@ public class DocumentCriteria {
* Tag IDs. * Tag IDs.
* The first level list will be AND'ed and the second level list will be OR'ed. * The first level list will be AND'ed and the second level list will be OR'ed.
*/ */
private List<List<String>> tagIdList; private List<List<String>> tagIdList = new ArrayList<>();
/** /**
* Tag IDs to exclude. * Tag IDs to exclude.
* The first and second level list will be excluded. * The first and second level list will be excluded.
*/ */
private List<List<String>> excludedTagIdList; private List<List<String>> excludedTagIdList = new ArrayList<>();
/** /**
* Shared status. * Shared status.
@ -131,19 +132,10 @@ public class DocumentCriteria {
return tagIdList; return tagIdList;
} }
public void setTagIdList(List<List<String>> tagIdList) {
this.tagIdList = tagIdList;
}
public List<List<String>> getExcludedTagIdList() { public List<List<String>> getExcludedTagIdList() {
return excludedTagIdList; return excludedTagIdList;
} }
public DocumentCriteria setExcludedTagIdList(List<List<String>> excludedTagIdList) {
this.excludedTagIdList = excludedTagIdList;
return this;
}
public Boolean getShared() { public Boolean getShared() {
return shared; return shared;
} }
@ -167,11 +159,7 @@ public class DocumentCriteria {
public void setCreatorId(String creatorId) { public void setCreatorId(String creatorId) {
this.creatorId = creatorId; this.creatorId = creatorId;
} }
public Boolean getActiveRoute() {
return activeRoute;
}
public Date getUpdateDateMin() { public Date getUpdateDateMin() {
return updateDateMin; return updateDateMin;
} }
@ -188,6 +176,10 @@ public class DocumentCriteria {
this.updateDateMax = updateDateMax; this.updateDateMax = updateDateMax;
} }
public Boolean getActiveRoute() {
return activeRoute;
}
public void setActiveRoute(Boolean activeRoute) { public void setActiveRoute(Boolean activeRoute) {
this.activeRoute = activeRoute; this.activeRoute = activeRoute;
} }

View File

@ -1,8 +1,8 @@
package com.sismics.docs.core.util; package com.sismics.docs.core.util;
import com.google.common.collect.Lists;
import com.sismics.docs.core.dao.dto.TagDto; import com.sismics.docs.core.dao.dto.TagDto;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -12,14 +12,14 @@ import java.util.List;
*/ */
public class TagUtil { public class TagUtil {
/** /**
* Recursively find children of a tags. * Recursively find children of a tag.
* *
* @param parentTagDto Parent tag * @param parentTagDto Parent tag
* @param allTagDtoList List of all tags * @param allTagDtoList List of all tags
* @return Children tags * @return Children tags
*/ */
public static List<TagDto> findChildren(TagDto parentTagDto, List<TagDto> allTagDtoList) { public static List<TagDto> findChildren(TagDto parentTagDto, List<TagDto> allTagDtoList) {
List<TagDto> childrenTagDtoList = Lists.newArrayList(); List<TagDto> childrenTagDtoList = new ArrayList<>();
for (TagDto tagDto : allTagDtoList) { for (TagDto tagDto : allTagDtoList) {
if (parentTagDto.getId().equals(tagDto.getParentId())) { if (parentTagDto.getId().equals(tagDto.getParentId())) {
@ -32,15 +32,15 @@ public class TagUtil {
} }
/** /**
* Find tags by name (start with). * Find tags by name (start with, ignore case).
* *
* @param name Name * @param name Name
* @param allTagDtoList List of all tags * @param allTagDtoList List of all tags
* @return List of filtered tags * @return List of filtered tags
*/ */
public static List<TagDto> findByName(String name, List<TagDto> allTagDtoList) { public static List<TagDto> findByName(String name, List<TagDto> allTagDtoList) {
List<TagDto> tagDtoList = Lists.newArrayList(); List<TagDto> tagDtoList = new ArrayList<>();
if (name == null || name.isEmpty()) { if (name.isEmpty()) {
return tagDtoList; return tagDtoList;
} }
name = name.toLowerCase(); name = name.toLowerCase();

View File

@ -299,7 +299,7 @@ public class LuceneIndexingHandler implements IndexingHandler {
criteriaList.add("d.DOC_TITLE_C = :title"); criteriaList.add("d.DOC_TITLE_C = :title");
parameterMap.put("title", criteria.getTitle()); parameterMap.put("title", criteria.getTitle());
} }
if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) { if (!criteria.getTagIdList().isEmpty()) {
int index = 0; int index = 0;
for (List<String> tagIdList : criteria.getTagIdList()) { for (List<String> tagIdList : criteria.getTagIdList()) {
List<String> tagCriteriaList = Lists.newArrayList(); List<String> tagCriteriaList = Lists.newArrayList();

View File

@ -67,6 +67,21 @@ import java.util.*;
*/ */
@Path("/document") @Path("/document")
public class DocumentResource extends BaseResource { public class DocumentResource extends BaseResource {
protected static final DateTimeParser YEAR_PARSER = DateTimeFormat.forPattern("yyyy").getParser();
protected static final DateTimeParser MONTH_PARSER = DateTimeFormat.forPattern("yyyy-MM").getParser();
protected static final DateTimeParser DAY_PARSER = DateTimeFormat.forPattern("yyyy-MM-dd").getParser();
private static final DateTimeFormatter DAY_FORMATTER = new DateTimeFormatter(null, DAY_PARSER);
private static final DateTimeFormatter MONTH_FORMATTER = new DateTimeFormatter(null, MONTH_PARSER);
private static final DateTimeFormatter YEAR_FORMATTER = new DateTimeFormatter(null, YEAR_PARSER);
private static final DateTimeParser[] DATE_PARSERS = new DateTimeParser[]{
YEAR_PARSER,
MONTH_PARSER,
DAY_PARSER};
private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().append( null, DATE_PARSERS).toFormatter();
/** /**
* Returns a document. * Returns a document.
* *
@ -349,7 +364,7 @@ public class DocumentResource extends BaseResource {
* @apiParam {String} offset Start at this index * @apiParam {String} offset Start at this index
* @apiParam {Number} sort_column Column index to sort on * @apiParam {Number} sort_column Column index to sort on
* @apiParam {Boolean} asc If true, sort in ascending order * @apiParam {Boolean} asc If true, sort in ascending order
* @apiParam {String} search Search query * @apiParam {String} search Search query (see "Document search syntax" on the top of the page for explanations)
* @apiParam {Booleans} files If true includes files information * @apiParam {Booleans} files If true includes files information
* @apiSuccess {Number} total Total number of documents * @apiSuccess {Number} total Total number of documents
* @apiSuccess {Object[]} documents List of documents * @apiSuccess {Object[]} documents List of documents
@ -492,16 +507,8 @@ public class DocumentResource extends BaseResource {
TagDao tagDao = new TagDao(); TagDao tagDao = new TagDao();
List<TagDto> allTagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), null); List<TagDto> allTagDtoList = tagDao.findByCriteria(new TagCriteria().setTargetIdList(getTargetIdList(null)), null);
UserDao userDao = new UserDao(); UserDao userDao = new UserDao();
DateTimeParser[] parsers = {
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(" *"); String[] criteriaList = search.split(" +");
List<String> query = new ArrayList<>(); List<String> query = new ArrayList<>();
List<String> fullQuery = new ArrayList<>(); List<String> fullQuery = new ArrayList<>();
for (String criteria : criteriaList) { for (String criteria : criteriaList) {
@ -511,20 +518,16 @@ public class DocumentResource extends BaseResource {
fullQuery.add(criteria); fullQuery.add(criteria);
continue; continue;
} }
String paramName = params[0];
String paramValue = params[1];
switch (params[0]) { switch (paramName) {
case "tag": case "tag":
case "!tag": case "!tag":
// New tag criteria // New tag criteria
List<TagDto> tagDtoList = TagUtil.findByName(params[1], allTagDtoList); List<TagDto> tagDtoList = TagUtil.findByName(paramValue, allTagDtoList);
if (documentCriteria.getTagIdList() == null) {
documentCriteria.setTagIdList(new ArrayList<>());
}
if (documentCriteria.getExcludedTagIdList() == null) {
documentCriteria.setExcludedTagIdList(new ArrayList<>());
}
if (tagDtoList.isEmpty()) { if (tagDtoList.isEmpty()) {
// No tag found, the request must returns nothing // No tag found, the request must return nothing
documentCriteria.getTagIdList().add(Lists.newArrayList(UUID.randomUUID().toString())); documentCriteria.getTagIdList().add(Lists.newArrayList(UUID.randomUUID().toString()));
} else { } else {
List<String> tagIdList = Lists.newArrayList(); List<String> tagIdList = Lists.newArrayList();
@ -535,7 +538,7 @@ public class DocumentResource extends BaseResource {
tagIdList.add(childrenTagDto.getId()); tagIdList.add(childrenTagDto.getId());
} }
} }
if (params[0].startsWith("!")) { if (paramName.startsWith("!")) {
documentCriteria.getExcludedTagIdList().add(tagIdList); documentCriteria.getExcludedTagIdList().add(tagIdList);
} else { } else {
documentCriteria.getTagIdList().add(tagIdList); documentCriteria.getTagIdList().add(tagIdList);
@ -548,9 +551,9 @@ public class DocumentResource extends BaseResource {
case "ubefore": case "ubefore":
// New date span criteria // New date span criteria
try { try {
boolean isUpdated = params[0].startsWith("u"); boolean isUpdated = paramName.startsWith("u");
DateTime date = formatter.parseDateTime(params[1]); DateTime date = DATE_FORMATTER.parseDateTime(paramValue);
if (params[0].endsWith("before")) { if (paramName.endsWith("before")) {
if (isUpdated) documentCriteria.setUpdateDateMax(date.toDate()); if (isUpdated) documentCriteria.setUpdateDateMax(date.toDate());
else documentCriteria.setCreateDateMax(date.toDate()); else documentCriteria.setCreateDateMax(date.toDate());
} else { } else {
@ -566,11 +569,11 @@ public class DocumentResource extends BaseResource {
case "uat": case "uat":
case "at": case "at":
// New specific date criteria // New specific date criteria
boolean isUpdated = params[0].startsWith("u");
try { try {
boolean isUpdated = params[0].startsWith("u"); switch (paramValue.length()) {
switch (params[1].length()) {
case 10: { case 10: {
DateTime date = dayFormatter.parseDateTime(params[1]); DateTime date = DATE_FORMATTER.parseDateTime(params[1]);
if (isUpdated) { if (isUpdated) {
documentCriteria.setUpdateDateMin(date.toDate()); documentCriteria.setUpdateDateMin(date.toDate());
documentCriteria.setUpdateDateMax(date.plusDays(1).minusSeconds(1).toDate()); documentCriteria.setUpdateDateMax(date.plusDays(1).minusSeconds(1).toDate());
@ -581,7 +584,7 @@ public class DocumentResource extends BaseResource {
break; break;
} }
case 7: { case 7: {
DateTime date = monthFormatter.parseDateTime(params[1]); DateTime date = MONTH_FORMATTER.parseDateTime(params[1]);
if (isUpdated) { if (isUpdated) {
documentCriteria.setUpdateDateMin(date.toDate()); documentCriteria.setUpdateDateMin(date.toDate());
documentCriteria.setUpdateDateMax(date.plusMonths(1).minusSeconds(1).toDate()); documentCriteria.setUpdateDateMax(date.plusMonths(1).minusSeconds(1).toDate());
@ -592,7 +595,7 @@ public class DocumentResource extends BaseResource {
break; break;
} }
case 4: { case 4: {
DateTime date = yearFormatter.parseDateTime(params[1]); DateTime date = YEAR_FORMATTER.parseDateTime(params[1]);
if (isUpdated) { if (isUpdated) {
documentCriteria.setUpdateDateMin(date.toDate()); documentCriteria.setUpdateDateMin(date.toDate());
documentCriteria.setUpdateDateMax(date.plusYears(1).minusSeconds(1).toDate()); documentCriteria.setUpdateDateMax(date.plusYears(1).minusSeconds(1).toDate());
@ -601,6 +604,10 @@ public class DocumentResource extends BaseResource {
documentCriteria.setCreateDateMax(date.plusYears(1).minusSeconds(1).toDate()); documentCriteria.setCreateDateMax(date.plusYears(1).minusSeconds(1).toDate());
} }
break; break;
} default: {
// Invalid format, returns no documents
documentCriteria.setCreateDateMin(new Date(0));
documentCriteria.setCreateDateMax(new Date(0));
} }
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -611,25 +618,26 @@ public class DocumentResource extends BaseResource {
break; break;
case "shared": case "shared":
// New shared state criteria // New shared state criteria
documentCriteria.setShared(params[1].equals("yes")); documentCriteria.setShared(paramValue.equals("yes"));
break; break;
case "lang": case "lang":
// New language criteria // New language criteria
if (Constants.SUPPORTED_LANGUAGES.contains(params[1])) { if (Constants.SUPPORTED_LANGUAGES.contains(paramValue)) {
documentCriteria.setLanguage(params[1]); documentCriteria.setLanguage(paramValue);
} else { } else {
// Unsupported language, returns no documents
documentCriteria.setLanguage(UUID.randomUUID().toString()); documentCriteria.setLanguage(UUID.randomUUID().toString());
} }
break; break;
case "mime": case "mime":
// New mime type criteria // New mime type criteria
documentCriteria.setMimeType(params[1]); documentCriteria.setMimeType(paramValue);
break; break;
case "by": case "by":
// New creator criteria // New creator criteria
User user = userDao.getActiveByUsername(params[1]); User user = userDao.getActiveByUsername(paramValue);
if (user == null) { if (user == null) {
// This user doesn't exists, return nothing // This user doesn't exist, return nothing
documentCriteria.setCreatorId(UUID.randomUUID().toString()); documentCriteria.setCreatorId(UUID.randomUUID().toString());
} else { } else {
// This user exists, search its documents // This user exists, search its documents
@ -638,19 +646,19 @@ public class DocumentResource extends BaseResource {
break; break;
case "workflow": case "workflow":
// New shared state criteria // New shared state criteria
documentCriteria.setActiveRoute(params[1].equals("me")); documentCriteria.setActiveRoute(paramValue.equals("me"));
break; break;
case "simple": case "simple":
// New simple search criteria // New simple search criteria
query.add(params[1]); query.add(paramValue);
break; break;
case "full": case "full":
// New fulltext search criteria // New fulltext search criteria
fullQuery.add(params[1]); fullQuery.add(paramValue);
break; break;
case "title": case "title":
// New title criteria // New title criteria
documentCriteria.setTitle(params[1]); documentCriteria.setTitle(paramValue);
break; break;
default: default:
fullQuery.add(criteria); fullQuery.add(criteria);

View File

@ -10,7 +10,7 @@ The base URL depends on your server. If your instance of Teedy is accessible thr
`https://teedy.mycompany.com`, then the base API URL is `https://teedy.mycompany.com/api`. `https://teedy.mycompany.com`, then the base API URL is `https://teedy.mycompany.com/api`.
## Verbs and status codes ## Verbs and status codes
The API uses restful verbs. The API uses RESTful verbs.
| Verb | Description | | Verb | Description |
|---|---| |---|---|
@ -46,4 +46,43 @@ curl -i -X GET -H "Cookie: auth_token=64085630-2ae6-415c-9a92-4b22c107eaa4" http
A call to this API with a given `auth_token` cookie will make it unusable for other calls. A call to this API with a given `auth_token` cookie will make it unusable for other calls.
``` ```
curl -i -X POST -H "Cookie: auth_token=64085630-2ae6-415c-9a92-4b22c107eaa4" https://docs.mycompany.com/api/user/logout curl -i -X POST -H "Cookie: auth_token=64085630-2ae6-415c-9a92-4b22c107eaa4" https://docs.mycompany.com/api/user/logout
``` ```
## Document search syntax
The `/api/document/list` endpoint use a String `search` parameter.
This parameter is split in segments using the space character (the other whitespace characters are not considered).
If a segment contains exactly one colon (`:`), it will used as a field criteria (see bellow).
In other cases (zero or more than one colon), the segment will be used as a search criteria for all fields including the document's files content.
### Search fields
If a search `VALUE` is considered invalid, the search result will be empty.
* Content
* `full:VALUE`: `VALUE` is used as search criteria for all fields, including the document's files content
* `simple:VALUE`: `VALUE` is used as a search criteria for all fields except the document's files content
* Date
* `after:VALUE`: the document must have been created after or at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd`
* `at:VALUE`: the document must have been created at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd` (for `yyyy` it must be the same year, for `yyyy-MM` the same month, for `yyyy-MM-dd` the same day)
* `before:VALUE`: the document must have been created before or at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd`
* `uafter:VALUE`: the document must have been last updated after or at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd`
* `at:VALUE`: the document must have been updated at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd` (for `yyyy` it must be the same year, for `yyyy-MM` the same month, for `yyyy-MM-dd` the same day)
* `ubefore:VALUE`: the document must have been updated before or at the `VALUE` moment, accepted format are `yyyy`, `yyyy-MM` and `yyyy-MM-dd`
* Language
* `lang:VALUE`: the document must be of the specified language (example: `en`)
* Mime
* `mime:VALUE`: the document must be of the specified mime type (example: `image/png`)
* Shared
* `shared:VALUE`: if `VALUE` is `yes`the document must be shared, for other `VALUE`s the criteria is ignored
* Tags
* `tag:VALUE`: the document must contain a tag or a child of a tag that starts with `VALUE`, case is ignored
* `!tag:VALUE`: the document must not contain a tag or a child of a tag that starts with `VALUE`, case is ignored
* Title
* `title:VALUE`: the title of the document must be `VALUE`
* User
* `by:VALUE`: the document creator's username must be `VALUE` with an exact match, the user must not be deleted
* Workflow
* `workflow:VALUE`: if `VALUE` is `me` the document must have an active route, for other `VALUE`s the criteria is ignored