Compare commits

..

No commits in common. "master" and "v1.5" have entirely different histories.
master ... v1.5

491 changed files with 8191 additions and 31168 deletions

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [jendib]

View File

@ -1,84 +0,0 @@
name: Maven CI/CD
on:
push:
branches: [master]
tags: [v*]
workflow_dispatch:
jobs:
build_and_publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: "11"
distribution: "temurin"
cache: maven
- name: Install test dependencies
run: sudo apt-get update && sudo apt-get -y -q --no-install-recommends install ffmpeg mediainfo tesseract-ocr tesseract-ocr-deu
- name: Build with Maven
run: mvn --batch-mode -Pprod clean install
- name: Upload war artifact
uses: actions/upload-artifact@v2
with:
name: docs-web-ci.war
path: docs-web/target/docs*.war
build_docker_image:
name: Publish to Docker Hub
runs-on: ubuntu-latest
needs: [build_and_publish]
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Download war artifact
uses: actions/download-artifact@v2
with:
name: docs-web-ci.war
path: docs-web/target
-
name: Setup up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Populate Docker metadata
id: metadata
uses: docker/metadata-action@v3
with:
images: sismics/docs
flavor: |
latest=false
tags: |
type=ref,event=tag
type=raw,value=latest,enable=${{ github.ref_type != 'tag' }}
labels: |
org.opencontainers.image.title = Teedy
org.opencontainers.image.description = Teedy is an open source, lightweight document management system for individuals and businesses.
org.opencontainers.image.created = ${{ github.event_created_at }}
org.opencontainers.image.author = Sismics
org.opencontainers.image.url = https://teedy.io/
org.opencontainers.image.vendor = Sismics
org.opencontainers.image.license = GPLv2
org.opencontainers.image.version = ${{ github.event_head_commit.id }}
-
name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}

8
.gitignore vendored
View File

@ -11,11 +11,3 @@
*.iml *.iml
node_modules node_modules
import_test import_test
teedy-importer-linux
teedy-importer-macos
teedy-importer-win.exe
docs/*
!docs/.gitkeep
#macos
.DS_Store

24
.travis.yml Normal file
View File

@ -0,0 +1,24 @@
sudo: required
dist: trusty
language: java
before_install:
- sudo apt-get -qq update
- sudo apt-get -y -q install tesseract-ocr tesseract-ocr-fra tesseract-ocr-ita tesseract-ocr-kor tesseract-ocr-rus tesseract-ocr-ukr tesseract-ocr-spa tesseract-ocr-ara tesseract-ocr-hin tesseract-ocr-deu tesseract-ocr-pol tesseract-ocr-jpn tesseract-ocr-por tesseract-ocr-tha tesseract-ocr-jpn tesseract-ocr-chi-sim tesseract-ocr-chi-tra
- sudo apt-get -y -q install haveged && sudo service haveged start
after_success:
- mvn -Pprod -DskipTests clean install
- docker login -u $DOCKER_USER -p $DOCKER_PASS
- export REPO=sismics/docs
- export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`
- docker build -f Dockerfile -t $REPO:$COMMIT .
- docker tag $REPO:$COMMIT $REPO:$TAG
- docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
- docker push $REPO
env:
global:
- TESSDATA_PREFIX=/usr/share/tesseract-ocr
- LC_NUMERIC=C
- secure: LRGpjWORb0qy6VuypZjTAfA8uRHlFUMTwb77cenS9PPRBxuSnctC531asS9Xg3DqC5nsRxBBprgfCKotn5S8nBSD1ceHh84NASyzLSBft3xSMbg7f/2i7MQ+pGVwLncusBU6E/drnMFwZBleo+9M8Tf96axY5zuUp90MUTpSgt0=
- secure: bCDDR6+I7PmSkuTYZv1HF/z98ANX/SFEESUCqxVmV5Gs0zFC0vQXaPJQ2xaJNRop1HZBFMZLeMMPleb0iOs985smpvK2F6Rbop9Tu+Vyo0uKqv9tbZ7F8Nfgnv9suHKZlL84FNeUQZJX6vsFIYPEJ/r7K5P/M0PdUy++fEwxEhU=
- secure: ewXnzbkgCIHpDWtaWGMa1OYZJ/ki99zcIl4jcDPIC0eB3njX/WgfcC6i0Ke9mLqDqwXarWJ6helm22sNh+xtQiz6isfBtBX+novfRt9AANrBe3koCMUemMDy7oh5VflBaFNP0DVb8LSCnwf6dx6ZB5E9EB8knvk40quc/cXpGjY=
- COMMIT=${TRAVIS_COMMIT::8}

View File

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@sismicsdocs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,75 +1,11 @@
FROM ubuntu:22.04 FROM sismics/jetty:9.2.20-jdk7
LABEL maintainer="b.gamard@sismics.com" MAINTAINER b.gamard@sismics.com
# Run Debian in non interactive mode RUN apt-get update && apt-get -y -q install tesseract-ocr tesseract-ocr-fra tesseract-ocr-ita tesseract-ocr-kor tesseract-ocr-rus tesseract-ocr-ukr tesseract-ocr-spa tesseract-ocr-ara tesseract-ocr-hin tesseract-ocr-deu tesseract-ocr-pol tesseract-ocr-jpn tesseract-ocr-por tesseract-ocr-tha tesseract-ocr-jpn tesseract-ocr-chi-sim tesseract-ocr-chi-tra && \
ENV DEBIAN_FRONTEND noninteractive apt-get clean && rm -rf /var/lib/apt/lists/*
# Configure env ENV TESSDATA_PREFIX /usr/share/tesseract-ocr
ENV LANG C.UTF-8 ENV LC_NUMERIC C
ENV LC_ALL C.UTF-8
ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64/
ENV JAVA_OPTIONS -Dfile.encoding=UTF-8 -Xmx1g
ENV JETTY_VERSION 11.0.20
ENV JETTY_HOME /opt/jetty
# Install packages ADD docs.xml /opt/jetty/webapps/docs.xml
RUN apt-get update && \ ADD docs-web/target/docs-web-*.war /opt/jetty/webapps/docs.war
apt-get -y -q --no-install-recommends install \
vim less procps unzip wget tzdata openjdk-11-jdk \
ffmpeg \
mediainfo \
tesseract-ocr \
tesseract-ocr-ara \
tesseract-ocr-ces \
tesseract-ocr-chi-sim \
tesseract-ocr-chi-tra \
tesseract-ocr-dan \
tesseract-ocr-deu \
tesseract-ocr-fin \
tesseract-ocr-fra \
tesseract-ocr-heb \
tesseract-ocr-hin \
tesseract-ocr-hun \
tesseract-ocr-ita \
tesseract-ocr-jpn \
tesseract-ocr-kor \
tesseract-ocr-lav \
tesseract-ocr-nld \
tesseract-ocr-nor \
tesseract-ocr-pol \
tesseract-ocr-por \
tesseract-ocr-rus \
tesseract-ocr-spa \
tesseract-ocr-swe \
tesseract-ocr-tha \
tesseract-ocr-tur \
tesseract-ocr-ukr \
tesseract-ocr-vie \
tesseract-ocr-sqi \
&& apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN dpkg-reconfigure -f noninteractive tzdata
# Install Jetty
RUN wget -nv -O /tmp/jetty.tar.gz \
"https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/${JETTY_VERSION}/jetty-home-${JETTY_VERSION}.tar.gz" \
&& tar xzf /tmp/jetty.tar.gz -C /opt \
&& mv /opt/jetty* /opt/jetty \
&& useradd jetty -U -s /bin/false \
&& chown -R jetty:jetty /opt/jetty \
&& mkdir /opt/jetty/webapps \
&& chmod +x /opt/jetty/bin/jetty.sh
EXPOSE 8080
# Install app
RUN mkdir /app && \
cd /app && \
java -jar /opt/jetty/start.jar --add-modules=server,http,webapp,deploy
ADD docs.xml /app/webapps/docs.xml
ADD docs-web/target/docs-web-*.war /app/webapps/docs.war
WORKDIR /app
CMD ["java", "-jar", "/opt/jetty/start.jar"]

218
README.md
View File

@ -1,45 +1,43 @@
<h3 align="center"> <h3 align="center">
<img src="https://teedy.io/img/github-title.png" alt="Teedy" width=500 /> <img src="https://www.sismicsdocs.com/img/github-title.png" alt="Sismics Docs" width=500 />
</h3> </h3>
[![Twitter: @sismicsdocs](https://img.shields.io/badge/contact-@sismicsdocs-blue.svg?style=flat)](https://twitter.com/sismicsdocs)
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Maven CI/CD](https://github.com/sismics/docs/actions/workflows/build-deploy.yml/badge.svg)](https://github.com/sismics/docs/actions/workflows/build-deploy.yml) [![Build Status](https://secure.travis-ci.org/sismics/docs.png)](http://travis-ci.org/sismics/docs)
Teedy is an open source, lightweight document management system for individuals and businesses. Docs is an open source, lightweight document management system for individuals and businesses.
<hr /> <hr />
<h2 align="center"> <h2 align="center">
<a href="https://github.com/users/jendib/sponsorship">Sponsor this project if you use and appreciate it!</a> We just launched a Cloud version of Sismics Docs! Head to <a href="https://www.sismicsdocs.com/">sismicsdocs.com</a> for more informations
</h2> </h2>
<hr /> <hr />
![New!](https://teedy.io/img/laptop-demo.png?20180301) ![New!](https://www.sismicsdocs.com/img/laptop-demo.png)
# Demo Demo
----
A demo is available at [demo.teedy.io](https://demo.teedy.io)
A demo is available at [demo.sismicsdocs.com](https://demo.sismicsdocs.com)
- Guest login is enabled with read access on all documents - Guest login is enabled with read access on all documents
- "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
- LDAP authentication ![New!](https://www.sismics.com/public/img/new.png) - Support image, PDF, ODT and DOCX files
- Support image, PDF, ODT, DOCX, PPTX files - Flexible search engine
- Video file support
- Flexible search engine with suggestions and highlighting
- Full text search in all supported files - Full text search in all supported files
- All [Dublin Core](http://dublincore.org/) metadata - All [Dublin Core](http://dublincore.org/) metadata
- Custom user-defined metadata ![New!](https://www.sismics.com/public/img/new.png)
- Workflow system ![New!](https://www.sismics.com/public/img/new.png) - Workflow system ![New!](https://www.sismics.com/public/img/new.png)
- 256-bit AES encryption of stored files - 256-bit AES encryption of stored files
- File versioning ![New!](https://www.sismics.com/public/img/new.png)
- Tag system with nesting - Tag system with nesting
- Import document from email (EML format) - Import document from email (EML format) ![New!](https://www.sismics.com/public/img/new.png)
- Automatic inbox scanning and importing - Automatic inbox scanning and importing ![New!](https://www.sismics.com/public/img/new.png)
- User/group permission system - User/group permission system
- 2-factor authentication - 2-factor authentication
- Hierarchical groups - Hierarchical groups
@ -48,158 +46,31 @@ A demo is available at [demo.teedy.io](https://demo.teedy.io)
- Storage quota per user - Storage quota per user
- Document sharing by URL - Document sharing by URL
- RESTful Web API - RESTful Web API
- Webhooks to trigger external service
- Fully featured Android client - Fully featured Android client
- [Bulk files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode) - [Mass files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode) ![New!](https://www.sismics.com/public/img/new.png)
- Tested to one million documents - Tested to 100k documents
# Install with Docker Download
--------
A preconfigured Docker image is available, including OCR and media conversion tools, listening on port 8080. If no PostgreSQL config is provided, the database is an embedded H2 database. The H2 embedded database should only be used for testing. For production usage use the provided PostgreSQL configuration (check the Docker Compose example)
**The default admin password is "admin". Don't forget to change it before going to production.**
- Master branch, can be unstable. Not recommended for production use: `sismics/docs:latest`
- Latest stable version: `sismics/docs:v1.11`
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)
## Available environment variables
- General
- `DOCS_BASE_URL`: The base url used by the application. Generated url's will be using this as base.
- `DOCS_GLOBAL_QUOTA`: Defines the default quota applying to all users.
- `DOCS_BCRYPT_WORK`: Defines the work factor which is used for password hashing. The default is `10`. This value may be `4...31` including `4` and `31`. The specified value will be used for all new users and users changing their password. Be aware that setting this factor to high can heavily impact login and user creation performance.
- Admin
- `DOCS_ADMIN_EMAIL_INIT`: Defines the e-mail-address the admin user should have upon initialization.
- `DOCS_ADMIN_PASSWORD_INIT`: Defines the password the admin user should have upon initialization. Needs to be a bcrypt hash. **Be aware that `$` within the hash have to be escaped with a second `$`.**
- Database
- `DATABASE_URL`: The jdbc connection string to be used by `hibernate`.
- `DATABASE_USER`: The user which should be used for the database connection.
- `DATABASE_PASSWORD`: The password to be used for the database connection.
- `DATABASE_POOL_SIZE`: The pool size to be used for the database connection.
- Language
- `DOCS_DEFAULT_LANGUAGE`: The language which will be used as default. Currently supported values are:
- `eng`, `fra`, `ita`, `deu`, `spa`, `por`, `pol`, `rus`, `ukr`, `ara`, `hin`, `chi_sim`, `chi_tra`, `jpn`, `tha`, `kor`, `nld`, `tur`, `heb`, `hun`, `fin`, `swe`, `lav`, `dan`
- E-Mail
- `DOCS_SMTP_HOSTNAME`: Hostname of the SMTP-Server to be used by Teedy.
- `DOCS_SMTP_PORT`: The port which should be used.
- `DOCS_SMTP_USERNAME`: The username to be used.
- `DOCS_SMTP_PASSWORD`: The password to be used.
## 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.
### Default, using PostgreSQL
```yaml
version: '3'
services:
# Teedy Application
teedy-server:
image: sismics/docs:v1.11
restart: unless-stopped
ports:
# Map internal port to host
- 8080:8080
environment:
# Base url to be used
DOCS_BASE_URL: "https://docs.example.com"
# Set the admin email
DOCS_ADMIN_EMAIL_INIT: "admin@example.com"
# Set the admin password (in this example: "superSecure")
DOCS_ADMIN_PASSWORD_INIT: "$$2a$$05$$PcMNUbJvsk7QHFSfEIDaIOjk1VI9/E7IPjTKx.jkjPxkx2EOKSoPS"
# Setup the database connection. "teedy-db" is the hostname
# and "teedy" is the name of the database the application
# will connect to.
DATABASE_URL: "jdbc:postgresql://teedy-db:5432/teedy"
DATABASE_USER: "teedy_db_user"
DATABASE_PASSWORD: "teedy_db_password"
DATABASE_POOL_SIZE: "10"
volumes:
- ./docs/data:/data
networks:
- docker-internal
- internet
depends_on:
- teedy-db
# DB for Teedy
teedy-db:
image: postgres:13.1-alpine
restart: unless-stopped
expose:
- 5432
environment:
POSTGRES_USER: "teedy_db_user"
POSTGRES_PASSWORD: "teedy_db_password"
POSTGRES_DB: "teedy"
volumes:
- ./docs/db:/var/lib/postgresql/data
networks:
- docker-internal
networks:
# Network without internet access. The db does not need
# access to the host network.
docker-internal:
driver: bridge
internal: true
internet:
driver: bridge
```
### Using the internal database (only for testing)
```yaml
version: '3'
services:
# Teedy Application
teedy-server:
image: sismics/docs:v1.11
restart: unless-stopped
ports:
# Map internal port to host
- 8080:8080
environment:
# Base url to be used
DOCS_BASE_URL: "https://docs.example.com"
# Set the admin email
DOCS_ADMIN_EMAIL_INIT: "admin@example.com"
# Set the admin password (in this example: "superSecure")
DOCS_ADMIN_PASSWORD_INIT: "$$2a$$05$$PcMNUbJvsk7QHFSfEIDaIOjk1VI9/E7IPjTKx.jkjPxkx2EOKSoPS"
volumes:
- ./docs/data:/data
```
# Manual installation
## Requirements
- Java 11
- Tesseract 4 for OCR
- ffmpeg for video thumbnails
- mediainfo for video metadata extraction
- A webapp server like [Jetty](http://eclipse.org/jetty/) or [Tomcat](http://tomcat.apache.org/)
## 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.** You will need a Java webapp server to run it, like [Jetty](http://eclipse.org/jetty/) or [Tomcat](http://tomcat.apache.org/).
The default admin password is "admin". Don't forget to change it before going to production.
## How to build Teedy from the sources Install with Docker
-------------------
Prerequisites: JDK 11, Maven 3, NPM, Grunt, Tesseract 4 From a Docker host, run this command to download and install Sismics Docs. The server will run on <http://[your-docker-host-ip]:8100>.
The default admin password is "admin". Don't forget to change it before going to production.
Teedy is organized in several Maven modules: docker run --rm --name sismics_docs_latest -d -p 8100:8080 -v sismics_docs_latest:/data sismics/docs:latest
How to build Docs from the sources
----------------------------------
Prerequisites: JDK 7 with JCE, Maven 3, Tesseract 3.02
Docs is organized in several Maven modules:
- docs-core - docs-core
- docs-web - docs-web
@ -208,39 +79,28 @@ 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:
```console
mvn clean -DskipTests install mvn clean -DskipTests install
```
### Run a stand-alone version #### Run a stand-alone version
From the `docs-web` directory: From the `docs-web` directory:
```console
mvn jetty:run 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:
```console
mvn -Pprod -DskipTests clean install 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 License
-------
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. Docs is released under the terms of the GPL license. See `COPYING` for more
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
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

@ -1,18 +0,0 @@
version: '3'
services:
# Teedy Application
teedy-server:
image: sismics/docs:v1.10
restart: unless-stopped
ports:
# Map internal port to host
- 8080:8080
environment:
# Base url to be used
DOCS_BASE_URL: "https://docs.example.com"
# Set the admin email
DOCS_ADMIN_EMAIL_INIT: "admin@example.com"
# Set the admin password (in this example: "superSecure")
DOCS_ADMIN_PASSWORD_INIT: "$$2a$$05$$PcMNUbJvsk7QHFSfEIDaIOjk1VI9/E7IPjTKx.jkjPxkx2EOKSoPS"
volumes:
- ./docs/data:/data

View File

@ -4,7 +4,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.android.tools.build:gradle:3.0.1'
} }
} }
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
@ -15,11 +15,11 @@ repositories {
} }
android { android {
compileSdkVersion 28 compileSdkVersion 26
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 28 targetSdkVersion 26
versionCode 1 versionCode 1
versionName '1.0' versionName '1.0'
} }
@ -30,14 +30,14 @@ android {
} }
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: '*.jar') compile fileTree(dir: 'libs', include: '*.jar')
implementation 'com.android.support:appcompat-v7:28.0.0' compile 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:28.0.0' compile 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support:design:28.0.0' compile 'com.android.support:design:26.1.0'
implementation 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5' compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
implementation 'org.greenrobot:eventbus:3.1.1' compile 'org.greenrobot:eventbus:3.0.0'
implementation 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.squareup.okhttp3:okhttp:3.10.0' compile 'com.squareup.okhttp3:okhttp:3.7.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0' compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.0'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
} }

View File

@ -8,7 +8,6 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
@ -29,7 +28,6 @@
android:name=".activity.MainActivity" android:name=".activity.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/AppTheme.NoActionBar"
android:windowSoftInputMode="adjustNothing"> android:windowSoftInputMode="adjustNothing">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH" />
@ -45,9 +43,6 @@
<activity <activity
android:name=".activity.DocumentViewActivity" android:name=".activity.DocumentViewActivity"
android:label=""> android:label="">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.DocumentEditActivity" android:name=".activity.DocumentEditActivity"

View File

@ -1,7 +1,6 @@
package com.sismics.docs; package com.sismics.docs;
import android.app.Application; import android.app.Application;
import android.support.v7.app.AppCompatDelegate;
import com.sismics.docs.model.application.ApplicationContext; import com.sismics.docs.model.application.ApplicationContext;
import com.sismics.docs.util.PreferenceUtil; import com.sismics.docs.util.PreferenceUtil;
@ -23,7 +22,5 @@ public class MainApplication extends Application {
// TODO Provide documents to intent action get content // TODO Provide documents to intent action get content
super.onCreate(); super.onCreate();
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} }
} }

View File

@ -52,7 +52,7 @@ public class AuditLogActivity extends AppCompatActivity {
} }
// Configure the swipe refresh layout // Configure the swipe refresh layout
SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout); SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright, swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light, android.R.color.holo_green_light,
android.R.color.holo_orange_light, android.R.color.holo_orange_light,
@ -65,7 +65,7 @@ public class AuditLogActivity extends AppCompatActivity {
}); });
// Navigate to user profile on click // Navigate to user profile on click
final ListView auditLogListView = findViewById(R.id.auditLogListView); final ListView auditLogListView = (ListView) findViewById(R.id.auditLogListView);
auditLogListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { auditLogListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@ -88,15 +88,15 @@ public class AuditLogActivity extends AppCompatActivity {
* Refresh the view. * Refresh the view.
*/ */
private void refreshView(String documentId) { private void refreshView(String documentId) {
final SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout); final SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
final ProgressBar progressBar = findViewById(R.id.progressBar); final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
final ListView auditLogListView = findViewById(R.id.auditLogListView); final ListView auditLogListView = (ListView) findViewById(R.id.auditLogListView);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
auditLogListView.setVisibility(View.GONE); auditLogListView.setVisibility(View.GONE);
AuditLogResource.list(this, documentId, new HttpCallback() { AuditLogResource.list(this, documentId, new HttpCallback() {
@Override @Override
public void onSuccess(JSONObject response) { public void onSuccess(JSONObject response) {
auditLogListView.setAdapter(new AuditLogListAdapter(AuditLogActivity.this, response.optJSONArray("logs"))); auditLogListView.setAdapter(new AuditLogListAdapter(response.optJSONArray("logs")));
} }
@Override @Override

View File

@ -9,13 +9,11 @@ import android.provider.SearchRecentSuggestions;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView; import android.widget.ListView;
import android.widget.SearchView; import android.widget.SearchView;
import android.widget.TextView; import android.widget.TextView;
@ -63,10 +61,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.main_activity); setContentView(R.layout.main_activity);
// Enable ActionBar app icon to behave as action to toggle nav drawer // Enable ActionBar app icon to behave as action to toggle nav drawer
drawerLayout = findViewById(R.id.drawer_layout); drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitleTextColor(getResources().getColor(android.R.color.white));
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setHomeButtonEnabled(true);
@ -80,15 +75,15 @@ public class MainActivity extends AppCompatActivity {
// Fill the drawer user info // Fill the drawer user info
JSONObject userInfo = ApplicationContext.getInstance().getUserInfo(); JSONObject userInfo = ApplicationContext.getInstance().getUserInfo();
TextView usernameTextView = findViewById(R.id.usernameTextView); TextView usernameTextView = (TextView) findViewById(R.id.usernameTextView);
usernameTextView.setText(userInfo.optString("username")); usernameTextView.setText(userInfo.optString("username"));
TextView emailTextView = findViewById(R.id.emailTextView); TextView emailTextView = (TextView) findViewById(R.id.emailTextView);
emailTextView.setText(userInfo.optString("email")); emailTextView.setText(userInfo.optString("email"));
// Get tag list to fill the drawer // Get tag list to fill the drawer
final ListView tagListView = findViewById(R.id.tagListView); final ListView tagListView = (ListView) findViewById(R.id.tagListView);
final View tagProgressView = findViewById(R.id.tagProgressView); final View tagProgressView = findViewById(R.id.tagProgressView);
final TextView tagEmptyView = findViewById(R.id.tagEmptyView); final TextView tagEmptyView = (TextView) findViewById(R.id.tagEmptyView);
tagListView.setEmptyView(tagProgressView); tagListView.setEmptyView(tagProgressView);
JSONObject cacheTags = PreferenceUtil.getCachedJson(this, PreferenceUtil.PREF_CACHED_TAGS_JSON); JSONObject cacheTags = PreferenceUtil.getCachedJson(this, PreferenceUtil.PREF_CACHED_TAGS_JSON);
if (cacheTags != null) { if (cacheTags != null) {
@ -150,15 +145,6 @@ public class MainActivity extends AppCompatActivity {
} }
}); });
// Add document button
ImageButton addDocumentButton = findViewById(R.id.addDocumentButton);
addDocumentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, DocumentEditActivity.class));
}
});
handleIntent(getIntent()); handleIntent(getIntent());
EventBus.getDefault().register(this); EventBus.getDefault().register(this);

