mirror of
https://github.com/sismics/docs.git
synced 2025-12-14 18:26:17 +00:00
Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
516a5f03e3 | ||
|
|
992150804a | ||
|
|
e905aa76a0 | ||
|
|
940b365447 | ||
|
|
d4d1c35264 | ||
|
|
5b818c8258 | ||
|
|
dedfae7b33 | ||
|
|
aa91a7fe24 | ||
|
|
822a4ae776 | ||
|
|
c6eb1c813c | ||
|
|
0d50676586 | ||
|
|
a2a3297986 | ||
|
|
8bdab73ae9 | ||
|
|
4469bb7bee | ||
|
|
b2dc460b4b | ||
|
|
3b281a8c3f | ||
|
|
fe40a0a677 | ||
|
|
b8c2bd3564 | ||
|
|
be236313e9 | ||
|
|
7a285d11a5 | ||
|
|
6e56a0f568 | ||
|
|
10d5c4334b | ||
|
|
8a5e90e562 | ||
|
|
c7c7badaf0 | ||
|
|
183e86aad6 | ||
|
|
5fbbcfc888 | ||
|
|
5169deb005 | ||
|
|
98fa89bd80 | ||
|
|
db4f5f9011 | ||
|
|
33aaf8afd2 | ||
|
|
3902d6361e | ||
|
|
d8d5249a23 | ||
|
|
42828efa19 | ||
|
|
a75b40bbfb | ||
|
|
4ebf621e11 | ||
|
|
cee82f39c2 | ||
|
|
eb9e0e0543 | ||
|
|
35c3ee023b | ||
|
|
2134f116da | ||
|
|
feb3d15968 | ||
|
|
4910dfd527 | ||
|
|
dc5a157dad | ||
|
|
bf8411cc24 | ||
|
|
a9648f803c | ||
|
|
b2b4eed4fa | ||
|
|
7665eb6bf2 | ||
|
|
40c1ff0e1a | ||
|
|
6ceb1f6c02 | ||
|
|
8c37af6207 | ||
|
|
7baf5e44fd | ||
|
|
8fff672d2f | ||
|
|
d4fe719a2c | ||
|
|
108d5ae830 | ||
|
|
867c3207c5 | ||
|
|
0c257b763d | ||
|
|
58af2b00cb | ||
|
|
1d78ce4b72 | ||
|
|
26d9d826a3 | ||
|
|
bb9957be24 | ||
|
|
0dce279fd0 | ||
|
|
884239bc26 | ||
|
|
dfdd5f8d20 | ||
|
|
b5f0612e78 | ||
|
|
dc044e684d | ||
|
|
8f1dddb8a3 | ||
|
|
763f91fd4c | ||
|
|
dd1c06013b | ||
|
|
748659e78e | ||
|
|
b265b8b1e0 | ||
|
|
7b3c0915d8 | ||
|
|
d0335b6b16 | ||
|
|
6d35020840 | ||
|
|
cedd4b47b3 | ||
|
|
45a672ab0d | ||
|
|
6798e01f49 | ||
|
|
c0678e9a90 | ||
|
|
156e67bc52 | ||
|
|
9b1456e1a7 | ||
|
|
f9b61546ab | ||
|
|
1b3a33104a | ||
|
|
d819c05669 | ||
|
|
68729e3b54 | ||
|
|
90a3d7aa68 | ||
|
|
b3349176d9 | ||
|
|
e72dab2a6e | ||
|
|
b54debe2e5 | ||
|
|
95ce4f0dc0 | ||
|
|
c9ba182a2e | ||
|
|
716954aa9a | ||
|
|
5c5a3f614f | ||
|
|
229d845a42 | ||
|
|
d1a8fa38b0 | ||
|
|
899f13cb35 | ||
|
|
0409c2ef79 | ||
|
|
83b065180f | ||
|
|
34a003d0e5 | ||
|
|
7b89bb449d | ||
|
|
4aca4ad495 | ||
|
|
99d44f2a92 | ||
|
|
c9606f98d3 | ||
|
|
af217b4831 | ||
|
|
f45f2d5df9 | ||
|
|
c8c4208bb4 | ||
|
|
dc8b8ae6c4 | ||
|
|
7aa4a1bf82 | ||
|
|
e2548ef6b1 | ||
|
|
abde9b7897 | ||
|
|
be1c2a7b90 | ||
|
|
55a4bb7621 | ||
|
|
37ca5ff84e | ||
|
|
d2256eabfa | ||
|
|
cbb8d4e1b6 | ||
|
|
785ad7f3a1 | ||
|
|
5d9b87dace | ||
|
|
feb5484cf6 | ||
|
|
3821a15f9d | ||
|
|
e5f85c931c | ||
|
|
6c99de1e89 | ||
|
|
3613f6f8de | ||
|
|
945e619d55 | ||
|
|
5220b13e7d | ||
|
|
7ea8d0c0f7 | ||
|
|
996585d7ac | ||
|
|
ce115eadbb | ||
|
|
aebdc9e208 | ||
|
|
b0bceefc0e | ||
|
|
bf37c5cb51 | ||
|
|
16215dde3b | ||
|
|
2ac10e8127 | ||
|
|
dcb924abac | ||
|
|
94e18146fd | ||
|
|
2a619849f4 | ||
|
|
1e57ee5fb3 | ||
|
|
db721a9d10 | ||
|
|
40951e8da0 | ||
|
|
f44b4bb0e0 | ||
|
|
b330d54ca2 | ||
|
|
2678ff4477 | ||
|
|
995e45d28f | ||
|
|
9ca27d7c12 | ||
|
|
4183dae458 | ||
|
|
5426be9fa0 | ||
|
|
9d8034e010 | ||
|
|
647ad841df | ||
|
|
a66a1e6f8e | ||
|
|
ebfd860458 | ||
|
|
740476460f | ||
|
|
2b6a14a348 | ||
|
|
77311f42cd | ||
|
|
a0e89103af | ||
|
|
5cdbe9338b | ||
|
|
f7b84238df | ||
|
|
8b039c61ed | ||
|
|
f227335e14 | ||
|
|
ce7a8590db | ||
|
|
d497fa8ed7 | ||
|
|
6b940c4366 | ||
|
|
f167e8ea0a | ||
|
|
de703531f6 | ||
|
|
c72f9fbdb1 | ||
|
|
09eaf18632 | ||
|
|
5cee20163d | ||
|
|
63c7e9710b | ||
|
|
6f27b9c13f | ||
|
|
76e68c09d8 | ||
|
|
aea389cd3d | ||
|
|
9ce18b128e | ||
|
|
a7c954c6bc | ||
|
|
a0880c4a16 | ||
|
|
2c90df2c2d | ||
|
|
71f15e1736 | ||
|
|
0b14ab5032 | ||
|
|
2771e56357 | ||
|
|
1479b818ea | ||
|
|
4f6de892b5 | ||
|
|
e540260377 | ||
|
|
f3f21bbf73 | ||
|
|
44a1389dd7 | ||
|
|
1b05261a97 | ||
|
|
d55334739c | ||
|
|
c511ed380e | ||
|
|
b59ecf0370 | ||
|
|
65b038afcd | ||
|
|
5fbde0dca0 | ||
|
|
ab69e502da | ||
|
|
52065dda6b | ||
|
|
7cd8e48145 | ||
|
|
2a7f143bbf | ||
|
|
4a676b01e1 | ||
|
|
18c9833104 | ||
|
|
7e2787704b | ||
|
|
b13c2ccd32 | ||
|
|
4795d8f48c | ||
|
|
808a06b0af | ||
|
|
70a42afab8 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,3 +11,6 @@
|
|||||||
*.iml
|
*.iml
|
||||||
node_modules
|
node_modules
|
||||||
import_test
|
import_test
|
||||||
|
docs-importer-linux
|
||||||
|
docs-importer-macos
|
||||||
|
docs-importer-win.exe
|
||||||
24
.travis.yml
24
.travis.yml
@@ -2,22 +2,24 @@ sudo: required
|
|||||||
dist: trusty
|
dist: trusty
|
||||||
language: java
|
language: java
|
||||||
before_install:
|
before_install:
|
||||||
|
- sudo add-apt-repository -y ppa:mc3man/trusty-media
|
||||||
- sudo apt-get -qq update
|
- 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 ffmpeg mediainfo 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 tesseract-ocr-nld
|
||||||
- sudo apt-get -y -q install haveged && sudo service haveged start
|
- sudo apt-get -y -q install haveged && sudo service haveged start
|
||||||
after_success:
|
after_success:
|
||||||
- mvn -Pprod -DskipTests clean install
|
- |
|
||||||
- docker login -u $DOCKER_USER -p $DOCKER_PASS
|
if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
|
||||||
- export REPO=sismics/docs
|
mvn -Pprod -DskipTests clean install
|
||||||
- export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`
|
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
- docker build -f Dockerfile -t $REPO:$COMMIT .
|
export REPO=sismics/docs
|
||||||
- docker tag $REPO:$COMMIT $REPO:$TAG
|
export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`
|
||||||
- docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
|
docker build -f Dockerfile -t $REPO:$COMMIT .
|
||||||
- docker push $REPO
|
docker tag $REPO:$COMMIT $REPO:$TAG
|
||||||
|
docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||||
|
docker push $REPO
|
||||||
|
fi
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- TESSDATA_PREFIX=/usr/share/tesseract-ocr
|
|
||||||
- LC_NUMERIC=C
|
|
||||||
- secure: LRGpjWORb0qy6VuypZjTAfA8uRHlFUMTwb77cenS9PPRBxuSnctC531asS9Xg3DqC5nsRxBBprgfCKotn5S8nBSD1ceHh84NASyzLSBft3xSMbg7f/2i7MQ+pGVwLncusBU6E/drnMFwZBleo+9M8Tf96axY5zuUp90MUTpSgt0=
|
- secure: LRGpjWORb0qy6VuypZjTAfA8uRHlFUMTwb77cenS9PPRBxuSnctC531asS9Xg3DqC5nsRxBBprgfCKotn5S8nBSD1ceHh84NASyzLSBft3xSMbg7f/2i7MQ+pGVwLncusBU6E/drnMFwZBleo+9M8Tf96axY5zuUp90MUTpSgt0=
|
||||||
- secure: bCDDR6+I7PmSkuTYZv1HF/z98ANX/SFEESUCqxVmV5Gs0zFC0vQXaPJQ2xaJNRop1HZBFMZLeMMPleb0iOs985smpvK2F6Rbop9Tu+Vyo0uKqv9tbZ7F8Nfgnv9suHKZlL84FNeUQZJX6vsFIYPEJ/r7K5P/M0PdUy++fEwxEhU=
|
- secure: bCDDR6+I7PmSkuTYZv1HF/z98ANX/SFEESUCqxVmV5Gs0zFC0vQXaPJQ2xaJNRop1HZBFMZLeMMPleb0iOs985smpvK2F6Rbop9Tu+Vyo0uKqv9tbZ7F8Nfgnv9suHKZlL84FNeUQZJX6vsFIYPEJ/r7K5P/M0PdUy++fEwxEhU=
|
||||||
- secure: ewXnzbkgCIHpDWtaWGMa1OYZJ/ki99zcIl4jcDPIC0eB3njX/WgfcC6i0Ke9mLqDqwXarWJ6helm22sNh+xtQiz6isfBtBX+novfRt9AANrBe3koCMUemMDy7oh5VflBaFNP0DVb8LSCnwf6dx6ZB5E9EB8knvk40quc/cXpGjY=
|
- secure: ewXnzbkgCIHpDWtaWGMa1OYZJ/ki99zcIl4jcDPIC0eB3njX/WgfcC6i0Ke9mLqDqwXarWJ6helm22sNh+xtQiz6isfBtBX+novfRt9AANrBe3koCMUemMDy7oh5VflBaFNP0DVb8LSCnwf6dx6ZB5E9EB8knvk40quc/cXpGjY=
|
||||||
|
|||||||
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# 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/
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
FROM sismics/jetty:9.2.20-jdk7
|
FROM sismics/ubuntu-jetty:9.4.12
|
||||||
MAINTAINER b.gamard@sismics.com
|
MAINTAINER b.gamard@sismics.com
|
||||||
|
|
||||||
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 && \
|
RUN apt-get update && apt-get -y -q install ffmpeg mediainfo 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 tesseract-ocr-nld && \
|
||||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV TESSDATA_PREFIX /usr/share/tesseract-ocr
|
# Remove the embedded javax.mail jar from Jetty
|
||||||
ENV LC_NUMERIC C
|
RUN rm -f /opt/jetty/lib/mail/javax.mail.glassfish-*.jar
|
||||||
|
|
||||||
ADD docs.xml /opt/jetty/webapps/docs.xml
|
ADD docs.xml /opt/jetty/webapps/docs.xml
|
||||||
ADD docs-web/target/docs-web-*.war /opt/jetty/webapps/docs.war
|
ADD docs-web/target/docs-web-*.war /opt/jetty/webapps/docs.war
|
||||||
|
|||||||
68
README.md
68
README.md
@@ -8,13 +8,15 @@
|
|||||||
|
|
||||||
Docs 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.
|
||||||
|
|
||||||
|
**Discuss it on [Product Hunt](https://www.producthunt.com/posts/sismics-docs) 🦄**
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<h2 align="center">
|
<h2 align="center">
|
||||||
✨ We just launched a Cloud version of Sismics Docs! Head to <a href="https://www.sismicsdocs.com/">sismicsdocs.com</a> for more informations ✨
|
✨ 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 />
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Demo
|
Demo
|
||||||
----
|
----
|
||||||
@@ -29,15 +31,17 @@ Features
|
|||||||
|
|
||||||
- Responsive user interface
|
- Responsive user interface
|
||||||
- Optical character recognition
|
- Optical character recognition
|
||||||
- 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
|
||||||
- Workflow system 
|
- Workflow system 
|
||||||
- 256-bit AES encryption of stored files
|
- 256-bit AES encryption of stored files
|
||||||
|
- File versioning 
|
||||||
- Tag system with nesting
|
- Tag system with nesting
|
||||||
- Import document from email (EML format) 
|
- Import document from email (EML format)
|
||||||
- Automatic inbox scanning and importing 
|
- Automatic inbox scanning and importing
|
||||||
- User/group permission system
|
- User/group permission system
|
||||||
- 2-factor authentication
|
- 2-factor authentication
|
||||||
- Hierarchical groups
|
- Hierarchical groups
|
||||||
@@ -46,29 +50,41 @@ Features
|
|||||||
- 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
|
||||||
- [Mass files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode) 
|
- [Bulk files importer](https://github.com/sismics/docs/tree/master/docs-importer) (single or scan mode)
|
||||||
- Tested to 100k documents
|
- Tested to one million documents
|
||||||
|
|
||||||
Download
|
|
||||||
--------
|
|
||||||
|
|
||||||
The latest release is downloadable here: <https://github.com/sismics/docs/releases> in WAR format.
|
|
||||||
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.
|
|
||||||
|
|
||||||
Install with Docker
|
Install with Docker
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
From a Docker host, run this command to download and install Sismics Docs. The server will run on <http://[your-docker-host-ip]:8100>.
|
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.
|
**The default admin password is "admin". Don't forget to change it before going to production.**
|
||||||
|
|
||||||
docker run --rm --name sismics_docs_latest -d -p 8100:8080 -v sismics_docs_latest:/data sismics/docs:latest
|
docker run --rm --name sismics_docs_latest -d -e DOCS_BASE_URL='http://[your-docker-host-ip]:8100' -p 8100:8080 -v sismics_docs_latest:/data sismics/docs:latest
|
||||||
|
<img src="http://www.newdesignfile.com/postpic/2011/01/green-info-icon_206509.png" width="16px" height="16px"> **Note:** You will need to change [your-docker-host-ip] with the IP address or FQDN of your docker host e.g.
|
||||||
|
|
||||||
|
FQDN: http://docs.sismics.com
|
||||||
|
IP: http://192.168.100.10
|
||||||
|
|
||||||
|
Manual installation
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
- Java 8 with the [Java Cryptography Extension](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html)
|
||||||
|
- Tesseract 3 or 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 default admin password is "admin". Don't forget to change it before going to production.**
|
||||||
|
|
||||||
How to build Docs from the sources
|
How to build Docs from the sources
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
Prerequisites: JDK 7 with JCE, Maven 3, Tesseract 3.02
|
Prerequisites: JDK 8 with JCE, Maven 3, Tesseract 3 or 4
|
||||||
|
|
||||||
Docs is organized in several Maven modules:
|
Docs is organized in several Maven modules:
|
||||||
|
|
||||||
@@ -99,6 +115,24 @@ From the `docs-web` directory:
|
|||||||
|
|
||||||
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
|
||||||
|
------------
|
||||||
|
|
||||||
|
All contributions are more than welcomed. Contributions may close an issue, fix a bug (reported or not reported), improve the existing code, add new feature, and so on.
|
||||||
|
|
||||||
|
The `master` branch is the default and base branch for the project. It is used for development and all Pull Requests should go there.
|
||||||
|
|
||||||
|
|
||||||
|
Community
|
||||||
|
---------
|
||||||
|
|
||||||
|
Get updates on Sismics Docs' development and chat with the project maintainers:
|
||||||
|
|
||||||
|
- Follow [@sismicsdocs on Twitter](https://twitter.com/sismicsdocs)
|
||||||
|
- Read and subscribe to [The Official Sismics Docs Blog](https://blog.sismicsdocs.com/)
|
||||||
|
- Check the [Official Website](https://www.sismicsdocs.com)
|
||||||
|
- Join us [on Facebook](https://www.facebook.com/sismicsdocs)
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
classpath 'com.android.tools.build:gradle:3.3.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
@@ -15,11 +15,11 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 26
|
compileSdkVersion 28
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 28
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName '1.0'
|
versionName '1.0'
|
||||||
}
|
}
|
||||||
@@ -30,14 +30,14 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
implementation fileTree(dir: 'libs', include: '*.jar')
|
||||||
compile 'com.android.support:appcompat-v7:26.1.0'
|
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||||
compile 'com.android.support:recyclerview-v7:26.1.0'
|
implementation 'com.android.support:recyclerview-v7:28.0.0'
|
||||||
compile 'com.android.support:design:26.1.0'
|
implementation 'com.android.support:design:28.0.0'
|
||||||
compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
|
implementation 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
|
||||||
compile 'org.greenrobot:eventbus:3.0.0'
|
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
implementation 'com.squareup.picasso:picasso:2.5.2'
|
||||||
compile 'com.squareup.okhttp3:okhttp:3.7.0'
|
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||||
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.0'
|
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0'
|
||||||
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
|
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<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"
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
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" />
|
||||||
@@ -43,6 +45,9 @@
|
|||||||
<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"
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class AuditLogActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure the swipe refresh layout
|
// Configure the swipe refresh layout
|
||||||
SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.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 = (ListView) findViewById(R.id.auditLogListView);
|
final ListView auditLogListView = 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 = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
|
final SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
|
||||||
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
final ProgressBar progressBar = findViewById(R.id.progressBar);
|
||||||
final ListView auditLogListView = (ListView) findViewById(R.id.auditLogListView);
|
final ListView auditLogListView = 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(response.optJSONArray("logs")));
|
auditLogListView.setAdapter(new AuditLogListAdapter(AuditLogActivity.this, response.optJSONArray("logs")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ 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;
|
||||||
@@ -61,7 +63,10 @@ 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 = (DrawerLayout) findViewById(R.id.drawer_layout);
|
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);
|
||||||
@@ -75,15 +80,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 = (TextView) findViewById(R.id.usernameTextView);
|
TextView usernameTextView = findViewById(R.id.usernameTextView);
|
||||||
usernameTextView.setText(userInfo.optString("username"));
|
usernameTextView.setText(userInfo.optString("username"));
|
||||||
TextView emailTextView = (TextView) findViewById(R.id.emailTextView);
|
TextView emailTextView = 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 = (ListView) findViewById(R.id.tagListView);
|
final ListView tagListView = findViewById(R.id.tagListView);
|
||||||
final View tagProgressView = findViewById(R.id.tagProgressView);
|
final View tagProgressView = findViewById(R.id.tagProgressView);
|
||||||
final TextView tagEmptyView = (TextView) findViewById(R.id.tagEmptyView);
|
final TextView tagEmptyView = 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) {
|
||||||
@@ -145,6 +150,15 @@ 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);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
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;
|
||||||
@@ -30,12 +28,19 @@ 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(JSONArray logs) {
|
public AuditLogListAdapter(Context context, 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++) {
|
||||||
@@ -67,11 +72,21 @@ public class AuditLogListAdapter extends BaseAdapter {
|
|||||||
|
|
||||||
// Build message
|
// Build message
|
||||||
final JSONObject log = getItem(position);
|
final JSONObject log = getItem(position);
|
||||||
StringBuilder message = new StringBuilder(log.optString("class"));
|
StringBuilder message = new StringBuilder();
|
||||||
|
|
||||||
|
// 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(" created"); break;
|
case "CREATE": message.append(context.getResources().getString(R.string.auditlog_created)); break;
|
||||||
case "UPDATE": message.append(" updated"); break;
|
case "UPDATE": message.append(context.getResources().getString(R.string.auditlog_updated)); break;
|
||||||
case "DELETE": message.append(" deleted"); break;
|
case "DELETE": message.append(context.getResources().getString(R.string.auditlog_deleted)); break;
|
||||||
}
|
}
|
||||||
switch (log.optString("class")) {
|
switch (log.optString("class")) {
|
||||||
case "Document":
|
case "Document":
|
||||||
@@ -85,9 +100,9 @@ public class AuditLogListAdapter extends BaseAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill the view
|
// Fill the view
|
||||||
TextView usernameTextView = (TextView) view.findViewById(R.id.usernameTextView);
|
TextView usernameTextView = view.findViewById(R.id.usernameTextView);
|
||||||
TextView messageTextView = (TextView) view.findViewById(R.id.messageTextView);
|
TextView messageTextView = view.findViewById(R.id.messageTextView);
|
||||||
TextView dateTextView = (TextView) view.findViewById(R.id.dateTextView);
|
TextView dateTextView = 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")));
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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;
|
||||||
@@ -9,12 +10,10 @@ 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;
|
||||||
@@ -46,11 +45,6 @@ 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;
|
||||||
@@ -60,11 +54,11 @@ public class DocListFragment extends Fragment {
|
|||||||
private int previousTotal = 0;
|
private int previousTotal = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull 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 = (EmptyRecyclerView) view.findViewById(R.id.docList);
|
recyclerView = view.findViewById(R.id.docList);
|
||||||
adapter = new DocListAdapter();
|
adapter = new DocListAdapter();
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
recyclerView.setHasFixedSize(true);
|
recyclerView.setHasFixedSize(true);
|
||||||
@@ -122,16 +116,6 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
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;
|
||||||
@@ -29,7 +31,8 @@ import okhttp3.internal.Util;
|
|||||||
* @author bgamard
|
* @author bgamard
|
||||||
*/
|
*/
|
||||||
public class FileUploadService extends IntentService {
|
public class FileUploadService extends IntentService {
|
||||||
private static final String TAG = "FileUploadService";
|
private static final String TAG = "sismicsdocs:fileupload";
|
||||||
|
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;
|
||||||
@@ -49,18 +52,30 @@ public class FileUploadService extends IntentService {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
notification = new NotificationCompat.Builder(this);
|
initChannels();
|
||||||
|
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();
|
wakeLock.acquire(60_000 * 30); // 30 minutes upload time maximum
|
||||||
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));
|
||||||
@@ -77,7 +92,7 @@ public class FileUploadService extends IntentService {
|
|||||||
*
|
*
|
||||||
* @param documentId Document ID
|
* @param documentId Document ID
|
||||||
* @param uri Data URI
|
* @param uri Data URI
|
||||||
* @throws IOException
|
* @throws IOException e
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
docs-android/app/src/main/res/drawable-xhdpi/deu.png
Normal file
BIN
docs-android/app/src/main/res/drawable-xhdpi/deu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
BIN
docs-android/app/src/main/res/drawable-xxhdpi/deu.png
Normal file
BIN
docs-android/app/src/main/res/drawable-xxhdpi/deu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -1,6 +1,5 @@
|
|||||||
<?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">
|
||||||
|
|
||||||
@@ -37,17 +36,4 @@
|
|||||||
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>
|
||||||
@@ -6,11 +6,47 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<fragment
|
<android.support.design.widget.CoordinatorLayout
|
||||||
android:id="@+id/main_fragment"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/overview_coordinator_layout"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
class="com.sismics.docs.fragment.DocListFragment"/>
|
|
||||||
|
<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/ThemeOverlay.AppCompat.Light"
|
||||||
|
app:layout_scrollFlags="enterAlways|scroll|snap" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/main_fragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
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"
|
||||||
|
|||||||
159
docs-android/app/src/main/res/values-de/strings.xml
Normal file
159
docs-android/app/src/main/res/values-de/strings.xml
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?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 Sismics Docs 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">Sismics Docs</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">Sismics Docs Datei Export</string>
|
||||||
|
<string name="download_document_title">Sismics Docs Dokumentenexport</string>
|
||||||
|
<string name="download_pdf_title">Sismics Docs 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>
|
||||||
@@ -141,4 +141,19 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
<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="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>
|
||||||
@@ -144,4 +145,19 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<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.NoActionBar">
|
<style name="AppThemeDark" parent="Theme.AppCompat.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>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#Tue Nov 14 23:55:56 CET 2017
|
#Wed Jan 30 16:31:31 CET 2019
|
||||||
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-4.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.sismics.docs</groupId>
|
<groupId>com.sismics.docs</groupId>
|
||||||
<artifactId>docs-parent</artifactId>
|
<artifactId>docs-parent</artifactId>
|
||||||
<version>1.5</version>
|
<version>1.6-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -112,10 +112,25 @@
|
|||||||
<artifactId>lucene-queryparser</artifactId>
|
<artifactId>lucene-queryparser</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-suggest</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.lucene</groupId>
|
||||||
|
<artifactId>lucene-highlighter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sun.mail</groupId>
|
<groupId>com.sun.mail</groupId>
|
||||||
<artifactId>javax.mail</artifactId>
|
<artifactId>javax.mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Only there to read old index and rebuild them -->
|
<!-- Only there to read old index and rebuild them -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -138,35 +153,41 @@
|
|||||||
<artifactId>bcprov-jdk15on</artifactId>
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>fr.opensagres.xdocreport</groupId>
|
<groupId>fr.opensagres.xdocreport</groupId>
|
||||||
<artifactId>org.odftoolkit.odfdom.converter.pdf</artifactId>
|
<artifactId>fr.opensagres.odfdom.converter.pdf</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>fr.opensagres.xdocreport</groupId>
|
|
||||||
<artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.jna</groupId>
|
<groupId>fr.opensagres.xdocreport</groupId>
|
||||||
<artifactId>jna</artifactId>
|
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</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-core</artifactId>
|
<artifactId>jai-imageio-jpeg2000</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 -->
|
||||||
@@ -209,20 +230,6 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -21,14 +21,9 @@ public class Constants {
|
|||||||
public static final String DEFAULT_ADMIN_PASSWORD = "$2a$05$6Ny3TjrW3aVAL1or2SlcR.fhuDgPKp5jp.P9fBXwVNePgeLqb4i3C";
|
public static final String DEFAULT_ADMIN_PASSWORD = "$2a$05$6Ny3TjrW3aVAL1or2SlcR.fhuDgPKp5jp.P9fBXwVNePgeLqb4i3C";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RAM Lucene directory storage.
|
* Administrator's default email.
|
||||||
*/
|
*/
|
||||||
public static final String LUCENE_DIRECTORY_STORAGE_RAM = "RAM";
|
public static final String DEFAULT_ADMIN_EMAIL = "admin@localhost";
|
||||||
|
|
||||||
/**
|
|
||||||
* File Lucene directory storage.
|
|
||||||
*/
|
|
||||||
public static final String LUCENE_DIRECTORY_STORAGE_FILE = "FILE";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guest user ID.
|
* Guest user ID.
|
||||||
@@ -43,7 +38,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");
|
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");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL environment variable.
|
* Base URL environment variable.
|
||||||
@@ -73,6 +68,11 @@ 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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expiration time of the password recovery in hours.
|
* Expiration time of the password recovery in hours.
|
||||||
*/
|
*/
|
||||||
@@ -87,4 +87,9 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.dto.AclDto;
|
import com.sismics.docs.core.dao.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 javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
@@ -68,17 +69,22 @@ public class AclDao {
|
|||||||
public List<AclDto> getBySourceId(String sourceId, AclType type) {
|
public List<AclDto> getBySourceId(String sourceId, AclType type) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
StringBuilder sb = new StringBuilder("select a.ACL_ID_C, a.ACL_PERM_C, a.ACL_TARGETID_C, ")
|
StringBuilder sb = new StringBuilder("select a.ACL_ID_C, a.ACL_PERM_C, a.ACL_TARGETID_C, ")
|
||||||
.append(" u.USE_USERNAME_C, s.SHA_ID_C, s.SHA_NAME_C, g.GRP_NAME_C ")
|
.append(" u.USE_USERNAME_C, s.SHA_ID_C, s.SHA_NAME_C, g.GRP_NAME_C ")
|
||||||
.append(" from T_ACL a ")
|
.append(" from T_ACL a ")
|
||||||
.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 and a.ACL_TYPE_C = :type ");
|
.append(" where a.ACL_DELETEDATE_D is null and a.ACL_SOURCEID_C = :sourceId ");
|
||||||
|
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);
|
||||||
q.setParameter("type", type.name());
|
if (type != null) {
|
||||||
|
q.setParameter("type", type.name());
|
||||||
|
}
|
||||||
List<Object[]> l = q.getResultList();
|
List<Object[]> l = q.getResultList();
|
||||||
|
|
||||||
// Assemble results
|
// Assemble results
|
||||||
@@ -119,12 +125,17 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
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 ");
|
sb.append(" select a.ACL_ID_C from T_ACL a, T_DOCUMENT_TAG dt, T_DOCUMENT d ");
|
||||||
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(" 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(" 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);
|
||||||
@@ -1,20 +1,10 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.AuditLogCriteria;
|
import com.sismics.docs.core.dao.criteria.AuditLogCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.AuditLogDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -22,6 +12,10 @@ 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 javax.persistence.EntityManager;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Audit log DAO.
|
* Audit log DAO.
|
||||||
*
|
*
|
||||||
@@ -33,7 +27,6 @@ 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
|
||||||
@@ -53,10 +46,9 @@ 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<String, Object>();
|
Map<String, Object> parameterMap = new HashMap<>();
|
||||||
|
|
||||||
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 ");
|
||||||
@@ -73,10 +65,15 @@ public class AuditLogDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (criteria.getUserId() != null) {
|
if (criteria.getUserId() != null) {
|
||||||
// Get all logs originating from the user, not necessarly on owned items
|
if (criteria.isAdmin()) {
|
||||||
// Filter out ACL logs
|
// For admin users, display all logs except ACL logs
|
||||||
queries.add(baseQuery + " where l.LOG_IDUSER_C = :userId and l.LOG_CLASSENTITY_C != 'Acl' ");
|
queries.add(baseQuery + " where l.LOG_CLASSENTITY_C != 'Acl' ");
|
||||||
parameterMap.put("userId", criteria.getUserId());
|
} else {
|
||||||
|
// Get all logs originating from the user, not necessarly on owned items
|
||||||
|
// Filter out ACL logs
|
||||||
|
queries.add(baseQuery + " where l.LOG_IDUSER_C = :userId and l.LOG_CLASSENTITY_C != 'Acl' ");
|
||||||
|
parameterMap.put("userId", criteria.getUserId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the search
|
// Perform the search
|
||||||
@@ -84,7 +81,7 @@ public class AuditLogDao {
|
|||||||
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<AuditLogDto>();
|
List<AuditLogDto> auditLogDtoList = new ArrayList<>();
|
||||||
for (Object[] o : l) {
|
for (Object[] o : l) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
AuditLogDto auditLogDto = new AuditLogDto();
|
AuditLogDto auditLogDto = new AuditLogDto();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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;
|
||||||
@@ -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 ato.AUT_LASTCONNECTIONDATE_D = :currentDate ");
|
sb.append(" set 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();
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
|
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 javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.NoResultException;
|
||||||
|
import javax.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.
|
||||||
*
|
*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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;
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.sismics.docs.core.dao.dto.ContributorDto;
|
||||||
import java.util.List;
|
import com.sismics.docs.core.model.jpa.Contributor;
|
||||||
import java.util.UUID;
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
import java.util.ArrayList;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.ContributorDto;
|
import java.util.List;
|
||||||
import com.sismics.docs.core.model.jpa.Contributor;
|
import java.util.UUID;
|
||||||
import com.sismics.util.context.ThreadLocalContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contributor DAO.
|
* Contributor DAO.
|
||||||
@@ -1,25 +1,19 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.DocumentCriteria;
|
import com.sismics.docs.core.dao.dto.DocumentDto;
|
||||||
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 javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.*;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document DAO.
|
* Document DAO.
|
||||||
@@ -37,6 +31,7 @@ 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();
|
||||||
@@ -50,16 +45,20 @@ 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
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<Document> findAll() {
|
public List<Document> findAll(int offset, int limit) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
Query q = em.createQuery("select d from Document d where d.deleteDate is null");
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of all active documents from a user.
|
* Returns the list of all active documents from a user.
|
||||||
*
|
*
|
||||||
@@ -89,14 +88,14 @@ 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_LANGUAGE_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_UPDATEDATE_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), ");
|
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(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(" (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(" 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 ");
|
||||||
sb.append(" where d.DOC_ID_C = :id and d.DOC_DELETEDATE_D is null ");
|
sb.append(" where d.DOC_ID_C = :id and d.DOC_DELETEDATE_D is null ");
|
||||||
|
|
||||||
Query q = em.createNativeQuery(sb.toString());
|
Query q = em.createNativeQuery(sb.toString());
|
||||||
q.setParameter("id", id);
|
q.setParameter("id", id);
|
||||||
|
|
||||||
@@ -121,6 +120,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.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());
|
||||||
@@ -189,113 +189,35 @@ public class DocumentDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches documents by criteria.
|
* Update a document and log the action.
|
||||||
*
|
|
||||||
* @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
|
||||||
* @return Updated document
|
* @return Updated document
|
||||||
*/
|
*/
|
||||||
public Document update(Document document, String userId) {
|
public Document update(Document document, String userId) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
Document documentDb = updateSilently(document);
|
||||||
|
|
||||||
|
// Create audit log
|
||||||
|
AuditLogUtil.create(documentDb, AuditLogType.UPDATE, userId);
|
||||||
|
|
||||||
|
return documentDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a document without audit log.
|
||||||
|
*
|
||||||
|
* @param document Document to update
|
||||||
|
* @return Updated document
|
||||||
|
*/
|
||||||
|
public Document updateSilently(Document document) {
|
||||||
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
|
|
||||||
// Get the document
|
// Get the document
|
||||||
Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null");
|
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 = (Document) q.getSingleResult();
|
Document documentDb = (Document) q.getSingleResult();
|
||||||
|
|
||||||
// Update the document
|
// Update the document
|
||||||
documentDb.setTitle(document.getTitle());
|
documentDb.setTitle(document.getTitle());
|
||||||
documentDb.setDescription(document.getDescription());
|
documentDb.setDescription(document.getDescription());
|
||||||
@@ -309,10 +231,9 @@ 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());
|
||||||
// Create audit log
|
documentDb.setUpdateDate(new Date());
|
||||||
AuditLogUtil.create(documentDb, AuditLogType.UPDATE, userId);
|
|
||||||
|
|
||||||
return documentDb;
|
return documentDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
import com.sismics.docs.core.constant.AuditLogType;
|
import com.sismics.docs.core.constant.AuditLogType;
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
@@ -42,13 +42,17 @@ public class FileDao {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of all files.
|
* Returns the list of all files.
|
||||||
*
|
*
|
||||||
|
* @param offset Offset
|
||||||
|
* @param limit Limit
|
||||||
* @return List of files
|
* @return List of files
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<File> findAll() {
|
public List<File> findAll(int offset, int limit) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
Query q = em.createQuery("select f from File f where f.deleteDate is null");
|
Query q = em.createQuery("select f from File f where f.deleteDate is null");
|
||||||
|
q.setFirstResult(offset);
|
||||||
|
q.setMaxResults(limit);
|
||||||
return q.getResultList();
|
return q.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,10 +144,13 @@ public class FileDao {
|
|||||||
|
|
||||||
// Update the file
|
// Update the file
|
||||||
fileDb.setDocumentId(file.getDocumentId());
|
fileDb.setDocumentId(file.getDocumentId());
|
||||||
|
fileDb.setName(file.getName());
|
||||||
fileDb.setContent(file.getContent());
|
fileDb.setContent(file.getContent());
|
||||||
fileDb.setOrder(file.getOrder());
|
fileDb.setOrder(file.getOrder());
|
||||||
fileDb.setMimeType(file.getMimeType());
|
fileDb.setMimeType(file.getMimeType());
|
||||||
|
fileDb.setVersionId(file.getVersionId());
|
||||||
|
fileDb.setLatestVersion(file.isLatestVersion());
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,12 +182,26 @@ public class FileDao {
|
|||||||
public List<File> getByDocumentId(String userId, String documentId) {
|
public List<File> getByDocumentId(String userId, String documentId) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
if (documentId == null) {
|
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");
|
Query 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");
|
||||||
q.setParameter("userId", userId);
|
q.setParameter("userId", userId);
|
||||||
return q.getResultList();
|
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");
|
Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.latestVersion = true and f.deleteDate is null order by f.order asc");
|
||||||
q.setParameter("documentId", documentId);
|
q.setParameter("documentId", documentId);
|
||||||
return q.getResultList();
|
return q.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all files from a version.
|
||||||
|
*
|
||||||
|
* @param versionId Version ID
|
||||||
|
* @return List of files
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public List<File> getByVersionId(String versionId) {
|
||||||
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
|
Query q = em.createQuery("select f from File f where f.versionId = :versionId and f.deleteDate is null order by f.order asc");
|
||||||
|
q.setParameter("versionId", versionId);
|
||||||
|
return q.getResultList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.GroupCriteria;
|
import com.sismics.docs.core.dao.criteria.GroupCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.GroupDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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;
|
||||||
@@ -1,17 +1,12 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.sismics.docs.core.dao.dto.RelationDto;
|
||||||
import java.util.Date;
|
import com.sismics.docs.core.model.jpa.Relation;
|
||||||
import java.util.List;
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
import java.util.*;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.RelationDto;
|
|
||||||
import com.sismics.docs.core.model.jpa.Relation;
|
|
||||||
import com.sismics.util.context.ThreadLocalContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relation DAO.
|
* Relation DAO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.sismics.util.context.ThreadLocalContext;
|
import com.sismics.util.context.ThreadLocalContext;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.RouteCriteria;
|
import com.sismics.docs.core.dao.criteria.RouteCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.RouteDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -95,12 +95,12 @@ public class RouteDao {
|
|||||||
public void deleteRoute(String routeId) {
|
public void deleteRoute(String routeId) {
|
||||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||||
|
|
||||||
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")
|
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 r.RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null")
|
em.createNativeQuery("update T_ROUTE r set 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();
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.RouteModelCriteria;
|
import com.sismics.docs.core.dao.criteria.RouteModelCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.RouteModelDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -124,6 +125,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()) {
|
if (!criteriaList.isEmpty()) {
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.RouteStepCriteria;
|
import com.sismics.docs.core.dao.criteria.RouteStepCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.RouteStepDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -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_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_TRANSITIONS_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 ")
|
||||||
@@ -124,7 +124,8 @@ 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;
|
||||||
@@ -140,7 +141,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 r.RTP_ENDDATE_D = :endDate, r.RTP_TRANSITION_C = :transition, r.RTP_COMMENT_C = :comment, r.RTP_IDVALIDATORUSER_C = :validatorUserId ");
|
sb.append(" set RTP_ENDDATE_D = :endDate, RTP_TRANSITION_C = :transition, RTP_COMMENT_C = :comment, 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();
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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 javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.Query;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Share DAO.
|
* Share DAO.
|
||||||
*
|
*
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.jpa.criteria.TagCriteria;
|
import com.sismics.docs.core.dao.criteria.TagCriteria;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.TagDto;
|
import com.sismics.docs.core.dao.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;
|
||||||
@@ -130,6 +131,10 @@ public class TagDao {
|
|||||||
q.setParameter("tagId", tagId);
|
q.setParameter("tagId", tagId);
|
||||||
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);
|
||||||
@@ -181,7 +186,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) {
|
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 = 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());
|
||||||
@@ -191,14 +196,6 @@ 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");
|
||||||
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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.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;
|
||||||
@@ -71,6 +72,8 @@ 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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa;
|
package com.sismics.docs.core.dao;
|
||||||
|
|
||||||
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;
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
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 javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.NoResultException;
|
||||||
|
import javax.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");
|
||||||
|
|
||||||
|
if (!criteriaList.isEmpty()) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,6 +16,11 @@ public class AuditLogCriteria {
|
|||||||
* User ID.
|
* User ID.
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
@@ -32,4 +37,13 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -36,9 +36,20 @@ public class DocumentCriteria {
|
|||||||
private Date createDateMax;
|
private Date createDateMax;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag IDs.
|
* Minimum update date.
|
||||||
*/
|
*/
|
||||||
private List<String> tagIdList;
|
private Date updateDateMin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum update date.
|
||||||
|
*/
|
||||||
|
private Date updateDateMax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag IDs.
|
||||||
|
* The first level list will be AND'ed and the second level list will be OR'ed.
|
||||||
|
*/
|
||||||
|
private List<List<String>> tagIdList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared status.
|
* Shared status.
|
||||||
@@ -54,6 +65,11 @@ public class DocumentCriteria {
|
|||||||
* Creator ID.
|
* Creator ID.
|
||||||
*/
|
*/
|
||||||
private String creatorId;
|
private String creatorId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A route is active.
|
||||||
|
*/
|
||||||
|
private Boolean activeRoute;
|
||||||
|
|
||||||
public List<String> getTargetIdList() {
|
public List<String> getTargetIdList() {
|
||||||
return targetIdList;
|
return targetIdList;
|
||||||
@@ -95,11 +111,11 @@ public class DocumentCriteria {
|
|||||||
this.createDateMax = createDateMax;
|
this.createDateMax = createDateMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getTagIdList() {
|
public List<List<String>> getTagIdList() {
|
||||||
return tagIdList;
|
return tagIdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTagIdList(List<String> tagIdList) {
|
public void setTagIdList(List<List<String>> tagIdList) {
|
||||||
this.tagIdList = tagIdList;
|
this.tagIdList = tagIdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,4 +142,28 @@ public class DocumentCriteria {
|
|||||||
public void setCreatorId(String creatorId) {
|
public void setCreatorId(String creatorId) {
|
||||||
this.creatorId = creatorId;
|
this.creatorId = creatorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getActiveRoute() {
|
||||||
|
return activeRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdateDateMin() {
|
||||||
|
return updateDateMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateDateMin(Date updateDateMin) {
|
||||||
|
this.updateDateMin = updateDateMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdateDateMax() {
|
||||||
|
return updateDateMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateDateMax(Date updateDateMax) {
|
||||||
|
this.updateDateMax = updateDateMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveRoute(Boolean activeRoute) {
|
||||||
|
this.activeRoute = activeRoute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group criteria.
|
* Group criteria.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -23,16 +23,6 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -59,22 +49,4 @@ 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
package com.sismics.docs.core.dao.criteria;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User criteria.
|
* User criteria.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
import com.sismics.docs.core.constant.PermType;
|
import com.sismics.docs.core.constant.PermType;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
import com.sismics.docs.core.constant.AuditLogType;
|
import com.sismics.docs.core.constant.AuditLogType;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment DTO.
|
* Comment DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contributor DTO.
|
* Contributor DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document DTO.
|
* Document DTO.
|
||||||
@@ -10,7 +10,12 @@ public class DocumentDto {
|
|||||||
* Document ID.
|
* Document ID.
|
||||||
*/
|
*/
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main file ID.
|
||||||
|
*/
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title.
|
* Title.
|
||||||
*/
|
*/
|
||||||
@@ -71,6 +76,11 @@ public class DocumentDto {
|
|||||||
*/
|
*/
|
||||||
private Long createTimestamp;
|
private Long createTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update date.
|
||||||
|
*/
|
||||||
|
private Long updateTimestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared status.
|
* Shared status.
|
||||||
*/
|
*/
|
||||||
@@ -85,7 +95,22 @@ public class DocumentDto {
|
|||||||
* Document creator.
|
* Document creator.
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -94,6 +119,15 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -213,4 +247,38 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group DTO.
|
* Group DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag DTO.
|
* Tag DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route DTO.
|
* Route DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route model DTO.
|
* Route model DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.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;
|
||||||
@@ -62,6 +62,11 @@ public class RouteStepDto {
|
|||||||
*/
|
*/
|
||||||
private String validatorUserName;
|
private String validatorUserName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transitions data.
|
||||||
|
*/
|
||||||
|
private String transitions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route ID.
|
* Route ID.
|
||||||
*/
|
*/
|
||||||
@@ -166,6 +171,15 @@ 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.
|
||||||
*
|
*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag DTO.
|
* Tag DTO.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.dto;
|
package com.sismics.docs.core.dao.dto;
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.sismics.docs.core.dao.jpa.criteria;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Route model criteria.
|
|
||||||
*
|
|
||||||
* @author bgamard
|
|
||||||
*/
|
|
||||||
public class RouteModelCriteria {
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.sismics.docs.core.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL created event.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class AclCreatedAsyncEvent extends AclEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.sismics.docs.core.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL deleted event.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class AclDeletedAsyncEvent extends AclEvent {
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,78 +1,9 @@
|
|||||||
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 UserEvent {
|
public class FileCreatedAsyncEvent extends FileEvent {
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.sismics.docs.core.event;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New file event.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public abstract class FileEvent extends UserEvent {
|
||||||
|
/**
|
||||||
|
* Created file.
|
||||||
|
*/
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language of the file.
|
||||||
|
*/
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unencrypted original file.
|
||||||
|
*/
|
||||||
|
private Path unencryptedFile;
|
||||||
|
|
||||||
|
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 FileEvent setUnencryptedFile(Path unencryptedFile) {
|
||||||
|
this.unencryptedFile = unencryptedFile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("file", file)
|
||||||
|
.add("language", language)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.sismics.docs.core.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New file created event.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class FileUpdatedAsyncEvent extends FileEvent {
|
||||||
|
}
|
||||||
@@ -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.jpa.dto.UserDto;
|
import com.sismics.docs.core.dao.dto.UserDto;
|
||||||
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.jpa.dto.UserDto;
|
import com.sismics.docs.core.dao.dto.UserDto;
|
||||||
import com.sismics.docs.core.model.jpa.Document;
|
import com.sismics.docs.core.model.jpa.Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.sismics.docs.core.event;
|
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup temporary files event.
|
|
||||||
*
|
|
||||||
* @author bgamard
|
|
||||||
*/
|
|
||||||
public class TemporaryFileCleanupAsyncEvent {
|
|
||||||
/**
|
|
||||||
* Temporary files.
|
|
||||||
*/
|
|
||||||
private List<Path> fileList;
|
|
||||||
|
|
||||||
public TemporaryFileCleanupAsyncEvent(List<Path> fileList) {
|
|
||||||
this.fileList = fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Path> getFileList() {
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return MoreObjects.toStringHelper(this)
|
|
||||||
.add("files", fileList)
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.event.AclCreatedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener on ACL created.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class AclCreatedAsyncListener {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AclCreatedAsyncListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL created.
|
||||||
|
*
|
||||||
|
* @param event ACL created event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final AclCreatedAsyncEvent event) {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("ACL created event: " + event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> AppContext.getInstance().getIndexingHandler()
|
||||||
|
.createAcl(event.getSourceId(), event.getPerm(), event.getTargetId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.event.AclDeletedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener on ACL deleted.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class AclDeletedAsyncListener {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AclDeletedAsyncListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL deleted.
|
||||||
|
*
|
||||||
|
* @param event ACL deleted event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final AclDeletedAsyncEvent event) {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("ACL deleted event: " + event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> AppContext.getInstance().getIndexingHandler()
|
||||||
|
.deleteAcl(event.getSourceId(), event.getPerm(), event.getTargetId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.dao.jpa.ContributorDao;
|
import com.sismics.docs.core.dao.ContributorDao;
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
|
||||||
import com.sismics.docs.core.event.DocumentCreatedAsyncEvent;
|
import com.sismics.docs.core.event.DocumentCreatedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
import com.sismics.docs.core.model.jpa.Contributor;
|
import com.sismics.docs.core.model.jpa.Contributor;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -26,25 +27,22 @@ public class DocumentCreatedAsyncListener {
|
|||||||
* @param event Document created event
|
* @param event Document created event
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
public void on(final DocumentCreatedAsyncEvent event) {
|
public void on(final DocumentCreatedAsyncEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Document created event: " + event.toString());
|
log.info("Document created event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUtil.handle(new Runnable() {
|
TransactionUtil.handle(() -> {
|
||||||
@Override
|
// Add the first contributor (the creator of the document)
|
||||||
public void run() {
|
ContributorDao contributorDao = new ContributorDao();
|
||||||
// Add the first contributor (the creator of the document)
|
Contributor contributor = new Contributor();
|
||||||
ContributorDao contributorDao = new ContributorDao();
|
contributor.setDocumentId(event.getDocument().getId());
|
||||||
Contributor contributor = new Contributor();
|
contributor.setUserId(event.getUserId());
|
||||||
contributor.setDocumentId(event.getDocument().getId());
|
contributorDao.create(contributor);
|
||||||
contributor.setUserId(event.getUserId());
|
|
||||||
contributorDao.create(contributor);
|
// Update index
|
||||||
}
|
AppContext.getInstance().getIndexingHandler().createDocument(event.getDocument());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update Lucene index
|
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
|
||||||
luceneDao.createDocument(event.getDocument());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.event.DocumentDeletedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
|
||||||
import com.sismics.docs.core.event.DocumentDeletedAsyncEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener on document deleted.
|
* Listener on document deleted.
|
||||||
*
|
*
|
||||||
@@ -21,17 +22,18 @@ public class DocumentDeletedAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* Document deleted.
|
* Document deleted.
|
||||||
*
|
*
|
||||||
* @param documentDeletedAsyncEvent Document deleted event
|
* @param event Document deleted event
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void on(final DocumentDeletedAsyncEvent documentDeletedAsyncEvent) throws Exception {
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentDeletedAsyncEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Document deleted event: " + documentDeletedAsyncEvent.toString());
|
log.info("Document deleted event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Lucene index
|
TransactionUtil.handle(() -> {
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
// Update index
|
||||||
luceneDao.deleteDocument(documentDeletedAsyncEvent.getDocumentId());
|
AppContext.getInstance().getIndexingHandler().deleteDocument(event.getDocumentId());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.dao.jpa.ContributorDao;
|
import com.sismics.docs.core.dao.ContributorDao;
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
import com.sismics.docs.core.dao.DocumentDao;
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
import com.sismics.docs.core.dao.FileDao;
|
||||||
import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent;
|
import com.sismics.docs.core.event.DocumentUpdatedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
import com.sismics.docs.core.model.jpa.Contributor;
|
import com.sismics.docs.core.model.jpa.Contributor;
|
||||||
|
import com.sismics.docs.core.model.jpa.Document;
|
||||||
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -27,40 +31,53 @@ public class DocumentUpdatedAsyncListener {
|
|||||||
* Document updated.
|
* Document updated.
|
||||||
*
|
*
|
||||||
* @param event Document updated event
|
* @param event Document updated event
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
public void on(final DocumentUpdatedAsyncEvent event) {
|
public void on(final DocumentUpdatedAsyncEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Document updated event: " + event.toString());
|
log.info("Document updated event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUtil.handle(new Runnable() {
|
TransactionUtil.handle(() -> {
|
||||||
@Override
|
// Get the document
|
||||||
public void run() {
|
DocumentDao documentDao = new DocumentDao();
|
||||||
// Update Lucene index
|
Document document = documentDao.getById(event.getDocumentId());
|
||||||
DocumentDao documentDao = new DocumentDao();
|
if (document == null) {
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
// Document deleted since event fired
|
||||||
luceneDao.updateDocument(documentDao.getById(event.getDocumentId()));
|
return;
|
||||||
|
|
||||||
// Update contributors list
|
|
||||||
ContributorDao contributorDao = new ContributorDao();
|
|
||||||
List<Contributor> contributorList = contributorDao.findByDocumentId(event.getDocumentId());
|
|
||||||
|
|
||||||
// Check if the user firing this event is not already a contributor
|
|
||||||
for (Contributor contributor : contributorList) {
|
|
||||||
if (contributor.getUserId().equals(event.getUserId())) {
|
|
||||||
// The current user is already a contributor on this document, don't do anything
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new contributor
|
|
||||||
Contributor contributor = new Contributor();
|
|
||||||
contributor.setDocumentId(event.getDocumentId());
|
|
||||||
contributor.setUserId(event.getUserId());
|
|
||||||
contributorDao.create(contributor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the main file
|
||||||
|
FileDao fileDao = new FileDao();
|
||||||
|
List<File> fileList = fileDao.getByDocumentId(null, event.getDocumentId());
|
||||||
|
if (fileList.isEmpty()) {
|
||||||
|
document.setFileId(null);
|
||||||
|
} else {
|
||||||
|
document.setFileId(fileList.get(0).getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update database and index
|
||||||
|
documentDao.updateSilently(document);
|
||||||
|
AppContext.getInstance().getIndexingHandler().updateDocument(document);
|
||||||
|
|
||||||
|
// Update contributors list
|
||||||
|
ContributorDao contributorDao = new ContributorDao();
|
||||||
|
List<Contributor> contributorList = contributorDao.findByDocumentId(event.getDocumentId());
|
||||||
|
|
||||||
|
// Check if the user firing this event is not already a contributor
|
||||||
|
for (Contributor contributor : contributorList) {
|
||||||
|
if (contributor.getUserId().equals(event.getUserId())) {
|
||||||
|
// The current user is already a contributor on this document, don't do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new contributor
|
||||||
|
Contributor contributor = new Contributor();
|
||||||
|
contributor.setDocumentId(event.getDocumentId());
|
||||||
|
contributor.setUserId(event.getUserId());
|
||||||
|
contributorDao.create(contributor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import com.sismics.docs.core.dao.jpa.FileDao;
|
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
|
||||||
import com.sismics.docs.core.event.FileCreatedAsyncEvent;
|
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
|
||||||
import com.sismics.docs.core.util.FileUtil;
|
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener on file created.
|
|
||||||
*
|
|
||||||
* @author bgamard
|
|
||||||
*/
|
|
||||||
public class FileCreatedAsyncListener {
|
|
||||||
/**
|
|
||||||
* Logger.
|
|
||||||
*/
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FileCreatedAsyncListener.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File created.
|
|
||||||
*
|
|
||||||
* @param fileCreatedAsyncEvent File created event
|
|
||||||
* @throws Exception e
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void on(final FileCreatedAsyncEvent fileCreatedAsyncEvent) throws Exception {
|
|
||||||
if (log.isInfoEnabled()) {
|
|
||||||
log.info("File created event: " + fileCreatedAsyncEvent.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guess the mime type a second time, for open document format (first detected as simple ZIP file)
|
|
||||||
final File file = fileCreatedAsyncEvent.getFile();
|
|
||||||
|
|
||||||
// Extract text content from the file
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
final String content = FileUtil.extractContent(fileCreatedAsyncEvent.getLanguage(), file,
|
|
||||||
fileCreatedAsyncEvent.getUnencryptedFile(), fileCreatedAsyncEvent.getUnencryptedPdfFile());
|
|
||||||
log.info(MessageFormat.format("File content extracted in {0}ms", System.currentTimeMillis() - startTime));
|
|
||||||
|
|
||||||
// Store the text content in the database
|
|
||||||
TransactionUtil.handle(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
FileDao fileDao = new FileDao();
|
|
||||||
if (fileDao.getActiveById(file.getId()) == null) {
|
|
||||||
// The file has been deleted since the text extraction started, ignore the result
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.setContent(content);
|
|
||||||
fileDao.update(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update Lucene index
|
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
|
||||||
luceneDao.createFile(fileCreatedAsyncEvent.getFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
|
||||||
import com.sismics.docs.core.event.FileDeletedAsyncEvent;
|
import com.sismics.docs.core.event.FileDeletedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
import com.sismics.docs.core.util.FileUtil;
|
import com.sismics.docs.core.util.FileUtil;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener on file deleted.
|
* Listener on file deleted.
|
||||||
@@ -23,21 +24,23 @@ public class FileDeletedAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* File deleted.
|
* File deleted.
|
||||||
*
|
*
|
||||||
* @param fileDeletedAsyncEvent File deleted event
|
* @param event File deleted event
|
||||||
* @throws Exception
|
* @throws Exception e
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void on(final FileDeletedAsyncEvent fileDeletedAsyncEvent) throws Exception {
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileDeletedAsyncEvent event) throws Exception {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("File deleted event: " + fileDeletedAsyncEvent.toString());
|
log.info("File deleted event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the file from storage
|
// Delete the file from storage
|
||||||
File file = fileDeletedAsyncEvent.getFile();
|
File file = event.getFile();
|
||||||
FileUtil.delete(file);
|
FileUtil.delete(file);
|
||||||
|
|
||||||
// Update Lucene index
|
TransactionUtil.handle(() -> {
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
// Update index
|
||||||
luceneDao.deleteDocument(file.getId());
|
AppContext.getInstance().getIndexingHandler().deleteDocument(file.getId());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.dao.FileDao;
|
||||||
|
import com.sismics.docs.core.dao.UserDao;
|
||||||
|
import com.sismics.docs.core.event.FileCreatedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.event.FileEvent;
|
||||||
|
import com.sismics.docs.core.event.FileUpdatedAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
|
import com.sismics.docs.core.model.jpa.User;
|
||||||
|
import com.sismics.docs.core.util.DirectoryUtil;
|
||||||
|
import com.sismics.docs.core.util.EncryptionUtil;
|
||||||
|
import com.sismics.docs.core.util.FileUtil;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import com.sismics.docs.core.util.format.FormatHandler;
|
||||||
|
import com.sismics.docs.core.util.format.FormatHandlerUtil;
|
||||||
|
import com.sismics.util.ImageUtil;
|
||||||
|
import com.sismics.util.Scalr;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.CipherOutputStream;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener on file processing.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class FileProcessingAsyncListener {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FileProcessingAsyncListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File created.
|
||||||
|
*
|
||||||
|
* @param event File created event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileCreatedAsyncEvent event) {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("File created event: " + event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> {
|
||||||
|
// Generate thumbnail, extract content
|
||||||
|
processFile(event);
|
||||||
|
|
||||||
|
// Update index
|
||||||
|
AppContext.getInstance().getIndexingHandler().createFile(event.getFile());
|
||||||
|
});
|
||||||
|
|
||||||
|
FileUtil.endProcessingFile(event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File updated.
|
||||||
|
*
|
||||||
|
* @param event File updated event
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileUpdatedAsyncEvent event) {
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("File updated event: " + event.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> {
|
||||||
|
// Generate thumbnail, extract content
|
||||||
|
processFile(event);
|
||||||
|
|
||||||
|
// Update index
|
||||||
|
AppContext.getInstance().getIndexingHandler().updateFile(event.getFile());
|
||||||
|
});
|
||||||
|
|
||||||
|
FileUtil.endProcessingFile(event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the file (create/update).
|
||||||
|
*
|
||||||
|
* @param event File event
|
||||||
|
*/
|
||||||
|
private void processFile(FileEvent event) {
|
||||||
|
// Find a format handler
|
||||||
|
final File file = event.getFile();
|
||||||
|
FormatHandler formatHandler = FormatHandlerUtil.find(file.getMimeType());
|
||||||
|
if (formatHandler == null) {
|
||||||
|
log.error("Format unhandled: " + file.getMimeType());
|
||||||
|
FileUtil.endProcessingFile(file.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user from the database
|
||||||
|
UserDao userDao = new UserDao();
|
||||||
|
User user = userDao.getById(event.getUserId());
|
||||||
|
if (user == null) {
|
||||||
|
// The user has been deleted meanwhile
|
||||||
|
FileUtil.endProcessingFile(file.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate file variations
|
||||||
|
try {
|
||||||
|
Cipher cipher = EncryptionUtil.getEncryptionCipher(user.getPrivateKey());
|
||||||
|
BufferedImage image = formatHandler.generateThumbnail(event.getUnencryptedFile());
|
||||||
|
if (image != null) {
|
||||||
|
// Generate thumbnails from image
|
||||||
|
BufferedImage web = Scalr.resize(image, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.AUTOMATIC, 1280);
|
||||||
|
BufferedImage thumbnail = Scalr.resize(image, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.AUTOMATIC, 256);
|
||||||
|
image.flush();
|
||||||
|
|
||||||
|
// Write "web" encrypted image
|
||||||
|
Path outputFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_web");
|
||||||
|
try (OutputStream outputStream = new CipherOutputStream(Files.newOutputStream(outputFile), cipher)) {
|
||||||
|
ImageUtil.writeJpeg(web, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write "thumb" encrypted image
|
||||||
|
outputFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_thumb");
|
||||||
|
try (OutputStream outputStream = new CipherOutputStream(Files.newOutputStream(outputFile), cipher)) {
|
||||||
|
ImageUtil.writeJpeg(thumbnail, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unable to generate thumbnails", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract text content from the file
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
String content = null;
|
||||||
|
try {
|
||||||
|
content = formatHandler.extractContent(event.getLanguage(), event.getUnencryptedFile());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error extracting content from: " + event.getFile(), e);
|
||||||
|
}
|
||||||
|
log.info(MessageFormat.format("File content extracted in {0}ms", System.currentTimeMillis() - startTime));
|
||||||
|
|
||||||
|
// Save the file to database
|
||||||
|
FileDao fileDao = new FileDao();
|
||||||
|
if (fileDao.getActiveById(file.getId()) == null) {
|
||||||
|
// The file has been deleted since the text extraction started, ignore the result
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.setContent(content);
|
||||||
|
fileDao.update(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.constant.Constants;
|
import com.sismics.docs.core.constant.Constants;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
import com.sismics.docs.core.dao.dto.UserDto;
|
||||||
import com.sismics.docs.core.event.PasswordLostEvent;
|
import com.sismics.docs.core.event.PasswordLostEvent;
|
||||||
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
import com.sismics.docs.core.model.jpa.PasswordRecovery;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
@@ -27,27 +28,25 @@ public class PasswordLostAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* Handle events.
|
* Handle events.
|
||||||
*
|
*
|
||||||
* @param passwordLostEvent Event
|
* @param event Event
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onPasswordLost(final PasswordLostEvent passwordLostEvent) {
|
@AllowConcurrentEvents
|
||||||
|
public void on(final PasswordLostEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Password lost event: " + passwordLostEvent.toString());
|
log.info("Password lost event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUtil.handle(new Runnable() {
|
TransactionUtil.handle(() -> {
|
||||||
@Override
|
final UserDto user = event.getUser();
|
||||||
public void run() {
|
final PasswordRecovery passwordRecovery = event.getPasswordRecovery();
|
||||||
final UserDto user = passwordLostEvent.getUser();
|
|
||||||
final PasswordRecovery passwordRecovery = passwordLostEvent.getPasswordRecovery();
|
// Send the password recovery email
|
||||||
|
Map<String, Object> paramRootMap = new HashMap<>();
|
||||||
// Send the password recovery email
|
paramRootMap.put("user_name", user.getUsername());
|
||||||
Map<String, Object> paramRootMap = new HashMap<>();
|
paramRootMap.put("password_recovery_key", passwordRecovery.getId());
|
||||||
paramRootMap.put("user_name", user.getUsername());
|
|
||||||
paramRootMap.put("password_recovery_key", passwordRecovery.getId());
|
EmailUtil.sendEmail(Constants.EMAIL_TEMPLATE_PASSWORD_RECOVERY, user, paramRootMap);
|
||||||
|
|
||||||
EmailUtil.sendEmail(Constants.EMAIL_TEMPLATE_PASSWORD_RECOVERY, user, paramRootMap);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
import java.util.List;
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
import com.sismics.docs.core.dao.DocumentDao;
|
||||||
import com.sismics.docs.core.dao.jpa.FileDao;
|
import com.sismics.docs.core.dao.FileDao;
|
||||||
import com.sismics.docs.core.dao.lucene.LuceneDao;
|
|
||||||
import com.sismics.docs.core.event.RebuildIndexAsyncEvent;
|
import com.sismics.docs.core.event.RebuildIndexAsyncEvent;
|
||||||
|
import com.sismics.docs.core.model.context.AppContext;
|
||||||
import com.sismics.docs.core.model.jpa.Document;
|
import com.sismics.docs.core.model.jpa.Document;
|
||||||
import com.sismics.docs.core.model.jpa.File;
|
import com.sismics.docs.core.model.jpa.File;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener on rebuild index.
|
* Listener on rebuild index.
|
||||||
@@ -28,31 +28,44 @@ public class RebuildIndexAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* Rebuild Lucene index.
|
* Rebuild Lucene index.
|
||||||
*
|
*
|
||||||
* @param rebuildIndexAsyncEvent Index rebuild event
|
* @param event Index rebuild event
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void on(final RebuildIndexAsyncEvent rebuildIndexAsyncEvent) throws Exception {
|
@AllowConcurrentEvents
|
||||||
|
public void on(final RebuildIndexAsyncEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Rebuild index event: " + rebuildIndexAsyncEvent.toString());
|
log.info("Rebuild index event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all documents and files
|
// Clear the index
|
||||||
TransactionUtil.handle(new Runnable() {
|
AppContext.getInstance().getIndexingHandler().clearIndex();
|
||||||
@Override
|
|
||||||
public void run() {
|
// Index all documents
|
||||||
// Fetch all documents
|
TransactionUtil.handle(() -> {
|
||||||
DocumentDao documentDao = new DocumentDao();
|
int offset = 0;
|
||||||
List<Document> documentList = documentDao.findAll();
|
DocumentDao documentDao = new DocumentDao();
|
||||||
|
List<Document> documentList;
|
||||||
// Fetch all files
|
do {
|
||||||
FileDao fileDao = new FileDao();
|
documentList = documentDao.findAll(offset, 100);
|
||||||
List<File> fileList = fileDao.findAll();
|
AppContext.getInstance().getIndexingHandler().createDocuments(documentList);
|
||||||
|
offset += 100;
|
||||||
// Rebuild index
|
} while (documentList.size() > 0);
|
||||||
LuceneDao luceneDao = new LuceneDao();
|
|
||||||
luceneDao.rebuildIndex(documentList, fileList);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Index all files
|
||||||
|
TransactionUtil.handle(() -> {
|
||||||
|
int offset = 0;
|
||||||
|
FileDao fileDao = new FileDao();
|
||||||
|
List<File> fileList;
|
||||||
|
do {
|
||||||
|
fileList = fileDao.findAll(offset, 100);
|
||||||
|
AppContext.getInstance().getIndexingHandler().createFiles(fileList);
|
||||||
|
offset += 100;
|
||||||
|
} while (fileList.size() > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (log.isInfoEnabled()) {
|
||||||
|
log.info("Rebuilding index done");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.sismics.docs.core.constant.Constants;
|
import com.sismics.docs.core.constant.Constants;
|
||||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
import com.sismics.docs.core.dao.dto.UserDto;
|
||||||
import com.sismics.docs.core.event.RouteStepValidateEvent;
|
import com.sismics.docs.core.event.RouteStepValidateEvent;
|
||||||
import com.sismics.docs.core.util.TransactionUtil;
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
import com.sismics.util.EmailUtil;
|
import com.sismics.util.EmailUtil;
|
||||||
@@ -26,27 +27,25 @@ public class RouteStepValidateAsyncListener {
|
|||||||
/**
|
/**
|
||||||
* Handle events.
|
* Handle events.
|
||||||
*
|
*
|
||||||
* @param routeStepValidateEvent Event
|
* @param event Event
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onRouteStepValidate(final RouteStepValidateEvent routeStepValidateEvent) {
|
@AllowConcurrentEvents
|
||||||
|
public void on(final RouteStepValidateEvent event) {
|
||||||
if (log.isInfoEnabled()) {
|
if (log.isInfoEnabled()) {
|
||||||
log.info("Route step validate event: " + routeStepValidateEvent.toString());
|
log.info("Route step validate event: " + event.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUtil.handle(new Runnable() {
|
TransactionUtil.handle(() -> {
|
||||||
@Override
|
final UserDto user = event.getUser();
|
||||||
public void run() {
|
|
||||||
final UserDto user = routeStepValidateEvent.getUser();
|
|
||||||
|
|
||||||
// Send the password recovery email
|
// Send route step validated email
|
||||||
Map<String, Object> paramRootMap = new HashMap<>();
|
Map<String, Object> paramRootMap = new HashMap<>();
|
||||||
paramRootMap.put("user_name", user.getUsername());
|
paramRootMap.put("user_name", user.getUsername());
|
||||||
paramRootMap.put("document_id", routeStepValidateEvent.getDocument().getId());
|
paramRootMap.put("document_id", event.getDocument().getId());
|
||||||
paramRootMap.put("document_title", routeStepValidateEvent.getDocument().getTitle());
|
paramRootMap.put("document_title", event.getDocument().getTitle());
|
||||||
|
|
||||||
EmailUtil.sendEmail(Constants.EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE, user, paramRootMap);
|
EmailUtil.sendEmail(Constants.EMAIL_TEMPLATE_ROUTE_STEP_VALIDATE, user, paramRootMap);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package com.sismics.docs.core.listener.async;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import com.sismics.docs.core.event.TemporaryFileCleanupAsyncEvent;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener to cleanup temporary files created during a request.
|
|
||||||
*
|
|
||||||
* @author bgamard
|
|
||||||
*/
|
|
||||||
public class TemporaryFileCleanupAsyncListener {
|
|
||||||
/**
|
|
||||||
* Logger.
|
|
||||||
*/
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FileCreatedAsyncListener.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup temporary files.
|
|
||||||
*
|
|
||||||
* @param event Temporary file cleanup event
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void on(final TemporaryFileCleanupAsyncEvent event) throws Exception {
|
|
||||||
if (log.isInfoEnabled()) {
|
|
||||||
log.info("Cleanup temporary files event: " + event.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Path file : event.getFileList()) {
|
|
||||||
Files.delete(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.sismics.docs.core.listener.async;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.eventbus.AllowConcurrentEvents;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import com.sismics.docs.core.constant.WebhookEvent;
|
||||||
|
import com.sismics.docs.core.dao.WebhookDao;
|
||||||
|
import com.sismics.docs.core.dao.criteria.WebhookCriteria;
|
||||||
|
import com.sismics.docs.core.dao.dto.WebhookDto;
|
||||||
|
import com.sismics.docs.core.event.*;
|
||||||
|
import com.sismics.docs.core.util.TransactionUtil;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for triggering webhooks.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
public class WebhookAsyncListener {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(WebhookAsyncListener.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttp client.
|
||||||
|
*/
|
||||||
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentCreatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_CREATED, event.getDocument().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentUpdatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_UPDATED, event.getDocumentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final DocumentDeletedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.DOCUMENT_DELETED, event.getDocumentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileCreatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_CREATED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileUpdatedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_UPDATED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
@AllowConcurrentEvents
|
||||||
|
public void on(final FileDeletedAsyncEvent event) {
|
||||||
|
triggerWebhook(WebhookEvent.FILE_DELETED, event.getFile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger the webhooks for the specified event.
|
||||||
|
*
|
||||||
|
* @param event Event
|
||||||
|
* @param id ID
|
||||||
|
*/
|
||||||
|
private void triggerWebhook(WebhookEvent event, String id) {
|
||||||
|
List<String> webhookUrlList = Lists.newArrayList();
|
||||||
|
|
||||||
|
TransactionUtil.handle(() -> {
|
||||||
|
WebhookDao webhookDao = new WebhookDao();
|
||||||
|
List<WebhookDto> webhookDtoList = webhookDao.findByCriteria(new WebhookCriteria().setEvent(event), null);
|
||||||
|
for (WebhookDto webhookDto : webhookDtoList) {
|
||||||
|
webhookUrlList.add(webhookDto.getUrl());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(JSON, "{\"event\": \"" + event.name() + "\", \"id\": \"" + id + "\"}");
|
||||||
|
|
||||||
|
for (String webhookUrl : webhookUrlList) {
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(webhookUrl)
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
log.info("Successfully called the webhook at: " + webhookUrl + " - " + response.code());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error calling the webhook at: " + webhookUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.sismics.docs.core.listener.sync;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.DeadEvent;
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener for all unprocessed events.
|
|
||||||
*
|
|
||||||
* @author jtremeaux
|
|
||||||
*/
|
|
||||||
public class DeadEventListener {
|
|
||||||
/**
|
|
||||||
* Logger.
|
|
||||||
*/
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DeadEventListener.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process every dead event.
|
|
||||||
*
|
|
||||||
* @param deadEvent Catchall event
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void onDeadEvent(DeadEvent deadEvent) {
|
|
||||||
log.error("Dead event catched: " + deadEvent.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
package com.sismics.docs.core.model.context;
|
package com.sismics.docs.core.model.context;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.eventbus.AsyncEventBus;
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import com.sismics.docs.core.constant.ConfigType;
|
|
||||||
import com.sismics.docs.core.constant.Constants;
|
import com.sismics.docs.core.constant.Constants;
|
||||||
import com.sismics.docs.core.dao.jpa.ConfigDao;
|
import com.sismics.docs.core.dao.UserDao;
|
||||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
import com.sismics.docs.core.event.RebuildIndexAsyncEvent;
|
||||||
import com.sismics.docs.core.listener.async.*;
|
import com.sismics.docs.core.listener.async.*;
|
||||||
import com.sismics.docs.core.listener.sync.DeadEventListener;
|
|
||||||
import com.sismics.docs.core.model.jpa.Config;
|
|
||||||
import com.sismics.docs.core.model.jpa.User;
|
import com.sismics.docs.core.model.jpa.User;
|
||||||
|
import com.sismics.docs.core.service.FileService;
|
||||||
import com.sismics.docs.core.service.InboxService;
|
import com.sismics.docs.core.service.InboxService;
|
||||||
import com.sismics.docs.core.service.IndexingService;
|
|
||||||
import com.sismics.docs.core.util.PdfUtil;
|
import com.sismics.docs.core.util.PdfUtil;
|
||||||
|
import com.sismics.docs.core.util.indexing.IndexingHandler;
|
||||||
|
import com.sismics.util.ClasspathScanner;
|
||||||
import com.sismics.util.EnvironmentUtil;
|
import com.sismics.util.EnvironmentUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,19 +27,19 @@ import java.util.concurrent.TimeUnit;
|
|||||||
/**
|
/**
|
||||||
* Global application context.
|
* Global application context.
|
||||||
*
|
*
|
||||||
* @author jtremeaux
|
* @author jtremeaux
|
||||||
*/
|
*/
|
||||||
public class AppContext {
|
public class AppContext {
|
||||||
|
/**
|
||||||
|
* Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AppContext.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton instance.
|
* Singleton instance.
|
||||||
*/
|
*/
|
||||||
private static AppContext instance;
|
private static AppContext instance;
|
||||||
|
|
||||||
/**
|
|
||||||
* Event bus.
|
|
||||||
*/
|
|
||||||
private EventBus eventBus;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic asynchronous event bus.
|
* Generic asynchronous event bus.
|
||||||
*/
|
*/
|
||||||
@@ -49,35 +51,56 @@ public class AppContext {
|
|||||||
private EventBus mailEventBus;
|
private EventBus mailEventBus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indexing service.
|
* Indexing handler.
|
||||||
*/
|
*/
|
||||||
private IndexingService indexingService;
|
private IndexingHandler indexingHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inbox scanning service.
|
* Inbox scanning service.
|
||||||
*/
|
*/
|
||||||
private InboxService inboxService;
|
private InboxService inboxService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File service.
|
||||||
|
*/
|
||||||
|
private FileService fileService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronous executors.
|
* Asynchronous executors.
|
||||||
*/
|
*/
|
||||||
private List<ExecutorService> asyncExecutorList;
|
private List<ThreadPoolExecutor> asyncExecutorList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor.
|
* Start the application context.
|
||||||
*/
|
*/
|
||||||
private AppContext() {
|
private void startUp() {
|
||||||
resetEventBus();
|
resetEventBus();
|
||||||
|
|
||||||
// Start indexing service
|
// Start indexing handler
|
||||||
ConfigDao configDao = new ConfigDao();
|
try {
|
||||||
Config luceneStorageConfig = configDao.getById(ConfigType.LUCENE_DIRECTORY_STORAGE);
|
List<Class<? extends IndexingHandler>> indexingHandlerList = Lists.newArrayList(
|
||||||
indexingService = new IndexingService(luceneStorageConfig != null ? luceneStorageConfig.getValue() : null);
|
new ClasspathScanner<IndexingHandler>().findClasses(IndexingHandler.class, "com.sismics.docs.core.util.indexing"));
|
||||||
indexingService.startAsync();
|
for (Class<? extends IndexingHandler> handlerClass : indexingHandlerList) {
|
||||||
|
IndexingHandler handler = handlerClass.newInstance();
|
||||||
|
if (handler.accept()) {
|
||||||
|
indexingHandler = handler;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexingHandler.startUp();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error starting the indexing handler", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start file service
|
||||||
|
fileService = new FileService();
|
||||||
|
fileService.startAsync();
|
||||||
|
fileService.awaitRunning();
|
||||||
|
|
||||||
// Start inbox service
|
// Start inbox service
|
||||||
inboxService = new InboxService();
|
inboxService = new InboxService();
|
||||||
inboxService.startAsync();
|
inboxService.startAsync();
|
||||||
|
inboxService.awaitRunning();
|
||||||
|
|
||||||
// Register fonts
|
// Register fonts
|
||||||
PdfUtil.registerFonts();
|
PdfUtil.registerFonts();
|
||||||
@@ -92,25 +115,35 @@ public class AppContext {
|
|||||||
userDao.updateHashedPassword(adminUser);
|
userDao.updateHashedPassword(adminUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change the admin email if needed
|
||||||
|
String envAdminEmail = System.getenv(Constants.ADMIN_EMAIL_INIT_ENV);
|
||||||
|
if (envAdminEmail != null) {
|
||||||
|
UserDao userDao = new UserDao();
|
||||||
|
User adminUser = userDao.getById("admin");
|
||||||
|
if (Constants.DEFAULT_ADMIN_EMAIL.equals(adminUser.getEmail())) {
|
||||||
|
adminUser.setEmail(envAdminEmail);
|
||||||
|
userDao.update(adminUser, "admin");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Re)-initializes the event buses.
|
* (Re)-initializes the event buses.
|
||||||
*/
|
*/
|
||||||
private void resetEventBus() {
|
private void resetEventBus() {
|
||||||
eventBus = new EventBus();
|
|
||||||
eventBus.register(new DeadEventListener());
|
|
||||||
|
|
||||||
asyncExecutorList = new ArrayList<>();
|
asyncExecutorList = new ArrayList<>();
|
||||||
|
|
||||||
asyncEventBus = newAsyncEventBus();
|
asyncEventBus = newAsyncEventBus();
|
||||||
asyncEventBus.register(new FileCreatedAsyncListener());
|
asyncEventBus.register(new FileProcessingAsyncListener());
|
||||||
asyncEventBus.register(new FileDeletedAsyncListener());
|
asyncEventBus.register(new FileDeletedAsyncListener());
|
||||||
asyncEventBus.register(new DocumentCreatedAsyncListener());
|
asyncEventBus.register(new DocumentCreatedAsyncListener());
|
||||||
asyncEventBus.register(new DocumentUpdatedAsyncListener());
|
asyncEventBus.register(new DocumentUpdatedAsyncListener());
|
||||||
asyncEventBus.register(new DocumentDeletedAsyncListener());
|
asyncEventBus.register(new DocumentDeletedAsyncListener());
|
||||||
asyncEventBus.register(new RebuildIndexAsyncListener());
|
asyncEventBus.register(new RebuildIndexAsyncListener());
|
||||||
asyncEventBus.register(new TemporaryFileCleanupAsyncListener());
|
asyncEventBus.register(new AclCreatedAsyncListener());
|
||||||
|
asyncEventBus.register(new AclDeletedAsyncListener());
|
||||||
|
asyncEventBus.register(new WebhookAsyncListener());
|
||||||
|
|
||||||
mailEventBus = newAsyncEventBus();
|
mailEventBus = newAsyncEventBus();
|
||||||
mailEventBus.register(new PasswordLostAsyncListener());
|
mailEventBus.register(new PasswordLostAsyncListener());
|
||||||
@@ -119,59 +152,45 @@ public class AppContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a single instance of the application context.
|
* Returns a single instance of the application context.
|
||||||
*
|
*
|
||||||
* @return Application context
|
* @return Application context
|
||||||
*/
|
*/
|
||||||
public static AppContext getInstance() {
|
public static AppContext getInstance() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new AppContext();
|
instance = new AppContext();
|
||||||
|
instance.startUp();
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for termination of all asynchronous events.
|
|
||||||
* /!\ Must be used only in unit tests and never a multi-user environment.
|
|
||||||
*/
|
|
||||||
public void waitForAsync() {
|
|
||||||
if (EnvironmentUtil.isUnitTest()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
for (ExecutorService executor : asyncExecutorList) {
|
|
||||||
// Shutdown executor, don't accept any more tasks (can cause error with nested events)
|
|
||||||
try {
|
|
||||||
executor.shutdown();
|
|
||||||
executor.awaitTermination(60, TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
resetEventBus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new asynchronous event bus.
|
* Creates a new asynchronous event bus.
|
||||||
*
|
*
|
||||||
* @return Async event bus
|
* @return Async event bus
|
||||||
*/
|
*/
|
||||||
private EventBus newAsyncEventBus() {
|
private EventBus newAsyncEventBus() {
|
||||||
if (EnvironmentUtil.isUnitTest()) {
|
if (EnvironmentUtil.isUnitTest()) {
|
||||||
return new EventBus();
|
return new EventBus();
|
||||||
} else {
|
} else {
|
||||||
// /!\ Don't add more threads because a cleanup event is fired at the end of each request
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 8,
|
||||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,
|
1L, TimeUnit.MINUTES,
|
||||||
0L, TimeUnit.MILLISECONDS,
|
new LinkedBlockingQueue<>());
|
||||||
new LinkedBlockingQueue<Runnable>());
|
|
||||||
asyncExecutorList.add(executor);
|
asyncExecutorList.add(executor);
|
||||||
return new AsyncEventBus(executor);
|
return new AsyncEventBus(executor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBus getEventBus() {
|
/**
|
||||||
return eventBus;
|
* Return the current number of queued tasks waiting to be processed.
|
||||||
|
*
|
||||||
|
* @return Number of queued tasks
|
||||||
|
*/
|
||||||
|
public int getQueuedTaskCount() {
|
||||||
|
int queueSize = 0;
|
||||||
|
for (ThreadPoolExecutor executor : asyncExecutorList) {
|
||||||
|
queueSize += executor.getTaskCount() - executor.getCompletedTaskCount();
|
||||||
|
}
|
||||||
|
return queueSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBus getAsyncEventBus() {
|
public EventBus getAsyncEventBus() {
|
||||||
@@ -182,11 +201,42 @@ public class AppContext {
|
|||||||
return mailEventBus;
|
return mailEventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexingService getIndexingService() {
|
public IndexingHandler getIndexingHandler() {
|
||||||
return indexingService;
|
return indexingHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InboxService getInboxService() {
|
public InboxService getInboxService() {
|
||||||
return inboxService;
|
return inboxService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileService getFileService() {
|
||||||
|
return fileService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutDown() {
|
||||||
|
for (ExecutorService executor : asyncExecutorList) {
|
||||||
|
// Shutdown executor, don't accept any more tasks (can cause error with nested events)
|
||||||
|
try {
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(1, TimeUnit.MINUTES);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexingHandler != null) {
|
||||||
|
indexingHandler.shutDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inboxService != null) {
|
||||||
|
inboxService.stopAsync();
|
||||||
|
inboxService.awaitTerminated();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileService != null) {
|
||||||
|
fileService.stopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package com.sismics.docs.core.model.jpa;
|
package com.sismics.docs.core.model.jpa;
|
||||||
|
|
||||||
import java.util.Date;
|
import com.google.common.base.MoreObjects;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import java.util.Date;
|
||||||
import com.google.common.base.MoreObjects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Document entity.
|
* Document entity.
|
||||||
@@ -30,6 +29,12 @@ public class Document implements Loggable {
|
|||||||
@Column(name = "DOC_IDUSER_C", nullable = false, length = 36)
|
@Column(name = "DOC_IDUSER_C", nullable = false, length = 36)
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main file ID.
|
||||||
|
*/
|
||||||
|
@Column(name = "DOC_IDFILE_C", length = 36)
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Language (ISO 639-9).
|
* Language (ISO 639-9).
|
||||||
*/
|
*/
|
||||||
@@ -102,6 +107,12 @@ public class Document implements Loggable {
|
|||||||
@Column(name = "DOC_CREATEDATE_D", nullable = false)
|
@Column(name = "DOC_CREATEDATE_D", nullable = false)
|
||||||
private Date createDate;
|
private Date createDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creation date.
|
||||||
|
*/
|
||||||
|
@Column(name = "DOC_UPDATEDATE_D", nullable = false)
|
||||||
|
private Date updateDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletion date.
|
* Deletion date.
|
||||||
*/
|
*/
|
||||||
@@ -132,6 +143,15 @@ public class Document implements Loggable {
|
|||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFileId() {
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Document setFileId(String fileId) {
|
||||||
|
this.fileId = fileId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
@@ -229,6 +249,14 @@ public class Document implements Loggable {
|
|||||||
this.deleteDate = deleteDate;
|
this.deleteDate = deleteDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getUpdateDate() {
|
||||||
|
return updateDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateDate(Date updateDate) {
|
||||||
|
this.updateDate = updateDate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
|
|||||||
@@ -71,6 +71,24 @@ public class File implements Loggable {
|
|||||||
@Column(name = "FIL_ORDER_N")
|
@Column(name = "FIL_ORDER_N")
|
||||||
private Integer order;
|
private Integer order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version ID.
|
||||||
|
*/
|
||||||
|
@Column(name = "FIL_IDVERSION_C")
|
||||||
|
private String versionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version number (starting at 0).
|
||||||
|
*/
|
||||||
|
@Column(name = "FIL_VERSION_N", nullable = false)
|
||||||
|
private Integer version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if it's the latest version of the file.
|
||||||
|
*/
|
||||||
|
@Column(name = "FIL_LATESTVERSION_B", nullable = false)
|
||||||
|
private boolean latestVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private key to decrypt the file.
|
* Private key to decrypt the file.
|
||||||
* Not saved to database, of course.
|
* Not saved to database, of course.
|
||||||
@@ -160,6 +178,33 @@ public class File implements Loggable {
|
|||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVersionId() {
|
||||||
|
return versionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File setVersionId(String versionId) {
|
||||||
|
this.versionId = versionId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File setVersion(Integer version) {
|
||||||
|
this.version = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLatestVersion() {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File setLatestVersion(boolean latestVersion) {
|
||||||
|
this.latestVersion = latestVersion;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ public class RouteStep {
|
|||||||
@Column(name = "RTP_COMMENT_C", length = 500)
|
@Column(name = "RTP_COMMENT_C", length = 500)
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transitions JSON data.
|
||||||
|
*/
|
||||||
|
@Column(name = "RTP_TRANSITIONS_C", length = 2000)
|
||||||
|
private String transitions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target ID (user or group).
|
* Target ID (user or group).
|
||||||
*/
|
*/
|
||||||
@@ -198,6 +204,15 @@ public class RouteStep {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTransitions() {
|
||||||
|
return transitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteStep setTransitions(String transitions) {
|
||||||
|
this.transitions = transitions;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MoreObjects.toStringHelper(this)
|
return MoreObjects.toStringHelper(this)
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package com.sismics.docs.core.model.jpa;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.sismics.docs.core.constant.WebhookEvent;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhook entity.
|
||||||
|
*
|
||||||
|
* @author bgamard
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "T_WEBHOOK")
|
||||||
|
public class Webhook implements Loggable {
|
||||||
|
/**
|
||||||
|
* Webhook ID.
|
||||||
|
*/
|
||||||
|
@Id
|
||||||
|
@Column(name = "WHK_ID_C", nullable = false, length = 36)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event.
|
||||||
|
*/
|
||||||
|
@Column(name = "WHK_EVENT_C", nullable = false, length = 50)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private WebhookEvent event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL.
|
||||||
|
*/
|
||||||
|
@Column(name = "WHK_URL_C", nullable = false, length = 1024)
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creation date.
|
||||||
|
*/
|
||||||
|
@Column(name = "WHK_CREATEDATE_D", nullable = false)
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletion date.
|
||||||
|
*/
|
||||||
|
@Column(name = "WHK_DELETEDATE_D")
|
||||||
|
private Date deleteDate;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Webhook setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebhookEvent getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Webhook setEvent(WebhookEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Webhook setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateDate() {
|
||||||
|
return createDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Webhook setCreateDate(Date createDate) {
|
||||||
|
this.createDate = createDate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getDeleteDate() {
|
||||||
|
return deleteDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Webhook setDeleteDate(Date deleteDate) {
|
||||||
|
this.deleteDate = deleteDate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("id", id)
|
||||||
|
.add("event", event)
|
||||||
|
.add("url", url)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toMessage() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user