View File

@ -1,6 +1,8 @@
package com.sismics.docs.adapter; package com.sismics.docs.adapter;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -28,19 +30,12 @@ public class AuditLogListAdapter extends BaseAdapter {
*/ */
private List<JSONObject> logList; private List<JSONObject> logList;
/**
* Context.
*/
private Context context;
/** /**
* Audit log list adapter. * Audit log list adapter.
* *
* @param context Context
* @param logs Logs * @param logs Logs
*/ */
public AuditLogListAdapter(Context context, JSONArray logs) { public AuditLogListAdapter(JSONArray logs) {
this.context = context;
this.logList = new ArrayList<>(); this.logList = new ArrayList<>();
for (int i = 0; i < logs.length(); i++) { for (int i = 0; i < logs.length(); i++) {
@ -72,21 +67,11 @@ public class AuditLogListAdapter extends BaseAdapter {
// Build message // Build message
final JSONObject log = getItem(position); final JSONObject log = getItem(position);
StringBuilder message = new StringBuilder(); StringBuilder message = new StringBuilder(log.optString("class"));
// Translate entity name
int stringId = context.getResources().getIdentifier("auditlog_" + log.optString("class"), "string", context.getPackageName());
if (stringId == 0) {
message.append(log.optString("class"));
} else {
message.append(context.getResources().getString(stringId));
}
message.append(" ");
switch (log.optString("type")) { switch (log.optString("type")) {
case "CREATE": message.append(context.getResources().getString(R.string.auditlog_created)); break; case "CREATE": message.append(" created"); break;
case "UPDATE": message.append(context.getResources().getString(R.string.auditlog_updated)); break; case "UPDATE": message.append(" updated"); break;
case "DELETE": message.append(context.getResources().getString(R.string.auditlog_deleted)); break; case "DELETE": message.append(" deleted"); break;
} }
switch (log.optString("class")) { switch (log.optString("class")) {
case "Document": case "Document":
@ -100,9 +85,9 @@ public class AuditLogListAdapter extends BaseAdapter {
} }
// Fill the view // Fill the view
TextView usernameTextView = view.findViewById(R.id.usernameTextView); TextView usernameTextView = (TextView) view.findViewById(R.id.usernameTextView);
TextView messageTextView = view.findViewById(R.id.messageTextView); TextView messageTextView = (TextView) view.findViewById(R.id.messageTextView);
TextView dateTextView = view.findViewById(R.id.dateTextView); TextView dateTextView = (TextView) view.findViewById(R.id.dateTextView);
usernameTextView.setText(log.optString("username")); usernameTextView.setText(log.optString("username"));
messageTextView.setText(message); messageTextView.setText(message);
String date = DateFormat.getDateFormat(parent.getContext()).format(new Date(log.optLong("create_date"))); String date = DateFormat.getDateFormat(parent.getContext()).format(new Date(log.optLong("create_date")));

View File

@ -33,8 +33,6 @@ public class LanguageAdapter extends BaseAdapter {
} }
languageList.add(new Language("fra", R.string.language_french, R.drawable.fra)); languageList.add(new Language("fra", R.string.language_french, R.drawable.fra));
languageList.add(new Language("eng", R.string.language_english, R.drawable.eng)); languageList.add(new Language("eng", R.string.language_english, R.drawable.eng));
languageList.add(new Language("deu", R.string.language_german, R.drawable.deu));
languageList.add(new Language("pol", R.string.language_polish, R.drawable.pol));
} }
@Override @Override

View File

@ -2,7 +2,6 @@ package com.sismics.docs.fragment;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
@ -10,10 +9,12 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.sismics.docs.R; import com.sismics.docs.R;
import com.sismics.docs.activity.DocumentEditActivity;
import com.sismics.docs.activity.DocumentViewActivity; import com.sismics.docs.activity.DocumentViewActivity;
import com.sismics.docs.adapter.DocListAdapter; import com.sismics.docs.adapter.DocListAdapter;
import com.sismics.docs.event.DocumentAddEvent; import com.sismics.docs.event.DocumentAddEvent;
@ -45,6 +46,11 @@ public class DocListFragment extends Fragment {
*/ */
private String query; private String query;
/**
* Request code of adding document.
*/
private static final int REQUEST_CODE_ADD_DOCUMENT = 1;
// View cache // View cache
private EmptyRecyclerView recyclerView; private EmptyRecyclerView recyclerView;
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
@ -54,22 +60,23 @@ public class DocListFragment extends Fragment {
private int previousTotal = 0; private int previousTotal = 0;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.doc_list_fragment, container, false); final View view = inflater.inflate(R.layout.doc_list_fragment, container, false);
// Configure the RecyclerView // Configure the RecyclerView
recyclerView = view.findViewById(R.id.docList); recyclerView = (EmptyRecyclerView) view.findViewById(R.id.docList);
adapter = new DocListAdapter(); adapter = new DocListAdapter();
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
recyclerView.setLongClickable(true); recyclerView.setLongClickable(true);
recyclerView.addItemDecoration(new DividerItemDecoration(getResources().getDrawable(R.drawable.abc_list_divider_mtrl_alpha)));
// Configure the LayoutManager // Configure the LayoutManager
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
// Configure the swipe refresh layout // Configure the swipe refresh layout
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout); swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefreshLayout);
swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright, swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light, android.R.color.holo_green_light,
android.R.color.holo_orange_light, android.R.color.holo_orange_light,
@ -115,6 +122,16 @@ public class DocListFragment extends Fragment {
} }
}); });
// Add document button
ImageButton addDocumentButton = (ImageButton) view.findViewById(R.id.addDocumentButton);
addDocumentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), DocumentEditActivity.class);
startActivityForResult(intent, REQUEST_CODE_ADD_DOCUMENT);
}
});
// Grab the documents // Grab the documents
loadDocuments(view, true); loadDocuments(view, true);
@ -193,7 +210,7 @@ public class DocListFragment extends Fragment {
private void loadDocuments(final View view, final boolean reset) { private void loadDocuments(final View view, final boolean reset) {
if (view == null) return; if (view == null) return;
final View progressBar = view.findViewById(R.id.progressBar); final View progressBar = view.findViewById(R.id.progressBar);
final TextView documentsEmptyView = view.findViewById(R.id.documentsEmptyView); final TextView documentsEmptyView = (TextView) view.findViewById(R.id.documentsEmptyView);
if (reset) { if (reset) {
loading = true; loading = true;

View File

@ -1,12 +1,10 @@
package com.sismics.docs.service; package com.sismics.docs.service;
import android.app.IntentService; import android.app.IntentService;
import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder; import android.support.v4.app.NotificationCompat.Builder;
@ -31,8 +29,7 @@ import okhttp3.internal.Util;
* @author bgamard * @author bgamard
*/ */
public class FileUploadService extends IntentService { public class FileUploadService extends IntentService {
private static final String TAG = "sismicsdocs:fileupload"; private static final String TAG = "FileUploadService";
private static final String CHANNEL_ID = "FileUploadService";
private static final int UPLOAD_NOTIFICATION_ID = 1; private static final int UPLOAD_NOTIFICATION_ID = 1;
private static final int UPLOAD_NOTIFICATION_ID_DONE = 2; private static final int UPLOAD_NOTIFICATION_ID_DONE = 2;
@ -52,30 +49,18 @@ public class FileUploadService extends IntentService {
super.onCreate(); super.onCreate();
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
initChannels(); notification = new NotificationCompat.Builder(this);
notification = new NotificationCompat.Builder(this, CHANNEL_ID);
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
} }
private void initChannels() {
if (Build.VERSION.SDK_INT < 26) {
return;
}
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"File Upload", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("Used to show file upload progress");
notificationManager.createNotificationChannel(channel);
}
@Override @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
if (intent == null) { if (intent == null) {
return; return;
} }
wakeLock.acquire(60_000 * 30); // 30 minutes upload time maximum wakeLock.acquire();
try { try {
onStart(); onStart();
handleFileUpload(intent.getStringExtra(PARAM_DOCUMENT_ID), (Uri) intent.getParcelableExtra(PARAM_URI)); handleFileUpload(intent.getStringExtra(PARAM_DOCUMENT_ID), (Uri) intent.getParcelableExtra(PARAM_URI));
@ -92,7 +77,7 @@ public class FileUploadService extends IntentService {
* *
* @param documentId Document ID * @param documentId Document ID
* @param uri Data URI * @param uri Data URI
* @throws IOException e * @throws IOException
*/ */
private void handleFileUpload(final String documentId, final Uri uri) throws Exception { private void handleFileUpload(final String documentId, final Uri uri) throws Exception {
final InputStream is = getContentResolver().openInputStream(uri); final InputStream is = getContentResolver().openInputStream(uri);

View File

@ -1,47 +0,0 @@
package com.sismics.docs.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.View;
import com.sismics.docs.R;
public class ScrollingFABBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
private int toolbarHeight;
public ScrollingFABBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
this.toolbarHeight = getToolbarHeight(context);
}
@Override
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull FloatingActionButton fab, @NonNull View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull FloatingActionButton fab, @NonNull View dependency) {
if (dependency instanceof AppBarLayout) {
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
int distanceToScroll = fab.getHeight() + fabBottomMargin;
float ratio = dependency.getY() /(float) toolbarHeight;
fab.setTranslationY(- distanceToScroll * ratio);
}
return true;
}
private int getToolbarHeight(Context context) {
final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
new int[] { R.attr.actionBarSize });
int toolbarHeight = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
return toolbarHeight;
}
}

View File

@ -156,7 +156,7 @@ public class OkHttpUtil {
public static OkHttpClient buildClient(final Context context) { public static OkHttpClient buildClient(final Context context) {
// One-time header computation // One-time header computation
if (userAgent == null) { if (userAgent == null) {
userAgent = "Teedy Android " + ApplicationUtil.getVersionName(context) + "/Android " + Build.VERSION.RELEASE + "/" + Build.MODEL; userAgent = "Sismics Docs Android " + ApplicationUtil.getVersionName(context) + "/Android " + Build.VERSION.RELEASE + "/" + Build.MODEL;
} }
if (acceptLanguage == null) { if (acceptLanguage == null) {

View File

@ -39,9 +39,7 @@ public class SearchQueryBuilder {
*/ */
public SearchQueryBuilder simpleSearch(String simpleSearch) { public SearchQueryBuilder simpleSearch(String simpleSearch) {
if (isValid(simpleSearch)) { if (isValid(simpleSearch)) {
query.append(SEARCH_SEPARATOR) query.append(SEARCH_SEPARATOR).append(simpleSearch);
.append("simple:")
.append(simpleSearch);
} }
return this; return this;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -36,4 +37,17 @@
android:textSize="16sp" android:textSize="16sp"
android:layout_centerInParent="true"/> android:layout_centerInParent="true"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/addDocumentButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="20dp"
android:src="@drawable/ic_add_white_24dp"
app:fabSize="normal"/>
</RelativeLayout> </RelativeLayout>

View File

@ -29,7 +29,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="sans-serif-light" android:fontFamily="sans-serif-light"
android:textColor="?android:attr/textColorPrimary" android:textColor="#212121"
android:text="Test" android:text="Test"
android:textSize="16sp" android:textSize="16sp"
android:ellipsize="end" android:ellipsize="end"
@ -46,7 +46,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="sans-serif-light" android:fontFamily="sans-serif-light"
android:textColor="?android:attr/textColorPrimary" android:textColor="#777777"
android:text="test2" android:text="test2"
android:textSize="16sp" android:textSize="16sp"
android:maxLines="1" android:maxLines="1"
@ -69,7 +69,7 @@
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:textColor="?android:attr/textColorPrimary" android:textColor="#777777"
android:fontFamily="sans-serif-light"/> android:fontFamily="sans-serif-light"/>
</RelativeLayout> </RelativeLayout>

View File

@ -6,47 +6,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/overview_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/AppTheme"
app:layout_scrollFlags="enterAlways|scroll|snap" />
</android.support.design.widget.AppBarLayout>
<fragment <fragment
android:id="@+id/main_fragment" android:id="@+id/main_fragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
class="com.sismics.docs.fragment.DocListFragment"/> class="com.sismics.docs.fragment.DocListFragment"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/addDocumentButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="@drawable/ic_add_white_24dp"
app:layout_anchor="@id/main_fragment"
app:layout_behavior="com.sismics.docs.ui.ScrollingFABBehavior"
app:layout_anchorGravity="bottom|right|end"
app:fabSize="normal"/>
</android.support.design.widget.CoordinatorLayout>
<LinearLayout <LinearLayout
android:id="@+id/left_drawer" android:id="@+id/left_drawer"
android:layout_width="240dp" android:layout_width="240dp"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,159 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Validation -->
<string name="validate_error_email">Ungültige E-Mail</string>
<string name="validate_error_length_min">Zu kurz (min. %d)</string>
<string name="validate_error_length_max">Zu lang (max. %d)</string>
<string name="validate_error_required">Erforderlich</string>
<string name="validate_error_alphanumeric">Nur Buchstaben und Zahlen</string>
<!-- App -->
<string name="drawer_open">Navigationsleiste öffnen</string>
<string name="drawer_close">Navigationsleiste schließen</string>
<string name="login_explain"><![CDATA[Um zu beginnen, müssen Sie Teedy Server herunterladen und installieren <a href="https://github.com/sismics/docs">github.com/sismics/docs</a>, sowie die Login-Daten unten eingeben]]></string>
<string name="server">Server</string>
<string name="username">Username</string>
<string name="password">Password</string>
<string name="login">Login</string>
<string name="ok">OK</string>
<string name="cancel">Abbrechen</string>
<string name="login_fail_title">Login gescheitert</string>
<string name="login_fail">Benutzername oder Passwort falsch</string>
<string name="network_error_title">Netzwerkfehler</string>
<string name="network_error">Netzwerkfehler, überprüfen Sie die Internetverbindung und die Server-URL</string>
<string name="invalid_url_title">Ungültige URL</string>
<string name="invalid_url">Bitte überprüfen Sie die Server-URL und versuchen Sie es erneut</string>
<string name="crash_toast_text">Ein Absturz ist aufgetreten, ein Bericht wurde gesendet, um dieses Problem zu beheben</string>
<string name="created_date">Erstellungsdatum</string>
<string name="download_file">Aktuelle Datei herunterladen</string>
<string name="download_document">Herunterladen</string>
<string name="action_search">Dokumente durchsuchen</string>
<string name="all_documents">Alle Dokumente</string>
<string name="shared_documents">Geteilte Dokumente</string>
<string name="all_tags">Alle Tags</string>
<string name="no_tags">Keine Tags</string>
<string name="error_loading_tags">Fehler beim Laden von Tags</string>
<string name="no_documents">Keine Dokumente</string>
<string name="error_loading_documents">Fehler beim Laden von Dokumenten</string>
<string name="no_files">Keine Dateien</string>
<string name="error_loading_files">Fehler beim Laden von Dateien</string>
<string name="new_document">Neues Dokument</string>
<string name="share">Teilen</string>
<string name="close">Schließen</string>
<string name="add">Hinzufügen</string>
<string name="add_share_hint">Freigabename (optional)</string>
<string name="document_not_shared">Dieses Dokument wird derzeit nicht freigegeben</string>
<string name="delete_share">Diese Freigabe löschen</string>
<string name="send_share">Send this share link</string>
<string name="error_loading_shares">Fehler beim Laden von Freigaben</string>
<string name="error_adding_share">Fehler beim Hinzufügen der Freigabe</string>
<string name="share_default_name">Freigabe Link</string>
<string name="error_deleting_share">Fehler beim Löschen der Freigabe</string>
<string name="send_share_to">Freigabe senden an</string>
<string name="upload_file">Datei hinzufügen</string>
<string name="upload_from">Datei hochladen von</string>
<string name="settings">Einstellungen</string>
<string name="logout">Ausloggen</string>
<string name="version">Version</string>
<string name="build">Build</string>
<string name="pref_advanced_category">Erweiterte Einstellungen</string>
<string name="pref_about_category">Über</string>
<string name="pref_github">GitHub</string>
<string name="pref_issue">Fehler berichten</string>
<string name="pref_clear_cache_title">Cache leeren</string>
<string name="pref_clear_cache_summary">Zwischengespeicherte Dateien löschen</string>
<string name="pref_clear_cache_success">Cache wurde geleert</string>
<string name="pref_clear_history_title">Suchhistorie löschen</string>
<string name="pref_clear_history_summary">Leert die aktuellen Suchvorschläge</string>
<string name="pref_clear_history_success">Suchvorschläge wurden gelöscht</string>
<string name="pref_cache_size">Cache Größe</string>
<string name="save">Speichern</string>
<string name="edit_document">Bearbeiten</string>
<string name="error_editing_document">Netzwerkfehler, bitte versuchen Sie es erneut</string>
<string name="please_wait">Bitte warten</string>
<string name="document_editing_message">Daten werden gesendet</string>
<string name="delete_document">Löschen</string>
<string name="delete_document_title">Dokument löschen</string>
<string name="delete_document_message">Dieses Dokument und alle zugehörigen Dateien wirklich löschen?</string>
<string name="document_delete_failure">Netzwerkfehler beim Löschen des Dokuments</string>
<string name="document_deleting_message">Lösche Dokument</string>
<string name="delete_file_title">Datei löschen</string>
<string name="delete_file_message">Die aktuelle Datei wirklich löschen?</string>
<string name="file_delete_failure">Netzwerkfehler beim Löschen der Datei</string>
<string name="file_deleting_message">Lösche Datei</string>
<string name="error_reading_file">Fehler beim Lesen der Datei</string>
<string name="upload_notification_title">Teedy</string>
<string name="upload_notification_message">Neue Datei in das Dokument hochladen</string>
<string name="upload_notification_error">Fehler beim Hochladen der neuen Datei</string>
<string name="delete_file">Aktuelle Datei löschen</string>
<string name="advanced_search">Erweiterte Suche</string>
<string name="search">Suche</string>
<string name="add_tags">Tags hinzufügen</string>
<string name="creation_date">Erstellungsdatum</string>
<string name="description">Beschreibung</string>
<string name="title">Titel</string>
<string name="simple_search">Einfache Suche</string>
<string name="fulltext_search">Volltextsuche</string>
<string name="creator">Ersteller</string>
<string name="after_date">Nach Datum</string>
<string name="before_date">Vor Datum</string>
<string name="search_tags">Tags durchsuchen</string>
<string name="all_languages">Alle Sprachen</string>
<string name="toggle_informations">Informationen anzeigen</string>
<string name="who_can_access">Wer kann darauf zugreifen?</string>
<string name="comments">Kommentare</string>
<string name="no_comments">Keine Kommentare</string>
<string name="error_loading_comments">Fehler beim Laden von Kommentaren</string>
<string name="send">Senden</string>
<string name="add_comment">Kommentar hinzufügen</string>
<string name="comment_add_failure">Fehler beim Hinzufügen des Kommentars</string>
<string name="adding_comment">Füge Kommentar hinzu</string>
<string name="comment_delete">Kommentar löschen</string>
<string name="deleting_comment">Lösche Kommentar</string>
<string name="error_deleting_comment">Fehler beim Löschen des Kommentars</string>
<string name="export_pdf">PDF</string>
<string name="download">Download</string>
<string name="margin">Rand</string>
<string name="fit_image_to_page">Bild an Seite anpassen</string>
<string name="export_comments">Kommentare exportieren</string>
<string name="export_metadata">Metadaten exportieren</string>
<string name="mm">mm</string>
<string name="download_file_title">Teedy Datei Export</string>
<string name="download_document_title">Teedy Dokumentenexport</string>
<string name="download_pdf_title">Teedy PDF Export</string>
<string name="latest_activity">Letzte Aktivität</string>
<string name="activity">Aktivitäten</string>
<string name="email">E-Mail</string>
<string name="storage_quota">Speicherbegrenzung</string>
<string name="storage_display">%1$d/%2$d MB</string>
<string name="validation_code">Validierungscode</string>
<string name="shared">Geteilt</string>
<string name="language">Sprache</string>
<string name="coverage">Geltungsbereich</string>
<string name="type">Typ</string>
<string name="source">Quelle</string>
<string name="format">Format</string>
<string name="publisher">Verleger</string>
<string name="identifier">Identifikator</string>
<string name="subject">Thema</string>
<string name="rights">Rechte</string>
<string name="contributors">Mitwirkende</string>
<string name="relations">Beziehungen</string>
<!-- Audit log -->
<string name="auditlog_Acl">ACL</string>
<string name="auditlog_Comment">Kommentar</string>
<string name="auditlog_Document">Dokument</string>
<string name="auditlog_File">Datei</string>
<string name="auditlog_Group">Gruppe</string>
<string name="auditlog_Route">Workflow</string>
<string name="auditlog_RouteModel">Workflow-Muster</string>
<string name="auditlog_Tag">Tag</string>
<string name="auditlog_User">Benutzer</string>
<string name="auditlog_Webhook">Webhook</string>
<string name="auditlog_created">erstellt</string>
<string name="auditlog_updated">aktualisiert</string>
<string name="auditlog_deleted">gelöscht</string>
</resources>

View File

@ -11,7 +11,7 @@
<!-- App --> <!-- App -->
<string name="drawer_open">Ouvrir le menu de navigation</string> <string name="drawer_open">Ouvrir le menu de navigation</string>
<string name="drawer_close">Fermer le menu de navigation</string> <string name="drawer_close">Fermer le menu de navigation</string>
<string name="login_explain"><![CDATA[Pour commencer, vous devez télécharger et installer le serveur Teedy sur <a href="https://github.com/sismics/docs">github.com/sismics/docs</a> et entrer son URL ci-dessous]]></string> <string name="login_explain"><![CDATA[Pour commencer, vous devez télécharger et installer le serveur Sismics Docs sur <a href="https://github.com/sismics/docs">github.com/sismics/docs</a> et entrer son URL ci-dessous]]></string>
<string name="server">Serveur</string> <string name="server">Serveur</string>
<string name="username">Nom d\'utilisateur</string> <string name="username">Nom d\'utilisateur</string>
<string name="password">Mot de passe</string> <string name="password">Mot de passe</string>
@ -83,7 +83,7 @@
<string name="file_delete_failure">Erreur réseau lors de la suppression du fichier</string> <string name="file_delete_failure">Erreur réseau lors de la suppression du fichier</string>
<string name="file_deleting_message">Suppression du fichier</string> <string name="file_deleting_message">Suppression du fichier</string>
<string name="error_reading_file">Erreur lors de la lecture du fichier</string> <string name="error_reading_file">Erreur lors de la lecture du fichier</string>
<string name="upload_notification_title">Teedy</string> <string name="upload_notification_title">Sismics Docs</string>
<string name="upload_notification_message">Envoi du nouveau fichier</string> <string name="upload_notification_message">Envoi du nouveau fichier</string>
<string name="upload_notification_error">Erreur lors de l\'envoi du nouveau fichier</string> <string name="upload_notification_error">Erreur lors de l\'envoi du nouveau fichier</string>
<string name="delete_file">Supprimer ce fichier</string> <string name="delete_file">Supprimer ce fichier</string>
@ -119,9 +119,9 @@
<string name="export_comments">Exporter les commentaires</string> <string name="export_comments">Exporter les commentaires</string>
<string name="export_metadata">Exporter les métadonnées</string> <string name="export_metadata">Exporter les métadonnées</string>
<string name="mm">mm</string> <string name="mm">mm</string>
<string name="download_file_title">Export de fichier Teedy</string> <string name="download_file_title">Export de fichier Sismics Docs</string>
<string name="download_document_title">Export de document Teedy</string> <string name="download_document_title">Export de document Sismics Docs</string>
<string name="download_pdf_title">Export PDF Teedy</string> <string name="download_pdf_title">Export PDF Sismics Docs</string>
<string name="latest_activity">Activité récente</string> <string name="latest_activity">Activité récente</string>
<string name="activity">Activité</string> <string name="activity">Activité</string>
<string name="email">E-mail</string> <string name="email">E-mail</string>
@ -141,19 +141,4 @@
<string name="contributors">Contributeurs</string> <string name="contributors">Contributeurs</string>
<string name="relations">Relations</string> <string name="relations">Relations</string>
<!-- Audit log -->
<string name="auditlog_Acl">ACL</string>
<string name="auditlog_Comment">Commentaire</string>
<string name="auditlog_Document">Document</string>
<string name="auditlog_File">Fichier</string>
<string name="auditlog_Group">Groupe</string>
<string name="auditlog_Route">Workflow</string>
<string name="auditlog_RouteModel">Modèle de workflow</string>
<string name="auditlog_Tag">Tag</string>
<string name="auditlog_User">Utilisateur</string>
<string name="auditlog_Webhook">Webhook</string>
<string name="auditlog_created">créé</string>
<string name="auditlog_updated">mis à jour</string>
<string name="auditlog_deleted">supprimé</string>
</resources> </resources>

View File

@ -1,164 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Validation -->
<string name="validate_error_email">Nieprawidłowy email</string>
<string name="validate_error_length_min">Za krótki (min. %d)</string>
<string name="validate_error_length_max">Za długi (max. %d)</string>
<string name="validate_error_required">Wymagany</string>
<string name="validate_error_alphanumeric">Tylko litery i cyfry</string>
<!-- App -->
<string name="app_name" translatable="false">Teedy</string>
<string name="drawer_open">Otwórz szufladę nawigacji</string>
<string name="drawer_close">Zamknij szufladę nawigacji</string>
<string name="login_explain"><![CDATA[Aby rozpocząć, musisz pobrać i zainstalować serwer Teedy na <a href="https://github.com/sismics/docs">github.com/sismics/docs</a> i poniżej wprowadzić adres]]></string>
<string name="server">Serwer</string>
<string name="username">Użytkownik</string>
<string name="password">Hasło</string>
<string name="login">Zaloguj</string>
<string name="ok">OK</string>
<string name="cancel">Anuluj</string>
<string name="login_fail_title">Błąd logowania</string>
<string name="login_fail">Nieprawidłowa nazwa użytkownika lub hasło</string>
<string name="network_error_title">Błąd sieci</string>
<string name="network_error">Błąd sieci, sprawdź połączenie z interneterm oraz adres URL serwera</string>
<string name="invalid_url_title">Nieprawidłowy adres URL</string>
<string name="invalid_url">Sprawdź adres URL serwera i spróbuj ponownie</string>
<string name="crash_toast_text">Wystąpiła awaria, wysłano raport w celu rozwiązania tego problemu</string>
<string name="created_date">Data utworzenia</string>
<string name="download_file">Pobierz bieżący plik</string>
<string name="download_document">Pobierz</string>
<string name="action_search">Znadź dokumenty</string>
<string name="all_documents">Wszystkie dokumenty</string>
<string name="shared_documents">Udostępnione dokumenty</string>
<string name="all_tags">Wszystkie etykiety</string>
<string name="no_tags">Brak etykiet</string>
<string name="error_loading_tags">Błąd ładowania etykiet</string>
<string name="no_documents">Brak dokumentów</string>
<string name="error_loading_documents">Błąd ładowania dokumentów</string>
<string name="no_files">Brak plików</string>
<string name="error_loading_files">Błąd ładowania plików</string>
<string name="new_document">Nowy dokument</string>
<string name="share">Udostępnij</string>
<string name="close">Zamknij</string>
<string name="add">Dodaj</string>
<string name="add_share_hint">Nazwa udostępnienia (opcjonalnie)</string>
<string name="document_not_shared">Ten dokument nie jest obecnie udostępniony</string>
<string name="delete_share">Usuń udostępnienie</string>
<string name="send_share">Wyślij link udostępnienia</string>
<string name="error_loading_shares">Błąd ładowania udostępnień</string>
<string name="error_adding_share">Błąd dodawania udostępnienia</string>
<string name="share_default_name">Udostępnij link</string>
<string name="error_deleting_share">Błąd usuwania udostępnienia</string>
<string name="send_share_to">Wyślij link udostępnienia do</string>
<string name="upload_file">dodaj plik</string>
<string name="upload_from">Przeslij plik z</string>
<string name="settings">ustawienia</string>
<string name="logout">Wyloguj</string>
<string name="version">Wersja</string>
<string name="build">Kompilacja</string>
<string name="pref_advanced_category">Ustawienia zaawansowane</string>
<string name="pref_about_category">O programie</string>
<string name="pref_github">GitHub</string>
<string name="pref_issue">Zgłoś błąd</string>
<string name="pref_clear_cache_title">Wyczyść cache</string>
<string name="pref_clear_cache_summary">Wyczyść podręczne pliki</string>
<string name="pref_clear_cache_success">Cache wyczyszczony</string>
<string name="pref_clear_history_title">Wyczyść historię wyszukiwania</string>
<string name="pref_clear_history_summary">Opróżnij ostatnie sugestie wyszukiwania</string>
<string name="pref_clear_history_success">Historia wyszukiwania wyczyszczona</string>
<string name="pref_cache_size">Rozmiar cache</string>
<string name="language_french" translatable="false">Francuski</string>
<string name="language_english" translatable="false">Angielski</string>
<string name="language_german" translatable="false">Niemiecki</string>
<string name="language_polish" translatable="false">Polski</string>
<string name="save">Zapisz</string>
<string name="edit_document">Edytuj</string>
<string name="error_editing_document">Błąd sieci, spróbuj ponownie</string>
<string name="please_wait">Proszę czekać</string>
<string name="document_editing_message">Wysyłam twoje dane</string>
<string name="delete_document">Usuń</string>
<string name="delete_document_title">Usuń dokument</string>
<string name="delete_document_message">Naprawdę chcesz usunąć dokument i powiązane z nim pliki?</string>
<string name="document_delete_failure">Błąd sieci w czasie usuwania tego dokumentu</string>
<string name="document_deleting_message">Usuwanie dokumentu</string>
<string name="delete_file_title">Usuń plik</string>
<string name="delete_file_message">Naprawdę chcesz usunąć ten plik?</string>
<string name="file_delete_failure">Błąd sieci w czasie usuwania bieżącego pliku</string>
<string name="file_deleting_message">Usuwanie pliku</string>
<string name="error_reading_file">Błąd podczas odczytu pliku</string>
<string name="upload_notification_title">Teedy</string>
<string name="upload_notification_message">Przesyłanie nowego pliku do dokumentu</string>
<string name="upload_notification_error">Błąd przsyłania nowego pliku</string>
<string name="delete_file">Usuń bieżący plik</string>
<string name="advanced_search">Zaawansowane wyszukiwanie</string>
<string name="search">Znajdź</string>
<string name="add_tags">Dodaj eytkiety</string>
<string name="creation_date">Data utworzenia</string>
<string name="description">Opis</string>
<string name="title">Tytuł</string>
<string name="simple_search">Proste wyszukiwanie</string>
<string name="fulltext_search">Wyszukiwanie pełnotekstowe</string>
<string name="creator">Autor</string>
<string name="after_date">Po dacie</string>
<string name="before_date">Przed datą</string>
<string name="search_tags">Znajdź etykiety</string>
<string name="all_languages">Wszystkie języki</string>
<string name="toggle_informations">Przełącz informacje</string>
<string name="who_can_access">Kto ma dostęp</string>
<string name="comments">Komentarze</string>
<string name="no_comments">Brak komentarzy</string>
<string name="error_loading_comments">Błąd ładowania komentarzy</string>
<string name="send">Wyślij</string>
<string name="add_comment">Dodaj komentarz</string>
<string name="comment_add_failure">Błąd dodawania komentarza</string>
<string name="adding_comment">Dodawanie komentarza</string>
<string name="comment_delete">Usuń komentarz</string>
<string name="deleting_comment">Usuwanie komentarza</string>
<string name="error_deleting_comment">Błąd usuwania komentarza</string>
<string name="export_pdf">PDF</string>
<string name="download">Pobierz</string>
<string name="margin">Margines</string>
<string name="fit_image_to_page">Dostosuj obraz do strony</string>
<string name="export_comments">Eksport komentarzy</string>
<string name="export_metadata">Eksport metadanych</string>
<string name="mm">mm</string>
<string name="download_file_title">Eksport plików Teedy</string>
<string name="download_document_title">Eksport dokumentu Teedy</string>
<string name="download_pdf_title">Eksport Teedy jako PDF</string>
<string name="latest_activity">Ostatnie aktywności</string>
<string name="activity">Aktywności</string>
<string name="email">E-mail</string>
<string name="storage_quota">Limit magazynu</string>
<string name="storage_display">%1$d/%2$d MB</string>
<string name="validation_code">Kod weryfikujący</string>
<string name="shared">Udostępnienie</string>
<string name="language">Język</string>
<string name="coverage">Zakres</string>
<string name="type">Rodzaj</string>
<string name="source">Źródło</string>
<string name="format">Format</string>
<string name="publisher">Udostępniający</string>
<string name="identifier">Identifikator</string>
<string name="subject">temat</string>
<string name="rights">Prawa</string>
<string name="contributors">Współtwórcy</string>
<string name="relations">Powiązania</string>
<!-- Audit log -->
<string name="auditlog_Acl">ACL</string>
<string name="auditlog_Comment">Komentarz</string>
<string name="auditlog_Document">Dokument</string>
<string name="auditlog_File">Plik</string>
<string name="auditlog_Group">Grupa</string>
<string name="auditlog_Route">Przepływ</string>
<string name="auditlog_RouteModel">Model przepływu</string>
<string name="auditlog_Tag">Etykieta</string>
<string name="auditlog_User">Użytkownik</string>
<string name="auditlog_Webhook">Webhook</string>
<string name="auditlog_created">utworzony</string>
<string name="auditlog_updated">zaktualizowany</string>
<string name="auditlog_deleted">usunięty</string>
</resources>

View File

@ -9,10 +9,10 @@
<string name="validate_error_alphanumeric">Only letters and numbers</string> <string name="validate_error_alphanumeric">Only letters and numbers</string>
<!-- App --> <!-- App -->
<string name="app_name" translatable="false">Teedy</string> <string name="app_name" translatable="false">Sismics Docs</string>
<string name="drawer_open">Open navigation drawer</string> <string name="drawer_open">Open navigation drawer</string>
<string name="drawer_close">Close navigation drawer</string> <string name="drawer_close">Close navigation drawer</string>
<string name="login_explain"><![CDATA[To start, you must download and install Teedy Server on <a href="https://github.com/sismics/docs">github.com/sismics/docs</a> and enter its below]]></string> <string name="login_explain"><![CDATA[To start, you must download and install Sismics Docs Server on <a href="https://github.com/sismics/docs">github.com/sismics/docs</a> and enter its below]]></string>
<string name="server">Server</string> <string name="server">Server</string>
<string name="username">Username</string> <string name="username">Username</string>
<string name="password">Password</string> <string name="password">Password</string>
@ -71,8 +71,6 @@
<string name="pref_cache_size">Cache size</string> <string name="pref_cache_size">Cache size</string>
<string name="language_french" translatable="false">Français</string> <string name="language_french" translatable="false">Français</string>
<string name="language_english" translatable="false">English</string> <string name="language_english" translatable="false">English</string>
<string name="language_german" translatable="false">Deutsch</string>
<string name="language_polish" translatable="false">Polski</string>
<string name="save">Save</string> <string name="save">Save</string>
<string name="edit_document">Edit</string> <string name="edit_document">Edit</string>
<string name="error_editing_document">Network error, please try again</string> <string name="error_editing_document">Network error, please try again</string>
@ -88,7 +86,7 @@
<string name="file_delete_failure">Network error while deleting the current file</string> <string name="file_delete_failure">Network error while deleting the current file</string>
<string name="file_deleting_message">Deleting file</string> <string name="file_deleting_message">Deleting file</string>
<string name="error_reading_file">Error while reading the file</string> <string name="error_reading_file">Error while reading the file</string>
<string name="upload_notification_title">Teedy</string> <string name="upload_notification_title">Sismics Docs</string>
<string name="upload_notification_message">Uploading the new file to the document</string> <string name="upload_notification_message">Uploading the new file to the document</string>
<string name="upload_notification_error">Error uploading the new file</string> <string name="upload_notification_error">Error uploading the new file</string>
<string name="delete_file">Delete current file</string> <string name="delete_file">Delete current file</string>
@ -124,9 +122,9 @@
<string name="export_comments">Export comments</string> <string name="export_comments">Export comments</string>
<string name="export_metadata">Export metadata</string> <string name="export_metadata">Export metadata</string>
<string name="mm">mm</string> <string name="mm">mm</string>
<string name="download_file_title">Teedy file export</string> <string name="download_file_title">Sismics Docs file export</string>
<string name="download_document_title">Teedy document export</string> <string name="download_document_title">Sismics Docs document export</string>
<string name="download_pdf_title">Teedy PDF export</string> <string name="download_pdf_title">Sismics Docs PDF export</string>
<string name="latest_activity">Latest activity</string> <string name="latest_activity">Latest activity</string>
<string name="activity">Activity</string> <string name="activity">Activity</string>
<string name="email">E-mail</string> <string name="email">E-mail</string>
@ -146,19 +144,4 @@
<string name="contributors">Contributors</string> <string name="contributors">Contributors</string>
<string name="relations">Relations</string> <string name="relations">Relations</string>
<!-- Audit log -->
<string name="auditlog_Acl">ACL</string>
<string name="auditlog_Comment">Comment</string>
<string name="auditlog_Document">Document</string>
<string name="auditlog_File">File</string>
<string name="auditlog_Group">Group</string>
<string name="auditlog_Route">Workflow</string>
<string name="auditlog_RouteModel">Workflow model</string>
<string name="auditlog_Tag">Tag</string>
<string name="auditlog_User">User</string>
<string name="auditlog_Webhook">Webhook</string>
<string name="auditlog_created">created</string>
<string name="auditlog_updated">updated</string>
<string name="auditlog_deleted">deleted</string>
</resources> </resources>

View File

@ -1,20 +1,12 @@
<resources> <resources>
<style name="AppTheme" parent="Theme.AppCompat.DayNight"> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
</style> </style>
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar"> <style name="AppThemeDark" parent="Theme.AppCompat.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>

View File

@ -1,6 +1,6 @@
#Tue May 07 11:49:13 CEST 2019 #Tue Nov 14 23:55:56 CET 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

View File

@ -5,8 +5,8 @@
<parent> <parent>
<groupId>com.sismics.docs</groupId> <groupId>com.sismics.docs</groupId>
<artifactId>docs-parent</artifactId> <artifactId>docs-parent</artifactId>
<version>1.12-SNAPSHOT</version> <version>1.5</version>
<relativePath>../pom.xml</relativePath> <relativePath>..</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -17,10 +17,20 @@
<dependencies> <dependencies>
<!-- Persistence layer dependencies --> <!-- Persistence layer dependencies -->
<dependency> <dependency>
<groupId>org.hibernate.orm</groupId> <groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId> <artifactId>hibernate-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
</dependency>
<!-- Other external dependencies --> <!-- Other external dependencies -->
<dependency> <dependency>
<groupId>joda-time</groupId> <groupId>joda-time</groupId>
@ -38,8 +48,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>commons-lang</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@ -53,8 +63,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.json</groupId> <groupId>org.glassfish</groupId>
<artifactId>jakarta.json-api</artifactId> <artifactId>javax.json</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@ -83,8 +93,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>at.favre.lib</groupId> <groupId>org.mindrot</groupId>
<artifactId>bcrypt</artifactId> <artifactId>jbcrypt</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@ -103,28 +113,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.lucene</groupId> <groupId>com.sun.mail</groupId>
<artifactId>lucene-suggest</artifactId> <artifactId>javax.mail</artifactId>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.apache.directory.api</groupId>
<artifactId>api-ldap-client-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.directory.api</groupId>
<artifactId>api-ldap-codec-standalone</artifactId>
</dependency> </dependency>
<!-- Only there to read old index and rebuild them --> <!-- Only there to read old index and rebuild them -->
@ -150,39 +140,33 @@
<dependency> <dependency>
<groupId>fr.opensagres.xdocreport</groupId> <groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.odfdom.converter.pdf</artifactId> <artifactId>org.odftoolkit.odfdom.converter.pdf</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>fr.opensagres.xdocreport</groupId> <groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId> <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency> </dependency>
<!-- ImageIO plugins --> <!-- ImageIO plugins -->
<dependency>
<groupId>com.levigo.jbig2</groupId>
<artifactId>levigo-jbig2-imageio</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId> <artifactId>imageio-jpeg</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.github.jai-imageio</groupId> <groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-jpeg2000</artifactId> <artifactId>jai-imageio-core</artifactId>
</dependency>
<dependency>
<groupId>com.levigo.jbig2</groupId>
<artifactId>levigo-jbig2-imageio</artifactId>
</dependency>
<!-- Only for connecting to PostgreSQL database -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency> </dependency>
<!-- Test dependencies --> <!-- Test dependencies -->
@ -225,6 +209,20 @@
<profile> <profile>
<id>prod</id> <id>prod</id>
</profile> </profile>
<!-- Demo profile -->
<profile>
<id>demo</id>
<build>
<resources>
<resource>
<directory>src/demo/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
</profiles> </profiles>
<build> <build>

View File

@ -1,23 +0,0 @@
package com.sismics.docs.core.constant;
/**
* Action types.
*
* @author bgamard
*/
public enum ActionType {
/**
* Add a tag.
*/
ADD_TAG,
/**
* Remove a tag.
*/
REMOVE_TAG,
/**
* Process files.
*/
PROCESS_FILES
}

View File

@ -20,11 +20,6 @@ public enum ConfigType {
*/ */
GUEST_LOGIN, GUEST_LOGIN,
/**
* OCR enabled.
*/
OCR_ENABLED,
/** /**
* Default language. * Default language.
*/ */
@ -45,25 +40,7 @@ public enum ConfigType {
INBOX_ENABLED, INBOX_ENABLED,
INBOX_HOSTNAME, INBOX_HOSTNAME,
INBOX_PORT, INBOX_PORT,
INBOX_STARTTLS,
INBOX_USERNAME, INBOX_USERNAME,
INBOX_PASSWORD, INBOX_PASSWORD,
INBOX_FOLDER, INBOX_TAG
INBOX_TAG,
INBOX_AUTOMATIC_TAGS,
INBOX_DELETE_IMPORTED,
/**
* LDAP connection.
*/
LDAP_ENABLED,
LDAP_HOST,
LDAP_PORT,
LDAP_USESSL,
LDAP_ADMIN_DN,
LDAP_ADMIN_PASSWORD,
LDAP_BASE_DN,
LDAP_FILTER,
LDAP_DEFAULT_EMAIL,
LDAP_DEFAULT_STORAGE
} }

View File

@ -18,17 +18,17 @@ public class Constants {
/** /**
* Administrator's default password ("admin"). * Administrator's default password ("admin").
*/ */
public static final String DEFAULT_ADMIN_PASSWORD = "$2y$10$xg0EEKVUehutDI1m6qQhVeFz7SMQMl1jQzjf2KkVsR2c7aV2vyyjK"; public static final String DEFAULT_ADMIN_PASSWORD = "$2a$05$6Ny3TjrW3aVAL1or2SlcR.fhuDgPKp5jp.P9fBXwVNePgeLqb4i3C";
/** /**
* Administrator's default email. * RAM Lucene directory storage.
*/ */
public static final String DEFAULT_ADMIN_EMAIL = "admin@localhost"; public static final String LUCENE_DIRECTORY_STORAGE_RAM = "RAM";
/** /**
* Bcrypt default work factor * File Lucene directory storage.
*/ */
public static final int DEFAULT_BCRYPT_WORK = 10; public static final String LUCENE_DIRECTORY_STORAGE_FILE = "FILE";
/** /**
* Guest user ID. * Guest user ID.
@ -43,7 +43,7 @@ public class Constants {
/** /**
* Supported document languages. * Supported document languages.
*/ */
public static final List<String> SUPPORTED_LANGUAGES = Lists.newArrayList("eng", "fra", "ita", "deu", "spa", "por", "pol", "rus", "ukr", "ara", "hin", "chi_sim", "chi_tra", "jpn", "tha", "kor", "nld", "tur", "heb", "hun", "fin", "swe", "lav", "dan", "nor", "vie", "ces", "sqi"); public static final List<String> SUPPORTED_LANGUAGES = Lists.newArrayList("eng", "fra", "ita", "deu", "spa", "por", "pol", "rus", "ukr", "ara", "hin", "chi_sim", "chi_tra", "jpn", "tha", "kor");
/** /**
* Base URL environment variable. * Base URL environment variable.
@ -73,16 +73,6 @@ public class Constants {
*/ */
public static final String ADMIN_PASSWORD_INIT_ENV = "DOCS_ADMIN_PASSWORD_INIT"; public static final String ADMIN_PASSWORD_INIT_ENV = "DOCS_ADMIN_PASSWORD_INIT";
/**
* Initial admin password environment variable.
*/
public static final String ADMIN_EMAIL_INIT_ENV = "DOCS_ADMIN_EMAIL_INIT";
/**
* Work factor to be used by Bcrypt
*/
public static final String BCRYPT_WORK_ENV = "DOCS_BCRYPT_WORK";
/** /**
* Expiration time of the password recovery in hours. * Expiration time of the password recovery in hours.
*/ */
@ -97,9 +87,4 @@ public class Constants {
* Email template for route step validate. * Email template for route step validate.
*/ */
public static final String EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE = "route_step_validate"; public static final String EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE = "route_step_validate";
/**
* mm per inch.
*/
public static float MM_PER_INCH = 1 / (10 * 2.54f) * 72f;
} }

View File

@ -1,14 +0,0 @@
package com.sismics.docs.core.constant;
/**
* Metadata type.
*
* @author bgamard
*/
public enum MetadataType {
STRING,
INTEGER,
FLOAT,
DATE,
BOOLEAN
}

View File

@ -1,15 +0,0 @@
package com.sismics.docs.core.constant;
/**
* Webhook events.
*
* @author bgamard
*/
public enum WebhookEvent {
DOCUMENT_CREATED,
DOCUMENT_UPDATED,
DOCUMENT_DELETED,
FILE_CREATED,
FILE_UPDATED,
FILE_DELETED
}

View File

@ -1,89 +0,0 @@
package com.sismics.docs.core.dao;
import com.sismics.docs.core.constant.MetadataType;
import com.sismics.docs.core.dao.dto.DocumentMetadataDto;
import com.sismics.docs.core.model.jpa.DocumentMetadata;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Document metadata DAO.
*
* @author bgamard
*/
public class DocumentMetadataDao {
/**
* Creates a new document metadata.
*
* @param documentMetadata Document metadata
* @return New ID
*/
public String create(DocumentMetadata documentMetadata) {
// Create the UUID
documentMetadata.setId(UUID.randomUUID().toString());
// Create the document metadata
EntityManager em = ThreadLocalContext.get().getEntityManager();
em.persist(documentMetadata);
return documentMetadata.getId();
}
/**
* Updates a document metadata.
*
* @param documentMetadata Document metadata
* @return Updated document metadata
*/
public DocumentMetadata update(DocumentMetadata documentMetadata) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the document metadata
Query q = em.createQuery("select u from DocumentMetadata u where u.id = :id");
q.setParameter("id", documentMetadata.getId());
DocumentMetadata documentMetadataDb = (DocumentMetadata) q.getSingleResult();
// Update the document metadata
documentMetadataDb.setValue(documentMetadata.getValue());
return documentMetadata;
}
/**
* Returns the list of all metadata values on a document.
*
* @param documentId Document ID
* @return List of metadata
*/
@SuppressWarnings("unchecked")
public List<DocumentMetadataDto> getByDocumentId(String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select dm.DME_ID_C, dm.DME_IDDOCUMENT_C, dm.DME_IDMETADATA_C, dm.DME_VALUE_C, m.MET_TYPE_C");
sb.append(" from T_DOCUMENT_METADATA dm, T_METADATA m ");
sb.append(" where dm.DME_IDMETADATA_C = m.MET_ID_C and dm.DME_IDDOCUMENT_C = :documentId and m.MET_DELETEDATE_D is null");
// Perform the search
Query q = em.createNativeQuery(sb.toString());
q.setParameter("documentId", documentId);
List<Object[]> l = q.getResultList();
// Assemble results
List<DocumentMetadataDto> dtoList = new ArrayList<>();
for (Object[] o : l) {
int i = 0;
DocumentMetadataDto dto = new DocumentMetadataDto();
dto.setId((String) o[i++]);
dto.setDocumentId((String) o[i++]);
dto.setMetadataId((String) o[i++]);
dto.setValue((String) o[i++]);
dto.setType(MetadataType.valueOf((String) o[i]));
dtoList.add(dto);
}
return dtoList;
}
}

View File

@ -1,257 +0,0 @@
package com.sismics.docs.core.dao;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.model.jpa.File;
import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* File DAO.
*
* @author bgamard
*/
public class FileDao {
/**
* Creates a new file.
*
* @param file File
* @param userId User ID
* @return New ID
*/
public String create(File file, String userId) {
// Create the UUID
file.setId(UUID.randomUUID().toString());
// Create the file
EntityManager em = ThreadLocalContext.get().getEntityManager();
file.setCreateDate(new Date());
em.persist(file);
// Create audit log
AuditLogUtil.create(file, AuditLogType.CREATE, userId);
return file.getId();
}
/**
* Returns the list of all files.
*
* @param offset Offset
* @param limit Limit
* @return List of files
*/
public List<File> findAll(int offset, int limit) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.deleteDate is null", File.class);
q.setFirstResult(offset);
q.setMaxResults(limit);
return q.getResultList();
}
/**
* Returns the list of all files from a user.
*
* @param userId User ID
* @return List of files
*/
public List<File> findByUserId(String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.userId = :userId and f.deleteDate is null", File.class);
q.setParameter("userId", userId);
return q.getResultList();
}
/**
* Returns a list of active files.
*
* @param ids Files IDs
* @return List of files
*/
public List<File> getFiles(List<String> ids) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.id in :ids and f.deleteDate is null", File.class);
q.setParameter("ids", ids);
return q.getResultList();
}
/**
* Returns an active file or null.
*
* @param id File ID
* @return File
*/
public File getFile(String id) {
List<File> files = getFiles(List.of(id));
if (files.isEmpty()) {
return null;
} else {
return files.get(0);
}
}
/**
* Returns an active file.
*
* @param id File ID
* @param userId User ID
* @return File
*/
public File getFile(String id, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.id = :id and f.userId = :userId and f.deleteDate is null", File.class);
q.setParameter("id", id);
q.setParameter("userId", userId);
try {
return q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Deletes a file.
*
* @param id File ID
* @param userId User ID
*/
public void delete(String id, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the file
TypedQuery<File> q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null", File.class);
q.setParameter("id", id);
File fileDb = q.getSingleResult();
// Delete the file
Date dateNow = new Date();
fileDb.setDeleteDate(dateNow);
// Create audit log
AuditLogUtil.create(fileDb, AuditLogType.DELETE, userId);
}
/**
* Update a file.
*
* @param file File to update
* @return Updated file
*/
public File update(File file) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the file
TypedQuery<File> q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null", File.class);
q.setParameter("id", file.getId());
File fileDb = q.getSingleResult();
// Update the file
fileDb.setDocumentId(file.getDocumentId());
fileDb.setName(file.getName());
fileDb.setContent(file.getContent());
fileDb.setOrder(file.getOrder());
fileDb.setMimeType(file.getMimeType());
fileDb.setVersionId(file.getVersionId());
fileDb.setLatestVersion(file.isLatestVersion());
fileDb.setSize(file.getSize());
return file;
}
/**
* Gets a file by its ID.
*
* @param id File ID
* @return File
*/
public File getActiveById(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null", File.class);
q.setParameter("id", id);
try {
return q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Get files by document ID or all orphan files of a user.
*
* @param userId User ID
* @param documentId Document ID
* @return List of files
*/
public List<File> getByDocumentId(String userId, String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
if (documentId == null) {
TypedQuery<File> q = em.createQuery("select f from File f where f.documentId is null and f.deleteDate is null and f.latestVersion = true and f.userId = :userId order by f.createDate asc", File.class);
q.setParameter("userId", userId);
return q.getResultList();
} else {
return getByDocumentsIds(Collections.singleton(documentId));
}
}
/**
* Get files by documents IDs.
*
* @param documentIds Documents IDs
* @return List of files
*/
public List<File> getByDocumentsIds(Iterable<String> documentIds) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.documentId in :documentIds and f.latestVersion = true and f.deleteDate is null order by f.order asc", File.class);
q.setParameter("documentIds", documentIds);
return q.getResultList();
}
/**
* Get files count by documents IDs.
*
* @param documentIds Documents IDs
* @return the number of files per document id
*/
public Map<String, Long> countByDocumentsIds(Iterable<String> documentIds) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f.documentId, count(*) from File f where f.documentId in :documentIds and f.latestVersion = true and f.deleteDate is null group by (f.documentId)");
q.setParameter("documentIds", documentIds);
Map<String, Long> result = new HashMap<>();
q.getResultList().forEach(o -> {
Object[] resultLine = (Object[]) o;
result.put((String) resultLine[0], (Long) resultLine[1]);
});
return result;
}
/**
* Get all files from a version.
*
* @param versionId Version ID
* @return List of files
*/
public List<File> getByVersionId(String versionId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.versionId = :versionId and f.deleteDate is null order by f.order asc", File.class);
q.setParameter("versionId", versionId);
return q.getResultList();
}
public List<File> getFilesWithUnknownSize(int limit) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<File> q = em.createQuery("select f from File f where f.size = :size and f.deleteDate is null order by f.order asc", File.class);
q.setParameter("size", File.UNKNOWN_SIZE);
q.setMaxResults(limit);
return q.getResultList();
}
}

View File

@ -1,146 +0,0 @@
package com.sismics.docs.core.dao;
import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.constant.MetadataType;
import com.sismics.docs.core.dao.criteria.MetadataCriteria;
import com.sismics.docs.core.dao.dto.MetadataDto;
import com.sismics.docs.core.model.jpa.Metadata;
import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Query;
import java.util.*;
/**
* Metadata DAO.
*
* @author bgamard
*/
public class MetadataDao {
/**
* Creates a new metdata.
*
* @param metadata Metadata
* @param userId User ID
* @return New ID
*/
public String create(Metadata metadata, String userId) {
// Create the UUID
metadata.setId(UUID.randomUUID().toString());
// Create the metadata
EntityManager em = ThreadLocalContext.get().getEntityManager();
em.persist(metadata);
// Create audit log
AuditLogUtil.create(metadata, AuditLogType.CREATE, userId);
return metadata.getId();
}
/**
* Update a metadata.
*
* @param metadata Metadata to update
* @param userId User ID
* @return Updated metadata
*/
public Metadata update(Metadata metadata, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the metadata
Query q = em.createQuery("select r from Metadata r where r.id = :id and r.deleteDate is null");
q.setParameter("id", metadata.getId());
Metadata metadataDb = (Metadata) q.getSingleResult();
// Update the metadata
metadataDb.setName(metadata.getName());
// Create audit log
AuditLogUtil.create(metadataDb, AuditLogType.UPDATE, userId);
return metadataDb;
}
/**
* Gets an active metadata by its ID.
*
* @param id Metadata ID
* @return Metadata
*/
public Metadata getActiveById(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
try {
Query q = em.createQuery("select r from Metadata r where r.id = :id and r.deleteDate is null");
q.setParameter("id", id);
return (Metadata) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Deletes a metadata.
*
* @param id Metadata ID
* @param userId User ID
*/
public void delete(String id, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the metadata
Query q = em.createQuery("select r from Metadata r where r.id = :id and r.deleteDate is null");
q.setParameter("id", id);
Metadata metadataDb = (Metadata) q.getSingleResult();
// Delete the metadata
Date dateNow = new Date();
metadataDb.setDeleteDate(dateNow);
// Create audit log
AuditLogUtil.create(metadataDb, AuditLogType.DELETE, userId);
}
/**
* Returns the list of all metadata.
*
* @param criteria Search criteria
* @param sortCriteria Sort criteria
* @return List of metadata
*/
public List<MetadataDto> findByCriteria(MetadataCriteria criteria, SortCriteria sortCriteria) {
Map<String, Object> parameterMap = new HashMap<>();
List<String> criteriaList = new ArrayList<>();
StringBuilder sb = new StringBuilder("select m.MET_ID_C c0, m.MET_NAME_C c1, m.MET_TYPE_C c2");
sb.append(" from T_METADATA m ");
criteriaList.add("m.MET_DELETEDATE_D is null");
sb.append(" where ");
sb.append(Joiner.on(" and ").join(criteriaList));
// Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);
@SuppressWarnings("unchecked")
List<Object[]> l = QueryUtil.getNativeQuery(queryParam).getResultList();
// Assemble results
List<MetadataDto> dtoList = new ArrayList<>();
for (Object[] o : l) {
int i = 0;
MetadataDto dto = new MetadataDto();
dto.setId((String) o[i++]);
dto.setName((String) o[i++]);
dto.setType(MetadataType.valueOf((String) o[i]));
dtoList.add(dto);
}
return dtoList;
}
}

View File

@ -1,121 +0,0 @@
package com.sismics.docs.core.dao;
import com.google.common.base.Joiner;
import com.sismics.docs.core.dao.criteria.WebhookCriteria;
import com.sismics.docs.core.dao.dto.WebhookDto;
import com.sismics.docs.core.model.jpa.Webhook;
import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Query;
import java.sql.Timestamp;
import java.util.*;
/**
* Webhook DAO.
*
* @author bgamard
*/
public class WebhookDao {
/**
* Returns the list of all webhooks.
*
* @param criteria Search criteria
* @param sortCriteria Sort criteria
* @return List of webhooks
*/
public List<WebhookDto> findByCriteria(WebhookCriteria criteria, SortCriteria sortCriteria) {
Map<String, Object> parameterMap = new HashMap<>();
List<String> criteriaList = new ArrayList<>();
StringBuilder sb = new StringBuilder("select w.WHK_ID_C as c0, w.WHK_EVENT_C as c1, w.WHK_URL_C as c2, w.WHK_CREATEDATE_D as c3 ");
sb.append(" from T_WEBHOOK w ");
// Add search criterias
if (criteria.getEvent() != null) {
criteriaList.add("w.WHK_EVENT_C = :event");
parameterMap.put("event", criteria.getEvent().name());
}
criteriaList.add("w.WHK_DELETEDATE_D is null");
sb.append(" where ");
sb.append(Joiner.on(" and ").join(criteriaList));
// Perform the search
QueryParam queryParam = QueryUtil.getSortedQueryParam(new QueryParam(sb.toString(), parameterMap), sortCriteria);
@SuppressWarnings("unchecked")
List<Object[]> l = QueryUtil.getNativeQuery(queryParam).getResultList();
// Assemble results
List<WebhookDto> webhookDtoList = new ArrayList<>();
for (Object[] o : l) {
int i = 0;
WebhookDto webhookDto = new WebhookDto()
.setId((String) o[i++])
.setEvent((String) o[i++])
.setUrl((String) o[i++])
.setCreateTimestamp(((Timestamp) o[i]).getTime());
webhookDtoList.add(webhookDto);
}
return webhookDtoList;
}
/**
* Returns a webhook by ID.
*
* @param id Webhook ID
* @return Webhook
*/
public Webhook getActiveById(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select w from Webhook w where w.id = :id and w.deleteDate is null");
q.setParameter("id", id);
try {
return (Webhook) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Creates a new webhook.
*
* @param webhook Webhook
* @return New ID
*/
public String create(Webhook webhook) {
// Create the UUID
webhook.setId(UUID.randomUUID().toString());
// Create the webhook
EntityManager em = ThreadLocalContext.get().getEntityManager();
webhook.setCreateDate(new Date());
em.persist(webhook);
return webhook.getId();
}
/**
* Deletes a webhook.
*
* @param webhookId Webhook ID
*/
public void delete(String webhookId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the group
Query q = em.createQuery("select w from Webhook w where w.id = :id and w.deleteDate is null");
q.setParameter("id", webhookId);
Webhook webhookDb = (Webhook) q.getSingleResult();
// Delete the group
Date dateNow = new Date();
webhookDb.setDeleteDate(dateNow);
}
}

View File

@ -1,9 +0,0 @@
package com.sismics.docs.core.dao.criteria;
/**
* Metadata criteria.
*
* @author bgamard
*/
public class MetadataCriteria {
}

View File

@ -1,25 +0,0 @@
package com.sismics.docs.core.dao.criteria;
import java.util.List;
/**
* Route model criteria.
*
* @author bgamard
*/
public class RouteModelCriteria {
/**
* ACL target ID list.
*/
private List<String> targetIdList;
public List<String> getTargetIdList() {
return targetIdList;
}
public RouteModelCriteria setTargetIdList(List<String> targetIdList) {
this.targetIdList = targetIdList;
return this;
}
}

View File

@ -1,24 +0,0 @@
package com.sismics.docs.core.dao.criteria;
import com.sismics.docs.core.constant.WebhookEvent;
/**
* Webhook criteria.
*
* @author bgamard
*/
public class WebhookCriteria {
/**
* Webhook event.
*/
private WebhookEvent event;
public WebhookEvent getEvent() {
return event;
}
public WebhookCriteria setEvent(WebhookEvent event) {
this.event = event;
return this;
}
}

View File

@ -1,94 +0,0 @@
package com.sismics.docs.core.dao.dto;
import com.sismics.docs.core.constant.MetadataType;
/**
* Document metadata DTO.
*
* @author bgamard
*/
public class DocumentMetadataDto {
/**
* Document metadata ID.
*/
private String id;
/**
* Document ID.
*/
private String documentId;
/**
* Metadata ID.
*/
private String metadataId;
/**
* Name.
*/
private String name;
/**
* Value.
*/
private String value;
/**
* Type.
*/
private MetadataType type;
public String getId() {
return id;
}
public DocumentMetadataDto setId(String id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public DocumentMetadataDto setName(String name) {
this.name = name;
return this;
}
public MetadataType getType() {
return type;
}
public DocumentMetadataDto setType(MetadataType type) {
this.type = type;
return this;
}
public String getDocumentId() {
return documentId;
}
public DocumentMetadataDto setDocumentId(String documentId) {
this.documentId = documentId;
return this;
}
public String getMetadataId() {
return metadataId;
}
public DocumentMetadataDto setMetadataId(String metadataId) {
this.metadataId = metadataId;
return this;
}
public String getValue() {
return value;
}
public DocumentMetadataDto setValue(String value) {
this.value = value;
return this;
}
}

View File

@ -1,52 +0,0 @@
package com.sismics.docs.core.dao.dto;
import com.sismics.docs.core.constant.MetadataType;
/**
* Metadata DTO.
*
* @author bgamard
*/
public class MetadataDto {
/**
* Metadata ID.
*/
private String id;
/**
* Name.
*/
private String name;
/**
* Type.
*/
private MetadataType type;
public String getId() {
return id;
}
public MetadataDto setId(String id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public MetadataDto setName(String name) {
this.name = name;
return this;
}
public MetadataType getType() {
return type;
}
public MetadataDto setType(MetadataType type) {
this.type = type;
return this;
}
}

View File

@ -1,74 +0,0 @@
package com.sismics.docs.core.dao.dto;
/**
* Webhook DTO.
*
* @author bgamard
*/
public class WebhookDto {
/**
* Webhook ID.
*/
private String id;
/**
* Event.
*/
private String event;
/**
* URL.
*/
private String url;
/**
* Creation date.
*/
private Long createTimestamp;
public String getId() {
return id;
}
public WebhookDto setId(String id) {
this.id = id;
return this;
}
public String getEvent() {
return event;
}
public WebhookDto setEvent(String event) {
this.event = event;
return this;
}
public String getUrl() {
return url;
}
public WebhookDto setUrl(String url) {
this.url = url;
return this;
}
public Long getCreateTimestamp() {
return createTimestamp;
}
public WebhookDto setCreateTimestamp(Long createTimestamp) {
this.createTimestamp = createTimestamp;
return this;
}
@Override
public boolean equals(Object obj) {
return id.equals(((WebhookDto) obj).getId());
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View File

@ -1,17 +1,16 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.AclTargetType; import com.sismics.docs.core.constant.AclTargetType;
import com.sismics.docs.core.constant.AclType; import com.sismics.docs.core.constant.AclType;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.dto.AclDto; import com.sismics.docs.core.dao.jpa.dto.AclDto;
import com.sismics.docs.core.model.jpa.Acl; import com.sismics.docs.core.model.jpa.Acl;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.SecurityUtil;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -74,17 +73,12 @@ public class AclDao {
.append(" left join T_USER u on u.USE_ID_C = a.ACL_TARGETID_C ") .append(" left join T_USER u on u.USE_ID_C = a.ACL_TARGETID_C ")
.append(" left join T_SHARE s on s.SHA_ID_C = a.ACL_TARGETID_C ") .append(" left join T_SHARE s on s.SHA_ID_C = a.ACL_TARGETID_C ")
.append(" left join T_GROUP g on g.GRP_ID_C = a.ACL_TARGETID_C ") .append(" left join T_GROUP g on g.GRP_ID_C = a.ACL_TARGETID_C ")
.append(" where a.ACL_DELETEDATE_D is null and a.ACL_SOURCEID_C = :sourceId "); .append(" where a.ACL_DELETEDATE_D is null and a.ACL_SOURCEID_C = :sourceId and a.ACL_TYPE_C = :type ");
if (type != null) {
sb.append(" and a.ACL_TYPE_C = :type");
}
// Perform the query // Perform the query
Query q = em.createNativeQuery(sb.toString()); Query q = em.createNativeQuery(sb.toString());
q.setParameter("sourceId", sourceId); q.setParameter("sourceId", sourceId);
if (type != null) {
q.setParameter("type", type.name()); q.setParameter("type", type.name());
}
List<Object[]> l = q.getResultList(); List<Object[]> l = q.getResultList();
// Assemble results // Assemble results
@ -125,20 +119,12 @@ public class AclDao {
* @return True if the document is accessible * @return True if the document is accessible
*/ */
public boolean checkPermission(String sourceId, PermType perm, List<String> targetIdList) { public boolean checkPermission(String sourceId, PermType perm, List<String> targetIdList) {
if (SecurityUtil.skipAclCheck(targetIdList)) {
return true;
}
if (targetIdList.isEmpty()) {
return false;
}
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select a.ACL_ID_C from T_ACL a "); StringBuilder sb = new StringBuilder("select a.ACL_ID_C from T_ACL a ");
sb.append(" where a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = :sourceId and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null "); sb.append(" where a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = :sourceId and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null ");
sb.append(" union all "); sb.append(" union all ");
sb.append(" select a.ACL_ID_C from T_ACL a, T_DOCUMENT_TAG dt, T_DOCUMENT d "); sb.append(" select a.ACL_ID_C from T_ACL a, T_DOCUMENT_TAG dt ");
sb.append(" where a.ACL_SOURCEID_C = dt.DOT_IDTAG_C and dt.DOT_IDDOCUMENT_C = d.DOC_ID_C and dt.DOT_DELETEDATE_D is null "); sb.append(" where a.ACL_SOURCEID_C = dt.DOT_IDTAG_C and dt.DOT_IDDOCUMENT_C = :sourceId and dt.DOT_DELETEDATE_D is null ");
sb.append(" and d.DOC_ID_C = :sourceId and d.DOC_DELETEDATE_D is null ");
sb.append(" and a.ACL_TARGETID_C in (:targetIdList) and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null "); sb.append(" and a.ACL_TARGETID_C in (:targetIdList) and a.ACL_PERM_C = :perm and a.ACL_DELETEDATE_D is null ");
Query q = em.createNativeQuery(sb.toString()); Query q = em.createNativeQuery(sb.toString());
q.setParameter("sourceId", sourceId); q.setParameter("sourceId", sourceId);

View File

@ -1,10 +1,20 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.EntityManager;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.criteria.AuditLogCriteria; import com.sismics.docs.core.dao.jpa.criteria.AuditLogCriteria;
import com.sismics.docs.core.dao.dto.AuditLogDto; import com.sismics.docs.core.dao.jpa.dto.AuditLogDto;
import com.sismics.docs.core.model.jpa.AuditLog; import com.sismics.docs.core.model.jpa.AuditLog;
import com.sismics.docs.core.util.jpa.PaginatedList; import com.sismics.docs.core.util.jpa.PaginatedList;
import com.sismics.docs.core.util.jpa.PaginatedLists; import com.sismics.docs.core.util.jpa.PaginatedLists;
@ -12,10 +22,6 @@ import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import java.sql.Timestamp;
import java.util.*;
/** /**
* Audit log DAO. * Audit log DAO.
* *
@ -27,6 +33,7 @@ public class AuditLogDao {
* *
* @param auditLog Audit log * @param auditLog Audit log
* @return New ID * @return New ID
* @throws Exception
*/ */
public String create(AuditLog auditLog) { public String create(AuditLog auditLog) {
// Create the UUID // Create the UUID
@ -46,9 +53,10 @@ public class AuditLogDao {
* @param paginatedList List of audit logs (updated by side effects) * @param paginatedList List of audit logs (updated by side effects)
* @param criteria Search criteria * @param criteria Search criteria
* @param sortCriteria Sort criteria * @param sortCriteria Sort criteria
* @return List of audit logs
*/ */
public void findByCriteria(PaginatedList<AuditLogDto> paginatedList, AuditLogCriteria criteria, SortCriteria sortCriteria) { public void findByCriteria(PaginatedList<AuditLogDto> paginatedList, AuditLogCriteria criteria, SortCriteria sortCriteria) {
Map<String, Object> parameterMap = new HashMap<>(); Map<String, Object> parameterMap = new HashMap<String, Object>();
StringBuilder baseQuery = new StringBuilder("select l.LOG_ID_C c0, l.LOG_CREATEDATE_D c1, u.USE_USERNAME_C c2, l.LOG_IDENTITY_C c3, l.LOG_CLASSENTITY_C c4, l.LOG_TYPE_C c5, l.LOG_MESSAGE_C c6 from T_AUDIT_LOG l "); StringBuilder baseQuery = new StringBuilder("select l.LOG_ID_C c0, l.LOG_CREATEDATE_D c1, u.USE_USERNAME_C c2, l.LOG_IDENTITY_C c3, l.LOG_CLASSENTITY_C c4, l.LOG_TYPE_C c5, l.LOG_MESSAGE_C c6 from T_AUDIT_LOG l ");
baseQuery.append(" join T_USER u on l.LOG_IDUSER_C = u.USE_ID_C "); baseQuery.append(" join T_USER u on l.LOG_IDUSER_C = u.USE_ID_C ");
@ -61,28 +69,22 @@ public class AuditLogDao {
queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select f.FIL_ID_C from T_FILE f where f.FIL_IDDOC_C = :documentId) "); queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select f.FIL_ID_C from T_FILE f where f.FIL_IDDOC_C = :documentId) ");
queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select c.COM_ID_C from T_COMMENT c where c.COM_IDDOC_C = :documentId) "); queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select c.COM_ID_C from T_COMMENT c where c.COM_IDDOC_C = :documentId) ");
queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select a.ACL_ID_C from T_ACL a where a.ACL_SOURCEID_C = :documentId) "); queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select a.ACL_ID_C from T_ACL a where a.ACL_SOURCEID_C = :documentId) ");
queries.add(baseQuery + " where l.LOG_IDENTITY_C in (select r.RTE_ID_C from T_ROUTE r where r.RTE_IDDOCUMENT_C = :documentId) ");
parameterMap.put("documentId", criteria.getDocumentId()); parameterMap.put("documentId", criteria.getDocumentId());
} }
if (criteria.getUserId() != null) { if (criteria.getUserId() != null) {
if (criteria.isAdmin()) {
// For admin users, display all logs except ACL logs
queries.add(baseQuery + " where l.LOG_CLASSENTITY_C != 'Acl' ");
} else {
// Get all logs originating from the user, not necessarly on owned items // Get all logs originating from the user, not necessarly on owned items
// Filter out ACL logs // Filter out ACL logs
queries.add(baseQuery + " where l.LOG_IDUSER_C = :userId and l.LOG_CLASSENTITY_C != 'Acl' "); queries.add(baseQuery + " where l.LOG_IDUSER_C = :userId and l.LOG_CLASSENTITY_C != 'Acl' ");
parameterMap.put("userId", criteria.getUserId()); parameterMap.put("userId", criteria.getUserId());
} }
}
// Perform the search // Perform the search
QueryParam queryParam = new QueryParam(Joiner.on(" union ").join(queries), parameterMap); QueryParam queryParam = new QueryParam(Joiner.on(" union ").join(queries), parameterMap);
List<Object[]> l = PaginatedLists.executePaginatedQuery(paginatedList, queryParam, sortCriteria); List<Object[]> l = PaginatedLists.executePaginatedQuery(paginatedList, queryParam, sortCriteria);
// Assemble results // Assemble results
List<AuditLogDto> auditLogDtoList = new ArrayList<>(); List<AuditLogDto> auditLogDtoList = new ArrayList<AuditLogDto>();
for (Object[] o : l) { for (Object[] o : l) {
int i = 0; int i = 0;
AuditLogDto auditLogDto = new AuditLogDto(); AuditLogDto auditLogDto = new AuditLogDto();

View File

@ -1,11 +1,11 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.model.jpa.AuthenticationToken; import com.sismics.docs.core.model.jpa.AuthenticationToken;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -86,7 +86,7 @@ public class AuthenticationTokenDao {
*/ */
public void updateLastConnectionDate(String id) { public void updateLastConnectionDate(String id) {
StringBuilder sb = new StringBuilder("update T_AUTHENTICATION_TOKEN ato "); StringBuilder sb = new StringBuilder("update T_AUTHENTICATION_TOKEN ato ");
sb.append(" set AUT_LASTCONNECTIONDATE_D = :currentDate "); sb.append(" set ato.AUT_LASTCONNECTIONDATE_D = :currentDate ");
sb.append(" where ato.AUT_ID_C = :id"); sb.append(" where ato.AUT_ID_C = :id");
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();

View File

@ -1,20 +1,21 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.dto.CommentDto;
import com.sismics.docs.core.model.jpa.Comment;
import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Query;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.jpa.dto.CommentDto;
import com.sismics.docs.core.model.jpa.Comment;
import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.util.context.ThreadLocalContext;
/** /**
* Comment DAO. * Comment DAO.
* *
@ -27,6 +28,7 @@ public class CommentDao {
* @param comment Comment * @param comment Comment
* @param userId User ID * @param userId User ID
* @return New ID * @return New ID
* @throws Exception
*/ */
public String create(Comment comment, String userId) { public String create(Comment comment, String userId) {
// Create the UUID // Create the UUID
@ -98,7 +100,7 @@ public class CommentDao {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Object[]> l = q.getResultList(); List<Object[]> l = q.getResultList();
List<CommentDto> commentDtoList = new ArrayList<>(); List<CommentDto> commentDtoList = new ArrayList<CommentDto>();
for (Object[] o : l) { for (Object[] o : l) {
int i = 0; int i = 0;
CommentDto commentDto = new CommentDto(); CommentDto commentDto = new CommentDto();
@ -106,7 +108,7 @@ public class CommentDao {
commentDto.setContent((String) o[i++]); commentDto.setContent((String) o[i++]);
commentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime()); commentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
commentDto.setCreatorName((String) o[i++]); commentDto.setCreatorName((String) o[i++]);
commentDto.setCreatorEmail((String) o[i]); commentDto.setCreatorEmail((String) o[i++]);
commentDtoList.add(commentDto); commentDtoList.add(commentDto);
} }
return commentDtoList; return commentDtoList;

View File

@ -1,11 +1,11 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.ConfigType; import com.sismics.docs.core.constant.ConfigType;
import com.sismics.docs.core.model.jpa.Config; import com.sismics.docs.core.model.jpa.Config;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
/** /**
* Configuration parameter DAO. * Configuration parameter DAO.

View File

@ -1,15 +1,16 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.dao.dto.ContributorDto;
import com.sismics.docs.core.model.jpa.Contributor;
import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import com.sismics.docs.core.dao.jpa.dto.ContributorDto;
import com.sismics.docs.core.model.jpa.Contributor;
import com.sismics.util.context.ThreadLocalContext;
/** /**
* Contributor DAO. * Contributor DAO.
* *
@ -56,7 +57,7 @@ public class ContributorDao {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<ContributorDto> getByDocumentId(String documentId) { public List<ContributorDto> getByDocumentId(String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select distinct u.USE_USERNAME_C, u.USE_EMAIL_C from T_CONTRIBUTOR c "); StringBuilder sb = new StringBuilder("select u.USE_USERNAME_C, u.USE_EMAIL_C from T_CONTRIBUTOR c ");
sb.append(" join T_USER u on u.USE_ID_C = c.CTR_IDUSER_C "); sb.append(" join T_USER u on u.USE_ID_C = c.CTR_IDUSER_C ");
sb.append(" where c.CTR_IDDOC_C = :documentId "); sb.append(" where c.CTR_IDDOC_C = :documentId ");
Query q = em.createNativeQuery(sb.toString()); Query q = em.createNativeQuery(sb.toString());

View File

@ -1,20 +1,25 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.constant.PermType;
import com.sismics.docs.core.dao.dto.DocumentDto; import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
import com.sismics.docs.core.dao.lucene.LuceneDao;
import com.sismics.docs.core.model.jpa.Document; import com.sismics.docs.core.model.jpa.Document;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.jpa.PaginatedList;
import com.sismics.docs.core.util.jpa.PaginatedLists;
import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import jakarta.persistence.TypedQuery;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Date; import java.util.*;
import java.util.List;
import java.util.UUID;
/** /**
* Document DAO. * Document DAO.
@ -32,7 +37,6 @@ public class DocumentDao {
public String create(Document document, String userId) { public String create(Document document, String userId) {
// Create the UUID // Create the UUID
document.setId(UUID.randomUUID().toString()); document.setId(UUID.randomUUID().toString());
document.setUpdateDate(new Date());
// Create the document // Create the document
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
@ -47,15 +51,12 @@ public class DocumentDao {
/** /**
* Returns the list of all active documents. * Returns the list of all active documents.
* *
* @param offset Offset
* @param limit Limit
* @return List of documents * @return List of documents
*/ */
public List<Document> findAll(int offset, int limit) { @SuppressWarnings("unchecked")
public List<Document> findAll() {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<Document> q = em.createQuery("select d from Document d where d.deleteDate is null", Document.class); Query q = em.createQuery("select d from Document d where d.deleteDate is null");
q.setFirstResult(offset);
q.setMaxResults(limit);
return q.getResultList(); return q.getResultList();
} }
@ -65,9 +66,10 @@ public class DocumentDao {
* @param userId User ID * @param userId User ID
* @return List of documents * @return List of documents
*/ */
@SuppressWarnings("unchecked")
public List<Document> findByUserId(String userId) { public List<Document> findByUserId(String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<Document> q = em.createQuery("select d from Document d where d.userId = :userId and d.deleteDate is null", Document.class); Query q = em.createQuery("select d from Document d where d.userId = :userId and d.deleteDate is null");
q.setParameter("userId", userId); q.setParameter("userId", userId);
return q.getResultList(); return q.getResultList();
} }
@ -87,9 +89,9 @@ public class DocumentDao {
} }
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_UPDATEDATE_D, d.DOC_LANGUAGE_C, d.DOC_IDFILE_C,"); StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_LANGUAGE_C, ");
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) shareCount, "); sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null), ");
sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) fileCount, "); sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C), ");
sb.append(" u.USE_USERNAME_C "); sb.append(" u.USE_USERNAME_C ");
sb.append(" from T_DOCUMENT d "); sb.append(" from T_DOCUMENT d ");
sb.append(" join T_USER u on d.DOC_IDUSER_C = u.USE_ID_C "); sb.append(" join T_USER u on d.DOC_IDUSER_C = u.USE_ID_C ");
@ -119,9 +121,7 @@ public class DocumentDao {
documentDto.setCoverage((String) o[i++]); documentDto.setCoverage((String) o[i++]);
documentDto.setRights((String) o[i++]); documentDto.setRights((String) o[i++]);
documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime()); documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
documentDto.setUpdateTimestamp(((Timestamp) o[i++]).getTime());
documentDto.setLanguage((String) o[i++]); documentDto.setLanguage((String) o[i++]);
documentDto.setFileId((String) o[i++]);
documentDto.setShared(((Number) o[i++]).intValue() > 0); documentDto.setShared(((Number) o[i++]).intValue() > 0);
documentDto.setFileCount(((Number) o[i++]).intValue()); documentDto.setFileCount(((Number) o[i++]).intValue());
documentDto.setCreator((String) o[i]); documentDto.setCreator((String) o[i]);
@ -138,16 +138,16 @@ public class DocumentDao {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the document // Get the document
TypedQuery<Document> dq = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null");
dq.setParameter("id", id); q.setParameter("id", id);
Document documentDb = dq.getSingleResult(); Document documentDb = (Document) q.getSingleResult();
// Delete the document // Delete the document
Date dateNow = new Date(); Date dateNow = new Date();
documentDb.setDeleteDate(dateNow); documentDb.setDeleteDate(dateNow);
// Delete linked data // Delete linked data
Query q = em.createQuery("update File f set f.deleteDate = :dateNow where f.documentId = :documentId and f.deleteDate is null"); q = em.createQuery("update File f set f.deleteDate = :dateNow where f.documentId = :documentId and f.deleteDate is null");
q.setParameter("documentId", id); q.setParameter("documentId", id);
q.setParameter("dateNow", dateNow); q.setParameter("dateNow", dateNow);
q.executeUpdate(); q.executeUpdate();
@ -179,17 +179,110 @@ public class DocumentDao {
*/ */
public Document getById(String id) { public Document getById(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
TypedQuery<Document> q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null");
q.setParameter("id", id); q.setParameter("id", id);
try { try {
return q.getSingleResult(); return (Document) q.getSingleResult();
} catch (NoResultException e) { } catch (NoResultException e) {
return null; return null;
} }
} }
/** /**
* Update a document and log the action. * Searches documents by criteria.
*
* @param paginatedList List of documents (updated by side effects)
* @param criteria Search criteria
* @param sortCriteria Sort criteria
* @throws Exception
*/
public void findByCriteria(PaginatedList<DocumentDto> paginatedList, DocumentCriteria criteria, SortCriteria sortCriteria) throws Exception {
Map<String, Object> parameterMap = new HashMap<>();
List<String> criteriaList = new ArrayList<>();
StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C c0, d.DOC_TITLE_C c1, d.DOC_DESCRIPTION_C c2, d.DOC_CREATEDATE_D c3, d.DOC_LANGUAGE_C c4, ");
sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) c5, ");
sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) c6 ");
sb.append(" from T_DOCUMENT d ");
// Add search criterias
if (criteria.getTargetIdList() != null) {
// Read permission is enough for searching
sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = d.DOC_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
sb.append(" left join T_DOCUMENT_TAG dta on dta.DOT_IDDOCUMENT_C = d.DOC_ID_C and dta.DOT_DELETEDATE_D is null ");
sb.append(" left join T_ACL a2 on a2.ACL_TARGETID_C in (:targetIdList) and a2.ACL_SOURCEID_C = dta.DOT_IDTAG_C and a2.ACL_PERM_C = 'READ' and a2.ACL_DELETEDATE_D is null ");
criteriaList.add("(a.ACL_ID_C is not null or a2.ACL_ID_C is not null)");
parameterMap.put("targetIdList", criteria.getTargetIdList());
}
if (!Strings.isNullOrEmpty(criteria.getSearch()) || !Strings.isNullOrEmpty(criteria.getFullSearch())) {
LuceneDao luceneDao = new LuceneDao();
Set<String> documentIdList = luceneDao.search(criteria.getSearch(), criteria.getFullSearch());
if (documentIdList.isEmpty()) {
// If the search doesn't find any document, the request should return nothing
documentIdList.add(UUID.randomUUID().toString());
}
criteriaList.add("d.DOC_ID_C in :documentIdList");
parameterMap.put("documentIdList", documentIdList);
}
if (criteria.getCreateDateMin() != null) {
criteriaList.add("d.DOC_CREATEDATE_D >= :createDateMin");
parameterMap.put("createDateMin", criteria.getCreateDateMin());
}
if (criteria.getCreateDateMax() != null) {
criteriaList.add("d.DOC_CREATEDATE_D <= :createDateMax");
parameterMap.put("createDateMax", criteria.getCreateDateMax());
}
if (criteria.getTagIdList() != null && !criteria.getTagIdList().isEmpty()) {
int index = 0;
for (String tagId : criteria.getTagIdList()) {
sb.append(String.format(" join T_DOCUMENT_TAG dt%d on dt%d.DOT_IDDOCUMENT_C = d.DOC_ID_C and dt%d.DOT_IDTAG_C = :tagId%d and dt%d.DOT_DELETEDATE_D is null ", index, index, index, index, index));
parameterMap.put("tagId" + index, tagId);
index++;
}
}
if (criteria.getShared() != null && criteria.getShared()) {
criteriaList.add("(select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) > 0");
}
if (criteria.getLanguage() != null) {
criteriaList.add("d.DOC_LANGUAGE_C = :language");
parameterMap.put("language", criteria.getLanguage());
}
if (criteria.getCreatorId() != null) {
criteriaList.add("d.DOC_IDUSER_C = :creatorId");
parameterMap.put("creatorId", criteria.getCreatorId());
}
criteriaList.add("d.DOC_DELETEDATE_D is null");
if (!criteriaList.isEmpty()) {
sb.append(" where ");
sb.append(Joiner.on(" and ").join(criteriaList));
}
// Perform the search
QueryParam queryParam = new QueryParam(sb.toString(), parameterMap);
List<Object[]> l = PaginatedLists.executePaginatedQuery(paginatedList, queryParam, sortCriteria);
// Assemble results
List<DocumentDto> documentDtoList = new ArrayList<>();
for (Object[] o : l) {
int i = 0;
DocumentDto documentDto = new DocumentDto();
documentDto.setId((String) o[i++]);
documentDto.setTitle((String) o[i++]);
documentDto.setDescription((String) o[i++]);
documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
documentDto.setLanguage((String) o[i++]);
documentDto.setShared(((Number) o[i++]).intValue() > 0);
documentDto.setFileCount(((Number) o[i]).intValue());
documentDtoList.add(documentDto);
}
paginatedList.setResultList(documentDtoList);
}
/**
* Update a document.
* *
* @param document Document to update * @param document Document to update
* @param userId User ID * @param userId User ID
@ -199,9 +292,9 @@ public class DocumentDao {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the document // Get the document
TypedQuery<Document> q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null", Document.class); Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null");
q.setParameter("id", document.getId()); q.setParameter("id", document.getId());
Document documentDb = q.getSingleResult(); Document documentDb = (Document) q.getSingleResult();
// Update the document // Update the document
documentDb.setTitle(document.getTitle()); documentDb.setTitle(document.getTitle());
@ -216,8 +309,6 @@ public class DocumentDao {
documentDb.setRights(document.getRights()); documentDb.setRights(document.getRights());
documentDb.setCreateDate(document.getCreateDate()); documentDb.setCreateDate(document.getCreateDate());
documentDb.setLanguage(document.getLanguage()); documentDb.setLanguage(document.getLanguage());
documentDb.setFileId(document.getFileId());
documentDb.setUpdateDate(new Date());
// Create audit log // Create audit log
AuditLogUtil.create(documentDb, AuditLogType.UPDATE, userId); AuditLogUtil.create(documentDb, AuditLogType.UPDATE, userId);
@ -225,20 +316,6 @@ public class DocumentDao {
return documentDb; return documentDb;
} }
/**
* Update the file ID on a document.
*
* @param document Document
*/
public void updateFileId(Document document) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query query = em.createNativeQuery("update T_DOCUMENT d set DOC_IDFILE_C = :fileId, DOC_UPDATEDATE_D = :updateDate where d.DOC_ID_C = :id");
query.setParameter("updateDate", new Date());
query.setParameter("fileId", document.getFileId());
query.setParameter("id", document.getId());
query.executeUpdate();
}
/** /**
* Returns the number of documents. * Returns the number of documents.
* *

View File

@ -0,0 +1,186 @@
package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.model.jpa.File;
import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.util.context.ThreadLocalContext;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* File DAO.
*
* @author bgamard
*/
public class FileDao {
/**
* Creates a new file.
*
* @param file File
* @param userId User ID
* @return New ID
*/
public String create(File file, String userId) {
// Create the UUID
file.setId(UUID.randomUUID().toString());
// Create the file
EntityManager em = ThreadLocalContext.get().getEntityManager();
file.setCreateDate(new Date());
em.persist(file);
// Create audit log
AuditLogUtil.create(file, AuditLogType.CREATE, userId);
return file.getId();
}
/**
* Returns the list of all files.
*
* @return List of files
*/
@SuppressWarnings("unchecked")
public List<File> findAll() {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f from File f where f.deleteDate is null");
return q.getResultList();
}
/**
* Returns the list of all files from a user.
*
* @param userId User ID
* @return List of files
*/
@SuppressWarnings("unchecked")
public List<File> findByUserId(String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f from File f where f.userId = :userId and f.deleteDate is null");
q.setParameter("userId", userId);
return q.getResultList();
}
/**
* Returns an active file.
*
* @param id File ID
* @return Document
*/
public File getFile(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
q.setParameter("id", id);
try {
return (File) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Returns an active file.
*
* @param id File ID
* @param userId User ID
* @return Document
*/
public File getFile(String id, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f from File f where f.id = :id and f.userId = :userId and f.deleteDate is null");
q.setParameter("id", id);
q.setParameter("userId", userId);
try {
return (File) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Deletes a file.
*
* @param id File ID
* @param userId User ID
*/
public void delete(String id, String userId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the file
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
q.setParameter("id", id);
File fileDb = (File) q.getSingleResult();
// Delete the file
Date dateNow = new Date();
fileDb.setDeleteDate(dateNow);
// Create audit log
AuditLogUtil.create(fileDb, AuditLogType.DELETE, userId);
}
/**
* Update a file.
*
* @param file File to update
* @return Updated file
*/
public File update(File file) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the file
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
q.setParameter("id", file.getId());
File fileDb = (File) q.getSingleResult();
// Update the file
fileDb.setDocumentId(file.getDocumentId());
fileDb.setContent(file.getContent());
fileDb.setOrder(file.getOrder());
fileDb.setMimeType(file.getMimeType());
return file;
}
/**
* Gets a file by its ID.
*
* @param id File ID
* @return File
*/
public File getActiveById(String id) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
q.setParameter("id", id);
try {
return (File) q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
/**
* Get files by document ID or all orphan files of an user.
*
* @param userId User ID
* @param documentId Document ID
* @return List of files
*/
@SuppressWarnings("unchecked")
public List<File> getByDocumentId(String userId, String documentId) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
if (documentId == null) {
Query q = em.createQuery("select f from File f where f.documentId is null and f.deleteDate is null and f.userId = :userId order by f.createDate asc");
q.setParameter("userId", userId);
return q.getResultList();
}
Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.deleteDate is null order by f.order asc");
q.setParameter("documentId", documentId);
return q.getResultList();
}
}

View File

@ -1,9 +1,9 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.criteria.GroupCriteria; import com.sismics.docs.core.dao.jpa.criteria.GroupCriteria;
import com.sismics.docs.core.dao.dto.GroupDto; import com.sismics.docs.core.dao.jpa.dto.GroupDto;
import com.sismics.docs.core.model.jpa.Group; import com.sismics.docs.core.model.jpa.Group;
import com.sismics.docs.core.model.jpa.UserGroup; import com.sismics.docs.core.model.jpa.UserGroup;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
@ -12,9 +12,9 @@ import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.*; import java.util.*;
/** /**
@ -184,8 +184,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);

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.constant.Constants; import com.sismics.docs.core.constant.Constants;
import com.sismics.docs.core.model.jpa.PasswordRecovery; import com.sismics.docs.core.model.jpa.PasswordRecovery;
@ -6,9 +6,9 @@ import com.sismics.util.context.ThreadLocalContext;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DurationFieldType; import org.joda.time.DurationFieldType;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;

View File

@ -1,13 +1,18 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.dao.dto.RelationDto; import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import com.sismics.docs.core.dao.jpa.dto.RelationDto;
import com.sismics.docs.core.model.jpa.Relation; import com.sismics.docs.core.model.jpa.Relation;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import java.util.*;
/** /**
* Relation DAO. * Relation DAO.
* *
@ -36,13 +41,13 @@ public class RelationDao {
List<Object[]> l = q.getResultList(); List<Object[]> l = q.getResultList();
// Assemble results // Assemble results
List<RelationDto> relationDtoList = new ArrayList<>(); List<RelationDto> relationDtoList = new ArrayList<RelationDto>();
for (Object[] o : l) { for (Object[] o : l) {
int i = 0; int i = 0;
RelationDto relationDto = new RelationDto(); RelationDto relationDto = new RelationDto();
relationDto.setId((String) o[i++]); relationDto.setId((String) o[i++]);
relationDto.setTitle((String) o[i++]); relationDto.setTitle((String) o[i++]);
String fromDocId = (String) o[i]; String fromDocId = (String) o[i++];
relationDto.setSource(documentId.equals(fromDocId)); relationDto.setSource(documentId.equals(fromDocId));
relationDtoList.add(relationDto); relationDtoList.add(relationDto);
} }

View File

@ -1,10 +1,10 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.Set; import java.util.Set;
/** /**

View File

@ -1,9 +1,9 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.criteria.RouteCriteria; import com.sismics.docs.core.dao.jpa.criteria.RouteCriteria;
import com.sismics.docs.core.dao.dto.RouteDto; import com.sismics.docs.core.dao.jpa.dto.RouteDto;
import com.sismics.docs.core.model.jpa.Route; import com.sismics.docs.core.model.jpa.Route;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryParam;
@ -11,7 +11,7 @@ import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
@ -64,8 +64,10 @@ 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);
@ -89,21 +91,16 @@ public class RouteDao {
* Deletes a route and the associated steps. * Deletes a route and the associated steps.
* *
* @param routeId Route ID * @param routeId Route ID
* @param userId User ID
*/ */
public void deleteRoute(String routeId, String userId) { public void deleteRoute(String routeId) {
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();
// Create audit log em.createNativeQuery("update T_ROUTE_STEP rs set rs.RTP_DELETEDATE_D = :dateNow where rs.RTP_IDROUTE_C = :routeId and rs.RTP_DELETEDATE_D is null")
Route route = em.find(Route.class, routeId);
AuditLogUtil.create(route, AuditLogType.DELETE, userId);
em.createNativeQuery("update T_ROUTE_STEP rs set RTP_DELETEDATE_D = :dateNow where rs.RTP_IDROUTE_C = :routeId and rs.RTP_DELETEDATE_D is null")
.setParameter("routeId", routeId) .setParameter("routeId", routeId)
.setParameter("dateNow", new Date()) .setParameter("dateNow", new Date())
.executeUpdate(); .executeUpdate();
em.createNativeQuery("update T_ROUTE r set RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null") em.createNativeQuery("update T_ROUTE r set r.RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null")
.setParameter("routeId", routeId) .setParameter("routeId", routeId)
.setParameter("dateNow", new Date()) .setParameter("dateNow", new Date())
.executeUpdate(); .executeUpdate();

View File

@ -1,20 +1,19 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.criteria.RouteModelCriteria; import com.sismics.docs.core.dao.jpa.criteria.RouteModelCriteria;
import com.sismics.docs.core.dao.dto.RouteModelDto; import com.sismics.docs.core.dao.jpa.dto.RouteModelDto;
import com.sismics.docs.core.model.jpa.RouteModel; import com.sismics.docs.core.model.jpa.RouteModel;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.SecurityUtil;
import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil; import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
@ -61,7 +60,7 @@ public class RouteModelDao {
q.setParameter("id", routeModel.getId()); q.setParameter("id", routeModel.getId());
RouteModel routeModelDb = (RouteModel) q.getSingleResult(); RouteModel routeModelDb = (RouteModel) q.getSingleResult();
// Update the route model // Update the group
routeModelDb.setName(routeModel.getName()); routeModelDb.setName(routeModel.getName());
routeModelDb.setSteps(routeModel.getSteps()); routeModelDb.setSteps(routeModel.getSteps());
@ -88,18 +87,6 @@ public class RouteModelDao {
} }
} }
/**
* Returns the list of all route models.
*
* @return List of route models
*/
@SuppressWarnings("unchecked")
public List<RouteModel> findAll() {
EntityManager em = ThreadLocalContext.get().getEntityManager();
Query q = em.createQuery("select r from RouteModel r where r.deleteDate is null");
return q.getResultList();
}
/** /**
* Deletes a route model. * Deletes a route model.
* *
@ -137,16 +124,12 @@ public class RouteModelDao {
sb.append(" from T_ROUTE_MODEL rm "); sb.append(" from T_ROUTE_MODEL rm ");
// Add search criterias // Add search criterias
if (criteria.getTargetIdList() != null && !SecurityUtil.skipAclCheck(criteria.getTargetIdList())) {
sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = rm.RTM_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
criteriaList.add("a.ACL_ID_C is not null");
parameterMap.put("targetIdList", criteria.getTargetIdList());
}
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

@ -1,19 +1,19 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AclTargetType; import com.sismics.docs.core.constant.AclTargetType;
import com.sismics.docs.core.constant.RouteStepTransition; import com.sismics.docs.core.constant.RouteStepTransition;
import com.sismics.docs.core.constant.RouteStepType; import com.sismics.docs.core.constant.RouteStepType;
import com.sismics.docs.core.dao.criteria.RouteStepCriteria; import com.sismics.docs.core.dao.jpa.criteria.RouteStepCriteria;
import com.sismics.docs.core.dao.dto.RouteStepDto; import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
import com.sismics.docs.core.model.jpa.RouteStep; import com.sismics.docs.core.model.jpa.RouteStep;
import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil; import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
@ -68,7 +68,7 @@ public class RouteStepDao {
Map<String, Object> parameterMap = new HashMap<>(); Map<String, Object> parameterMap = new HashMap<>();
List<String> criteriaList = new ArrayList<>(); List<String> criteriaList = new ArrayList<>();
StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_IDROUTE_C, rs.RTP_TRANSITIONS_C, rs.RTP_ORDER_N c6") StringBuilder sb = new StringBuilder("select rs.RTP_ID_C, rs.RTP_NAME_C c0, rs.RTP_TYPE_C c1, rs.RTP_TRANSITION_C c2, rs.RTP_COMMENT_C c3, rs.RTP_IDTARGET_C c4, u.USE_USERNAME_C as targetUsername, g.GRP_NAME_C, rs.RTP_ENDDATE_D c5, uv.USE_USERNAME_C as validatorUsername, rs.RTP_IDROUTE_C, rs.RTP_ORDER_N c6")
.append(" from T_ROUTE_STEP rs ") .append(" from T_ROUTE_STEP rs ")
.append(" join T_ROUTE r on r.RTE_ID_C = rs.RTP_IDROUTE_C ") .append(" join T_ROUTE r on r.RTE_ID_C = rs.RTP_IDROUTE_C ")
.append(" left join T_USER uv on uv.USE_ID_C = rs.RTP_IDVALIDATORUSER_C ") .append(" left join T_USER uv on uv.USE_ID_C = rs.RTP_IDVALIDATORUSER_C ")
@ -90,8 +90,10 @@ 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);
@ -122,8 +124,7 @@ public class RouteStepDao {
Timestamp endDateTimestamp = (Timestamp) o[i++]; Timestamp endDateTimestamp = (Timestamp) o[i++];
dto.setEndDateTimestamp(endDateTimestamp == null ? null : endDateTimestamp.getTime()); dto.setEndDateTimestamp(endDateTimestamp == null ? null : endDateTimestamp.getTime());
dto.setValidatorUserName((String) o[i++]); dto.setValidatorUserName((String) o[i++]);
dto.setRouteId((String) o[i++]); dto.setRouteId((String) o[i]);
dto.setTransitions((String) o[i]);
dtoList.add(dto); dtoList.add(dto);
} }
return dtoList; return dtoList;
@ -139,7 +140,7 @@ public class RouteStepDao {
*/ */
public void endRouteStep(String id, RouteStepTransition transition, String comment, String validatorUserId) { public void endRouteStep(String id, RouteStepTransition transition, String comment, String validatorUserId) {
StringBuilder sb = new StringBuilder("update T_ROUTE_STEP r "); StringBuilder sb = new StringBuilder("update T_ROUTE_STEP r ");
sb.append(" set RTP_ENDDATE_D = :endDate, RTP_TRANSITION_C = :transition, RTP_COMMENT_C = :comment, RTP_IDVALIDATORUSER_C = :validatorUserId "); sb.append(" set r.RTP_ENDDATE_D = :endDate, r.RTP_TRANSITION_C = :transition, r.RTP_COMMENT_C = :comment, r.RTP_IDVALIDATORUSER_C = :validatorUserId ");
sb.append(" where r.RTP_ID_C = :id"); sb.append(" where r.RTP_ID_C = :id");
EntityManager em = ThreadLocalContext.get().getEntityManager(); EntityManager em = ThreadLocalContext.get().getEntityManager();

View File

@ -1,13 +1,14 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import java.util.Date;
import java.util.UUID;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import com.sismics.docs.core.model.jpa.Share; import com.sismics.docs.core.model.jpa.Share;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import java.util.Date;
import java.util.UUID;
/** /**
* Share DAO. * Share DAO.
* *
@ -19,6 +20,7 @@ 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

@ -1,21 +1,20 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.dao.criteria.TagCriteria; import com.sismics.docs.core.dao.jpa.criteria.TagCriteria;
import com.sismics.docs.core.dao.dto.TagDto; import com.sismics.docs.core.dao.jpa.dto.TagDto;
import com.sismics.docs.core.model.jpa.DocumentTag; import com.sismics.docs.core.model.jpa.DocumentTag;
import com.sismics.docs.core.model.jpa.Tag; import com.sismics.docs.core.model.jpa.Tag;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.SecurityUtil;
import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil; import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.*; import java.util.*;
/** /**
@ -132,10 +131,6 @@ public class TagDao {
q.setParameter("dateNow", dateNow); q.setParameter("dateNow", dateNow);
q.executeUpdate(); q.executeUpdate();
q = em.createQuery("update Tag t set t.parentId = null where t.parentId = :tagId and t.deleteDate is null");
q.setParameter("tagId", tagId);
q.executeUpdate();
// Create audit log // Create audit log
AuditLogUtil.create(tagDb, AuditLogType.DELETE, userId); AuditLogUtil.create(tagDb, AuditLogType.DELETE, userId);
} }
@ -186,7 +181,7 @@ public class TagDao {
criteriaList.add("t.TAG_ID_C = :id"); criteriaList.add("t.TAG_ID_C = :id");
parameterMap.put("id", criteria.getId()); parameterMap.put("id", criteria.getId());
} }
if (criteria.getTargetIdList() != null && !SecurityUtil.skipAclCheck(criteria.getTargetIdList())) { if (criteria.getTargetIdList() != null) {
sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = t.TAG_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null "); sb.append(" left join T_ACL a on a.ACL_TARGETID_C in (:targetIdList) and a.ACL_SOURCEID_C = t.TAG_ID_C and a.ACL_PERM_C = 'READ' and a.ACL_DELETEDATE_D is null ");
criteriaList.add("a.ACL_ID_C is not null"); criteriaList.add("a.ACL_ID_C is not null");
parameterMap.put("targetIdList", criteria.getTargetIdList()); parameterMap.put("targetIdList", criteria.getTargetIdList());
@ -196,11 +191,21 @@ public class TagDao {
criteriaList.add("dt.DOT_IDDOCUMENT_C = :documentId"); criteriaList.add("dt.DOT_IDDOCUMENT_C = :documentId");
parameterMap.put("documentId", criteria.getDocumentId()); parameterMap.put("documentId", criteria.getDocumentId());
} }
if (criteria.getName() != null) {
criteriaList.add("t.TAG_NAME_C = :name");
parameterMap.put("name", criteria.getName());
}
if (criteria.getNameLike() != null) {
criteriaList.add("t.TAG_NAME_C like :nameLike");
parameterMap.put("nameLike", criteria.getNameLike() + "%");
}
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

@ -1,27 +1,21 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import at.favre.lib.crypto.bcrypt.BCrypt;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;
import com.sismics.docs.core.constant.Constants; import com.sismics.docs.core.dao.jpa.criteria.UserCriteria;
import com.sismics.docs.core.dao.criteria.UserCriteria; import com.sismics.docs.core.dao.jpa.dto.UserDto;
import com.sismics.docs.core.dao.dto.UserDto;
import com.sismics.docs.core.model.jpa.User; import com.sismics.docs.core.model.jpa.User;
import com.sismics.docs.core.util.AuditLogUtil; import com.sismics.docs.core.util.AuditLogUtil;
import com.sismics.docs.core.util.EncryptionUtil;
import com.sismics.docs.core.util.jpa.QueryParam; import com.sismics.docs.core.util.jpa.QueryParam;
import com.sismics.docs.core.util.jpa.QueryUtil; import com.sismics.docs.core.util.jpa.QueryUtil;
import com.sismics.docs.core.util.jpa.SortCriteria; import com.sismics.docs.core.util.jpa.SortCriteria;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import org.joda.time.DateTime;
import org.mindrot.jbcrypt.BCrypt;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
@ -31,11 +25,6 @@ import java.util.*;
* @author jtremeaux * @author jtremeaux
*/ */
public class UserDao { public class UserDao {
/**
* Logger.
*/
private static final Logger log = LoggerFactory.getLogger(UserDao.class);
/** /**
* Authenticates an user. * Authenticates an user.
* *
@ -49,8 +38,7 @@ public class UserDao {
q.setParameter("username", username); q.setParameter("username", username);
try { try {
User user = (User) q.getSingleResult(); User user = (User) q.getSingleResult();
BCrypt.Result result = BCrypt.verifyer().verify(password.toCharArray(), user.getPassword()); if (!BCrypt.checkpw(password, user.getPassword()) || user.getDisableDate() != null) {
if (!result.verified || user.getDisableDate() != null) {
return null; return null;
} }
return user; return user;
@ -83,8 +71,6 @@ public class UserDao {
// Create the user // Create the user
user.setCreateDate(new Date()); user.setCreateDate(new Date());
user.setPassword(hashPassword(user.getPassword())); user.setPassword(hashPassword(user.getPassword()));
user.setPrivateKey(EncryptionUtil.generatePrivateKey());
user.setStorageCurrent(0L);
em.persist(user); em.persist(user);
// Create audit log // Create audit log
@ -182,26 +168,6 @@ public class UserDao {
return user; return user;
} }
/**
* Update the onboarding status.
*
* @param user User to update
* @return Updated user
*/
public User updateOnboarding(User user) {
EntityManager em = ThreadLocalContext.get().getEntityManager();
// Get the user
Query q = em.createQuery("select u from User u where u.id = :id and u.deleteDate is null");
q.setParameter("id", user.getId());
User userDb = (User) q.getSingleResult();
// Update the user
userDb.setOnboarding(user.isOnboarding());
return user;
}
/** /**
* Gets a user by its ID. * Gets a user by its ID.
* *
@ -288,21 +254,7 @@ public class UserDao {
* @return Hashed password * @return Hashed password
*/ */
private String hashPassword(String password) { private String hashPassword(String password) {
int bcryptWork = Constants.DEFAULT_BCRYPT_WORK; return BCrypt.hashpw(password, BCrypt.gensalt());
String envBcryptWork = System.getenv(Constants.BCRYPT_WORK_ENV);
if (!Strings.isNullOrEmpty(envBcryptWork)) {
try {
int envBcryptWorkInt = Integer.parseInt(envBcryptWork);
if (envBcryptWorkInt >= 4 && envBcryptWorkInt <= 31) {
bcryptWork = envBcryptWorkInt;
} else {
log.warn(Constants.BCRYPT_WORK_ENV + " needs to be in range 4...31. Falling back to " + Constants.DEFAULT_BCRYPT_WORK + ".");
}
} catch (NumberFormatException e) {
log.warn(Constants.BCRYPT_WORK_ENV + " needs to be a number in range 4...31. Falling back to " + Constants.DEFAULT_BCRYPT_WORK + ".");
}
}
return BCrypt.withDefaults().hashToString(bcryptWork, password.toCharArray());
} }
/** /**

View File

@ -1,11 +1,11 @@
package com.sismics.docs.core.dao; package com.sismics.docs.core.dao.jpa;
import com.sismics.docs.core.model.jpa.Vocabulary; import com.sismics.docs.core.model.jpa.Vocabulary;
import com.sismics.util.context.ThreadLocalContext; import com.sismics.util.context.ThreadLocalContext;
import jakarta.persistence.EntityManager; import javax.persistence.EntityManager;
import jakarta.persistence.NoResultException; import javax.persistence.NoResultException;
import jakarta.persistence.Query; import javax.persistence.Query;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -20,6 +20,7 @@ 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

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
/** /**
@ -17,11 +17,6 @@ public class AuditLogCriteria {
*/ */
private String userId; private String userId;
/**
* The search is done for an admin user.
*/
private boolean isAdmin = false;
public String getDocumentId() { public String getDocumentId() {
return documentId; return documentId;
} }
@ -37,13 +32,4 @@ public class AuditLogCriteria {
public void setUserId(String userId) { public void setUserId(String userId) {
this.userId = userId; this.userId = userId;
} }
public boolean isAdmin() {
return isAdmin;
}
public AuditLogCriteria setAdmin(boolean admin) {
isAdmin = admin;
return this;
}
} }

View File

@ -1,6 +1,5 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -19,7 +18,7 @@ public class DocumentCriteria {
/** /**
* Search query. * Search query.
*/ */
private String simpleSearch; private String search;
/** /**
* Full content search query. * Full content search query.
@ -36,27 +35,10 @@ public class DocumentCriteria {
*/ */
private Date createDateMax; private Date createDateMax;
/**
* Minimum update date.
*/
private Date updateDateMin;
/**
* Maximum update date.
*/
private Date updateDateMax;
/** /**
* Tag IDs. * Tag IDs.
* The first level list will be AND'ed and the second level list will be OR'ed.
*/ */
private List<List<String>> tagIdList = new ArrayList<>(); private List<String> tagIdList;
/**
* Tag IDs to exclude.
* The first and second level list will be excluded.
*/
private List<List<String>> excludedTagIdList = new ArrayList<>();
/** /**
* Shared status. * Shared status.
@ -73,21 +55,6 @@ public class DocumentCriteria {
*/ */
private String creatorId; private String creatorId;
/**
* A route is active.
*/
private Boolean activeRoute;
/**
* MIME type of a file.
*/
private String mimeType;
/**
* Titles to include.
*/
private List<String> titleList = new ArrayList<>();
public List<String> getTargetIdList() { public List<String> getTargetIdList() {
return targetIdList; return targetIdList;
} }
@ -96,12 +63,12 @@ public class DocumentCriteria {
this.targetIdList = targetIdList; this.targetIdList = targetIdList;
} }
public String getSimpleSearch() { public String getSearch() {
return simpleSearch; return search;
} }
public void setSimpleSearch(String search) { public void setSearch(String search) {
this.simpleSearch = search; this.search = search;
} }
public String getFullSearch() { public String getFullSearch() {
@ -128,12 +95,12 @@ public class DocumentCriteria {
this.createDateMax = createDateMax; this.createDateMax = createDateMax;
} }
public List<List<String>> getTagIdList() { public List<String> getTagIdList() {
return tagIdList; return tagIdList;
} }
public List<List<String>> getExcludedTagIdList() { public void setTagIdList(List<String> tagIdList) {
return excludedTagIdList; this.tagIdList = tagIdList;
} }
public Boolean getShared() { public Boolean getShared() {
@ -159,40 +126,4 @@ public class DocumentCriteria {
public void setCreatorId(String creatorId) { public void setCreatorId(String creatorId) {
this.creatorId = creatorId; this.creatorId = creatorId;
} }
public Date getUpdateDateMin() {
return updateDateMin;
}
public void setUpdateDateMin(Date updateDateMin) {
this.updateDateMin = updateDateMin;
}
public Date getUpdateDateMax() {
return updateDateMax;
}
public void setUpdateDateMax(Date updateDateMax) {
this.updateDateMax = updateDateMax;
}
public Boolean getActiveRoute() {
return activeRoute;
}
public void setActiveRoute(Boolean activeRoute) {
this.activeRoute = activeRoute;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public List<String> getTitleList() {
return titleList;
}
} }

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
/** /**
* Group criteria. * Group criteria.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
/** /**

View File

@ -0,0 +1,10 @@
package com.sismics.docs.core.dao.jpa.criteria;
/**
* Route model criteria.
*
* @author bgamard
*/
public class RouteModelCriteria {
}

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
/** /**

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
import java.util.List; import java.util.List;
@ -23,6 +23,16 @@ public class TagCriteria {
*/ */
private String documentId; private String documentId;
/**
* Tag name.
*/
private String name;
/**
* Approximate tag name.
*/
private String nameLike;
public String getId() { public String getId() {
return id; return id;
} }
@ -49,4 +59,22 @@ public class TagCriteria {
this.documentId = documentId; this.documentId = documentId;
return this; return this;
} }
public String getName() {
return name;
}
public TagCriteria setName(String name) {
this.name = name;
return this;
}
public String getNameLike() {
return nameLike;
}
public TagCriteria setNameLike(String nameLike) {
this.nameLike = nameLike;
return this;
}
} }

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.criteria; package com.sismics.docs.core.dao.jpa.criteria;
/** /**
* User criteria. * User criteria.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
import com.sismics.docs.core.constant.PermType; import com.sismics.docs.core.constant.PermType;

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
import com.sismics.docs.core.constant.AuditLogType; import com.sismics.docs.core.constant.AuditLogType;

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Comment DTO. * Comment DTO.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Contributor DTO. * Contributor DTO.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Document DTO. * Document DTO.
@ -11,11 +11,6 @@ public class DocumentDto {
*/ */
private String id; private String id;
/**
* Main file ID.
*/
private String fileId;
/** /**
* Title. * Title.
*/ */
@ -76,11 +71,6 @@ public class DocumentDto {
*/ */
private Long createTimestamp; private Long createTimestamp;
/**
* Update date.
*/
private Long updateTimestamp;
/** /**
* Shared status. * Shared status.
*/ */
@ -96,21 +86,6 @@ public class DocumentDto {
*/ */
private String creator; private String creator;
/**
* A route is active.
*/
private boolean activeRoute;
/**
* Current route step name.
*/
private String currentStepName;
/**
* Search highlight.
*/
private String highlight;
public String getId() { public String getId() {
return id; return id;
} }
@ -119,15 +94,6 @@ public class DocumentDto {
this.id = id; this.id = id;
} }
public String getFileId() {
return fileId;
}
public DocumentDto setFileId(String fileId) {
this.fileId = fileId;
return this;
}
public String getTitle() { public String getTitle() {
return title; return title;
} }
@ -247,38 +213,4 @@ public class DocumentDto {
public void setCreator(String creator) { public void setCreator(String creator) {
this.creator = creator; this.creator = creator;
} }
public boolean isActiveRoute() {
return activeRoute;
}
public void setActiveRoute(boolean activeRoute) {
this.activeRoute = activeRoute;
}
public String getCurrentStepName() {
return currentStepName;
}
public Long getUpdateTimestamp() {
return updateTimestamp;
}
public void setUpdateTimestamp(Long updateTimestamp) {
this.updateTimestamp = updateTimestamp;
}
public DocumentDto setCurrentStepName(String currentStepName) {
this.currentStepName = currentStepName;
return this;
}
public String getHighlight() {
return highlight;
}
public DocumentDto setHighlight(String highlight) {
this.highlight = highlight;
return this;
}
} }

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Group DTO. * Group DTO.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Tag DTO. * Tag DTO.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Route DTO. * Route DTO.

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Route model DTO. * Route model DTO.

View File

@ -1,10 +1,10 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
import com.sismics.docs.core.constant.RouteStepType; import com.sismics.docs.core.constant.RouteStepType;
import com.sismics.util.JsonUtil; import com.sismics.util.JsonUtil;
import jakarta.json.Json; import javax.json.Json;
import jakarta.json.JsonObjectBuilder; import javax.json.JsonObjectBuilder;
/** /**
* Route step DTO. * Route step DTO.
@ -62,11 +62,6 @@ public class RouteStepDto {
*/ */
private String validatorUserName; private String validatorUserName;
/**
* Transitions data.
*/
private String transitions;
/** /**
* Route ID. * Route ID.
*/ */
@ -171,15 +166,6 @@ public class RouteStepDto {
return this; return this;
} }
public String getTransitions() {
return transitions;
}
public RouteStepDto setTransitions(String transitions) {
this.transitions = transitions;
return this;
}
/** /**
* Transform in JSON. * Transform in JSON.
* *

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
/** /**
* Tag DTO. * Tag DTO.

View File

@ -0,0 +1,30 @@
package com.sismics.docs.core.dao.jpa.dto;
/**
* Tag stat DTO.
*
* @author bgamard
*/
public class TagStatDto extends TagDto {
private int count;
/**
* Getter of count.
*
* @return the count
*/
public int getCount() {
return count;
}
/**
* Setter of count.
*
* @param count count
*/
public void setCount(int count) {
this.count = count;
}
}

View File

@ -1,4 +1,4 @@
package com.sismics.docs.core.dao.dto; package com.sismics.docs.core.dao.jpa.dto;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;

View File

@ -0,0 +1,238 @@
package com.sismics.docs.core.dao.lucene;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.flexible.standard.QueryParserUtil;
import org.apache.lucene.queryparser.flexible.standard.StandardQueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import com.sismics.docs.core.model.context.AppContext;
import com.sismics.docs.core.model.jpa.Document;
import com.sismics.docs.core.model.jpa.File;
import com.sismics.docs.core.util.LuceneUtil;
import com.sismics.docs.core.util.LuceneUtil.LuceneRunnable;
/**
* Lucene DAO.
*
* @author bgamard
*/
public class LuceneDao {
/**
* Destroy and rebuild index.
*
* @param fileList List of files
*/
public void rebuildIndex(final List<Document> documentList, final List<File> fileList) {
LuceneUtil.handle(new LuceneRunnable() {
@Override
public void run(IndexWriter indexWriter) throws Exception {
// Empty index
indexWriter.deleteAll();
// Add all documents
for (Document document : documentList) {
org.apache.lucene.document.Document luceneDocument = getDocumentFromDocument(document);
indexWriter.addDocument(luceneDocument);
}
// Add all files
for (File file : fileList) {
org.apache.lucene.document.Document luceneDocument = getDocumentFromFile(file);
indexWriter.addDocument(luceneDocument);
}
}
});
}
/**
* Add document to the index.
*
* @param document Document to add
*/
public void createDocument(final Document document) {
LuceneUtil.handle(new LuceneRunnable() {
@Override
public void run(IndexWriter indexWriter) throws Exception {
org.apache.lucene.document.Document luceneDocument = getDocumentFromDocument(document);
indexWriter.addDocument(luceneDocument);
}
});
}
/**
* Add file to the index.
*
* @param file File to add
*/
public void createFile(final File file) {
LuceneUtil.handle(new LuceneRunnable() {
@Override
public void run(IndexWriter indexWriter) throws Exception {
org.apache.lucene.document.Document luceneDocument = getDocumentFromFile(file);
indexWriter.addDocument(luceneDocument);
}
});
}
/**
* Update document index.
*
* @param document Updated document
*/
public void updateDocument(final Document document) {
LuceneUtil.handle(new LuceneRunnable() {
@Override
public void run(IndexWriter indexWriter) throws Exception {
org.apache.lucene.document.Document luceneDocument = getDocumentFromDocument(document);
indexWriter.updateDocument(new Term("id", document.getId()), luceneDocument);
}
});
}
/**
* Delete document from the index.
*
* @param id Document ID to delete
*/
public void deleteDocument(final String id) {
LuceneUtil.handle(new LuceneRunnable() {
@Override
public void run(IndexWriter indexWriter) throws Exception {
indexWriter.deleteDocuments(new Term("id", id));
}
});
}
/**
* Search files.
*
* @param searchQuery Search query on title and description
* @param fullSearchQuery Search query on all fields
* @return List of document IDs
* @throws Exception
*/
public Set<String> search(String searchQuery, String fullSearchQuery) throws Exception {
// Escape query and add quotes so QueryParser generate a PhraseQuery
searchQuery = "\"" + QueryParserUtil.escape(searchQuery + " " + fullSearchQuery) + "\"";
fullSearchQuery = "\"" + QueryParserUtil.escape(fullSearchQuery) + "\"";
// Build search query
StandardQueryParser qpHelper = new StandardQueryParser(new StandardAnalyzer());
qpHelper.setPhraseSlop(100000); // PhraseQuery add terms
// Search on documents and files
BooleanQuery query = new BooleanQuery.Builder()
.add(qpHelper.parse(searchQuery, "title"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "description"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "subject"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "identifier"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "publisher"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "format"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "source"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "type"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "coverage"), Occur.SHOULD)
.add(qpHelper.parse(searchQuery, "rights"), Occur.SHOULD)
.add(qpHelper.parse(fullSearchQuery, "content"), Occur.SHOULD)
.build();
// Search
DirectoryReader directoryReader = AppContext.getInstance().getIndexingService().getDirectoryReader();
Set<String> documentIdList = new HashSet<>();
if (directoryReader == null) {
// The directory reader is not yet initialized (probably because there is nothing indexed)
return documentIdList;
}
IndexSearcher searcher = new IndexSearcher(directoryReader);
TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
ScoreDoc[] docs = topDocs.scoreDocs;
// Extract document IDs
for (ScoreDoc doc : docs) {
org.apache.lucene.document.Document document = searcher.doc(doc.doc);
String type = document.get("doctype");
String documentId = null;
if (type.equals("document")) {
documentId = document.get("id");
} else if (type.equals("file")) {
documentId = document.get("document_id");
}
documentIdList.add(documentId);
}
return documentIdList;
}
/**
* Build Lucene document from database document.
*
* @param document Document
* @return Document
*/
private org.apache.lucene.document.Document getDocumentFromDocument(Document document) {
org.apache.lucene.document.Document luceneDocument = new org.apache.lucene.document.Document();
luceneDocument.add(new StringField("id", document.getId(), Field.Store.YES));
luceneDocument.add(new StringField("doctype", "document", Field.Store.YES));
luceneDocument.add(new TextField("title", document.getTitle(), Field.Store.NO));
if (document.getDescription() != null) {
luceneDocument.add(new TextField("description", document.getDescription(), Field.Store.NO));
}
if (document.getSubject() != null) {
luceneDocument.add(new TextField("subject", document.getSubject(), Field.Store.NO));
}
if (document.getIdentifier() != null) {
luceneDocument.add(new TextField("identifier", document.getIdentifier(), Field.Store.NO));
}
if (document.getPublisher() != null) {
luceneDocument.add(new TextField("publisher", document.getPublisher(), Field.Store.NO));
}
if (document.getFormat() != null) {
luceneDocument.add(new TextField("format", document.getFormat(), Field.Store.NO));
}
if (document.getSource() != null) {
luceneDocument.add(new TextField("source", document.getSource(), Field.Store.NO));
}
if (document.getType() != null) {
luceneDocument.add(new TextField("type", document.getType(), Field.Store.NO));
}
if (document.getCoverage() != null) {
luceneDocument.add(new TextField("coverage", document.getCoverage(), Field.Store.NO));
}
if (document.getRights() != null) {
luceneDocument.add(new TextField("rights", document.getRights(), Field.Store.NO));
}
return luceneDocument;
}
/**
* Build Lucene document from file.
*
* @param file File
* @return Document
*/
private org.apache.lucene.document.Document getDocumentFromFile(File file) {
org.apache.lucene.document.Document luceneDocument = new org.apache.lucene.document.Document();
luceneDocument.add(new StringField("id", file.getId(), Field.Store.YES));
luceneDocument.add(new StringField("doctype", "file", Field.Store.YES));
luceneDocument.add(new StringField("document_id", file.getDocumentId(), Field.Store.YES));
if (file.getContent() != null) {
luceneDocument.add(new TextField("content", file.getContent(), Field.Store.NO));
}
return luceneDocument;
}
}

View File

@ -1,9 +0,0 @@
package com.sismics.docs.core.event;
/**
* ACL created event.
*
* @author bgamard
*/
public class AclCreatedAsyncEvent extends AclEvent {
}

View File

@ -1,9 +0,0 @@
package com.sismics.docs.core.event;
/**
* ACL deleted event.
*
* @author bgamard
*/
public class AclDeletedAsyncEvent extends AclEvent {
}

View File

@ -1,62 +0,0 @@
package com.sismics.docs.core.event;
import com.google.common.base.MoreObjects;
import com.sismics.docs.core.constant.PermType;
/**
* ACL event.
*
* @author bgamard
*/
public abstract class AclEvent extends UserEvent {
/**
* Source ID.
*/
private String sourceId;
/**
* Permission type.
*/
private PermType perm;
/**
* Target ID.
*/
private String targetId;
public String getSourceId() {
return sourceId;
}
public AclEvent setSourceId(String sourceId) {
this.sourceId = sourceId;
return this;
}
public PermType getPerm() {
return perm;
}
public AclEvent setPerm(PermType permType) {
this.perm = permType;
return this;
}
public String getTargetId() {
return targetId;
}
public AclEvent setTargetId(String targetId) {
this.targetId = targetId;
return this;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("sourceId", sourceId)
.add("perm", perm)
.add("targetId", targetId)
.toString();
}
}

View File

@ -1,6 +1,7 @@
package com.sismics.docs.core.event; package com.sismics.docs.core.event;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.sismics.docs.core.model.jpa.Document;
/** /**
* Document created event. * Document created event.
@ -9,22 +10,32 @@ import com.google.common.base.MoreObjects;
*/ */
public class DocumentCreatedAsyncEvent extends UserEvent { public class DocumentCreatedAsyncEvent extends UserEvent {
/** /**
* Document ID. * Created document.
*/ */
private String documentId; private Document document;
public String getDocumentId() { /**
return documentId; * Getter of document.
*
* @return the document
*/
public Document getDocument() {
return document;
} }
public void setDocumentId(String documentId) { /**
this.documentId = documentId; * Setter of document.
*
* @param document document
*/
public void setDocument(Document document) {
this.document = document;
} }
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("documentId", documentId) .add("document", document)
.toString(); .toString();
} }
} }

View File

@ -1,9 +1,78 @@
package com.sismics.docs.core.event; package com.sismics.docs.core.event;
import java.io.InputStream;
import java.nio.file.Path;
import com.google.common.base.MoreObjects;
import com.sismics.docs.core.model.jpa.File;
/** /**
* New file created event. * New file created event.
* *
* @author bgamard * @author bgamard
*/ */
public class FileCreatedAsyncEvent extends FileEvent { public class FileCreatedAsyncEvent extends UserEvent {
/**
* Created file.
*/
private File file;
/**
* Language of the file.
*/
private String language;
/**
* Unencrypted original file.
*/
private Path unencryptedFile;
/**
* Unencrypted file containing PDF representation
* of the original file. May be null if the PDF conversion is not
* necessary or not possible.
*/
private Path unencryptedPdfFile;
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public Path getUnencryptedFile() {
return unencryptedFile;
}
public FileCreatedAsyncEvent setUnencryptedFile(Path unencryptedFile) {
this.unencryptedFile = unencryptedFile;
return this;
}
public Path getUnencryptedPdfFile() {
return unencryptedPdfFile;
}
public FileCreatedAsyncEvent setUnencryptedPdfFile(Path unencryptedPdfFile) {
this.unencryptedPdfFile = unencryptedPdfFile;
return this;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("file", file)
.add("language", language)
.toString();
}
} }

View File

@ -1,6 +1,7 @@
package com.sismics.docs.core.event; package com.sismics.docs.core.event;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.sismics.docs.core.model.jpa.File;
/** /**
* File deleted event. * File deleted event.
@ -9,33 +10,22 @@ import com.google.common.base.MoreObjects;
*/ */
public class FileDeletedAsyncEvent extends UserEvent { public class FileDeletedAsyncEvent extends UserEvent {
/** /**
* File ID. * Deleted file.
*/ */
private String fileId; private File file;
private Long fileSize; public File getFile() {
return file;
public String getFileId() {
return fileId;
} }
public void setFileId(String fileId) { public void setFile(File file) {
this.fileId = fileId; this.file = file;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
} }
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("fileId", fileId) .add("file", file)
.add("fileSize", fileSize)
.toString(); .toString();
} }
} }

View File

@ -1,60 +0,0 @@
package com.sismics.docs.core.event;
import com.google.common.base.MoreObjects;
import java.nio.file.Path;
/**
* New file event.
*
* @author bgamard
*/
public abstract class FileEvent extends UserEvent {
/**
* File ID.
*/
private String fileId;
/**
* Language of the file.
*/
private String language;
/**
* Unencrypted original file.
*/
private Path unencryptedFile;
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public Path getUnencryptedFile() {
return unencryptedFile;
}
public FileEvent setUnencryptedFile(Path unencryptedFile) {
this.unencryptedFile = unencryptedFile;
return this;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("fileId", fileId)
.add("language", language)
.toString();
}
}

View File

@ -1,9 +0,0 @@
package com.sismics.docs.core.event;
/**
* New file created event.
*
* @author bgamard
*/
public class FileUpdatedAsyncEvent extends FileEvent {
}

View File

@ -1,7 +1,7 @@
package com.sismics.docs.core.event; package com.sismics.docs.core.event;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.sismics.docs.core.dao.dto.UserDto; import com.sismics.docs.core.dao.jpa.dto.UserDto;
import com.sismics.docs.core.model.jpa.PasswordRecovery; import com.sismics.docs.core.model.jpa.PasswordRecovery;
/** /**

Some files were not shown because too many files have changed in this diff Show More