Compare commits

...

293 Commits

Author SHA1 Message Date
44ad9ad1ee master branch only 2024-11-21 13:26:00 +03:00
e97c8a8393 actions for go 2024-11-21 13:23:19 +03:00
78fe9e02ce Merge pull request 'release/v1.11.0' from release/v1.11.0 into master
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/16
2024-10-31 13:49:25 +00:00
8e260dec56 nodejs: fix lint (b36bfdec4d) 2024-10-31 16:45:37 +03:00
3010db6bec Merge pull request 'build: update documentserver version to 8.2 in docker-compose files' from documentserver-version into release/v1.11.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/14
2024-10-28 10:11:33 +00:00
9f922ccdbe build: update documentserver version to 8.2 in docker-compose files 2024-10-28 13:10:46 +03:00
cb8b4d1681 fix(nodejs): replace localhost in unsupported converted file url. Fix Bug 70551 (c4d80f6b5e) 2024-10-21 14:09:42 +03:00
decb722cf9 1.11.0 2024-10-20 17:08:13 +03:00
d7d31bd6b7 fix changelog 2024-10-16 11:56:16 +03:00
e4f5f0bca7 submit not for viewer
This reverts commit 35cf2fb0b0.
2024-10-15 18:06:37 +03:00
8714cc3d69 Revert "nodejs: comment only is not for pdf"
This reverts commit 146d26c868.
2024-10-14 12:08:22 +03:00
f1c5be0401 Merge remote-tracking branch 'remotes/origin/master' into release/v8.2.0 2024-10-11 12:33:49 +03:00
d68860f025 Merge pull request 'release/v1.10.0 from release/v1.10.0 into master
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/9
2024-10-11 09:27:13 +00:00
fdd90fd851 python: fix lint 2024-10-11 12:20:12 +03:00
abb7f6e893 Merge remote-tracking branch 'remotes/origin/release/v1.10.0' into release/v8.2.0 2024-10-10 13:47:38 +03:00
89c60280ba php-laravel: lint 2024-10-10 13:40:12 +03:00
8522e08670 php-laravel: lint 2024-10-10 13:29:10 +03:00
52b792f3a2 Merge pull request 'fix(java-spring): error saving non-existent file. Fix Bug 70788' from fix-java-spring-forgotten into release/v1.10.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/8
2024-10-10 10:18:41 +00:00
05f7fa2b84 fix(java-spring): error saving non-existent file. Fix Bug 70788 2024-10-10 17:11:48 +07:00
06c3dc1446 Merge remote-tracking branch 'remotes/origin/release/v1.10.0' into release/v8.2.0 2024-10-08 12:54:10 +03:00
b751d44a51 Merge pull request '1.10.0-bugfix' (#5) from 1.10.0-bugfix into release/v1.10.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/5
2024-10-08 09:52:38 +00:00
35cf2fb0b0 submit for all modes 2024-10-07 14:54:16 +03:00
25ec76084f coauthoring/CommandService.ashx address replaced with command 2024-10-07 11:35:55 +03:00
c72218d3ae ConvertService.ashx address replaced with converter 2024-10-07 11:34:22 +03:00
17458ec5b3 fix(java-spring): сut out directUrl. Fix Bug 70571 2024-10-07 14:42:24 +07:00
c4d80f6b5e fix(nodejs): replace localhost in unsupported converted file url. Fix Bug 70551 2024-10-03 15:15:42 +07:00
50bbd86cf5 Merge branch 'release/v1.10.0' into release/v8.2.0 2024-09-30 12:52:43 +03:00
2b0b902f9c using default empty files (For Bug 70101) 2024-09-30 12:50:09 +03:00
b36bfdec4d fix(nodejs): fix maxfilesize issue on upload (Fix Bug 70516) 2024-09-27 14:25:21 +03:00
97b70cceb5 Merge branch 'release/v1.10.0' into release/v8.2.0 2024-09-24 15:07:22 +03:00
596d445439 revert empty files (For Bug 70101) 2024-09-24 15:06:16 +03:00
4943adc21a nodejs: WOPI rename 2024-09-24 14:37:32 +03:00
db3ccd7482 Revert "nodejs: filling by default if possible" (Fix Bug 70284)
This reverts commit 15e09fece2.

# Conflicts:
#	web/documentserver-example/nodejs/app.js
2024-09-24 12:06:41 +03:00
4c7ea51207 Merge remote-tracking branch 'remotes/origin/release/v1.10.0' into release/v8.2.0 2024-09-24 12:02:52 +03:00
4f8f7399bb Merge pull request 'bugfix-1.10.0' (#3) from bugfix-1.10.0 into release/v1.10.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/3
2024-09-24 09:02:19 +00:00
581f2aaef6 he-IL skin language 2024-09-23 10:51:25 +03:00
62f98954b4 fix(python): exclude nochanges(4) error in command service request 2024-09-20 18:10:53 +07:00
819faf84f1 fix(ruby): exclude nochanges(4) error in command service request. Fix Bug 69913 2024-09-20 18:03:38 +07:00
66cf2aca8c Merge remote-tracking branch 'remotes/origin/release/v1.10.0' into bugfix-1.10.0
# Conflicts:
#	web/documentserver-example/csharp-mvc/Scripts/jscript.js
#	web/documentserver-example/csharp/script/jscript.js
#	web/documentserver-example/python/static/js/jscript.js
2024-09-20 09:57:35 +03:00
73b727ff9f Merge pull request 'fix: add file existence check before save. Fix Bug 69948' (#2) from fix/java-check-file-exist into release/v1.10.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/2
2024-09-18 08:55:32 +00:00
4c8fb6b3be nodejs: getting name in wopi (Fix Bug 70092) 2024-09-18 11:53:31 +03:00
dcc5a8f56d build(java-spring): update SDK dependency. Fix Bug 69951 2024-09-18 15:38:34 +07:00
14df5fcfa0 fix: add file existence check before save 2024-09-17 14:17:00 +03:00
e2e8087800 fix(python): extension without dot in conversion script. Fix Bug 69931 2024-09-16 15:59:12 +07:00
4c6e6dc235 fix(java): not blank page goback for uid-2. Fix Bug 69945 2024-09-13 16:31:05 +07:00
cd4ff5e045 fix(php): replacing localhost in saveas file url. Fix Bug 69936 2024-09-13 14:16:58 +07:00
b9b4aeffac fix working with formats (893303c27f) (Fix Bug 70022) 2024-09-12 10:10:05 +03:00
e25b10d618 fix(csharp-mvc): extension without dot in conversion script. Fix Bug 70022 2024-09-12 14:03:49 +07:00
f00abbc9e7 fix(csharp): extension without dot in conversion script. Fix Bug 70022 2024-09-12 14:03:15 +07:00
09344f6bbb fix(ruby): replace url to public server for forgotten files (Fix Bug 69930) 2024-09-11 15:58:47 +03:00
c23e9b6a0f fix(php): replace url to public server for forgotten files 2024-09-11 15:58:05 +03:00
814ed51134 fix(python): replace url to public server for forgotten files 2024-09-11 15:58:05 +03:00
63237f52ca fix(csharp): forgotten pdf logo. Fix Bug 70023 2024-09-11 16:13:46 +07:00
8cf285c51b nodejs: separate method for getting fileName from url (Fix Bug 70092) 2024-09-10 22:36:21 +03:00
4ae4687d29 nodejs: replace unsupported symbols in file name 2024-09-10 22:36:21 +03:00
f55beaa8ac update empty files (Fix Bug 70100) 2024-09-10 18:11:50 +03:00
4be1abca19 update submodule with tiff ext 2024-09-09 09:24:36 +03:00
7eac06aa57 nodejs: fix default actions on mobile (For Bug 65920) 2024-09-06 17:25:16 +03:00
763512afc4 nodejs: fix lint (194ad60648) 2024-09-06 17:22:39 +03:00
1b0867af69 nodejs: percentage on converting (Fix Bug 69567) 2024-09-06 15:15:24 +03:00
aa42745a3a nodejs: opening history for wopi (Fix Bug 70025) 2024-09-06 14:52:14 +03:00
194ad60648 nodejs: decode filename from utf7 in "save as" process (Fix Bug 69827) 2024-09-05 18:21:13 +03:00
1e6465aef7 update templates 2024-08-26 11:06:04 +03:00
6b6fa50e49 Merge pull request #586 from ONLYOFFICE/feature/ruby-update-deps
chore(ruby): update dependencies
2024-08-05 16:53:35 +03:00
c01bcf1807 chore(ruby): update dependencies 2024-08-05 16:30:11 +03:00
7201ec4f9e tabs to changelog (efac5b9d70) 2024-08-01 13:16:07 +03:00
c46b4e16d5 fix remove favorite status (0e1a580a86) 2024-07-31 14:28:21 +03:00
8d7767e4a7 1.10.0 2024-07-25 09:50:41 +03:00
6d4484cbe5 reorder changelog 2024-07-25 09:47:58 +03:00
4f6a0d554c Merge remote-tracking branch 'remotes/origin/master' into develop 2024-07-25 09:43:50 +03:00
a3430f7aec Merge pull request #580 from ONLYOFFICE/pdf-form
PDF-forms
2024-07-24 15:01:55 +03:00
aaea7e4cb8 feat(java-spring): permission submitForm (John Smith: true) 2024-07-24 14:20:57 +03:00
5fd90b295f Merge pull request #581 from ONLYOFFICE/fix/nodejs-conversion-error
Fix/nodejs conversion error
2024-07-19 12:35:01 +03:00
9fda921107 nodejs: display error message if it is the only param in convert response 2024-07-19 13:44:41 +05:00
b55c19f886 nodejs: add tag for displaying conversion error message 2024-07-19 13:42:08 +05:00
d0b1cc9900 feat(java): creating and editing pdf instead docxf 2024-07-16 16:21:15 +07:00
16580f4a00 feat(csharp): creating and editing pdf instead docxf 2024-07-16 15:35:12 +07:00
2f4b28343c feat(csharp-mvc): creating and editing pdf instead docxf 2024-07-16 15:10:17 +07:00
0d37b7ef7c feat(java-spring): creating and editing pdf instead docxf 2024-07-15 17:41:03 +07:00
597b3dfac7 feat(php): creating and editing pdf instead docxf 2024-07-15 17:41:02 +07:00
1936274a13 feat(python): creating and editing pdf instead docxf 2024-07-15 17:41:02 +07:00
b7837f8dcb feat(ruby): creating and editing pdf instead docxf 2024-07-15 17:40:31 +07:00
e088efe744 fix link in readme 2024-07-02 11:02:08 +03:00
f3a56acae9 reorder changelog 2024-07-02 10:41:07 +03:00
b937d304d7 nodejs: form type is pdf 2024-07-02 10:39:15 +03:00
4fb7062b95 Merge remote-tracking branch 'remotes/origin/hotfix/v8.1.1' into develop
# Conflicts:
#	web/documentserver-example/nodejs/app.js
2024-07-02 10:27:41 +03:00
b36388124d Merge pull request #579 from ONLYOFFICE/release/v1.9.0
Release/1.9.0
2024-07-02 10:20:10 +03:00
2c6c5e3a1f nodejs: saving deleted file (Fix Bug 68926) 2024-07-01 12:46:30 +03:00
ed3aa3485e nodejs: search referenceData for current user 2024-06-24 14:06:02 +03:00
6f12493e59 nodejs: check path in referenceData at first 2024-06-24 13:58:12 +03:00
22f98fda0f nodejs: search referenceData for current user 2024-06-24 13:52:00 +03:00
b91772e7d4 Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop 2024-06-24 12:34:59 +03:00
052f73e47f nodejs: formats v2.0.0 2024-06-24 12:32:45 +03:00
55b062d64a Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop 2024-06-20 13:26:36 +03:00
b06c872a4c Merge pull request #578 from ONLYOFFICE/fix/python-linter
update and fixate flake8 version in python example
2024-06-20 13:23:45 +03:00
ce846f489b build(python): update and fixate flake8 version 2024-06-20 13:20:27 +03:00
7a5fdc9821 Merge pull request #542 from ONLYOFFICE/fix/compose-prod ( Fix Bug 68727 )
Fix/compose prod
2024-06-20 11:36:46 +03:00
fe50a6f1ab fix(python): starting server on localhost in prod container 2024-06-20 11:34:47 +03:00
8268b633c7 fix(ruby): installing dev dependencies in prod container 2024-06-20 11:34:46 +03:00
5974a62fd2 Merge pull request #570 from ONLYOFFICE/feature/mobile-design
Feature/mobile design
2024-06-18 09:00:46 +03:00
56540846f1 Merge pull request #577 from ONLYOFFICE/fix/lint-ruby-workflow
fix(ruby): bundle install in linter workflow
2024-06-18 09:00:26 +03:00
54210428ef fix(ruby): bundle install in linter workflow 2024-06-17 14:11:20 +07:00
458920771c Merge remote-tracking branch 'remotes/origin/develop' into feature/mobile-design 2024-06-14 13:39:30 +03:00
dd189175a1 Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop 2024-06-14 13:38:57 +03:00
93c723eb47 nodejs: fix lint 2024-06-14 13:37:33 +03:00
d564e78b2c Merge remote-tracking branch 'remotes/origin/develop' into feature/mobile-design 2024-06-14 13:31:31 +03:00
27c01046af Merge pull request #576 from ONLYOFFICE/fix/csharp-mvc-missing-formats
fix(csharp-mvc): add missing formats js file to scripts bundle
2024-06-14 13:30:37 +03:00
aa7b6aae8b fix(csharp-mvc): add missing formats js file to scripts bundle 2024-06-14 14:50:24 +05:00
be58fa39b2 Merge pull request #575 from ONLYOFFICE/fix/ruby-linter
ruby lint fix
2024-06-14 11:15:43 +03:00
6c827aa8bc Merge pull request #574 from ONLYOFFICE/feature/ruby-gemfile-update
ruby gemfile update
2024-06-14 11:10:51 +03:00
da1111a867 Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop 2024-06-14 11:04:40 +03:00
8cc0580310 nodejs: fix comment collumn (146d26c868) 2024-06-14 11:03:58 +03:00
d4b82453d2 fix(ruby): call super without arguments when signature is identical 2024-06-13 17:48:08 +07:00
3420b20c2f build(ruby): update some dependencies 2024-06-13 17:28:21 +07:00
cfe6db3fd4 Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop 2024-06-07 12:18:37 +03:00
8c44f4a653 nodejs: switch back templates branch 2024-06-07 12:18:01 +03:00
0561a1068c Merge remote-tracking branch 'remotes/origin/release/v1.9.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-06-07 09:46:26 +03:00
d6309505ff 1.9.0 2024-06-07 09:43:21 +03:00
2308abaf80 Merge branch 'feature/editnew-from-wopi-discovery-pdf' into develop 2024-06-07 08:50:45 +03:00
95e7aff092 Merge remote-tracking branch 'remotes/origin/release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/java-spring/src/main/resources/application.properties
#	web/documentserver-example/nodejs/app.js
#	web/documentserver-example/nodejs/views/wopiIndex.ejs
2024-06-07 08:49:20 +03:00
8207aec7a5 sr-Cyrl-RS skin language
# Conflicts:
#	CHANGELOG.md
2024-06-06 17:26:17 +03:00
a5fa0096e8 en-GB skin language
# Conflicts:
#	CHANGELOG.md
2024-06-06 17:25:51 +03:00
0c886264ba fix sr-Latn-RS
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/csharp-mvc/web.appsettings.config
#	web/documentserver-example/csharp/settings.config
#	web/documentserver-example/java-spring/src/main/resources/application.properties
#	web/documentserver-example/java/src/main/resources/settings.properties
2024-06-06 17:25:23 +03:00
871b08018f filling to changelog 2024-06-06 14:53:00 +03:00
88220ddf7c nodejs: upade pdf icon (Fix Bug 68355) 2024-06-05 10:01:03 +03:00
cfd010cc99 sr-Cyrl-RS skin language 2024-05-27 13:22:33 +03:00
e933e918dd Merge pull request #571 from ONLYOFFICE/fix/php-check-fileid
fix(php): check if fileid parameter is present and not empty
2024-05-22 14:16:57 +03:00
3d11876f59 fix(php): check if fileid parameter is present and not empty 2024-05-21 17:55:01 +05:00
259c121707 feat(csharp): implement design for mobile devices 2024-05-21 13:11:01 +05:00
083de6993c feat(csharp-mvc): implement design for mobile devices 2024-05-21 13:10:30 +05:00
b162076378 feat(java-spring): implement design for mobile devices 2024-05-20 19:13:47 +05:00
a37fee7192 feat(java): implement design for mobile devices 2024-05-20 19:09:26 +05:00
96bc425eb5 feat(ruby): implement design for mobile devices 2024-05-20 19:07:00 +05:00
9054e4919d feat(python): implement design for mobile devices 2024-05-20 19:05:42 +05:00
e573bb4cc4 feat(php): implement design for mobile devices 2024-05-20 19:04:18 +05:00
f568f7ae18 feat(nodejs): implement design for mobile devices 2024-05-20 19:01:26 +05:00
4238de80cc nodejs: update pdf icon 2024-05-20 14:10:03 +03:00
146d26c868 nodejs: comment only is not for pdf 2024-05-20 13:56:06 +03:00
ecb520e4cb nodejs: submitting in embedded mode 2024-05-20 13:44:54 +03:00
efac5b9d70 Merge pull request #561 from ONLYOFFICE/feature/forgotten-page
Feature/forgotten page
2024-05-15 12:52:47 +03:00
9f20706205 forgotten to changelog 2024-05-15 12:48:30 +03:00
f48734b235 nodejs: disable forgotten by default 2024-05-15 12:46:21 +03:00
3b4b1b3684 Merge pull request #568 from ONLYOFFICE/fix/java-spring-filename-check
fix(java-spring): check for null value first
2024-05-14 15:29:07 +03:00
0280503110 fix(java-spring): check for null value first 2024-05-14 15:58:48 +05:00
057d15e00d Merge pull request #563 from ONLYOFFICE/fix/zip-upload
fix(nodejs): uploading only files with actions. Fix Bug 67497
2024-05-14 13:43:48 +03:00
9a22cd66d9 refactor(java-spring): use sdk for fetching and deleting forgotten files 2024-05-14 14:10:14 +05:00
67137ad6e1 fix(nodejs): ignore zip from saveAs 2024-05-14 15:38:48 +07:00
1d3ae82f1c Merge branch 'develop' into feature/forgotten-page 2024-05-14 13:11:13 +05:00
a512a0ed26 Merge pull request #566 from ONLYOFFICE/docs/java-spring-license
docs(java-spring): update 3rd-Party.license file
2024-05-13 14:38:38 +03:00
27a9817f46 update license file 2024-05-13 14:35:12 +03:00
354b500077 Merge branch 'develop' into feature/forgotten-page 2024-05-13 14:02:51 +05:00
7852934047 docs(java-spring): update 3rd-Party.license file 2024-05-08 15:39:57 +03:00
06482fa72c Merge pull request #555 from ONLYOFFICE/feature/editnew-from-wopi-discovery
Creating only files with editnew in wopi discovery
2024-05-08 12:00:04 +03:00
9efc5237aa nodejs: fix creation pdf in wopi 2024-05-08 11:56:04 +03:00
4fa2bb8459 Merge remote-tracking branch 'remotes/origin/develop' into feature/editnew-from-wopi-discovery 2024-05-08 11:45:27 +03:00
38581960f3 Merge pull request #564 from ONLYOFFICE/fix/makefile-compose-migration
makefile docker compose V2 migration. Fix Bug 67214
2024-05-08 11:43:18 +03:00
43bdef50a1 java-spring: using sdk to changelog 2024-05-08 11:03:47 +03:00
4c71114177 nodejs: revert formats (fix 729065fed0) 2024-05-08 11:03:35 +03:00
5eb6171954 Merge pull request #557 from ONLYOFFICE/feature/docs-integration-sdk
Feature/docs integration sdk
2024-05-08 10:45:01 +03:00
26782137e7 csharp: remove unnecessary angel bracket 2024-05-02 13:52:49 +05:00
8680ed5970 php: catch and log commandrequest errors 2024-04-25 20:03:28 +05:00
af39abbf00 php: throw exception if there is connection error or command service returns error code other than 0 2024-04-25 20:01:16 +05:00
dec31c2f59 python: log error 2024-04-25 19:40:48 +05:00
9ae6252e53 feat(python): raise error if command service returns error code other than 0 2024-04-25 19:37:27 +05:00
3c84ab6633 makefile docker compose V2 migration. Fix Bug 67214 2024-04-25 15:11:39 +07:00
7cffe4cee9 fix(nodejs): uploading only files with actions. Fix Bug 67497 2024-04-24 18:04:24 +07:00
107459cf19 en-GB skin language 2024-04-24 13:22:57 +03:00
a9b63ef903 build(nodejs): bump formidable from 1.2.2 to 3.2.4 2024-04-24 15:24:06 +07:00
e863fd60f4 fix(ruby): show empty table in forgotten files page if error occurs 2024-04-23 23:33:45 +05:00
172a501247 feat(ruby): raise error if command service returns error code other than 0 2024-04-23 23:30:27 +05:00
e487a89203 fix(csharp-mvc): show empty table in forgotten files page if error occurs 2024-04-23 18:03:23 +05:00
aeb2394b39 feat(csharp-mvc): control access to forgotten page using config variable 2024-04-23 17:55:22 +05:00
5c804c1e1e feat(csharp-mvc): display message in error template 2024-04-23 17:54:27 +05:00
6b319f1dc1 fix(csharp): show empty table in forgotten files page if error occurs 2024-04-23 17:47:47 +05:00
4a029f8f40 feat(csharp): control access to forgotten page using config variable 2024-04-23 17:42:49 +05:00
26673ec668 docxf, oform as pdf documentType 2024-04-23 11:26:16 +03:00
030cf91c65 fix(nodejs): show empty forgotten files list if error occurs 2024-04-23 00:02:55 +05:00
c60d2236d5 fix: linter offences 2024-04-22 23:30:24 +05:00
0a181bd04e feat(java-spring): control access to forgotten page using config variable 2024-04-22 23:24:56 +05:00
3fc658b0f8 feat(java): control access to forgotten page using config variable 2024-04-22 22:52:06 +05:00
403c2e2d8c feat(ruby): control access to forgotten page using config variable 2024-04-22 18:11:00 +05:00
beb831173d feat(python): control access to forgotten page using config variable 2024-04-22 17:30:09 +05:00
06a8668107 feat(php): control access to forgotten page using config variable 2024-04-22 16:40:32 +05:00
a722b142bb feat(nodejs): control access to forgotten page using config variable 2024-04-22 15:47:58 +05:00
39a61835ea fix main panel overflow in forgotten page 2024-04-22 13:44:13 +05:00
df3e018e3c fix link on logo 2024-04-22 12:37:03 +05:00
0f32feb1b9 csharp-mvc: fix link on logo 2024-04-19 13:47:05 +03:00
d61ebb27ae csharp-mvc: include files to project 2024-04-19 13:46:15 +03:00
e86118a56f csharp: fix link on logo 2024-04-19 13:43:45 +03:00
096edcfa66 csharp: include files to project 2024-04-19 13:43:15 +03:00
c5c1196a6f nodejs: copyright 2024 2024-04-19 13:24:29 +03:00
844e723387 save as for pdf 2024-04-19 12:29:47 +03:00
57087f0465 fix(nodejs): type confusion through parameter tampering 2024-04-17 22:23:22 +05:00
86339c8ea6 fix(php): fix linter offences 2024-04-17 18:33:16 +05:00
528cc5538e refactor(php): handle commandrequest failure 2024-04-17 18:31:35 +05:00
2880604546 fix(nodejs): fix linter offences 2024-04-17 18:06:41 +05:00
61d7a8003f refactor(nodejs): return correct response statuses 2024-04-17 18:04:29 +05:00
9e52d6d8b1 fix(nodejs): fix responsive design issues 2024-04-17 18:00:03 +05:00
6565fd2178 refactor(nodejs): rewrite delete event using dom and fetch and place it in separate file 2024-04-17 17:52:39 +05:00
f12fc29a57 feature(nodejs): add links to navbar 2024-04-17 17:44:55 +05:00
cd465a633e fix: responsive header image in forgotten files page 2024-04-17 16:36:28 +05:00
5fc22799e1 fix: fix table content overflow 2024-04-17 16:31:04 +05:00
59057a5905 feature(csharp-mvc): add navbar 2024-04-17 13:33:26 +05:00
8be3cfd66a feature(csharp): add navbar 2024-04-17 13:29:38 +05:00
b1167516d4 feature(csharp-mvc): forgotten files page 2024-04-17 13:24:01 +05:00
2f2ef0e65f feature(csharp): forgotten files page 2024-04-17 13:14:40 +05:00
33aba9a404 feature(java-spring): add navbar 2024-04-16 23:32:32 +05:00
82003763fa feature(java): add navbar 2024-04-16 23:19:34 +05:00
ea41130297 feature(ruby): add navbar 2024-04-16 22:57:49 +05:00
f909c31250 feature(python): add navbar 2024-04-16 22:45:39 +05:00
352b4c0ded feature(php): add navbar 2024-04-16 22:32:16 +05:00
7ec588280b feature(java-spring): forgotten files page 2024-04-16 19:15:30 +05:00
d43e4a98df feature(java): forgotten files page 2024-04-16 17:21:27 +05:00
461122a052 feature(ruby): forgotten files page 2024-04-16 13:31:54 +05:00
d1a1127b63 feature(python): forgotten files page 2024-04-16 13:02:55 +05:00
4263175871 refactor(python): return response in commandrequest method 2024-04-16 12:52:58 +05:00
98b93b3bc5 feature(php): forgotten files page 2024-04-16 00:38:07 +05:00
e32438218f refactor(java-spring): return response in commandrequest method 2024-04-15 19:11:10 +05:00
613d5e30a9 refactor(java): return response in commandrequest method 2024-04-15 19:09:55 +05:00
ccaf607cef refactor(csharp-mvc): return response in commandrequest method 2024-04-15 19:08:55 +05:00
837e63f372 refactor(csharp): return response in commandrequest method 2024-04-15 19:07:30 +05:00
a2a4c2b32f Merge branch 'develop' into feature/forgotten-page 2024-04-15 18:45:39 +05:00
fa303e9bf2 switching from filling to editing 2024-04-15 16:32:44 +03:00
2bed0f0bb7 build: delete com.inversoft:prime-jwt dependency 2024-04-03 15:44:53 +03:00
3570f189a0 build: ossrh snapshot repository 2024-04-03 15:17:16 +03:00
afd5a88b1d Merge remote-tracking branch 'remotes/origin/develop' into feature/docs-integration-sdk
# Conflicts:
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/controllers/IndexController.java
2024-04-03 15:16:19 +03:00
a0ce620f84 build: use com.onlyoffice:docs-integration-sdk from maven 2024-04-02 16:36:50 +03:00
e3c82eed09 feat(nodejs): creating only files with editnew in wopi discovery 2024-04-01 12:10:26 +07:00
1df3c046ee docs: license 2024 2024-03-29 10:27:50 +03:00
1f2623dc07 refactor: settings for connect doc-server to application.properties 2024-03-29 10:19:39 +03:00
317018df5b fix: convert file after upload 2024-03-29 09:54:19 +03:00
729065fed0 Merge branch 'develop' into feature/docs-integration-sdk
# Conflicts:
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/controllers/FileController.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/template/TemplateManager.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/AbstractModel.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/Format.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Customization.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Embedded.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Goback.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Info.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ConvertErrorType.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Mode.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ToolbarDocked.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Type.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/CommentGroup.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Document.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/EditorConfig.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/FileModel.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Permission.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/ReferenceData.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Template.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/User.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/SSLUtils.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/file/DefaultFileUtility.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/file/FileUtility.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultFormatService.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultServiceConverter.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/util/service/ServiceConverter.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/Action.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/ChangesHistory.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/ChangesUser.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/Convert.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/ConvertedData.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/History.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/ReferenceData.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/dto/Track.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/mappers/AbstractMapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/mappers/Mapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/mappers/PermissionsMapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/mappers/UsersMapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/Configurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/CustomizationConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/DocumentConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/EditorConfigConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/EmbeddedConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/FileConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultCustomizationConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultDocumentConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEditorConfigConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEmbeddedConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultFileConfigurer.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultDocumentWrapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultEmbeddedWrapper.java
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultFileWrapper.java
#	web/documentserver-example/java-spring/src/main/resources/assets/document-formats
2024-03-28 17:17:16 +03:00
248595472d build: docs-integration-sdk-1.1.3-SNAPSHOT.jar 2024-03-28 15:19:18 +03:00
ead7e8de06 fix: condition upload file 2024-03-28 15:18:43 +03:00
c55142bd73 Merge remote-tracking branch 'remotes/origin/feature/create-pdf' into release/v8.1.0 2024-03-21 16:06:24 +03:00
6c03b145e2 nodejs: editing pdf form 2024-03-21 15:24:47 +03:00
15e09fece2 nodejs: filling by default if possible 2024-03-21 15:23:57 +03:00
abf382a03b nodejs: creating pdf form 2024-03-21 15:03:13 +03:00
a763e2b9fe add: using replaceToInnerDocumentServerUrl() 2023-12-18 12:57:32 +03:00
841a4cd47e delete: SSLUtils 2023-12-18 12:52:10 +03:00
a5cd051303 change: method saveAs in FileController 2023-12-18 12:45:19 +03:00
381c9d74aa revert: docservice.properties 2023-12-18 12:41:58 +03:00
154dbb63e9 hange: dependency docs-integration-sdk as jar file 2023-12-18 12:41:51 +03:00
11614ca5be delete: gitmodule document-formats 2023-12-15 11:16:33 +03:00
23caedfeff add: using model ReferenceData from sdk 2023-12-15 11:10:39 +03:00
3c10bdd9c6 delete: unused application.properties 2023-12-15 11:00:57 +03:00
56f4cb2208 refactoring: docservice.properties 2023-12-15 10:08:08 +03:00
bb2b9de205 delete: unused application.properties 2023-12-15 10:07:45 +03:00
6431ee33a8 delete: unused models and dto 2023-12-15 09:58:45 +03:00
9750b37f97 delete: unused FormatService 2023-12-15 09:49:19 +03:00
6dc02a3f43 delete: unused FileUtility 2023-12-15 09:48:16 +03:00
3bb39f4fb0 delete: unused ServiceConverter 2023-12-15 09:47:15 +03:00
5a9933f002 change: FileController, DefaultCallbackManager, DefaultHistoryManager with using sdk DocumentManager 2023-12-15 09:47:11 +03:00
5829794052 add: method generateRevisionId to DocumentManager 2023-12-15 09:46:58 +03:00
870e14af73 change: IndexController with using sdk DocumentManager 2023-12-15 09:36:10 +03:00
e6f6e0572b change: DefaultHistoryManager with using sdk DocumentManager 2023-12-15 09:34:26 +03:00
f4165d7715 change: DefaultCallbackManager with using sdk DocumentManager 2023-12-15 09:34:16 +03:00
bea8fd534e change: method getDocumentName in DocumentMangerImpl 2023-12-15 09:34:10 +03:00
2a59733e61 add: methods getFileName, generateFilepath to LocalFileStorage 2023-12-15 09:33:48 +03:00
ce937a58bb delete: unused DocumentManager 2023-12-14 16:27:46 +03:00
5955137575 change: FileController, DefaultCallbackManager with using sdk DocumentManager 2023-12-14 16:27:28 +03:00
91182b1967 add: method versionDir to HistoryManager 2023-12-14 16:26:47 +03:00
931f2db9d1 change: sdk DocumentManager, moved methods from DocumentManager (getCorrectName, getFilesInfo, createDemo) 2023-12-14 16:19:28 +03:00
bcf6ba1428 delete: FileUtility from sdk UrlManager 2023-12-14 16:02:23 +03:00
32d914c78c delete: unused TemplateManager 2023-12-14 15:59:46 +03:00
e324cb333b add: mathod getTemplateImageUrl to sdk UrlManager 2023-12-14 15:58:11 +03:00
88e80de4fc change: DocumentManager moved url methods to sdk UrlManager 2023-12-14 15:50:46 +03:00
b16e35275b change: FileController replace FileUtility method to sdk DocumentManager 2023-12-14 15:16:46 +03:00
5519ac4afc changed: DefaultHistoryManager with using sdk history models 2023-12-14 13:14:35 +03:00
32a66f4495 change: replace using JwtManager to sdk JwtManager 2023-12-14 12:35:31 +03:00
682265078c change: CallbackManager with using sdk CommandService 2023-12-14 12:13:36 +03:00
8db11243fd change: CallbackServiceImpl with using method processEditing from CallbackManager 2023-12-14 12:09:31 +03:00
45b6bfa443 add: method processEditing to CallbackManager 2023-12-14 12:08:27 +03:00
ad43b9298f change: FileController with using sdk CommandService 2023-12-14 12:04:52 +03:00
5577f5388f add: sdk service (CommandService) to spring context 2023-12-14 12:04:32 +03:00
f504b2be6e delete: unused callback handlers (EditCallback, ForcesaveCallback, SaveCallback) 2023-12-14 11:29:59 +03:00
776a34a5a0 change: FileController with using sdk CallbackService 2023-12-14 11:28:41 +03:00
6fcc535468 add: implementations sdk CallbackService (CallbackServiceImpl) 2023-12-14 11:28:07 +03:00
ced855d6ac delete: unused method (getConvertedData) from ServiceConverter 2023-12-13 16:45:24 +03:00
3725020468 change: process conversion with using sdk service convertService (FileController, DefaultCallbackManager) 2023-12-13 16:40:24 +03:00
e230d8ea9b add: sdk service (ConvertService) to spring context 2023-12-13 16:38:05 +03:00
a10366bae9 add: setting docservice.lossyEdit to docservice.properties 2023-12-13 16:37:17 +03:00
a7fc3d38e4 delete: unused mappers (PermissionsMapper, UsersMapper) 2023-12-13 14:57:44 +03:00
11ead2e57f delete: unused wrappers (DefaultCustomizationWrapper, DefaultDocumentWrapper, DefaultEmbeddedWrapper, DefaultFileWrapper) 2023-12-13 14:57:44 +03:00
59a2b1b439 delete: unused services (CustomizationConfigurer, DocumentConfigurer, EditorConfigConfigurer, EmbeddedConfigurer, FileConfigurer) 2023-12-13 14:57:44 +03:00
1bedfa0cf2 change: EditorController with using sdk ConfigService 2023-12-13 14:57:44 +03:00
b9137b1d86 add: sdk service (ConfigService) 2023-12-13 14:57:44 +03:00
892d390fff add: method getCurrentUser to UserServices 2023-12-13 14:57:43 +03:00
2e55bf1cfc add: docservice.properties file 2023-12-13 14:57:43 +03:00
9fe8701718 add: sdk managers (JwtManager, RequestManager) to spring context 2023-12-13 14:57:30 +03:00
c2c14dd2f4 add: implementations sdk managers (DocumentMangerImpl, SettingsManagerImpl, UrlManagerImpl) 2023-12-13 14:43:49 +03:00
d1a67fa322 add: dependency com.onlyoffice.docs-intagration-sdk 2023-12-13 14:42:41 +03:00
3820f76d27 nodejs: added page for forgotten files 2023-11-03 09:14:41 +03:00
327 changed files with 8514 additions and 4606 deletions

32
.github/workflows/artifact-go.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Artifact Golang
on:
workflow_dispatch:
push:
branches: [master]
paths: ['web/documentserver-example/go/**']
pull_request:
branches: [master]
paths: ['web/documentserver-example/go/**']
jobs:
artifact:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Build Artifact
run: |
cd ${{ github.workspace }}
cwd=$(pwd)
git submodule update --init --recursive
cd ./web/documentserver-example/go
mkdir -p ./deploy/'Go Example'
rsync -av --exclude='deploy' ./ ./deploy/'Go Example'
rm -rf ./deploy/'Go Example'/static/assets/document-formats/.git
rm -rf ./deploy/'Go Example'/static/assets/document-templates/.git
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: Go.Example
path: ${{ github.workspace }}/web/documentserver-example/go/deploy

View File

@ -0,0 +1,31 @@
name: Artifact PHP Laravel
on:
workflow_dispatch:
push:
branches: [master]
paths: ['web/documentserver-example/php-laravel/**']
pull_request:
branches: [master]
paths: ['web/documentserver-example/php-laravel/**']
jobs:
artifact:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Build Artifact
run: |
cd ${{ github.workspace }}
git submodule update --init --recursive
cd ./web/documentserver-example/php-laravel
mkdir -p ./deploy/'PHP Laravel Example'
rsync -av --exclude='deploy' ./ ./deploy/'PHP Laravel Example'
rm -rf ./deploy/'PHP Laravel Example'/public/assets/document-formats/.git
rm -rf ./deploy/'PHP Laravel Example'/public/assets/document-templates/.git
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: PHP-Laravel.Example
path: ${{ github.workspace }}/web/documentserver-example/php-laravel/deploy

29
.github/workflows/lint-go.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Golangci
on:
workflow_dispatch:
push:
branches: [master]
paths: ['web/documentserver-example/go/**']
pull_request:
branches: [master, develop]
paths: ['web/documentserver-example/go/**']
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./web/documentserver-example/go
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Lint Golangci
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
golangci-lint run

View File

@ -3,10 +3,10 @@ name: Lint Java
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/java/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/java/**']
jobs:

View File

@ -3,10 +3,10 @@ name: ESLint
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/nodejs/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/nodejs/**']
env:

37
.github/workflows/lint-php-laravel.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Laravel Pint
on:
workflow_dispatch:
push:
branches: [master]
paths: ['web/documentserver-example/php-laravel/**']
pull_request:
branches: [master, develop]
paths: ['web/documentserver-example/php-laravel/**']
jobs:
lint:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php: [8.2]
defaults:
run:
working-directory: ./web/documentserver-example/php-laravel
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: json, dom, curl, libxml, mbstring
coverage: none
- name: Install Pint
run: composer global require laravel/pint
- name: Run Pint
run: pint --test

View File

@ -3,10 +3,10 @@ name: PHPCs
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/php/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/php/**']
jobs:

View File

@ -3,10 +3,10 @@ name: PyLint
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/python/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/python/**']
jobs:

View File

@ -3,10 +3,10 @@ name: Rubocop
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/ruby/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/ruby/**']
jobs:
@ -30,7 +30,7 @@ jobs:
- name: Install Dependencies
run: |
bundle update
bundle install
- name: Rubocop
run: |

View File

@ -3,10 +3,10 @@ name: Lint Spring
on:
workflow_dispatch:
push:
branches: [master, main]
branches: [master]
paths: ['web/documentserver-example/java-spring/**']
pull_request:
branches: [master, main, develop]
branches: [master, develop]
paths: ['web/documentserver-example/java-spring/**']
jobs:

View File

@ -2,7 +2,7 @@ name: Release
on:
push:
branches: [master,main]
branches: [master]
permissions:
contents: write

21
.gitmodules vendored
View File

@ -1,22 +1,21 @@
[submodule "web/documentserver-example/nodejs/public/assets/document-templates"]
path = web/documentserver-example/nodejs/public/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/nodejs/public/assets/document-formats"]
path = web/documentserver-example/nodejs/public/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = feature/v8.0
[submodule "web/documentserver-example/csharp-mvc/assets/document-templates"]
path = web/documentserver-example/csharp-mvc/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/csharp-mvc/assets/document-formats"]
path = web/documentserver-example/csharp-mvc/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
[submodule "web/documentserver-example/php/assets/document-templates"]
path = web/documentserver-example/php/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/php/assets/document-formats"]
path = web/documentserver-example/php/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
@ -24,19 +23,19 @@
[submodule "web/documentserver-example/python/assets/document-templates"]
path = web/documentserver-example/python/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/java/src/main/resources/assets/document-templates"]
path = web/documentserver-example/java/src/main/resources/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/ruby/assets/document-templates"]
path = web/documentserver-example/ruby/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/java-spring/src/main/resources/assets/document-templates"]
path = web/documentserver-example/java-spring/src/main/resources/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/python/assets/document-formats"]
path = web/documentserver-example/python/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
@ -49,14 +48,10 @@
path = web/documentserver-example/java/src/main/resources/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = master
[submodule "web/documentserver-example/java-spring/src/main/resources/assets/document-formats"]
path = web/documentserver-example/java-spring/src/main/resources/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = master
[submodule "web/documentserver-example/csharp/assets/document-templates"]
path = web/documentserver-example/csharp/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
branch = main/default
[submodule "web/documentserver-example/csharp/assets/document-formats"]
path = web/documentserver-example/csharp/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats

View File

@ -1,6 +1,5 @@
Document Server integration example uses code from the following 3rd party projects.
web/documentserver-example/csharp
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
@ -132,6 +131,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
License: Apache 2.0
License File: jackson-databind.license
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
License: Apache 2.0
License File: jackson-dataformat-properties.license
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
License: MIT, GPL
License File: jQuery.BlockUI.license
@ -156,6 +159,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
License: MIT
License File: jQuery.UI.license
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
License Public Domain
License File: json.license
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
License: Apache 2.0
License File: JSON.simple.license
@ -168,14 +175,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
License: Apache 2.0
License File modelmapper.license
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
License: Apache 2.0
License File: prime-jwt.license
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
@ -271,6 +278,9 @@ urllib - Request HTTP URLs in a complex world — basic and digest authen
License: MIT
License File: urllib.license
utf7 - Encodes and decodes JavaScript (Unicode/UCS-2) strings to UTF-7 ASCII strings. (https://github.com/kkaefer/utf7/blob/master/LICENSE)
License: MIT
License File: utf7.license
web/documentserver-example/php

View File

@ -1,14 +1,33 @@
# Change Log
- fill permission in embedded mode
- delete all files
- handling conversion -9 error
- nodejs: wopi formsubmit icon
- nodejs: tabs menu
- change insert image
- different goback for users
## 1.11.0
- he-IL skin language
- ConvertService.ashx address replaced with converter
- coauthoring/CommandService.ashx address replaced with command
- without submitForm in viewer
## 1.10.0
- nodejs: converting function on index page
- java-spring: using java docs-integration-sdk
- tabs menu
- creating and editing pdf instead docxf
- filling by default
- forgotten files
- delete all files
- save as for pdf
- handling conversion -9 error
- change inserted image
- different goback for users
## 1.9.0
- nodejs: filling by default
- nodejs: docxf, oform as pdf documentType
- nodejs: creating and editing pdf instead docxf
- nodejs: wopi formsubmit icon
- nodejs: close editor
- en-GB, sr-Cyrl-RS skin languages
- switching from filling to editing
- fill permission in embedded mode
## 1.8.0
- nodejs: pdf, djvu, xps, oxps as pdf documentType

View File

@ -38,9 +38,15 @@ namespace OnlineEditorsExampleMVC
// create the main script bundle
bundles.Add(new ScriptBundle("~/bundles/scripts").Include(
"~/Scripts/formats.js",
"~/Scripts/jscript.js"
));
// create the forgotten page script bundle
bundles.Add(new ScriptBundle("~/bundles/forgotten").Include(
"~/Scripts/forgotten.js"
));
// create a style bundle
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/stylesheet.css",
@ -52,6 +58,11 @@ namespace OnlineEditorsExampleMVC
bundles.Add(new StyleBundle("~/Content/editor").Include(
"~/Content/editor.css"
));
// create the forgotten page style bundle
bundles.Add(new StyleBundle("~/Content/forgotten").Include(
"~/Content/forgotten.css"
));
}
}
}

View File

@ -0,0 +1,161 @@
.center {
width: auto;
}
.left-panel {
width: 256px;
}
.main-panel {
width: 832px;
margin: 0 32px;
padding: 48px 0;
left: 0;
}
.tableRow {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #E2E2E2;
}
.tableRow td:first-child {
width: 70%;
flex-grow: 0;
max-width: none;
}
.tableHeader td:first-child {
text-align: left;
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: center;
padding: 0 !important;
}
.tableHeader {
width: 100%;
}
.stored-edit {
display: block;
padding-top: 0;
max-width: none;
}
menu.links {
width: 100%;
}
.scroll-table-body table {
table-layout: fixed;
}
.stored-edit span {
font-size: 12px;
line-height: normal;
position: static;
}
.scroll-table-body {
overflow-y: auto;
}
.stored-list {
height: calc(100% - 58px);
}
header {
min-width:auto;
}
header a {
display: block;
margin: 0 auto;
width: 1152px;
}
@media (max-width: 1279px) and (min-width: 1024px) {
.left-panel {
width: 208px;
}
.main-panel {
width: 688px;
}
header a {
width: 928px;
}
header img {
margin-left: 16px;
}
}
@media (max-width: 1023px) and (min-width: 593px) {
.center {
max-width: 768px;
width: calc(100% - 80px);
}
.table-main {
width: 100%;
}
.left-panel {
width: 208px;
}
.main-panel {
width: calc(100% - 32px);
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 20%;
}
header a {
width: 768px;
}
header img {
margin-left: 40px;
}
}
@media (max-width: 592px) and (min-width: 320px) {
.center, .table-main {
width: 100%;
}
.left-panel {
display: none;
}
.main-panel {
width: 100%;
margin: 0;
padding: 28px 16px;
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 25%;
}
header a {
width: auto;
}
.scroll-table-body {
top: 40px;
}
.tableRow {
padding: 8px 0;
}
}

View File

@ -1 +0,0 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 3c0-1.65685 1.34315-3 3-3h20l7 7v30c0 1.6569-1.3431 3-3 3H3c-1.65685 0-3-1.3431-3-3V3z" fill="#27ABA3"/><path d="M23 0l7 7h-4c-1.6569 0-3-1.34315-3-3V0z" fill="#008078"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 14H6v7h18v-7zm-.8182 5.9978H6.81818V15H23.1818v4.9978zM24 23H6v7h18v-7zm-.8182 5.9978H6.81818V24H23.1818v4.9978z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 463 B

View File

@ -0,0 +1,5 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 3C0 1.34315 1.34315 0 3 0H23L30 7V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#9E1919"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0062 15V16.0065H24V15H17.0062ZM17.0062 19V20.0163H24V19H17.0062ZM24 23H17.0062V24.0261H24V23ZM6 28V27.0293H24V28H6ZM7 16H14V23H7V16ZM6 15H7H14H15V16V23V24H14H7H6V23V16V15Z" fill="white"/>
<path d="M23 0L30 7H26C24.3431 7 23 5.65685 23 4V0Z" fill="black" fill-opacity="0.25"/>
</svg>

After

Width:  |  Height:  |  Size: 558 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 17V11H12V17H17V9H20L10 0L0 9H3V17H8Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

View File

@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 1h8l4 4v10H2V1z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5l-4-4H2v14h12V5zm-4-5l5 5v11H1V0h9z" fill="#BFBFBF"/><path fill="#9E1919" d="M3 10h10v4H3z"/><path d="M7 7V2H3v5h4zM8 3V2h2v1H8zM8 5V4h5v1H8zM13 6H8v1h5V6zM13 8H3v1h10V8z" fill="#BFBFBF"/><path opacity=".3" d="M9 1h1v3h4l1 1H9V1z" fill="#333"/></svg>

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5332 22.2243L0.632544 17.5921C-0.210848 17.1877 -0.210848 16.5627 0.632544 16.1951L4.07945 14.5775L10.4966 17.5921C11.34 17.9965 12.6967 17.9965 13.5034 17.5921L19.9206 14.5775L23.3675 16.1951C24.2108 16.5995 24.2108 17.2245 23.3675 17.5921L13.4668 22.2243C12.6967 22.592 11.34 22.592 10.5332 22.2243Z" fill="#FF6F3D"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 16.4922L0.630617 11.8546C-0.210206 11.4497 -0.210206 10.824 0.630617 10.456L3.99391 8.87329L10.5011 11.9282C11.342 12.3331 12.6946 12.3331 13.4989 11.9282L20.0061 8.87329L23.3694 10.456C24.2102 10.8608 24.2102 11.4865 23.3694 11.8546L13.4989 16.4922C12.658 16.897 11.3054 16.897 10.5011 16.4922Z" fill="#95C038"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 10.8195L0.630617 6.24863C-0.210206 5.84959 -0.210206 5.23289 0.630617 4.87013L10.5011 0.299281C11.342 -0.0997605 12.6946 -0.0997605 13.4989 0.299281L23.3694 4.87013C24.2102 5.26917 24.2102 5.88587 23.3694 6.24863L13.4989 10.8195C12.658 11.1822 11.3054 11.1822 10.5011 10.8195Z" fill="#5DC0E8"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,5 @@
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13H7C6.44772 13 6 12.5523 6 12C6 11.4477 6.44772 11 7 11H11V7C11 6.44772 11.4477 6 12 6C12.5523 6 13 6.44772 13 7V11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H13V17Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B

View File

@ -79,7 +79,8 @@
margin-left: 0;
}
.tableRow {
.tableRow,
menu.links {
width: 90%;
}
@ -119,7 +120,8 @@
.contentCells-icon{
width: 5%;
}
.tableRow {
.tableRow,
menu.links {
width: 55%;
}
@ -175,7 +177,8 @@
}
@media (max-width: 715px) {
.tableRow {
.tableRow,
menu.links {
width: 45%;
}
}
@ -263,7 +266,8 @@
padding-left: 0;
}
.tableRow {
.tableRow,
menu.links {
width: 75%;
}
@ -293,7 +297,8 @@
width: 580px;
}
.tableRow {
.tableRow,
menu.links {
width: 95%;
}
@ -407,7 +412,8 @@
padding: 16px 0 6px;
}
.tableRow {
.tableRow,
menu.links {
width: 40%;
}
@ -538,7 +544,8 @@
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow {
.tableRow,
menu.links {
width: 35%;
}
@ -564,7 +571,8 @@
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
@ -599,7 +607,8 @@
}
@media (max-width: 420px) and (min-width: 320px) {
.tableRow {
.tableRow,
menu.links {
width: 25%;
}
@ -649,7 +658,8 @@
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow{
.tableRow,
menu.links {
width: 50%;
}
}
@ -698,3 +708,216 @@
max-width: none;
}
}
@media (max-width: 592px) and (min-width: 320px) {
body.menu-open {
overflow: hidden;
}
header {
min-width: auto;
height: fit-content;
}
header a {
display: block;
}
header img {
margin: 0;
}
header, footer {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 0;
z-index: 100;
}
.center {
width: 100%;
margin: 0;
}
.left-panel {
background-color: rgba(186, 186, 186, 0.6);
display: none;
flex-direction: row;
align-items: start;
max-width: none;
width: 100%;
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
display: flex;
}
.help-block {
height: 100%;
margin: 0;
background-color: #F5F5F5;
width: 248px;
padding-left: 16px;
padding-top: 33px;
padding-bottom: 33px;
padding-right: 40px;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
}
.table-main {
width: 100%;
}
.mobile-close-btn {
display: block;
width: 48px;
height: 48px;
background-color: #E2E2E2;
border-radius: 2px;
border-color: #E2E2E2;
color: #808080;
cursor: pointer;
outline: inherit;
border: none;
}
.main-panel {
width: 100%;
left: 0;
padding: 28px 16px;
}
#portal-info {
width: 100%;
max-width: fit-content;
}
menu.links {
width: 100%;
margin-top: 0;
padding: 0;
}
span.portal-name {
font-size: 16px;
}
span.portal-descr:first-child {
font-size: 13px;
}
span.portal-descr {
font-size: 12px;
}
.user-descr {
width: 100%;
max-width: none;
min-width: auto;
border-bottom: 1px solid #E5E5E5;
padding: 12px 0;
margin: 0;
cursor: pointer;
}
.user-descr ul {
display: none;
}
.user-descr ul.active {
display: block;
}
.user-descr b {
font-size: 13px;
display: flex;
align-items: center;
column-gap: 8px;
margin: 0;
}
.user-descr b::before {
content: url("images/plus.svg");
display: inline-block;
width: 24px;
height: 24px;
}
.storedHeader {
width: 100%;
}
.storedHeaderClearAll {
padding-right: 0;
}
.scroll-table-body {
top: 36px;
}
.scroll-table-body tr:first-child {
padding-top: 0;
}
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 16px 0;
width: 100%;
}
.tableRow td:first-child {
width: 100%;
}
.stored-edit span {
font-size: 14px;
}
.header-list {
font-size: 16px;
}
.firstContentCellViewers {
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
border-bottom: none !important;
}
.downloadContentCellShift:after {
display: none;
}
.main-nav {
display: none;
}
.responsive-nav {
height: 44px;
display: flex;
flex-direction: row;
margin: 0;
align-items: center;
column-gap: 16px;
padding: 10px 16px;
width: 100%;
box-sizing: border-box;
list-style: none;
}
.main {
height: calc(100% - 124px);
}
.user-block-table {
height: auto;
}
}

View File

@ -65,6 +65,14 @@ header img {
margin: 10px 0 22px 32px;
}
.responsive-nav {
display: none;
}
.mobile-close-btn {
display: none;
}
.center {
position:relative;
margin: 0 auto 0;
@ -164,7 +172,7 @@ label .checkbox {
}
.try-editor.form {
background-image: url("images/file_docxf.svg");
background-image: url("images/file_pdf.svg");
}
.side-option {
@ -298,6 +306,43 @@ label .checkbox {
border-bottom: 1px solid #D0D5DA;
}
.links {
display: flex;
padding: 0;
column-gap: 30px;
align-items: center;
list-style: none;
border-bottom: 1px solid #E2E2E2;
margin: 0;
margin-bottom: 24px;
}
.links li {
padding: 4px;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.links li.active {
border-bottom: 2px solid #FF6F3D;
}
.links li.active a {
color: #FF6F3D;
}
.links li.active a img {
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
}
.links a {
display: inline-block;
padding: 2px 0;
line-height: 20px;
font-size: 13px;
text-decoration: none;
}
#mainProgress {
color: #333333;
display: none;
@ -491,6 +536,11 @@ footer table tr td:first-child {
background-image: url("images/icon_pptx.svg");
}
.stored-edit.pdf,
.uploadFileName.pdf {
background-image: url("images/icon_pdf.svg");
}
.stored-edit span {
font-size: 12px;
line-height: 12px;

View File

@ -17,10 +17,13 @@
*/
using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Web.Mvc;
using OnlineEditorsExampleMVC.Helpers;
using OnlineEditorsExampleMVC.Models;
using System.Web.Configuration;
namespace OnlineEditorsExampleMVC.Controllers
{
@ -31,6 +34,46 @@ namespace OnlineEditorsExampleMVC.Controllers
return View();
}
public ActionResult Forgotten()
{
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
{
ViewData["Message"] = "The forgotten page is disabled";
return View("~/Views/Shared/Error.aspx");
}
var files = new List<Dictionary<string, string>>();
try
{
var response = TrackManager.commandRequest("getForgottenList", null);
ArrayList keys = (ArrayList)response["keys"];
// fetch all the forgotten files from the document server
foreach (string key in keys)
{
var file = new Dictionary<string, string>();
var fileResult = TrackManager.commandRequest("getForgotten", key);
file.Add("key", fileResult["key"].ToString());
file.Add("url", fileResult["url"].ToString());
file.Add(
"type",
FileUtility.GetFileType(fileResult["url"].ToString())
.ToString()
.ToLower()
);
files.Add(file);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
return View("Forgotten", new ForgottenFilesModel(files));
}
// viewing file in the editor
public ActionResult Editor(string fileName, string editorsMode, string editorsType, string directUrl)
{
@ -52,7 +95,7 @@ namespace OnlineEditorsExampleMVC.Controllers
var id = Request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id);
DocManagerHelper.CreateMeta(fileName, user.id, user.name); // create meta information for the sample document
Response.Redirect(Url.Action("Editor", "Home", new { fileName = fileName }));
Response.Redirect(Url.Action("Editor", "Home", new { fileName = fileName, editorsMode="edit" }));
return null;
}
}

View File

@ -225,7 +225,7 @@ namespace OnlineEditorsExampleMVC.Helpers
private static void ProcessResponseError(int errorCode)
{
var errorMessage = string.Empty;
const string errorMessageTemplate = "Error occurred in the ConvertService.ashx: {0}";
const string errorMessageTemplate = "Error occurred in the ConvertService: {0}";
switch (errorCode)
{

View File

@ -282,7 +282,7 @@ namespace OnlineEditorsExampleMVC.Helpers
}
// create a command request
public static void commandRequest(string method, string key, object meta = null)
public static Dictionary<string, object> commandRequest(string method, string key, object meta = null)
{
DocManagerHelper.VerifySSL();
@ -345,6 +345,7 @@ namespace OnlineEditorsExampleMVC.Helpers
{
throw new Exception(dataResponse);
}
return responseObj;
}
// save file

View File

@ -77,18 +77,19 @@ namespace OnlineEditorsExampleMVC.Models
var jss = new JavaScriptSerializer();
var ext = Path.GetExtension(FileName).ToLower(); // get file extension
var editorsMode = Mode ?? "edit"; // get editor mode
var canFill = DocManagerHelper.FillFormExts.Contains(ext);
var editorsMode = Mode ?? (canFill ? "fillForms" : "edit"); // get editor mode
var canEdit = DocManagerHelper.EditedExts.Contains(ext); // check if the file with such an extension can be edited
var id = request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id); // get the user
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && DocManagerHelper.FillFormExts.Contains(ext)) {
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && canFill) {
editorsMode = "fillForms";
canEdit = true;
}
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1"); // check if the Submit form button is displayed or not
var submitForm = !editorsMode.Equals("view") && user.id.Equals("uid-1"); // check if the Submit form button is displayed or not
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // set the mode parameter: change it to view if the document can't be edited
// favorite icon state

View File

@ -33,7 +33,8 @@ namespace OnlineEditorsExampleMVC.Models
{
Word,
Cell,
Slide
Slide,
Pdf
}
// get file type
@ -41,6 +42,7 @@ namespace OnlineEditorsExampleMVC.Models
{
var ext = Path.GetExtension(fileName).ToLower();
if (FormatManager.PdfExtensions().Contains(ext)) return FileType.Pdf; // pdf type for document extensions
if (FormatManager.DocumentExtensions().Contains(ext)) return FileType.Word; // word type for document extensions
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return FileType.Cell; // cell type for spreadsheet extensions
if (FormatManager.PresentationExtensions().Contains(ext)) return FileType.Slide; // slide type for presentation extensions
@ -185,6 +187,20 @@ namespace OnlineEditorsExampleMVC.Models
.ToList();
}
public static List<string> PdfExtensions()
{
return Pdfs()
.Select(format => format.Extension())
.ToList();
}
public static List<Format> Pdfs()
{
return All()
.Where(format => format.Type == FileType.Pdf)
.ToList();
}
public static List<string> AllExtensions()
{
return All()

View File

@ -1,4 +1,4 @@
/**
/**
*
* (c) Copyright Ascensio System SIA 2024
*
@ -16,16 +16,15 @@
*
*/
package com.onlyoffice.integration.dto;
using System.Collections.Generic;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
namespace OnlineEditorsExampleMVC.Models
{
// create file model
public class ForgottenFilesModel
{
public List<Dictionary<string, string>> files { get; set; }
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChangesHistory {
private String created;
private ChangesUser user;
}
public ForgottenFilesModel(List<Dictionary<string, string>> files) { this.files = files; }
}
}

View File

@ -116,6 +116,7 @@
<Compile Include="Helpers\Utils.cs" />
<Compile Include="Models\FileModel.cs" />
<Compile Include="Models\FileUtility.cs" />
<Compile Include="Models\ForgottenFilesModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WebEditor.ashx.cs">
<DependentUpon>WebEditor.ashx</DependentUpon>
@ -123,6 +124,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Content\editor.css" />
<Content Include="Content\forgotten.css" />
<Content Include="Content\images\block-content.svg" />
<Content Include="Content\images\cell.ico" />
<Content Include="Content\images\close.svg" />
@ -140,6 +142,7 @@
<Content Include="Content\images\file_xlsx.svg" />
<Content Include="Content\images\fill-forms.svg" />
<Content Include="Content\images\filter.svg" />
<Content Include="Content\images\home.svg" />
<Content Include="Content\images\icon_docx.svg" />
<Content Include="Content\images\icon_pptx.svg" />
<Content Include="Content\images\icon_xlsx.svg" />
@ -151,6 +154,8 @@
<Content Include="Content\images\notdone.svg" />
<Content Include="Content\images\review.svg" />
<Content Include="Content\images\slide.ico" />
<Content Include="Content\images\uid-1.png" />
<Content Include="Content\images\uid-2.png" />
<Content Include="Content\images\word.ico" />
<Content Include="Content\jquery-ui.css" />
<Content Include="Content\media.css" />
@ -158,6 +163,10 @@
<Content Include="favicon.ico" />
<Content Include="Global.asax" />
<Content Include="LICENSE" />
<Content Include="Scripts\forgotten.js" />
<Content Include="Scripts\formats.js" />
<Content Include="Scripts\jquery-3.6.4.js" />
<Content Include="Scripts\jquery-migrate-3.4.1.js" />
<Content Include="Scripts\jquery-ui.js" />
<Content Include="Scripts\jquery.blockUI.js" />
<Content Include="Scripts\jquery.dropdownToggle.js" />
@ -165,17 +174,13 @@
<Content Include="Scripts\jquery.iframe-transport.js" />
<Content Include="Scripts\jscript.js" />
<Content Include="Views\Home\Editor.aspx" />
<Content Include="Views\Home\Forgotten.aspx" />
<Content Include="Views\Home\Index.aspx" />
<Content Include="Web.config">
<SubType>Designer</SubType>
</Content>
<Content Include="Views\Web.config" />
<Content Include="Views\Shared\Error.aspx" />
<Content Include="licenses\EntityFramework.license" />
<Content Include="licenses\Microsoft.Web.Infrastructure.license" />
<Content Include="licenses\Newtonsoft.Json.license" />
<Content Include="licenses\jquery.license" />
<Content Include="licenses\WebGrease.license" />
<Content Include="web.appsettings.config" />
<Content Include="WebEditor.ashx" />
</ItemGroup>

View File

@ -0,0 +1,19 @@
function deleteFile(event) {
let filename = event.currentTarget.getAttribute("data");
filename = encodeURIComponent(filename);
let url = `webeditor.ashx?type=removeforgotten&filename=${filename}`;
fetch(url, {
headers: {
"Content-Type": "application/json",
}
}).then(result => {
if(result.status == 204) {
document.location.reload(true);
}
});
}
document.querySelectorAll('.delete-file').forEach(el => {
el.addEventListener('click', deleteFile);
});

View File

@ -109,7 +109,7 @@ if (typeof jQuery != "undefined") {
var timer = null;
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
}
@ -121,7 +121,7 @@ if (typeof jQuery != "undefined") {
jq("#filePass").val("");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (!formatManager.isAutoConvertible(posExt)) {
@ -421,4 +421,27 @@ if (typeof jQuery != "undefined") {
}).mouseout(function () {
jq("div.tooltip").remove();
});
}
}
function toggleSidePanel(event) {
event.preventDefault();
let sidePanel = document.querySelector(".left-panel");
let body = document.querySelector("body");
if (sidePanel.classList.contains("active")) {
sidePanel.classList.remove("active");
body.classList.remove("menu-open");
} else {
sidePanel.classList.add("active")
body.classList.add("menu-open");
}
}
function toggleUserDescr(event) {
let list = event.currentTarget.querySelector("ul");
let cursor = window.getComputedStyle(event.currentTarget).getPropertyValue("cursor");
if (cursor === "pointer") {
if (list.classList.contains("active")) list.classList.remove("active");
else list.classList.add("active");
}
}

View File

@ -68,7 +68,7 @@
// the user is trying to switch the document from the viewing into the editing mode
var onRequestEditRights = function () {
location.href = location.href.replace(RegExp("editorsMode=view\&?", "i"), "");
location.href = location.href.replace(RegExp("editorsMode=\\w+\&?", "i"), "") + "&editorsMode=edit";
};
// an error or some other specific event occurs
@ -108,7 +108,7 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
if (event.data.favorite) {
if (event.data.favorite !== undefined) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
@ -337,6 +337,7 @@
config.events['onRequestUsers'] = onRequestUsers;
<% } %>
config.events['onRequestSaveAs'] = onRequestSaveAs;
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
@ -347,10 +348,6 @@
config.events['onRequestOpen'] = onRequestOpen;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
};
var сonnectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -0,0 +1,144 @@
<%@ Page Title="ONLYOFFICE" Language="C#" Inherits="System.Web.Mvc.ViewPage<OnlineEditorsExampleMVC.Models.ForgottenFilesModel>" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="OnlineEditorsExampleMVC.Helpers" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width" />
<meta name="server-version" content=<%= DocManagerHelper.GetVersion() %> />
<!--
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
-->
<title>ONLYOFFICE</title>
<link href="<%: Url.Content("~/favicon.ico") %>" rel="shortcut icon" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
<%: Styles.Render("~/Content/css") %>
<%: Styles.Render("~/Content/forgotten") %>
</head>
<body>
<header>
<div class="center main-nav">
<a href="./">
<img src ="content/images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
<menu class="responsive-nav">
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="./">
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
</header>
<div class="center main">
<table class="table-main">
<tbody>
<tr>
<td class="left-panel section"></td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link" >
<a href="./">
<img src="content/images/home.svg" alt="Home"/>
</a>
</li>
<li class="active">
<a href="/Forgotten">Forgotten files</a>
</li>
</menu>
<div class="stored-list">
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Forgotten files</span>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
<td class="tableHeaderCell">Filename</td>
<td class="tableHeaderCell">Action</td>
</tr>
</thead>
</table>
<div class="scroll-table-body">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<% foreach (var file in Model.files) { %>
<tr class="tableRow" title="<%= file["key"] %>">
<td>
<a class="stored-edit action-link <%= file["type"] %>" href="<%= file["url"] %>" target="_blank">
<span><%= file["key"] %></span>
</a>
</td>
<td>
<a href="<%= file["url"] %>">
<img class="icon-download" src="content/images/download.svg" alt="Download" title="Download" /></a>
<a class="delete-file" data="<%= file["key"] %>">
<img class="icon-action" src="content/images/delete.svg" alt="Delete" title="Delete" /></a>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<footer>
<div class="center">
<table>
<tbody>
<tr>
<td>
<a href="http://api.onlyoffice.com/editors/howitworks" target="_blank">API Documentation</a>
</td>
<td>
<a href="mailto:sales@onlyoffice.com">Submit your request</a>
</td>
<td class="copy">
&copy; Ascensio System SIA <%= DateTime.Now.Year.ToString() %>. All rights reserved.
</td>
</tr>
</tbody>
</table>
</div>
</footer>
<%: Scripts.Render("~/bundles/jquery", "~/bundles/forgotten") %>
</body>
</html>

View File

@ -41,11 +41,23 @@
</head>
<body>
<header>
<div class="center">
<a href="">
<div class="center main-nav">
<a href="./">
<img src ="content/images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
<menu class="responsive-nav">
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="./">
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
</header>
<div class="center main">
@ -68,7 +80,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">PDF form</a>
<a class="try-editor form" data-type="pdf">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -122,9 +134,24 @@
</tbody>
</table>
</div>
<button class="mobile-close-btn" onclick="toggleSidePanel(event)">
<img src="content/images/close.svg" alt="">
</button>
</td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link active" >
<a href="./">
<img src="content/images/home.svg" alt="Home"/>
</a>
</li>
<% if (bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"])) { %>
<li>
<a href="/Forgotten">Forgotten files</a>
</li>
<% } %>
</menu>
<% var storedFiles = DocManagerHelper.GetStoredFiles(); %>
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
@ -136,7 +163,7 @@
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
<% foreach (User user in Users.getAllUsers())
{ %>
<div class="user-descr">
<div class="user-descr" onclick="toggleUserDescr(event)">
<b><%= user.name.IsEmpty() ? "Anonymous" : user.name %></b>
<ul>
<% foreach (string description in user.descriptions)
@ -200,11 +227,13 @@
<img src="content/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% if (docType != "pdf") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
<img src="content/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "review", directUrl = isEnabledDirectUrl }) %>" target="_blank">

View File

@ -26,6 +26,7 @@
<hgroup>
<h1>Error.</h1>
<h2>An error occurred while processing your request.</h2>
<p><%= ViewData["Message"] %></p>
</hgroup>
</body>
</html>

View File

@ -69,6 +69,9 @@ namespace OnlineEditorsExampleMVC
case "remove":
Remove(context);
break;
case "removeforgotten":
RemoveForgotten(context);
break;
case "assets":
Assets(context);
break;
@ -996,6 +999,32 @@ namespace OnlineEditorsExampleMVC
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
// delete a forgotten file from the document server
private static void RemoveForgotten(HttpContext context)
{
try
{
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
{
throw new HttpException(403, "The forgotten page is disabled");
}
string filename = context.Request["filename"];
if (!String.IsNullOrEmpty(filename))
{
TrackManager.commandRequest("deleteForgotten", filename);
}
context.Response.StatusCode = 204;
}
catch (Exception e)
{
context.Response.StatusCode = 500;
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -1,11 +1,12 @@
<?xml version="1.0"?>
<appSettings>
<clear />
<add key="version" value="1.8.0"/>
<add key="version" value="1.11.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
<add key="filename-max" value="50"/>
<add key="enable-forgotten" value="true"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
@ -15,14 +16,14 @@
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|en-GB:English (United Kingdom)|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|he-IL:Hebrew (Israel)|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Cyrl-RS:Serbian (Cyrillic)|sr-Latn-RS:Serbian (Latin)|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>
<add key="files.docservice.url.converter" value="ConvertService.ashx"/>
<add key="files.docservice.url.converter" value="converter"/>
<add key="files.docservice.url.api" value="web-apps/apps/api/documents/api.js"/>
<add key="files.docservice.url.preloader" value="web-apps/apps/api/documents/cache-scripts.html"/>
<add key="files.docservice.url.command" value="coauthoring/CommandService.ashx"/>
<add key="files.docservice.url.command" value="command"/>
<add key="files.docservice.url.example" value=""/>

View File

@ -0,0 +1,161 @@
.center {
width: auto;
}
.left-panel {
width: 256px;
}
.main-panel {
width: 832px;
margin: 0 32px;
padding: 48px 0;
left: 0;
}
.tableRow {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #E2E2E2;
}
.tableRow td:first-child {
width: 70%;
flex-grow: 0;
max-width: none;
}
.tableHeader td:first-child {
text-align: left;
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 10%;
text-align: center;
padding: 0 !important;
}
.tableHeader {
width: 100%;
}
.stored-edit {
display: block;
padding-top: 0;
max-width: none;
}
menu.links {
width: 100%;
}
.scroll-table-body table {
table-layout: fixed;
}
.stored-edit span {
font-size: 12px;
line-height: normal;
position: static;
}
.scroll-table-body {
overflow-y: auto;
}
.stored-list {
height: calc(100% - 58px);
}
header {
min-width:auto;
}
header a {
display: block;
margin: 0 auto;
width: 1152px;
}
@media (max-width: 1279px) and (min-width: 1024px) {
.left-panel {
width: 208px;
}
.main-panel {
width: 688px;
}
header a {
width: 928px;
}
header img {
margin-left: 16px;
}
}
@media (max-width: 1023px) and (min-width: 593px) {
.center {
max-width: 768px;
width: calc(100% - 80px);
}
.table-main {
width: 100%;
}
.left-panel {
width: 208px;
}
.main-panel {
width: calc(100% - 32px);
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 20%;
}
header a {
width: 768px;
}
header img {
margin-left: 40px;
}
}
@media (max-width: 592px) and (min-width: 320px) {
.center, .table-main {
width: 100%;
}
.left-panel {
display: none;
}
.main-panel {
width: 100%;
margin: 0;
padding: 28px 16px;
}
.tableHeader td:last-child, .tableRow td:last-child {
width: 25%;
}
header a {
width: auto;
}
.scroll-table-body {
top: 40px;
}
.tableRow {
padding: 8px 0;
}
}

View File

@ -1 +0,0 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 3c0-1.65685 1.34315-3 3-3h20l7 7v30c0 1.6569-1.3431 3-3 3H3c-1.65685 0-3-1.3431-3-3V3z" fill="#27ABA3"/><path d="M23 0l7 7h-4c-1.6569 0-3-1.34315-3-3V0z" fill="#008078"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 14H6v7h18v-7zm-.8182 5.9978H6.81818V15H23.1818v4.9978zM24 23H6v7h18v-7zm-.8182 5.9978H6.81818V24H23.1818v4.9978z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 463 B

View File

@ -0,0 +1,5 @@
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 3C0 1.34315 1.34315 0 3 0H23L30 7V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#9E1919"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0062 15V16.0065H24V15H17.0062ZM17.0062 19V20.0163H24V19H17.0062ZM24 23H17.0062V24.0261H24V23ZM6 28V27.0293H24V28H6ZM7 16H14V23H7V16ZM6 15H7H14H15V16V23V24H14H7H6V23V16V15Z" fill="white"/>
<path d="M23 0L30 7H26C24.3431 7 23 5.65685 23 4V0Z" fill="black" fill-opacity="0.25"/>
</svg>

After

Width:  |  Height:  |  Size: 558 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 17V11H12V17H17V9H20L10 0L0 9H3V17H8Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

View File

@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 1h8l4 4v10H2V1z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5l-4-4H2v14h12V5zm-4-5l5 5v11H1V0h9z" fill="#BFBFBF"/><path fill="#9E1919" d="M3 10h10v4H3z"/><path d="M7 7V2H3v5h4zM8 3V2h2v1H8zM8 5V4h5v1H8zM13 6H8v1h5V6zM13 8H3v1h10V8z" fill="#BFBFBF"/><path opacity=".3" d="M9 1h1v3h4l1 1H9V1z" fill="#333"/></svg>

After

Width:  |  Height:  |  Size: 441 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5332 22.2243L0.632544 17.5921C-0.210848 17.1877 -0.210848 16.5627 0.632544 16.1951L4.07945 14.5775L10.4966 17.5921C11.34 17.9965 12.6967 17.9965 13.5034 17.5921L19.9206 14.5775L23.3675 16.1951C24.2108 16.5995 24.2108 17.2245 23.3675 17.5921L13.4668 22.2243C12.6967 22.592 11.34 22.592 10.5332 22.2243Z" fill="#FF6F3D"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 16.4922L0.630617 11.8546C-0.210206 11.4497 -0.210206 10.824 0.630617 10.456L3.99391 8.87329L10.5011 11.9282C11.342 12.3331 12.6946 12.3331 13.4989 11.9282L20.0061 8.87329L23.3694 10.456C24.2102 10.8608 24.2102 11.4865 23.3694 11.8546L13.4989 16.4922C12.658 16.897 11.3054 16.897 10.5011 16.4922Z" fill="#95C038"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 10.8195L0.630617 6.24863C-0.210206 5.84959 -0.210206 5.23289 0.630617 4.87013L10.5011 0.299281C11.342 -0.0997605 12.6946 -0.0997605 13.4989 0.299281L23.3694 4.87013C24.2102 5.26917 24.2102 5.88587 23.3694 6.24863L13.4989 10.8195C12.658 11.1822 11.3054 11.1822 10.5011 10.8195Z" fill="#5DC0E8"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,5 @@
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="2" rx="1" fill="white"/>
<rect y="6" width="20" height="2" rx="1" fill="white"/>
<rect y="12" width="20" height="2" rx="1" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 278 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13H7C6.44772 13 6 12.5523 6 12C6 11.4477 6.44772 11 7 11H11V7C11 6.44772 11.4477 6 12 6C12.5523 6 13 6.44772 13 7V11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H13V17Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B

View File

@ -79,7 +79,8 @@
margin-left: 0;
}
.tableRow {
.tableRow,
menu.links {
width: 90%;
}
@ -119,7 +120,8 @@
.contentCells-icon{
width: 5%;
}
.tableRow {
.tableRow,
menu.links {
width: 55%;
}
@ -175,7 +177,8 @@
}
@media (max-width: 715px) {
.tableRow {
.tableRow,
menu.links {
width: 45%;
}
}
@ -263,7 +266,8 @@
padding-left: 0;
}
.tableRow {
.tableRow,
menu.links {
width: 75%;
}
@ -293,7 +297,8 @@
width: 580px;
}
.tableRow {
.tableRow,
menu.links {
width: 95%;
}
@ -407,7 +412,8 @@
padding: 16px 0 6px;
}
.tableRow {
.tableRow,
menu.links {
width: 40%;
}
@ -538,7 +544,8 @@
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow {
.tableRow,
menu.links {
width: 35%;
}
@ -564,7 +571,8 @@
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow {
.tableRow,
menu.links {
width: 30%;
}
.tableRow td:first-child{
@ -599,7 +607,8 @@
}
@media (max-width: 420px) and (min-width: 320px) {
.tableRow {
.tableRow,
menu.links {
width: 25%;
}
@ -649,7 +658,8 @@
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow{
.tableRow,
menu.links {
width: 50%;
}
}
@ -698,3 +708,216 @@
max-width: none;
}
}
@media (max-width: 592px) and (min-width: 320px) {
body.menu-open {
overflow: hidden;
}
header {
min-width: auto;
height: fit-content;
}
header a {
display: block;
}
header img {
margin: 0;
}
header, footer {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 0;
z-index: 100;
}
.center {
width: 100%;
margin: 0;
}
.left-panel {
background-color: rgba(186, 186, 186, 0.6);
display: none;
flex-direction: row;
align-items: start;
max-width: none;
width: 100%;
margin: 0;
position: fixed;
left: 0;
height: calc(100% - 124px);
z-index:99;
}
.left-panel.active {
display: flex;
}
.help-block {
height: 100%;
margin: 0;
background-color: #F5F5F5;
width: 248px;
padding-left: 16px;
padding-top: 33px;
padding-bottom: 33px;
padding-right: 40px;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
}
.table-main {
width: 100%;
}
.mobile-close-btn {
display: block;
width: 48px;
height: 48px;
background-color: #E2E2E2;
border-radius: 2px;
border-color: #E2E2E2;
color: #808080;
cursor: pointer;
outline: inherit;
border: none;
}
.main-panel {
width: 100%;
left: 0;
padding: 28px 16px;
}
#portal-info {
width: 100%;
max-width: fit-content;
}
menu.links {
width: 100%;
margin-top: 0;
padding: 0;
}
span.portal-name {
font-size: 16px;
}
span.portal-descr:first-child {
font-size: 13px;
}
span.portal-descr {
font-size: 12px;
}
.user-descr {
width: 100%;
max-width: none;
min-width: auto;
border-bottom: 1px solid #E5E5E5;
padding: 12px 0;
margin: 0;
cursor: pointer;
}
.user-descr ul {
display: none;
}
.user-descr ul.active {
display: block;
}
.user-descr b {
font-size: 13px;
display: flex;
align-items: center;
column-gap: 8px;
margin: 0;
}
.user-descr b::before {
content: url("images/plus.svg");
display: inline-block;
width: 24px;
height: 24px;
}
.storedHeader {
width: 100%;
}
.storedHeaderClearAll {
padding-right: 0;
}
.scroll-table-body {
top: 36px;
}
.scroll-table-body tr:first-child {
padding-top: 0;
}
.tableRow {
border-bottom: 1px solid #e5e5e5;
padding: 16px 0;
width: 100%;
}
.tableRow td:first-child {
width: 100%;
}
.stored-edit span {
font-size: 14px;
}
.header-list {
font-size: 16px;
}
.firstContentCellViewers {
border-bottom: none !important;
}
.firstContentCellViewers ~ td {
border-bottom: none !important;
}
.downloadContentCellShift:after {
display: none;
}
.main-nav {
display: none;
}
.responsive-nav {
height: 44px;
display: flex;
flex-direction: row;
margin: 0;
align-items: center;
column-gap: 16px;
padding: 10px 16px;
width: 100%;
box-sizing: border-box;
list-style: none;
}
.main {
height: calc(100% - 124px);
}
.user-block-table {
height: auto;
}
}

View File

@ -65,6 +65,14 @@ header img {
margin: 10px 0 22px 32px;
}
.responsive-nav {
display: none;
}
.mobile-close-btn {
display: none;
}
.center {
position: relative;
margin: 0 auto 0;
@ -164,7 +172,7 @@ label .checkbox {
}
.try-editor.form {
background-image: url("images/file_docxf.svg");
background-image: url("images/file_pdf.svg");
}
.side-option {
@ -298,6 +306,43 @@ label .checkbox {
border-bottom: 1px solid #D0D5DA;
}
.links {
display: flex;
padding: 0;
column-gap: 30px;
align-items: center;
list-style: none;
border-bottom: 1px solid #E2E2E2;
margin: 0;
margin-bottom: 24px;
}
.links li {
padding: 4px;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.links li.active {
border-bottom: 2px solid #FF6F3D;
}
.links li.active a {
color: #FF6F3D;
}
.links li.active a img {
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
}
.links a {
display: inline-block;
padding: 2px 0;
line-height: 20px;
font-size: 13px;
text-decoration: none;
}
#mainProgress {
color: #333333;
display: none;
@ -495,6 +540,11 @@ footer a:hover {
background-image: url("images/icon_pptx.svg");
}
.stored-edit.pdf,
.uploadFileName.pdf {
background-image: url("images/icon_pdf.svg");
}
.stored-edit span {
font-size: 12px;
line-height: 12px;

View File

@ -45,11 +45,23 @@
<body>
<form id="form1" runat="server">
<header>
<div class="center">
<a href="">
<div class="center main-nav">
<a href="./">
<img src ="app_themes/images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
<menu class="responsive-nav">
<li>
<a href="#" onclick="toggleSidePanel(event)">
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="./">
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
</header>
<div class="center main">
<table class="table-main">
@ -71,7 +83,7 @@
<a class="try-editor slide" data-type="slide">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">PDF form</a>
<a class="try-editor form" data-type="pdf">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -124,10 +136,25 @@
</tbody>
</table>
</div>
<button class="mobile-close-btn" onclick="toggleSidePanel(event)">
<img src="app_themes/images/close.svg" alt="">
</button>
</td>
<td class="section">
<% var storedFiles = GetStoredFiles(); %>
<div class="main-panel">
<menu class="links">
<li class="home-link active" >
<a href="./">
<img src="app_themes/images/home.svg" alt="Home"/>
</a>
</li>
<% if (bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"])) { %>
<li>
<a href="/Forgotten.aspx">Forgotten files</a>
</li>
<% } %>
</menu>
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
@ -138,7 +165,7 @@
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
<% foreach (User user in Users.getAllUsers())
{ %>
<div class="user-descr">
<div class="user-descr" onclick="toggleUserDescr(event)">
<b><%= user.name.IsEmpty() ? "Anonymous" : user.name %></b>
<ul>
<% foreach (string description in user.descriptions)
@ -202,11 +229,13 @@
<img src="app_themes/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
</a>
</td>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
<img src="app_themes/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% if (docType != "pdf") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
<img src="app_themes/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
</a>
</td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=review" %>" target="_blank">

View File

@ -250,6 +250,7 @@ namespace OnlineEditorsExample
{
var ext = Path.GetExtension(fileName).ToLower();
if (FormatManager.PdfExtensions().Contains(ext)) return "pdf"; // pdf for pdf extensions
if (FormatManager.DocumentExtensions().Contains(ext)) return "word"; // word for text document extensions
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return "cell"; // cell for spreadsheet extensions
if (FormatManager.PresentationExtensions().Contains(ext)) return "slide"; // slide for presentation extensions

View File

@ -86,7 +86,7 @@
// the user is trying to switch the document from the viewing into the editing mode
var onRequestEditRights = function () {
location.href = location.href.replace(RegExp("editorsMode=view\&?", "i"), "");
location.href = location.href.replace(RegExp("editorsMode=\\w+\&?", "i"), "") + "&editorsMode=edit";
};
// an error or some other specific event occurs
@ -126,7 +126,7 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
if (event.data.favorite) {
if (event.data.favorite !== undefined) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
@ -338,6 +338,7 @@
config.events['onRequestUsers'] = onRequestUsers;
<% } %>
config.events['onRequestSaveAs'] = onRequestSaveAs;
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = onRequestSendNotify;
// prevent file renaming for anonymous users
@ -348,10 +349,6 @@
config.events['onRequestOpen'] = onRequestOpen;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
};
var сonnectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -135,14 +135,14 @@ namespace OnlineEditorsExample
{
// create demo document of a specified file type
Try(type, Request["sample"], Request);
Response.Redirect("doceditor.aspx?fileID=" + HttpUtility.UrlEncode(FileName));
Response.Redirect("doceditor.aspx?editorsMode=edit&fileID=" + HttpUtility.UrlEncode(FileName));
}
// get file extension
var ext = Path.GetExtension(FileName).ToLower();
var canFill = _Default.FillFormsExts.Contains(ext);
// get editor mode or set the default one (edit)
var editorsMode = Request.GetOrDefault("editorsMode", "edit");
var editorsMode = Request.GetOrDefault("editorsMode", canFill ? "fillForms" : "edit");
var canEdit = _Default.EditedExts.Contains(ext); // check if this file can be edited
var editorsType = Request.GetOrDefault("editorsType", "desktop");
@ -150,11 +150,11 @@ namespace OnlineEditorsExample
var id = Request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id); // get the user
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && _Default.FillFormsExts.Contains(ext)) {
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && canFill) {
editorsMode = "fillForms";
canEdit = true;
}
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1"); // check if the Submit form button is displayed or hidden
var submitForm = !editorsMode.Equals("view") && user.id.Equals("uid-1"); // check if the Submit form button is displayed or hidden
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // get the editor opening mode (edit or view)
var jss = new JavaScriptSerializer();
@ -489,8 +489,8 @@ namespace OnlineEditorsExample
case "slide":
ext = ".pptx"; // .pptx for slide document type
break;
case "docxf":
ext = ".docxf";
case "pdf":
ext = ".pdf";
break;
default:
return;

View File

@ -227,7 +227,7 @@ namespace ASC.Api.DocumentConverter
private static void ProcessResponseError(int errorCode)
{
var errorMessage = string.Empty;
const string errorMessageTemplate = "Error occurred in the ConvertService.ashx: {0}";
const string errorMessageTemplate = "Error occurred in the ConvertService: {0}";
switch (errorCode)
{

View File

@ -0,0 +1,147 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Forgotten.aspx.cs" Inherits="OnlineEditorsExample.Forgotten" Title="ONLYOFFICE" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="OnlineEditorsExample" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="server-version" content=<%= GetVersion() %> />
<title>ONLYOFFICE</title>
<!--
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
-->
<link rel="icon" href="~/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
<link rel="stylesheet" type="text/css" href="app_themes/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="app_themes/media.css" />
<link rel="stylesheet" type="text/css" href="app_themes/forgotten.css" />
<link rel="stylesheet" type="text/css" href="app_themes/jquery-ui.css" />
</head>
<body>
<form id="form1" runat="server">
<header>
<div class="center main-nav">
<a href="./">
<img src ="app_themes/images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
<menu class="responsive-nav">
<li>
<a href="#">
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
</a>
</li>
<li>
<a href="./">
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
</a>
</li>
</menu>
</header>
<div class="center main">
<table class="table-main">
<tbody>
<tr>
<td class="left-panel section"></td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link" >
<a href="./">
<img src="app_themes/images/home.svg" alt="Home"/>
</a>
</li>
<li class="active">
<a href="/Forgotten.aspx">Forgotten files</a>
</li>
</menu>
<div class="stored-list">
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Forgotten files</span>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
<td class="tableHeaderCell">Filename</td>
<td class="tableHeaderCell">Action</td>
</tr>
</thead>
</table>
<div class="scroll-table-body">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<% foreach (var file in GetForgottenFiles()) { %>
<tr class="tableRow" title="<%= file["key"] %>">
<td>
<a class="stored-edit <%= file["type"] %>" href="<%= file["url"] %>" target="_blank">
<span><%= file["key"] %></span>
</a>
</td>
<td>
<a href="<%= file["url"] %>">
<img class="icon-download" src="app_themes/images/download.svg" alt="Download" title="Download" /></a>
<a class="delete-file" data="<%= file["key"] %>">
<img class="icon-action" src="app_themes/images/delete.svg" alt="Delete" title="Delete" /></a>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<footer>
<div class="center">
<table>
<tbody>
<tr>
<td>
<a href="http://api.onlyoffice.com/editors/howitworks" target="_blank">API Documentation</a>
</td>
<td>
<a href="mailto:sales@onlyoffice.com">Submit your request</a>
</td>
<td class="copy">
&copy; Ascensio System SIA <%= DateTime.Now.Year.ToString() %>. All rights reserved.
</td>
</tr>
</tbody>
</table>
</div>
</footer>
</form>
<script language="javascript" type="text/javascript" src="script/forgotten.js"></script>
</body>
</html>

View File

@ -0,0 +1,97 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web.Configuration;
using System.Web.UI;
namespace OnlineEditorsExample
{
public partial class Forgotten : Page
{
//get server version
public static string GetVersion()
{
return WebConfigurationManager.AppSettings["version"];
}
private static bool? _ismono;
public static bool IsMono
{
get { return _ismono.HasValue ? _ismono.Value : (_ismono = (bool?)(Type.GetType("Mono.Runtime") != null)).Value; }
}
// get the document type
public static string DocumentType(string fileName)
{
var ext = Path.GetExtension(fileName).ToLower();
if (FormatManager.PdfExtensions().Contains(ext)) return "pdf"; // pdf for pdf extensions
if (FormatManager.DocumentExtensions().Contains(ext)) return "word"; // word for text document extensions
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return "cell"; // cell for spreadsheet extensions
if (FormatManager.PresentationExtensions().Contains(ext)) return "slide"; // slide for presentation extensions
return "word"; // the default document type is word
}
protected void Page_Load(object sender, EventArgs e)
{
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
{
Response.Clear();
Response.StatusCode = 403;
Response.End();
}
}
// fetch forgotten files from the document server
public static List<Dictionary<string, string>> GetForgottenFiles()
{
var files = new List<Dictionary<string, string>>();
try
{
var response = TrackManager.commandRequest("getForgottenList", null);
ArrayList keys = (ArrayList) response["keys"];
// fetch all the forgotten files from the document server
foreach (string key in keys)
{
var file = new Dictionary<string, string>();
var fileResult = TrackManager.commandRequest("getForgotten", key);
file.Add("key", fileResult["key"].ToString());
file.Add("url", fileResult["url"].ToString());
file.Add("type", DocumentType(fileResult["url"].ToString()));
files.Add(file);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
return files;
}
}
}

View File

@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace OnlineEditorsExample {
public partial class Forgotten {
/// <summary>
/// form1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
}
}

View File

@ -150,6 +150,20 @@ namespace OnlineEditorsExample
.ToList();
}
public static List<string> PdfExtensions()
{
return Pdfs()
.Select(format => format.Extension())
.ToList();
}
public static List<Format> Pdfs()
{
return All()
.Where(format => format.Type == "pdf")
.ToList();
}
public static List<string> AllExtensions()
{
return All()

View File

@ -77,6 +77,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="App_Themes\forgotten.css" />
<Content Include="App_Themes\images\block-content.svg" />
<Content Include="App_Themes\images\cell.ico" />
<Content Include="App_Themes\images\close.svg" />
@ -94,6 +95,7 @@
<Content Include="App_Themes\images\file_xlsx.svg" />
<Content Include="App_Themes\images\fill-forms.svg" />
<Content Include="App_Themes\images\filter.svg" />
<Content Include="App_Themes\images\home.svg" />
<Content Include="App_Themes\images\icon_docx.svg" />
<Content Include="App_Themes\images\icon_pptx.svg" />
<Content Include="App_Themes\images\icon_xlsx.svg" />
@ -104,10 +106,16 @@
<Content Include="App_Themes\images\notdone.svg" />
<Content Include="App_Themes\images\review.svg" />
<Content Include="App_Themes\images\slide.ico" />
<Content Include="App_Themes\images\uid-1.png" />
<Content Include="App_Themes\images\uid-2.png" />
<Content Include="App_Themes\images\word.ico" />
<Content Include="App_Themes\media.css" />
<Content Include="Forgotten.aspx" />
<Content Include="LICENSE" />
<Content Include="licenses\jquery.license" />
<Content Include="script\forgotten.js" />
<Content Include="script\formats.js" />
<Content Include="script\jquery-3.6.4.min.js" />
<Content Include="script\jquery-migrate-3.4.1.min.js" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
@ -119,6 +127,12 @@
<DependentUpon>DocEditor.aspx</DependentUpon>
</Compile>
<Compile Include="DocumentConverter.cs" />
<Compile Include="Forgotten.aspx.cs">
<DependentUpon>Forgotten.aspx</DependentUpon>
</Compile>
<Compile Include="Forgotten.aspx.designer.cs">
<DependentUpon>Forgotten.aspx</DependentUpon>
</Compile>
<Compile Include="FormatManager.cs" />
<Compile Include="JwtManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -285,7 +285,7 @@ namespace OnlineEditorsExample
}
// create a command request
public static void commandRequest(string method, string key, object meta = null)
public static Dictionary<string, object> commandRequest(string method, string key, object meta = null)
{
_Default.VerifySSL();
@ -348,6 +348,7 @@ namespace OnlineEditorsExample
{
throw new Exception(dataResponse);
}
return responseObj;
}
private static void SaveFile(byte[] data, string path)

View File

@ -69,6 +69,9 @@ namespace OnlineEditorsExample
case "remove":
Remove(context);
break;
case "removeforgotten":
RemoveForgotten(context);
break;
case "assets":
Assets(context);
break;
@ -811,5 +814,30 @@ namespace OnlineEditorsExample
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
// delete a forgotten file from the document server
private static void RemoveForgotten(HttpContext context)
{
try
{
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
{
throw new HttpException(403, "The forgotten page is disabled");
}
string filename = context.Request["filename"];
if (!String.IsNullOrEmpty(filename))
{
TrackManager.commandRequest("deleteForgotten", filename);
}
context.Response.StatusCode = 204;
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -0,0 +1,19 @@
function deleteFile(event) {
let filename = event.currentTarget.getAttribute("data");
filename = encodeURIComponent(filename);
let url = `webeditor.ashx?type=removeforgotten&filename=${filename}`;
fetch(url, {
headers: {
"Content-Type": "application/json",
}
}).then(result => {
if (result.status == 204) {
document.location.reload(true);
}
});
}
document.querySelectorAll('.delete-file').forEach(el => {
el.addEventListener('click', deleteFile);
});

View File

@ -109,7 +109,7 @@ if (typeof jQuery != "undefined") {
var timer = null;
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
}
@ -121,7 +121,7 @@ if (typeof jQuery != "undefined") {
jq("#filePass").val("");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (!formatManager.isAutoConvertible(posExt)) {
@ -421,4 +421,27 @@ if (typeof jQuery != "undefined") {
}).mouseout(function () {
jq("div.tooltip").remove();
});
}
function toggleSidePanel(event) {
event.preventDefault();
let sidePanel = document.querySelector(".left-panel");
let body = document.querySelector("body");
if (sidePanel.classList.contains("active")) {
sidePanel.classList.remove("active");
body.classList.remove("menu-open");
} else {
sidePanel.classList.add("active")
body.classList.add("menu-open");
}
}
function toggleUserDescr(event) {
let list = event.currentTarget.querySelector("ul");
let cursor = window.getComputedStyle(event.currentTarget).getPropertyValue("cursor");
if (cursor === "pointer") {
if (list.classList.contains("active")) list.classList.remove("active");
else list.classList.add("active");
}
}

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<clear />
<add key="version" value="1.8.0"/>
<add key="version" value="1.11.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
<add key="filename-max" value="50"/>
<add key="enable-forgotten" value="true"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
@ -14,14 +15,14 @@
<add key="files.docservice.token.useforrequest" value="true" />
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-RS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.languages" value="en:English|ar:Arabic|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|en-GB:English (United Kingdom)|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|he-IL:Hebrew (Israel)|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Cyrl-RS:Serbian (Cyrillic)|sr-Latn-RS:Serbian (Latin)|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>
<add key="files.docservice.url.converter" value="ConvertService.ashx"/>
<add key="files.docservice.url.converter" value="converter"/>
<add key="files.docservice.url.api" value="web-apps/apps/api/documents/api.js"/>
<add key="files.docservice.url.preloader" value="web-apps/apps/api/documents/cache-scripts.html"/>
<add key="files.docservice.url.command" value="coauthoring/CommandService.ashx"/>
<add key="files.docservice.url.command" value="command"/>
<add key="files.docservice.url.example" value=""/>

View File

@ -1,6 +1,5 @@
ONLYOFFICE Applications example uses code from the following 3rd party projects:
Gson - Gson is a Java library that can be used to convert Java Objects into their JSON representation. (https://github.com/google/gson/blob/master/LICENSE)
License: Apache 2.0
License File: gson.license
@ -13,6 +12,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
License: Apache 2.0
License File: jackson-databind.license
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
License: Apache 2.0
License File: jackson-dataformat-properties.license
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
License: MIT, GPL
License File: jQuery.BlockUI.license
@ -37,6 +40,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
License: MIT
License File: jQuery.UI.license
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
License Public Domain
License File: json.license
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
License: Apache 2.0
License File: JSON.simple.license
@ -49,14 +56,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
License: Apache 2.0
License File modelmapper.license
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
License: Apache 2.0
License File: prime-jwt.license
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license

View File

@ -135,9 +135,9 @@ See the detailed guide to learn how to install Document Server [for Linux](https
a) archive with Java-Spring:
```
wget https://api.onlyoffice.com/app_data/editor/Java.Spring.Example.zip
wget https://github.com/ONLYOFFICE/document-server-integration/releases/latest/download/Java.Spring.Example.zip
```
```
unzip Java.Spring.Example.zip
```

View File

@ -1,6 +1,5 @@
ONLYOFFICE Applications example uses code from the following 3rd party projects:
Gson - Gson is a Java library that can be used to convert Java Objects into their JSON representation. (https://github.com/google/gson/blob/master/LICENSE)
License: Apache 2.0
License File: gson.license
@ -13,6 +12,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
License: Apache 2.0
License File: jackson-databind.license
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
License: Apache 2.0
License File: jackson-dataformat-properties.license
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
License: MIT, GPL
License File: jQuery.BlockUI.license
@ -37,6 +40,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
License: MIT
License File: jQuery.UI.license
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
License Public Domain
License File: json.license
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
License: Apache 2.0
License File: JSON.simple.license
@ -49,14 +56,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
License: Apache 2.0
License File modelmapper.license
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
License: Apache 2.0
License File: prime-jwt.license
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
License: Apache 2.0
License File: spring-boot.license

View File

@ -1,4 +1,5 @@
Apache License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@ -178,7 +179,7 @@ Apache License
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
@ -186,7 +187,7 @@ Apache License
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -0,0 +1 @@
Public Domain.

View File

@ -50,11 +50,6 @@
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<dependency>
<groupId>com.inversoft</groupId>
<artifactId>prime-jwt</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@ -71,12 +66,39 @@
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-properties</artifactId>
<version>2.13.5</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
<dependency>
<groupId>com.onlyoffice</groupId>
<artifactId>docs-integration-sdk</artifactId>
<version>1.2.1-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>ossrh</id>
<name>Sonatype OSSRH</name>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>

View File

@ -102,23 +102,25 @@ public class ExampleData {
userService.createUser("John Smith", "smith@example.com", descriptionUserFirst,
"", List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), null, true, true, true, new Goback(null, false));
List.of(FilterState.NULL.toString()), null, true, true, true,
new Goback(null, false), true);
// create user 2 with the specified parameters
userService.createUser("Mark Pottato", "pottato@example.com", descriptionUserSecond,
"group-2", List.of("", "group-2"), List.of(FilterState.NULL.toString()),
List.of("group-2", ""), List.of("group-2"), List.of("group-2", ""), true, true,
true, true, new Goback("Go to Documents", null));
true, true, new Goback("Go to Documents", null), false);
// create user 3 with the specified parameters
userService.createUser("Hamish Mitchell", null, descriptionUserThird,
"group-3", List.of("group-2"), List.of("group-2", "group-3"), List.of("group-2"),
new ArrayList<>(), List.of("group-2"), false, true, true, false, null);
new ArrayList<>(), List.of("group-2"), false, true, true, false,
null, false);
// create user 0 with the specified parameters
userService.createUser("Anonymous", null, descriptionUserZero, "",
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
new ArrayList<>(), null, false, false, false, null);
new ArrayList<>(), null, false, false, false, null, false);
}
}

View File

@ -20,6 +20,17 @@ package com.onlyoffice.integration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.manager.document.DocumentManager;
import com.onlyoffice.manager.request.DefaultRequestManager;
import com.onlyoffice.manager.request.RequestManager;
import com.onlyoffice.manager.security.DefaultJwtManager;
import com.onlyoffice.manager.security.JwtManager;
import com.onlyoffice.manager.settings.SettingsManager;
import com.onlyoffice.manager.url.UrlManager;
import com.onlyoffice.service.command.CommandService;
import com.onlyoffice.service.command.DefaultCommandService;
import com.onlyoffice.service.convert.ConvertService;
import com.onlyoffice.service.convert.DefaultConvertService;
import org.json.simple.parser.JSONParser;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
@ -30,23 +41,15 @@ import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import com.onlyoffice.integration.documentserver.util.SSLUtils;
@Configuration
public class IntegrationConfiguration {
@Value("${files.storage}")
private String storageAddress;
@Value("${files.docservice.verify-peer-off}")
private String verifyPerrOff;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private SSLUtils ssl;
@Bean
public ModelMapper mapper() { // create the model mapper
ModelMapper mapper = new ModelMapper();
@ -67,21 +70,34 @@ public class IntegrationConfiguration {
@PostConstruct
public void init() { // initialize the storage path builder
storagePathBuilder.configure(storageAddress.isBlank() ? null : storageAddress);
if (!verifyPerrOff.isEmpty()) {
try {
if (verifyPerrOff.equals("true")) {
ssl.turnOffSslChecking(); //the certificate will be ignored
} else {
ssl.turnOnSslChecking(); //the certificate will be verified
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Bean
public ObjectMapper objectMapper() { // create the object mapper
return new ObjectMapper();
}
@Bean
public JwtManager jwtManager(final SettingsManager settingsManager) {
return new DefaultJwtManager(settingsManager);
}
@Bean
public RequestManager requestManager(final UrlManager urlManager, final JwtManager jwtManager,
final SettingsManager settingsManager) {
return new DefaultRequestManager(urlManager, jwtManager, settingsManager);
}
@Bean
public ConvertService convertService(final DocumentManager documentManager, final UrlManager urlManager,
final RequestManager requestManager,
final SettingsManager settingsManager) {
return new DefaultConvertService(documentManager, urlManager, requestManager, settingsManager);
}
@Bean
public CommandService commandService(final RequestManager requestManager) {
return new DefaultCommandService(requestManager);
}
}

View File

@ -20,19 +20,21 @@ package com.onlyoffice.integration.controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
import com.onlyoffice.integration.documentserver.models.enums.Action;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.dto.Mentions;
import com.onlyoffice.integration.dto.UserInfo;
import com.onlyoffice.integration.dto.Protect;
import com.onlyoffice.integration.documentserver.models.enums.Type;
import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
import com.onlyoffice.integration.dto.UserInfo;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.sdk.manager.UrlManager;
import com.onlyoffice.integration.sdk.service.ConfigService;
import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.services.configurers.FileConfigurer;
import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper;
import com.onlyoffice.manager.security.JwtManager;
import com.onlyoffice.manager.settings.SettingsManager;
import com.onlyoffice.model.documenteditor.Config;
import com.onlyoffice.model.documenteditor.config.document.Type;
import lombok.SneakyThrows;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
@ -56,12 +58,6 @@ import static com.onlyoffice.integration.documentserver.util.Constants.ANONYMOUS
@Controller
public class EditorController {
@Value("${files.docservice.url.site}")
private String docserviceSite;
@Value("${files.docservice.url.api}")
private String docserviceApiUrl;
@Value("${files.docservice.languages}")
private String langs;
@ -78,7 +74,13 @@ public class EditorController {
private ObjectMapper objectMapper;
@Autowired
private FileConfigurer<DefaultFileWrapper> fileConfigurer;
private SettingsManager settingsManager;
@Autowired
private ConfigService configService;
@Autowired
private UrlManager urlManager;
@GetMapping(path = "${url.editor}")
// process request to open the editor page
@ -86,20 +88,18 @@ public class EditorController {
@RequestParam(value = "action", required = false) final String actionParam,
@RequestParam(value = "type", required = false) final String typeParam,
@RequestParam(value = "actionLink", required = false) final String actionLink,
@RequestParam(value = "directUrl", required = false,
defaultValue = "false") final Boolean directUrl,
@CookieValue(value = "uid") final String uid,
@CookieValue(value = "ulang") final String lang,
final Model model) throws JsonProcessingException {
Action action = Action.edit;
Type type = Type.desktop;
Action action = null;
Type type = Type.DESKTOP;
Locale locale = new Locale("en");
if (actionParam != null) {
action = Action.valueOf(actionParam);
}
if (typeParam != null) {
type = Type.valueOf(typeParam);
type = Type.valueOf(typeParam.toUpperCase());
}
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
@ -118,39 +118,34 @@ public class EditorController {
return "index.html";
}
User user = optionalUser.get();
user.setImage(user.getAvatar() ? storagePathBuilder.getServerUrl(true) + "/css/img/uid-"
+ user.getId() + ".png" : null);
// get file model with the default file parameters
FileModel fileModel = fileConfigurer.getFileModel(
DefaultFileWrapper
.builder()
.fileName(fileName)
.type(type)
.lang(locale.toLanguageTag())
.action(action)
.user(user)
.actionData(actionLink)
.isEnableDirectUrl(directUrl)
.build()
Config config = configService.createConfig(
fileName,
action,
type
);
// add attributes to the specified model
// add file model with the default parameters to the original model
model.addAttribute("model", fileModel);
JSONObject actionData = null;
if (actionLink != null && !actionLink.isEmpty()) {
actionData = new JSONObject(actionLink);
}
config.getEditorConfig().setActionLink(actionData);
config.getEditorConfig().setLang(locale.toLanguageTag());
model.addAttribute("model", config);
// create the document service api URL and add it to the model
model.addAttribute("docserviceApiUrl", docserviceSite + docserviceApiUrl);
model.addAttribute("docserviceApiUrl", urlManager.getDocumentServerApiUrl());
// get an image and add it to the model
model.addAttribute("dataInsertImage", getInsertImage(directUrl));
model.addAttribute("dataInsertImage", getInsertImage());
// get a document for comparison and add it to the model
model.addAttribute("dataDocument", getCompareFile(directUrl));
model.addAttribute("dataDocument", getCompareFile());
// get recipients data for mail merging and add it to the model
model.addAttribute("dataSpreadsheet", getSpreadsheet(directUrl));
model.addAttribute("dataSpreadsheet", getSpreadsheet());
// get user data for mentions and add it to the model
model.addAttribute("usersForMentions", getUserMentions(uid));
@ -210,17 +205,13 @@ public class EditorController {
@SneakyThrows
private String getInsertImage(final Boolean directUrl) { // get an image that will be inserted into the document
private String getInsertImage() { // get an image that will be inserted into the document
Map<String, Object> dataInsertImage = new HashMap<>();
dataInsertImage.put("fileType", "svg");
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.svg");
if (directUrl) {
dataInsertImage.put("directUrl", storagePathBuilder
.getServerUrl(false) + "/css/img/logo.svg");
}
// check if the document token is enabled
if (jwtManager.tokenEnabled()) {
if (settingsManager.isSecurityEnabled()) {
// create token from the dataInsertImage object
dataInsertImage.put("token", jwtManager.createToken(dataInsertImage));
@ -232,17 +223,13 @@ public class EditorController {
// get a document that will be compared with the current document
@SneakyThrows
private String getCompareFile(final Boolean directUrl) {
private String getCompareFile() {
Map<String, Object> dataDocument = new HashMap<>();
dataDocument.put("fileType", "docx");
dataDocument.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx");
if (directUrl) {
dataDocument.put("directUrl", storagePathBuilder
.getServerUrl(false) + "/assets?name=sample.docx");
}
// check if the document token is enabled
if (jwtManager.tokenEnabled()) {
if (settingsManager.isSecurityEnabled()) {
// create token from the dataDocument object
dataDocument.put("token", jwtManager.createToken(dataDocument));
@ -252,16 +239,13 @@ public class EditorController {
}
@SneakyThrows
private String getSpreadsheet(final Boolean directUrl) {
private String getSpreadsheet() {
Map<String, Object> dataSpreadsheet = new HashMap<>(); // get recipients data for mail merging
dataSpreadsheet.put("fileType", "csv");
dataSpreadsheet.put("url", storagePathBuilder.getServerUrl(true) + "/csv");
if (directUrl) {
dataSpreadsheet.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv");
}
// check if the document token is enabled
if (jwtManager.tokenEnabled()) {
if (settingsManager.isSecurityEnabled()) {
// create token from the dataSpreadsheet object
dataSpreadsheet.put("token", jwtManager.createToken(dataSpreadsheet));

View File

@ -21,32 +21,38 @@ package com.onlyoffice.integration.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.onlyoffice.integration.documentserver.callbacks.CallbackHandler;
import com.onlyoffice.integration.documentserver.managers.history.HistoryManager;
import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.dto.Converter;
import com.onlyoffice.integration.dto.ConvertedData;
import com.onlyoffice.integration.dto.Reference;
import com.onlyoffice.integration.dto.ReferenceData;
import com.onlyoffice.integration.dto.Rename;
import com.onlyoffice.integration.dto.Restore;
import com.onlyoffice.integration.dto.SaveAs;
import com.onlyoffice.integration.dto.Track;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
import com.onlyoffice.integration.sdk.manager.DocumentManager;
import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
import com.onlyoffice.manager.request.RequestManager;
import com.onlyoffice.manager.security.JwtManager;
import com.onlyoffice.manager.settings.SettingsManager;
import com.onlyoffice.manager.url.UrlManager;
import com.onlyoffice.model.commandservice.CommandRequest;
import com.onlyoffice.model.commandservice.CommandResponse;
import com.onlyoffice.model.commandservice.commandrequest.Command;
import com.onlyoffice.model.commandservice.commandrequest.Meta;
import com.onlyoffice.model.convertservice.ConvertRequest;
import com.onlyoffice.model.convertservice.ConvertResponse;
import com.onlyoffice.model.documenteditor.Callback;
import com.onlyoffice.model.documenteditor.config.document.ReferenceData;
import com.onlyoffice.service.command.CommandService;
import com.onlyoffice.service.convert.ConvertService;
import com.onlyoffice.service.documenteditor.callback.CallbackService;
import org.apache.http.HttpEntity;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
@ -74,7 +80,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -91,22 +96,6 @@ import java.util.Optional;
@Controller
public class FileController {
@Value("${files.docservice.header}")
private String documentJwtHeader;
@Value("${filesize-max}")
private String filesizeMax;
@Value("${files.docservice.url.site}")
private String docserviceUrlSite;
@Value("${files.docservice.url.command}")
private String docserviceUrlCommand;
@Autowired
private FileUtility fileUtility;
@Autowired
private DocumentManager documentManager;
@Autowired
private JwtManager jwtManager;
@Autowired
@ -116,20 +105,29 @@ public class FileController {
@Autowired
private UserServices userService;
@Autowired
private CallbackHandler callbackHandler;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ServiceConverter serviceConverter;
@Autowired
private CallbackManager callbackManager;
@Autowired
private HistoryManager historyManager;
@Autowired
private DocumentManager documentManager;
@Autowired
private ConvertService convertService;
@Autowired
private RequestManager requestManager;
@Autowired
private SettingsManager settingsManager;
@Autowired
private CallbackService callbackService;
@Autowired
private CommandService commandService;
@Autowired
private UrlManager urlManager;
// create user metadata
private String createUserMetadata(final String uid, final String fullFileName) {
Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID
String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase(); // get document type
// get document type
String documentType = documentManager.getDocumentType(fullFileName).toString().toLowerCase();
if (optionalUser.isPresent()) {
User user = optionalUser.get();
storageMutator.createMeta(fullFileName, // create meta information with the user ID and name specified
@ -196,17 +194,17 @@ public class FileController {
@CookieValue("uid") final String uid) {
try {
String fullFileName = file.getOriginalFilename(); // get file name
String fileExtension = fileUtility.getFileExtension(fullFileName); // get file extension
String fileExtension = documentManager.getExtension(fullFileName); // get file extension
long fileSize = file.getSize(); // get file size
byte[] bytes = file.getBytes(); // get file in bytes
// check if the file size exceeds the maximum file size or is less than 0
if (fileUtility.getMaxFileSize() < fileSize || fileSize <= 0) {
if (documentManager.getMaxFileSize() < fileSize || fileSize <= 0) {
return "{ \"error\": \"File size is incorrect\"}"; // if so, write an error message to the response
}
// check if file extension is supported by the editor
if (!fileUtility.getFileExts().contains(fileExtension)) {
if (documentManager.getDocumentType(fullFileName) == null) {
// if not, write an error message to the response
return "{ \"error\": \"File type is not supported\"}";
@ -217,7 +215,7 @@ public class FileController {
throw new IOException("Could not update a file"); // if the file cannot be updated, an error occurs
}
fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath)
fullFileName = documentManager.getBaseName(fileNamePath)
+ "." + fileExtension; // get full file name
return createUserMetadata(uid, fullFileName); // create user metadata and return it
@ -235,56 +233,54 @@ public class FileController {
@CookieValue("uid") final String uid, @CookieValue("ulang") final String lang) {
// get file name
String fileName = body.getFileName();
// get URL for downloading a file with the specified name
String fileUri = documentManager.getDownloadUrl(fileName, true);
// get file password if it exists
String filePass = body.getFilePass() != null ? body.getFilePass() : null;
// get file extension
String fileExt = fileUtility.getFileExtension(fileName);
// get document type (word, cell or slide)
DocumentType type = fileUtility.getDocumentType(fileName);
// get an auto-conversion extension from the request body or set it to the ooxml extension
String conversionExtension = body.getFileExt() != null ? body.getFileExt() : "ooxml";
try {
// check if the file with such an extension can be converted
if (fileUtility.getConvertExts().contains(fileExt)) {
String key = serviceConverter.generateRevisionId(fileUri); // generate document key
ConvertedData response = serviceConverter // get the URL to the converted file
.getConvertedData(fileUri, fileExt, conversionExtension, key, filePass, true, lang);
if (documentManager.getDefaultConvertExtension(fileName) != null) {
ConvertRequest convertRequest = ConvertRequest.builder()
.password(filePass)
.outputtype(conversionExtension)
.region(lang)
.async(true)
.build();
String newFileUri = response.getUri();
String newFileType = "." + response.getFileType();
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
if (newFileUri.isEmpty()) {
return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}";
if (convertResponse.getError() != null || convertResponse.getFileUrl() == null) {
return objectMapper.writeValueAsString(convertResponse);
}
String newFileUri = convertResponse.getFileUrl();
String newFileType = convertResponse.getFileType();
/* get a file name of an internal file extension with an index if the file
with such a name already exists */
String nameWithInternalExt = fileUtility.getFileNameWithoutExtension(fileName) + newFileType;
final String oldFileName = fileName;
String nameWithInternalExt = documentManager.getBaseName(fileName) + "." + newFileType;
String correctedName = documentManager.getCorrectName(nameWithInternalExt);
URL url = new URL(newFileUri);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
InputStream stream = connection.getInputStream(); // get input stream of the converted file
fileName = requestManager.executeGetRequest(newFileUri, new RequestManager.Callback<String>() {
public String doWork(final Object response) throws IOException {
InputStream stream = ((HttpEntity) response).getContent(); // get input stream of the converted
// file
if (stream == null) {
connection.disconnect();
throw new RuntimeException("Input stream is null");
}
if (stream == null) {
throw new RuntimeException("Input stream is null");
}
// remove source file
storageMutator.deleteFile(fileName);
// create the converted file with input stream
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream);
fileName = correctedName;
// remove source file
storageMutator.deleteFile(oldFileName);
// create the converted file with input stream
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream);
return correctedName;
}
});
}
// create meta information about the converted file with the user ID and name specified
@ -305,7 +301,7 @@ public class FileController {
boolean success = false;
if (filename != null) {
String fullFileName = fileUtility.getFileName(filename); // get full file name
String fullFileName = documentManager.getDocumentName(filename); // get full file name
// delete a file from the storage and return the status of this operation (true or false)
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
@ -331,13 +327,12 @@ public class FileController {
@RequestParam("file") final String file) { // history file
try {
// check if a token is enabled or not
if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
String header = request.getHeader(documentJwtHeader == null // get the document JWT header
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if (settingsManager.isSecurityEnabled()) {
String header = request.getHeader(settingsManager.getSecurityHeader());
if (header != null && !header.isEmpty()) {
String token = header
.replace("Bearer ", ""); // token is the header without the Bearer prefix
jwtManager.readToken(token); // read the token
jwtManager.verify(token); // read the token
} else {
return null;
}
@ -355,13 +350,12 @@ public class FileController {
final String userAddress) {
try {
// check if a token is enabled or not
if (jwtManager.tokenEnabled() && userAddress != null && jwtManager.tokenUseForRequest()) {
String header = request.getHeader(documentJwtHeader == null // get the document JWT header
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if (settingsManager.isSecurityEnabled() && userAddress != null) {
String header = request.getHeader(settingsManager.getSecurityHeader());
if (header != null && !header.isEmpty()) {
String token = header
.replace("Bearer ", ""); // token is the header without the Bearer prefix
jwtManager.readToken(token); // read the token
jwtManager.verify(token); // read the token
} else {
return null;
}
@ -391,10 +385,10 @@ public class FileController {
sampleData,
uid,
user.get().getName()); // create a demo document with the sample data
if (fileName.isBlank() || fileName == null) {
if (fileName == null || fileName.isBlank()) {
throw new RuntimeException("You must have forgotten to add asset files");
}
return "redirect:editor?fileName=" + URLEncoder
return "redirect:editor?action=edit&fileName=" + URLEncoder
.encode(fileName, StandardCharsets.UTF_8); // redirect the request
} catch (Exception ex) {
model.addAttribute("error", ex.getMessage());
@ -427,28 +421,29 @@ public class FileController {
public String track(final HttpServletRequest request, // track file changes
@RequestParam("fileName") final String fileName,
@RequestParam("userAddress") final String userAddress,
@RequestBody final Track body) {
Track track;
@RequestBody final Callback body) {
Callback callback;
try {
String bodyString = objectMapper
.writeValueAsString(body); // write the request body to the object mapper as a string
String header = request.getHeader(documentJwtHeader == null // get the request header
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if (bodyString.isEmpty()) { // if the request body is empty, an error occurs
throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}");
}
JSONObject bodyCheck = jwtManager.parseBody(bodyString, header); // parse the request body
track = objectMapper.readValue(bodyCheck.toJSONString(), Track.class); // read the request body
String authorizationHeader = request.getHeader(settingsManager.getSecurityHeader());
callback = callbackService.verifyCallback(body, authorizationHeader);
callbackService.processCallback(callback, fileName);
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
String message = e.getMessage();
if (!message.contains("\"error\":1")) {
e.printStackTrace();
}
return message;
}
int error = callbackHandler.handle(track, fileName);
return "{\"error\":" + error + "}";
return "{\"error\":\"0\"}";
}
@PostMapping("/saveas")
@ -456,24 +451,30 @@ public class FileController {
public String saveAs(@RequestBody final SaveAs body, @CookieValue("uid") final String uid) {
try {
String fileName = documentManager.getCorrectName(body.getTitle());
String curExt = fileUtility.getFileExtension(fileName);
if (!fileUtility.getFileExts().contains(curExt)) {
if (documentManager.getDocumentType(fileName) == null) {
return "{\"error\":\"File type is not supported\"}";
}
URL url = new URL(body.getUrl());
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
InputStream stream = connection.getInputStream();
String url = body.getUrl();
if (Integer.parseInt(filesizeMax) < stream.available() || stream.available() <= 0) {
return "{\"error\":\"File size is incorrect\"}";
}
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream);
createUserMetadata(uid, fileName);
url = urlManager.replaceToInnerDocumentServerUrl(url);
return "{\"file\": \"" + fileName + "\"}";
} catch (IOException e) {
return requestManager.executeGetRequest(url, new RequestManager.Callback<String>() {
@Override
public String doWork(final Object response) throws Exception {
InputStream stream = ((HttpEntity) response).getContent();
if (documentManager.getMaxFileSize() < stream.available() || stream.available() <= 0) {
return "{\"error\":\"File size is incorrect\"}";
}
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream);
createUserMetadata(uid, fileName);
return "{\"file\": \"" + fileName + "\"}";
}
});
} catch (Exception e) {
e.printStackTrace();
return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
}
@ -482,14 +483,18 @@ public class FileController {
@PostMapping("/rename")
@ResponseBody
public String rename(@RequestBody final Rename body) {
String fileName = body.getFileName();
HashMap<String, String> meta = new HashMap<>();
meta.put("title", fileName + "." + body.getFileType());
CommandRequest commandRequest = CommandRequest.builder()
.key(body.getFileKey())
.c(Command.META)
.meta(Meta.builder()
.title(body.getFileName() + "." + body.getFileType())
.build())
.build();
try {
callbackManager.commandRequest("meta", body.getFileKey(), meta);
return "result ok";
CommandResponse commandResponse = commandService.processCommand(commandRequest, body.getFileName());
return commandResponse.getError().getDescription();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
@ -523,7 +528,6 @@ public class FileController {
if (!link.contains(storagePathBuilder.getServerUrl(true))) {
HashMap<String, String> data = new HashMap<>();
data.put("url", link);
data.put("directUrl", link);
return gson.toJson(data);
}
@ -538,7 +542,8 @@ public class FileController {
if (fileName.equals("")) {
try {
String path = (String) body.getPath();
path = fileUtility.getFileName(path);
path = path.substring(path.lastIndexOf('/') + 1);
path = path.split("\\?")[0];
File f = new File(storagePathBuilder.getFileLocation(path));
if (f.exists()) {
fileName = path;
@ -561,19 +566,18 @@ public class FileController {
referenceData.put("fileKey", gson.toJson(fileKey));
HashMap<String, Object> data = new HashMap<>();
data.put("fileType", fileUtility.getFileExtension(fileName));
data.put("key", serviceConverter.generateRevisionId(
data.put("fileType", documentManager.getDocumentName(fileName));
data.put("key", documentManager.generateRevisionId(
storagePathBuilder.getStorageLocation()
+ "/" + fileName + "/"
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified()
));
data.put("url", documentManager.getDownloadUrl(fileName, true));
data.put("directUrl", body.getDirectUrl() ? documentManager.getDownloadUrl(fileName, false) : null);
data.put("url", urlManager.getFileUrl(fileName));
data.put("referenceData", referenceData);
data.put("path", fileName);
data.put("link", storagePathBuilder.getServerUrl(true) + "/editor?fileName=" + fileName);
if (jwtManager.tokenEnabled()) {
if (settingsManager.isSecurityEnabled()) {
String token = jwtManager.createToken(data);
data.put("token", token);
}
@ -593,9 +597,8 @@ public class FileController {
@GetMapping("/historydata")
@ResponseBody
public String history(@RequestParam("fileName") final String fileName,
@RequestParam("version") final String version,
@RequestParam(value = "directUrl", defaultValue = "false") final Boolean directUrl) {
return historyManager.getHistoryData(fileName, version, directUrl);
@RequestParam("version") final String version) {
return historyManager.getHistoryData(fileName, version);
}
@PutMapping("/restore")
@ -608,7 +611,7 @@ public class FileController {
String historyDirectory = storagePathBuilder.getHistoryDir(sourcePathFile.toString());
Integer bumpedVersion = storagePathBuilder.getFileVersion(historyDirectory, false);
String bumpedVersionStringDirectory = documentManager.versionDir(historyDirectory, bumpedVersion, true);
String bumpedVersionStringDirectory = historyManager.versionDir(historyDirectory, bumpedVersion, true);
File bumpedVersionDirectory = new File(bumpedVersionStringDirectory);
if (!bumpedVersionDirectory.exists()) {
bumpedVersionDirectory.mkdir();
@ -617,7 +620,7 @@ public class FileController {
Path bumpedKeyPathFile = Paths.get(bumpedVersionStringDirectory, "key.txt");
String bumpedKeyStringFile = bumpedKeyPathFile.toString();
File bumpedKeyFile = new File(bumpedKeyStringFile);
String bumpedKey = serviceConverter.generateRevisionId(
String bumpedKey = documentManager.generateRevisionId(
storagePathBuilder.getStorageLocation()
+ "/"
+ body.getFileName()
@ -651,13 +654,13 @@ public class FileController {
bumpedChangesFileWriter.write(bumpedChangesContent);
bumpedChangesFileWriter.close();
String sourceExtension = fileUtility.getFileExtension(body.getFileName());
String sourceExtension = documentManager.getExtension(body.getFileName());
String previousBasename = "prev." + sourceExtension;
Path bumpedFile = Paths.get(bumpedVersionStringDirectory, previousBasename);
Files.move(sourcePathFile, bumpedFile);
String recoveryVersionStringDirectory = documentManager.versionDir(
String recoveryVersionStringDirectory = historyManager.versionDir(
historyDirectory,
body.getVersion(),
true

View File

@ -0,0 +1,121 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.controllers;
import com.onlyoffice.integration.dto.ForgottenFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import com.onlyoffice.model.commandservice.CommandRequest;
import com.onlyoffice.model.commandservice.CommandResponse;
import com.onlyoffice.model.commandservice.commandrequest.Command;
import com.onlyoffice.manager.document.DocumentManager;
import com.onlyoffice.service.command.CommandService;
import java.util.ArrayList;
import java.util.List;
@CrossOrigin("*")
@Controller
public class ForgottenController {
@Value("${server.version}")
private String serverVersion;
@Value("${enable-forgotten}")
private String enableForgotten;
@Autowired
private CommandService commandService;
@Autowired
private DocumentManager documentManager;
@GetMapping("${url.forgotten}")
public String index(final Model model) {
if (!forgottenEnabled()) {
model.addAttribute("error", "The forgotten page is disabled");
return "error.html";
}
model.addAttribute("files", getForgottenFiles());
model.addAttribute("serverVersion", serverVersion);
return "forgotten.html";
}
private ArrayList<ForgottenFile> getForgottenFiles() {
ArrayList<ForgottenFile> files = new ArrayList<ForgottenFile>();
try {
CommandRequest commandRequest = CommandRequest.builder()
.c(Command.GET_FORGOTTEN_LIST)
.build();
CommandResponse commandResponse = commandService.processCommand(commandRequest, null);
List<String> keys = commandResponse.getKeys();
for (int i = 0; i < keys.size(); i++) {
commandRequest = CommandRequest.builder()
.c(Command.GET_FORGOTTEN)
.key(keys.get(i))
.build();
commandResponse = commandService.processCommand(commandRequest, null);
ForgottenFile file = new ForgottenFile(
commandResponse.getKey(),
documentManager.getDocumentType(commandResponse.getUrl()).toString().toLowerCase(),
commandResponse.getUrl()
);
files.add(file);
}
} catch (Exception e) {
e.printStackTrace();
}
return files;
}
private boolean forgottenEnabled() {
return Boolean.valueOf(enableForgotten);
}
@DeleteMapping("/forgotten/{filename}")
public ResponseEntity<String> delete(@PathVariable("filename") final String filename) {
if (!forgottenEnabled()) {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
try {
CommandRequest commandRequest = CommandRequest.builder()
.c(Command.DELETE_FORGOTTEN)
.key(filename)
.build();
CommandResponse commandResponse = commandService.processCommand(commandRequest, null);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}

View File

@ -21,9 +21,9 @@ package com.onlyoffice.integration.controllers;
import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.Misc;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.FormatService;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.sdk.manager.DocumentManager;
import com.onlyoffice.integration.sdk.manager.UrlManager;
import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.dto.FormatsList;
import org.springframework.beans.factory.annotation.Autowired;
@ -33,7 +33,6 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.ResponseEntity;
@ -55,9 +54,6 @@ public class IndexController {
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private FileUtility fileUtility;
@Autowired
private Misc mistUtility;
@ -65,13 +61,10 @@ public class IndexController {
private UserServices userService;
@Autowired
private FormatService formatService;
private DocumentManager documentManager;
@Value("${files.docservice.url.site}")
private String docserviceSite;
@Value("${files.docservice.url.preloader}")
private String docservicePreloader;
@Autowired
private UrlManager urlManager;
@Value("${url.converter}")
private String urlConverter;
@ -85,9 +78,11 @@ public class IndexController {
@Value("${server.version}")
private String serverVersion;
@Value("${enable-forgotten}")
private String enableForgotten;
@GetMapping("${url.index}")
public String index(@RequestParam(value = "directUrl", required = false) final Boolean directUrl,
final Model model) {
public String index(final Model model) {
java.io.File[] files = storageMutator.getStoredFiles(); // get all the stored files from the storage
List<String> docTypes = new ArrayList<>();
List<Boolean> filesEditable = new ArrayList<>();
@ -111,15 +106,14 @@ public class IndexController {
for (java.io.File file:files) { // run through all the files
String fileName = file.getName(); // get file name
docTypes.add(fileUtility
docTypes.add(documentManager
.getDocumentType(fileName)
.toString()
.toLowerCase()); // add a document type of each file to the list
filesEditable.add(fileUtility.getEditedExts()
.contains(fileUtility.getFileExtension(fileName))); // specify if a file is editable or not
filesEditable.add(documentManager.isEditable(fileName)); // specify if a file is editable or not
versions.add(" [" + storagePathBuilder.
getFileVersion(fileName, true) + "]"); // add a file version to the list
isFillFormDoc.add(fileUtility.getFillExts().contains(fileUtility.getFileExtension(fileName)));
isFillFormDoc.add(documentManager.isFillable(fileName));
}
// add all the parameters to the model
@ -128,12 +122,12 @@ public class IndexController {
model.addAttribute("files", files);
model.addAttribute("docTypes", docTypes);
model.addAttribute("filesEditable", filesEditable);
model.addAttribute("datadocs", docserviceSite + docservicePreloader);
model.addAttribute("datadocs", urlManager.getDocumentServerPreloaderApiUrl());
model.addAttribute("tooltip", tooltip);
model.addAttribute("users", users);
model.addAttribute("languages", languages);
model.addAttribute("directUrl", directUrl);
model.addAttribute("serverVersion", serverVersion);
model.addAttribute("enableForgotten", Boolean.valueOf(enableForgotten));
return "index.html";
}
@ -151,7 +145,7 @@ public class IndexController {
@GetMapping("/formats")
@ResponseBody
public ResponseEntity<FormatsList> formats() { // return all the supported formats
FormatsList list = new FormatsList(formatService.getFormats());
FormatsList list = new FormatsList(documentManager.getFormats());
return ResponseEntity.ok(list);
}
}

View File

@ -1,32 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks;
import com.onlyoffice.integration.dto.Track;
import org.springframework.beans.factory.annotation.Autowired;
// specify the callback handler functions
public interface Callback {
int handle(Track body, String fileName); // handle the callback
int getStatus(); // get document status
@Autowired
default void selfRegistration(CallbackHandler callbackHandler) { // register a callback handler
callbackHandler.register(getStatus(), this);
}
}

View File

@ -1,50 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks;
import com.onlyoffice.integration.dto.Track;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class CallbackHandler {
private Logger logger = LoggerFactory.getLogger(CallbackHandler.class);
private Map<Integer, Callback> callbackHandlers = new HashMap<>();
public void register(final int code, final Callback callback) { // register a callback handler
callbackHandlers.put(code, callback);
}
public int handle(final Track body, final String fileName) { // handle a callback
Callback callback = callbackHandlers.get(body.getStatus());
if (callback == null) {
logger.warn("Callback status " + body.getStatus() + " is not supported yet");
return 0;
}
int result = callback.handle(body, fileName);
return result;
}
}

View File

@ -1,35 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks;
// document status
public enum Status {
EDITING(1), // 1 - document is being edited
SAVE(2), // 2 - document is ready for saving
CORRUPTED(3), // 3 - document saving error has occurred
MUST_FORCE_SAVE(6), // 6 - document is being edited, but the current document state is saved
CORRUPTED_FORCE_SAVE(7); // 7 - error has occurred while force saving the document
private int code;
Status(final int codeParam) {
this.code = codeParam;
}
public int getCode() { // get document status
return this.code;
}
}

View File

@ -1,59 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks.implementations;
import com.onlyoffice.integration.documentserver.callbacks.Callback;
import com.onlyoffice.integration.documentserver.callbacks.Status;
import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
import com.onlyoffice.integration.dto.Action;
import com.onlyoffice.integration.dto.Track;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class EditCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(final Track body,
final String fileName) { // handle the callback when the document is being edited
int result = 0;
Action action = body.getActions().get(0); // get the user ID who is editing the document
if (action.getType().equals(com.onlyoffice.integration.documentserver.models.enums
.Action.edit)) { // if this value is not equal to the user ID
String user = action.getUserid(); // get user ID
if (!body.getUsers().contains(user)) { // if this user is not specified in the body
String key = body.getKey(); // get document key
try {
// create a command request to forcibly save the document being edited without closing it
callbackManager.commandRequest("forcesave", key, null);
} catch (Exception e) {
e.printStackTrace();
result = 1;
}
}
}
return result;
}
@Override
public int getStatus() { // get document status
return Status.EDITING.getCode(); // return status 1 - document is being edited
}
}

View File

@ -1,50 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks.implementations;
import com.onlyoffice.integration.documentserver.callbacks.Callback;
import com.onlyoffice.integration.documentserver.callbacks.Status;
import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
import com.onlyoffice.integration.dto.Track;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ForcesaveCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(final Track body,
final String fileName) { // handle the callback when the force saving request is performed
int result = 0;
try {
callbackManager.processForceSave(body, fileName); // file force saving process
} catch (Exception ex) {
ex.printStackTrace();
result = 1;
}
return result;
}
@Override
public int getStatus() { // get document status
// return status 6 - document is being edited, but the current document state is saved
return Status.MUST_FORCE_SAVE.getCode();
}
}

View File

@ -1,50 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.callbacks.implementations;
import com.onlyoffice.integration.documentserver.callbacks.Callback;
import com.onlyoffice.integration.documentserver.callbacks.Status;
import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
import com.onlyoffice.integration.dto.Track;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SaveCallback implements Callback {
@Autowired
private CallbackManager callbackManager;
@Override
public int handle(final Track body,
final String fileName) { // handle the callback when the saving request is performed
int result = 0;
try {
callbackManager.processSave(body, fileName); // file saving process
} catch (Exception ex) {
ex.printStackTrace();
result = 1;
}
return result;
}
@Override
public int getStatus() { // get document status
return Status.SAVE.getCode(); // return status 2 - document is ready for saving
}
}

View File

@ -18,11 +18,10 @@
package com.onlyoffice.integration.documentserver.managers.callback;
import com.onlyoffice.integration.dto.Track;
import java.util.HashMap;
import com.onlyoffice.model.documenteditor.Callback;
public interface CallbackManager { // specify the callback manager functions
void processSave(Track body, String fileName); // file saving process
void commandRequest(String method, String key, HashMap meta); // create a command request
void processForceSave(Track body, String fileName); // file force saving process
void processEditing(Callback callback, String fileName);
void processSave(Callback callback, String fileName);
void processForceSave(Callback callback, String fileName);
}

View File

@ -19,62 +19,60 @@
package com.onlyoffice.integration.documentserver.managers.callback;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
import com.onlyoffice.integration.documentserver.managers.history.HistoryManager;
import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.dto.Action;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import com.onlyoffice.integration.dto.Track;
import com.onlyoffice.integration.sdk.manager.DocumentManager;
import com.onlyoffice.integration.sdk.manager.UrlManager;
import com.onlyoffice.manager.request.RequestManager;
import com.onlyoffice.model.commandservice.CommandRequest;
import com.onlyoffice.model.commandservice.commandrequest.Command;
import com.onlyoffice.model.convertservice.ConvertRequest;
import com.onlyoffice.model.convertservice.ConvertResponse;
import com.onlyoffice.model.documenteditor.Callback;
import com.onlyoffice.model.documenteditor.callback.Action;
import com.onlyoffice.model.documenteditor.callback.ForcesaveType;
import com.onlyoffice.model.documenteditor.callback.action.Type;
import com.onlyoffice.service.command.CommandService;
import com.onlyoffice.service.convert.ConvertService;
import lombok.SneakyThrows;
import org.apache.http.HttpEntity;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.onlyoffice.integration.documentserver.util.Constants.FILE_SAVE_TIMEOUT;
// todo: Refactoring
@Component
@Primary
public class DefaultCallbackManager implements CallbackManager {
@Value("${files.docservice.url.site}")
private String docserviceUrlSite;
@Value("${files.docservice.url.command}")
private String docserviceUrlCommand;
@Value("${files.docservice.header}")
private String documentJwtHeader;
@Autowired
private DocumentManager documentManager;
@Autowired
private JwtManager jwtManager;
@Autowired
private FileUtility fileUtility;
@Autowired
private FileStorageMutator storageMutator;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ServiceConverter serviceConverter;
private ConvertService convertService;
@Autowired
private RequestManager requestManager;
@Autowired
private CommandService commandService;
@Autowired
private HistoryManager historyManager;
@Autowired
private UrlManager urlManager;
// download file from url
@SneakyThrows
@ -83,23 +81,18 @@ public class DefaultCallbackManager implements CallbackManager {
throw new RuntimeException("Url argument is not specified"); // URL isn't specified
}
URL uri = new URL(url);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection();
connection.setConnectTimeout(FILE_SAVE_TIMEOUT);
InputStream stream = connection.getInputStream(); // get input stream of the file information from the URL
return requestManager.executeGetRequest(url, new RequestManager.Callback<byte[]>() {
public byte[] doWork(final Object response) throws IOException {
InputStream stream = ((HttpEntity) response).getContent(); // get input stream of the converted
// file
int statusCode = connection.getResponseCode();
if (statusCode != HttpStatus.OK.value()) { // checking status code
connection.disconnect();
throw new RuntimeException("Document editing service returned status: " + statusCode);
}
if (stream == null) {
throw new RuntimeException("Input stream is null");
}
if (stream == null) {
connection.disconnect();
throw new RuntimeException("Input stream is null");
}
return stream.readAllBytes();
return stream.readAllBytes();
}
});
}
// file saving
@ -112,40 +105,76 @@ public class DefaultCallbackManager implements CallbackManager {
storageMutator.createOrUpdateFile(path, new ByteArrayInputStream(byteArray));
}
@Override
public void processEditing(final Callback callback, final String fileName) {
Action action = callback.getActions().get(0); // get the user ID who is editing the document
if (action.getType().equals(Type.CONNECTED)) { // if this value is not equal to the user ID
String user = action.getUserid(); // get user ID
if (!callback.getUsers().contains(user)) { // if this user is not specified in the body
CommandRequest commandRequest = CommandRequest.builder()
.c(Command.FORCESAVE)
.key(callback.getKey())
.build();
// create a command request to forcibly save the document being edited without closing it
try {
commandService.processCommand(commandRequest, fileName);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
@SneakyThrows
public void processSave(final Track body, final String fileName) { // file saving process
String downloadUri = body.getUrl();
String changesUri = body.getChangesurl();
String key = body.getKey();
public void processSave(final Callback callback, final String fileName) { // file saving process
String downloadUri = callback.getUrl();
String changesUri = callback.getChangesurl();
String key = callback.getKey();
String newFileName = fileName;
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = body.getFiletype(); // get an extension of the downloaded file
String curExt = documentManager.getExtension(fileName); // get current file extension
String downloadExt = callback.getFiletype(); // get an extension of the downloaded file
String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file
if (!Paths.get(storagePath).toFile().exists()) {
throw new RuntimeException("{\"error\":1, \"message\":\"file does not exist\"}");
}
downloadUri = urlManager.replaceToInnerDocumentServerUrl(downloadUri);
changesUri = urlManager.replaceToInnerDocumentServerUrl(changesUri);
// todo: Refactoring
// convert downloaded file to the file with the current extension if these extensions aren't equal
if (!curExt.equals(downloadExt)) {
try {
String newFileUri = serviceConverter
.getConvertedData(downloadUri, downloadExt, curExt,
serviceConverter.generateRevisionId(downloadUri), null, false,
null).getUri(); // convert a file and get URL to a new file
if (newFileUri.isEmpty()) {
ConvertRequest convertRequest = ConvertRequest.builder()
.key(documentManager.generateRevisionId(downloadUri))
.url(downloadUri)
.outputtype(curExt)
.async(false)
.build();
// convert a file and get URL to a new file
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
String newFileUri = convertResponse.getFileUrl();
if (newFileUri == null || newFileUri.isEmpty()) {
newFileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "."
.getCorrectName(documentManager.getBaseName(fileName) + "."
+ downloadExt); // get the correct file name if it already exists
} else {
downloadUri = newFileUri;
}
} catch (Exception e) {
newFileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "." + downloadExt);
.getCorrectName(documentManager.getBaseName(fileName) + "." + downloadExt);
}
}
byte[] byteArrayFile = getDownloadFile(downloadUri); // download document file
String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file
Path lastVersion = Paths.get(storagePathBuilder
.getFileLocation(fileName)); // get the path to the last file version
@ -153,7 +182,7 @@ public class DefaultCallbackManager implements CallbackManager {
Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath)); // get the history directory
storageMutator.createDirectory(histDir); // and create it
String versionDir = documentManager
String versionDir = historyManager
.versionDir(histDir.toAbsolutePath().toString(), // get the file version directory
storagePathBuilder
.getFileVersion(histDir.toAbsolutePath().toString(), false), true);
@ -172,13 +201,13 @@ public class DefaultCallbackManager implements CallbackManager {
.of(versionDir + File.separator + "diff.zip")); // save file changes to the diff.zip archive
JSONObject jsonChanges = new JSONObject(); // create a json object for document changes
jsonChanges.put("changes", body.getHistory().getChanges()); // put the changes to the json object
jsonChanges.put("serverVersion", body.getHistory()
jsonChanges.put("changes", callback.getHistory().getChanges()); // put the changes to the json object
jsonChanges.put("serverVersion", callback.getHistory()
.getServerVersion()); // put the server version to the json object
String history = objectMapper.writeValueAsString(jsonChanges);
if (history == null && body.getHistory() != null) {
history = objectMapper.writeValueAsString(body.getHistory());
if (history == null && callback.getHistory() != null) {
history = objectMapper.writeValueAsString(callback.getHistory());
}
if (history != null && !history.isEmpty()) {
@ -194,82 +223,16 @@ public class DefaultCallbackManager implements CallbackManager {
}
}
// todo: Replace (String method) with (Enum method)
@SneakyThrows
public void commandRequest(final String method,
final String key,
final HashMap meta) { // create a command request
String documentCommandUrl = docserviceUrlSite + docserviceUrlCommand;
public void processForceSave(final Callback callback, final String fileNameParam) { // file force saving process
URL url = new URL(documentCommandUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("c", method);
params.put("key", key);
if (meta != null) {
params.put("meta", meta);
}
String headerToken;
// check if a secret key to generate token exists or not
if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
Map<String, Object> payloadMap = new HashMap<>();
payloadMap.put("payload", params);
headerToken = jwtManager.createToken(payloadMap); // encode a payload object into a header token
// add a header Authorization with a header token and Authorization prefix in it
connection.setRequestProperty(documentJwtHeader.equals("")
? "Authorization" : documentJwtHeader, "Bearer " + headerToken);
String token = jwtManager.createToken(params); // encode a payload object into a body token
params.put("token", token);
}
String bodyString = objectMapper.writeValueAsString(params);
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
connection.setRequestMethod("POST"); // set the request method
connection
.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // set the Content-Type header
connection.setDoOutput(true); // set the doOutput field to true
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte); // write bytes to the output stream
}
InputStream stream = connection.getInputStream(); // get input stream
if (stream == null) {
throw new RuntimeException("Could not get an answer");
}
String jsonString = serviceConverter.convertStreamToString(stream); // convert stream to json string
connection.disconnect();
JSONObject response = serviceConverter.convertStringToJSON(jsonString); // convert json string to json object
// todo: Add errors ENUM
String responseCode = response.get("error").toString();
switch (responseCode) {
case "0":
case "4":
break;
default:
throw new RuntimeException(response.toJSONString());
}
}
@SneakyThrows
public void processForceSave(final Track body, final String fileNameParam) { // file force saving process
String downloadUri = body.getUrl();
String downloadUri = callback.getUrl();
String fileName = fileNameParam;
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = body.getFiletype(); // get an extension of the downloaded file
String curExt = documentManager.getExtension(fileName); // get current file extension
String downloadExt = callback.getFiletype(); // get an extension of the downloaded file
downloadUri = urlManager.replaceToInnerDocumentServerUrl(downloadUri);
Boolean newFileName = false;
@ -277,11 +240,19 @@ public class DefaultCallbackManager implements CallbackManager {
// todo: Extract function
if (!curExt.equals(downloadExt)) {
try {
// convert file and get URL to a new file
String newFileUri = serviceConverter
.getConvertedData(downloadUri, downloadExt, curExt, serviceConverter
.generateRevisionId(downloadUri), null, false, null).getUri();
if (newFileUri.isEmpty()) {
ConvertRequest convertRequest = ConvertRequest.builder()
.key(documentManager.generateRevisionId(downloadUri))
.url(downloadUri)
.outputtype(curExt)
.async(false)
.build();
// convert a file and get URL to a new file
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
String newFileUri = convertResponse.getFileUrl();
if (newFileUri == null || newFileUri.isEmpty()) {
newFileName = true;
} else {
downloadUri = newFileUri;
@ -296,32 +267,34 @@ public class DefaultCallbackManager implements CallbackManager {
// todo: Use ENUMS
// todo: Pointless toString conversion
boolean isSubmitForm = body.getForcesavetype().toString().equals("3");
boolean isSubmitForm = callback.getForcesavetype().equals(ForcesaveType.SUBMIT_FORM);
// todo: Extract function
if (isSubmitForm) { // if the form is submitted
if (newFileName) {
// get the correct file name if it already exists
fileName = documentManager
.getCorrectName(fileUtility
.getFileNameWithoutExtension(fileName) + "-form." + downloadExt);
.getCorrectName(documentManager
.getBaseName(fileName) + "-form." + downloadExt);
} else {
fileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form." + curExt);
.getCorrectName(documentManager.getBaseName(fileName) + "-form." + curExt);
}
forcesavePath = storagePathBuilder.getFileLocation(fileName); // create forcesave path if it doesn't exist
List<Action> actions = body.getActions();
Action action = actions.get(0);
List<com.onlyoffice.model.documenteditor.callback.Action> actions = callback.getActions();
com.onlyoffice.model.documenteditor.callback.Action action = actions.get(0);
String user = action.getUserid(); // get the user ID
// create meta data for the forcesaved file
storageMutator.createMeta(fileName, user, "Filling Form");
try {
String formsDataUrl = body.getFormsdataurl();
String formsDataUrl = callback.getFormsdataurl();
formsDataUrl = urlManager.replaceToInnerDocumentServerUrl(formsDataUrl);
if (formsDataUrl != null && !formsDataUrl.isEmpty()) {
String formsName = documentManager.getCorrectName(fileUtility
.getFileNameWithoutExtension(fileName) + ".txt");
String formsName = documentManager.getCorrectName(documentManager
.getBaseName(fileName) + ".txt");
String formsPath = storagePathBuilder.getFileLocation(formsName);
byte[] byteArrayFormsData = getDownloadFile(formsDataUrl);
@ -336,7 +309,7 @@ public class DefaultCallbackManager implements CallbackManager {
} else {
if (newFileName) {
fileName = documentManager
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt);
.getCorrectName(documentManager.getBaseName(fileName) + "." + downloadExt);
}
forcesavePath = storagePathBuilder.getForcesavePath(fileName, false);

View File

@ -1,246 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.document;
import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.onlyoffice.integration.documentserver.util.Constants.KILOBYTE_SIZE;
@Component
@Primary
public class DefaultDocumentManager implements DocumentManager {
@Value("${files.storage.folder}")
private String storageFolder;
@Value("${files.storage}")
private String filesStorage;
@Value("${url.track}")
private String trackUrl;
@Value("${url.download}")
private String downloadUrl;
@Autowired
private FileStorageMutator storageMutator;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private FileUtility fileUtility;
@Autowired
private ServiceConverter serviceConverter;
// get URL to the created file
public String getCreateUrl(final String fileName, final Boolean sample) {
String fileExt = fileUtility.getFileExtension(fileName);
String url = storagePathBuilder.getServerUrl(true)
+ "/create?fileExt=" + fileExt + "&sample=" + sample;
return url;
}
// get a file name with an index if the file with such a name already exists
public String getCorrectName(final String fileName) {
String baseName = fileUtility.getFileNameWithoutExtension(fileName); // get file name without extension
String ext = fileUtility.getFileExtension(fileName); // get file extension
String name = baseName + "." + ext; // create a full file name
Path path = Paths.get(storagePathBuilder.getFileLocation(name));
// run through all the files with such a name in the storage directory
for (int i = 1; Files.exists(path); i++) {
name = baseName + " (" + i + ")." + ext; // and add an index to the base name
path = Paths.get(storagePathBuilder.getFileLocation(name));
}
return name;
}
// get file URL
public String getFileUri(final String fileName, final Boolean forDocumentServer) {
try {
String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL
String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory
String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName
: fileName.substring(fileName.indexOf(InetAddress.getLocalHost()
.getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1);
if (!filesStorage.isEmpty() && filePathDownload.contains(filesStorage)) {
filePathDownload = filePathDownload.substring(filesStorage.length() + 1);
}
String filePath = serverPath + "/download?fileName=" + URLEncoder
.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString()) + "&userAddress"
+ URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
return filePath;
} catch (UnsupportedEncodingException | UnknownHostException e) {
return "";
}
}
// get file URL
public String getHistoryFileUrl(final String fileName, final Integer version, final String file,
final Boolean forDocumentServer) {
try {
String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL
String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory
String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName
: fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress())
+ InetAddress.getLocalHost().getHostAddress().length() + 1);
String userAddress = forDocumentServer ? "&userAddress" + URLEncoder
.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : "";
String filePath = serverPath + "/downloadhistory?fileName=" + URLEncoder
.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString())
+ "&ver=" + version + "&file=" + file
+ userAddress;
return filePath;
} catch (UnsupportedEncodingException | UnknownHostException e) {
return "";
}
}
// get the callback URL
public String getCallback(final String fileName) {
String serverPath = storagePathBuilder.getServerUrl(true);
String storageAddress = storagePathBuilder.getStorageLocation();
try {
String query = trackUrl + "?fileName="
+ URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString())
+ "&userAddress=" + URLEncoder
.encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
return serverPath + query;
} catch (UnsupportedEncodingException e) {
return "";
}
}
// get URL to download a file
public String getDownloadUrl(final String fileName, final Boolean isServer) {
String serverPath = storagePathBuilder.getServerUrl(isServer);
String storageAddress = storagePathBuilder.getStorageLocation();
try {
String userAddress = isServer ? "&userAddress=" + URLEncoder
.encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : "";
String query = downloadUrl + "?fileName="
+ URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString())
+ userAddress;
return serverPath + query;
} catch (UnsupportedEncodingException e) {
return "";
}
}
// get file information
public ArrayList<Map<String, Object>> getFilesInfo() {
ArrayList<Map<String, Object>> files = new ArrayList<>();
// run through all the stored files
for (File file : storageMutator.getStoredFiles()) {
Map<String, Object> map = new LinkedHashMap<>(); // write all the parameters to the map
map.put("version", storagePathBuilder.getFileVersion(file.getName(), false));
map.put("id", serviceConverter
.generateRevisionId(storagePathBuilder.getStorageLocation()
+ "/" + file.getName() + "/"
+ Paths.get(storagePathBuilder.getFileLocation(file.getName()))
.toFile()
.lastModified()));
map.put("contentLength", new BigDecimal(String.valueOf((file.length() / Double.valueOf(KILOBYTE_SIZE))))
.setScale(2, RoundingMode.HALF_UP) + " KB");
map.put("pureContentLength", file.length());
map.put("title", file.getName());
map.put("updated", String.valueOf(new Date(file.lastModified())));
files.add(map);
}
return files;
}
// get file information by its ID
public ArrayList<Map<String, Object>> getFilesInfo(final String fileId) {
ArrayList<Map<String, Object>> file = new ArrayList<>();
for (Map<String, Object> map : getFilesInfo()) {
if (map.get("id").equals(fileId)) {
file.add(map);
break;
}
}
return file;
}
// get the path to the file version by the history path and file version
public String versionDir(final String path, final Integer version, final boolean historyPath) {
if (!historyPath) {
return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version;
}
return path + File.separator + version;
}
// create demo document
public String createDemo(final String fileExt, final Boolean sample, final String uid, final String uname) {
String demoName = (sample ? "sample." : "new.")
+ fileExt; // create sample or new template file with the necessary extension
String demoPath =
"assets"
+ File.separator
+ "document-templates"
+ File.separator
+ (sample ? "sample" : "new")
+ File.separator
+ demoName;
// get a file name with an index if the file with such a name already exists
String fileName = getCorrectName(demoName);
InputStream stream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(demoPath); // get the input file stream
if (stream == null) {
return null;
}
storageMutator.createFile(Path.of(storagePathBuilder
.getFileLocation(fileName)), stream); // create a file in the specified directory
storageMutator.createMeta(fileName, uid, uname); // create meta information of the demo file
return fileName;
}
}

View File

@ -1,42 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.document;
import java.util.ArrayList;
import java.util.Map;
// specify the document manager functions
public interface DocumentManager {
// get a file name with an index if the file with such a name already exists
String getCorrectName(String fileName);
String getFileUri(String fileName, Boolean forDocumentServer); // get file URL
String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer); // get file URL
String getCallback(String fileName); // get the callback URL
String getDownloadUrl(String fileName, Boolean forDocumentServer); // get URL to download a file
ArrayList<Map<String, Object>> getFilesInfo(); // get file information
ArrayList<Map<String, Object>> getFilesInfo(String fileId); // get file information by its ID
// get the path to the file version by the history path and file version
String versionDir(String path, Integer version, boolean historyPath);
// create demo document
String createDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception;
String getCreateUrl(String fileName, Boolean sample); // get URL to the created file
}

View File

@ -20,14 +20,17 @@ package com.onlyoffice.integration.documentserver.managers.history;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
import com.onlyoffice.integration.documentserver.models.filemodel.Document;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import com.onlyoffice.integration.sdk.manager.DocumentManager;
import com.onlyoffice.integration.sdk.manager.UrlManager;
import com.onlyoffice.manager.security.JwtManager;
import com.onlyoffice.manager.settings.SettingsManager;
import com.onlyoffice.model.common.User;
import com.onlyoffice.model.documenteditor.HistoryData;
import com.onlyoffice.model.documenteditor.callback.History;
import com.onlyoffice.model.documenteditor.history.Version;
import com.onlyoffice.model.documenteditor.historydata.Previous;
import lombok.SneakyThrows;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,6 +38,7 @@ import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -49,15 +53,9 @@ public class DefaultHistoryManager implements HistoryManager {
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private DocumentManager documentManager;
@Autowired
private JwtManager jwtManager;
@Autowired
private FileUtility fileUtility;
@Autowired
private JSONParser parser;
@ -65,109 +63,13 @@ public class DefaultHistoryManager implements HistoryManager {
private ObjectMapper objectMapper;
@Autowired
private ServiceConverter serviceConverter;
private SettingsManager settingsManager;
// todo: Refactoring
@SneakyThrows
public String[] getHistory(final Document document) { // get document history
@Autowired
private UrlManager urlManager;
// get history directory
String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle()));
Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version
if (curVer > 0) { // check if the current file version is greater than 0
List<Object> hist = new ArrayList<>();
Map<String, Object> histData = new HashMap<>();
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
Map<String, Object> obj = new HashMap<String, Object>();
Map<String, Object> dataObj = new HashMap<String, Object>();
String verDir = documentManager
.versionDir(histDir, i, true); // get the path to the given file version
String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir
+ File.separator + "key.txt")); // get document key
obj.put("key", key);
obj.put("version", i);
if (i == 1) { // check if the version number is equal to 1
String createdInfo = readFileToEnd(new File(histDir
+ File.separator + "createdInfo.json")); // get file with meta data
JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object
// write meta information to the object (user information and creation date)
obj.put("created", json.get("created"));
Map<String, Object> user = new HashMap<String, Object>();
user.put("id", json.get("id"));
user.put("name", json.get("name"));
obj.put("user", user);
}
dataObj.put("fileType", fileUtility
.getFileExtension(document.getTitle()));
dataObj.put("key", key);
dataObj.put("url", i == curVer ? document.getUrl()
: documentManager.getHistoryFileUrl(document.getTitle(), i, "prev." + fileUtility
.getFileExtension(document.getTitle()), true));
if (!document.getDirectUrl().equals("")) {
dataObj.put("directUrl", i == curVer ? document.getDirectUrl()
: documentManager.getHistoryFileUrl(document.getTitle(), i, "prev." + fileUtility
.getFileExtension(document.getTitle()), false));
}
dataObj.put("version", i);
if (i > 1) { //check if the version number is greater than 1
// if so, get the path to the changes.json file
JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(documentManager
.versionDir(histDir, i - 1, true) + File.separator + "changes.json")));
JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
// write information about changes to the object
obj.put("changes", changes.get("changes"));
obj.put("serverVersion", changes.get("serverVersion"));
obj.put("created", change.get("created"));
obj.put("user", change.get("user"));
// get the history data from the previous file version
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));
Map<String, Object> prevInfo = new HashMap<String, Object>();
prevInfo.put("fileType", prev.get("fileType"));
prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version
prevInfo.put("url", prev.get("url"));
if (!document.getDirectUrl().equals("")) {
prevInfo.put("directUrl", prev.get("directUrl"));
}
// write information about previous file version to the data object
dataObj.put("previous", prevInfo);
// write the path to the diff.zip archive with differences in this file version
Integer verdiff = i - 1;
dataObj.put("changesUrl", documentManager
.getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true));
}
if (jwtManager.tokenEnabled()) {
dataObj.put("token", jwtManager.createToken(dataObj));
}
hist.add(obj);
histData.put(Integer.toString(i - 1), dataObj);
}
// write history information about the current file version to the history object
Map<String, Object> histObj = new HashMap<String, Object>();
histObj.put("currentVersion", curVer);
histObj.put("history", hist);
try {
return new String[]{objectMapper.writeValueAsString(histObj),
objectMapper.writeValueAsString(histData)};
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return new String[]{"", ""};
}
@Autowired
private DocumentManager documentManager;
// todo: Refactoring
@SneakyThrows
@ -178,16 +80,14 @@ public class DefaultHistoryManager implements HistoryManager {
Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version
if (curVer > 0) { // check if the current file version is greater than 0
List<Object> hist = new ArrayList<>();
List<Version> history = new ArrayList<>();
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
Map<String, Object> obj = new HashMap<String, Object>();
String verDir = documentManager
.versionDir(histDir, i, true); // get the path to the given file version
String verDir = versionDir(histDir, i, true); // get the path to the given file version
String key;
if (i == curVer) {
key = serviceConverter
key = documentManager
.generateRevisionId(storagePathBuilder.getStorageLocation()
+ "/" + fileName + "/"
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
@ -195,8 +95,10 @@ public class DefaultHistoryManager implements HistoryManager {
key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
}
obj.put("key", key);
obj.put("version", i);
Version version = Version.builder()
.key(key)
.version(String.valueOf(i))
.build();
if (i == 1) { // check if the version number is equal to 1
String createdInfo = readFileToEnd(new File(histDir
@ -204,33 +106,35 @@ public class DefaultHistoryManager implements HistoryManager {
JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object
// write meta information to the object (user information and creation date)
obj.put("created", json.get("created"));
Map<String, Object> user = new HashMap<String, Object>();
user.put("id", json.get("id"));
user.put("name", json.get("name"));
obj.put("user", user);
version.setCreated(String.valueOf(json.get("created")));
version.setUser(User.builder()
.id(String.valueOf(json.get("id")))
.name(String.valueOf(json.get("name")))
.build()
);
}
if (i > 1) { //check if the version number is greater than 1
// if so, get the path to the changes.json file
JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(documentManager
.versionDir(histDir, i - 1, true) + File.separator + "changes.json")));
JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
InputStream changesSteam = new FileInputStream(
versionDir(histDir, i - 1, true) + File.separator + "changes.json");
History changes = objectMapper.readValue(changesSteam, History.class);
// write information about changes to the object
obj.put("changes", changes.get("changes"));
obj.put("serverVersion", changes.get("serverVersion"));
obj.put("created", change.get("created"));
obj.put("user", change.get("user"));
version.setChanges(changes.getChanges());
version.setServerVersion(changes.getServerVersion());
version.setCreated(changes.getChanges().get(0).getCreated());
version.setUser(changes.getChanges().get(0).getUser());
}
hist.add(obj);
history.add(version);
}
// write history information about the current file version to the history object
Map<String, Object> histObj = new HashMap<String, Object>();
histObj.put("currentVersion", curVer);
histObj.put("history", hist);
histObj.put("history", history);
try {
return objectMapper.writeValueAsString(histObj);
@ -243,74 +147,65 @@ public class DefaultHistoryManager implements HistoryManager {
// todo: Refactoring
@SneakyThrows
public String getHistoryData(final String fileName, final String version, final Boolean directUrl) {
public String getHistoryData(final String fileName, final String version) {
// get history directory
String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(fileName));
Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version
if (curVer > 0) { // check if the current file version is greater than 0
Map<String, Object> histData = new HashMap<>();
Map<String, HistoryData> historyDataMap = new HashMap<>();
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
Map<String, Object> dataObj = new HashMap<String, Object>();
String verDir = documentManager
.versionDir(histDir, i, true); // get the path to the given file version
String verDir = versionDir(histDir, i, true); // get the path to the given file version
String key;
if (i == curVer) {
key = serviceConverter
key = documentManager
.generateRevisionId(storagePathBuilder.getStorageLocation()
+ "/" + fileName + "/"
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
} else {
key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
}
HistoryData historyData = HistoryData.builder()
.fileType(documentManager.getExtension(fileName))
.key(key)
.url(i == curVer ? urlManager.getFileUrl(fileName)
: urlManager.getHistoryFileUrl(fileName, i, "prev" + documentManager
.getExtension(fileName), true))
.build();
dataObj.put("fileType", fileUtility
.getFileExtension(fileName).replace(".", ""));
dataObj.put("key", key);
dataObj.put("url", i == curVer ? documentManager.getDownloadUrl(fileName, true)
: documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
.getFileExtension(fileName), true));
if (directUrl) {
dataObj.put("directUrl", i == curVer
? documentManager.getDownloadUrl(fileName, false)
: documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
.getFileExtension(fileName), false));
}
dataObj.put("version", i);
historyData.setVersion(String.valueOf(i));
if (i > 1) { //check if the version number is greater than 1
Integer verdiff = i - 1;
// get the history data from the previous file version
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(verdiff));
Map<String, Object> prevInfo = new HashMap<String, Object>();
prevInfo.put("fileType", prev.get("fileType"));
prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version
prevInfo.put("url", prev.get("url"));
if (directUrl) {
prevInfo.put("directUrl", prev.get("directUrl"));
}
HistoryData historyDataPrev = historyDataMap.get(Integer.toString(verdiff));
Previous previous = Previous.builder()
.fileType(historyDataPrev.getFileType())
.key(historyDataPrev.getKey())
.url(historyDataPrev.getUrl())
.build();
// write information about previous file version to the data object
dataObj.put("previous", prevInfo);
historyData.setPrevious(previous);
if (diffExists(histDir, verdiff)) {
// write the path to the diff.zip archive with differences in this file version
dataObj.put("changesUrl", documentManager
historyData.setChangesUrl(urlManager
.getHistoryFileUrl(fileName, verdiff, "diff.zip", true));
}
}
if (jwtManager.tokenEnabled()) {
dataObj.put("token", jwtManager.createToken(dataObj));
if (settingsManager.isSecurityEnabled()) {
historyData.setToken(jwtManager.createToken(historyData));
}
histData.put(Integer.toString(i), dataObj);
historyDataMap.put(Integer.toString(i), historyData);
}
try {
return objectMapper.writeValueAsString(histData.get(version));
return objectMapper.writeValueAsString(historyDataMap.get(version));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
@ -318,6 +213,14 @@ public class DefaultHistoryManager implements HistoryManager {
return "";
}
@Override
public String versionDir(final String path, final Integer version, final boolean historyPath) {
if (!historyPath) {
return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version;
}
return path + File.separator + version;
}
// read a file
private String readFileToEnd(final File file) {

View File

@ -21,6 +21,6 @@ package com.onlyoffice.integration.documentserver.managers.history;
// specify the history manager functions
public interface HistoryManager {
String getHistory(String fileName); // get document history
String getHistoryData(String fileName, String version, Boolean directUrl); // get document history data
String getHistoryData(String fileName, String version); // get document history data
String versionDir(String path, Integer version, boolean historyPath);
}

View File

@ -1,130 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.jwt;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.primeframework.jwt.Signer;
import org.primeframework.jwt.Verifier;
import org.primeframework.jwt.domain.JWT;
import org.primeframework.jwt.hmac.HMACSigner;
import org.primeframework.jwt.hmac.HMACVerifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.Map;
@Component
public class DefaultJwtManager implements JwtManager {
@Value("${files.docservice.secret}")
private String tokenSecret;
@Value("${files.docservice.token-use-for-request}")
private String tokenUseForRequest;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private JSONParser parser;
// create document token
public String createToken(final Map<String, Object> payloadClaims) {
try {
// build a HMAC signer using a SHA-256 hash
Signer signer = HMACSigner.newSHA256Signer(tokenSecret);
JWT jwt = new JWT();
for (String key : payloadClaims.keySet()) { // run through all the keys from the payload
jwt.addClaim(key, payloadClaims.get(key)); // and write each claim to the jwt
}
return JWT.getEncoder().encode(jwt, signer); // sign and encode the JWT to a JSON string representation
} catch (Exception e) {
return "";
}
}
// check if the token is enabled
public boolean tokenEnabled() {
return tokenSecret != null && !tokenSecret.isEmpty();
}
public boolean tokenUseForRequest() {
return Boolean.parseBoolean(tokenUseForRequest) && !tokenUseForRequest.isEmpty();
}
// read document token
public JWT readToken(final String token) {
try {
// build a HMAC verifier using the token secret
Verifier verifier = HMACVerifier.newVerifier(tokenSecret);
// verify and decode the encoded string JWT to a rich object
return JWT.getDecoder().decode(token, verifier);
} catch (Exception exception) {
return null;
}
}
// parse the body
public JSONObject parseBody(final String payload, final String header) {
JSONObject body;
try {
Object obj = parser.parse(payload); // get body parameters by parsing the payload
body = (JSONObject) obj;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"JSON Parsing error\"}");
}
if (tokenEnabled() && tokenUseForRequest()) { // check if the token is enabled
String token = (String) body.get("token"); // get token from the body
if (token == null) { // if token is empty
if (header != null && !header.isBlank()) { // and the header is defined
// get token from the header (it is placed after the Bearer prefix if it exists)
token = header.startsWith("Bearer ") ? header.substring("Bearer ".length()) : header;
}
}
if (token == null || token.isBlank()) {
throw new RuntimeException("{\"error\":1,\"message\":\"JWT expected\"}");
}
JWT jwt = readToken(token); // read token
if (jwt == null) {
throw new RuntimeException("{\"error\":1,\"message\":\"JWT validation failed\"}");
}
if (jwt.getObject("payload") != null) { // get payload from the token and check if it is not empty
try {
@SuppressWarnings("unchecked") LinkedHashMap<String, Object> jwtPayload =
(LinkedHashMap<String, Object>) jwt.getObject("payload");
jwt.claims = jwtPayload;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"Wrong payload\"}");
}
}
try {
Object obj = parser.parse(objectMapper.writeValueAsString(jwt.claims));
body = (JSONObject) obj;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"Parsing error\"}");
}
}
return body;
}
}

View File

@ -1,33 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.jwt;
import org.json.simple.JSONObject;
import org.primeframework.jwt.domain.JWT;
import java.util.Map;
// specify the jwt manager functions
public interface JwtManager {
boolean tokenEnabled(); // check if the token is enabled
boolean tokenUseForRequest(); // check if the token is enabled
String createToken(Map<String, Object> payloadClaims); // create document token
JWT readToken(String token); // read document token
JSONObject parseBody(String payload, String header); // parse the body
}

View File

@ -1,70 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.template;
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
import com.onlyoffice.integration.documentserver.models.filemodel.Template;
import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Qualifier("sample")
public class SampleTemplateManager implements TemplateManager {
@Autowired
private DocumentManager documentManager;
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Autowired
private FileUtility fileUtility;
// create a template document with the specified name
public List<Template> createTemplates(final String fileName) {
List<Template> templates = List.of(
new Template("", "Blank", documentManager
.getCreateUrl(fileName, false)), // create a blank template
new Template(getTemplateImageUrl(fileName), "With sample content", documentManager
.getCreateUrl(fileName,
true)) // create a template with sample content using the template image
);
return templates;
}
// get the template image URL for the specified file
public String getTemplateImageUrl(final String fileName) {
DocumentType fileType = fileUtility.getDocumentType(fileName); // get the file type
String path = storagePathBuilder.getServerUrl(true); // get server URL
if (fileType.equals(DocumentType.word)) { // get URL to the template image for the word document type
return path + "/css/img/file_docx.svg";
} else if (fileType.equals(DocumentType.slide)) { // get URL to the template image for the slide document type
return path + "/css/img/file_pptx.svg";
} else if (fileType.equals(DocumentType.cell)) { // get URL to the template image for the cell document type
return path + "/css/img/file_xlsx.svg";
}
return path + "/css/img/file_docx.svg"; // get URL to the template image for the default document type (word)
}
}

View File

@ -1,28 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.managers.template;
import com.onlyoffice.integration.documentserver.models.filemodel.Template;
import java.util.List;
// specify the template manager functions
public interface TemplateManager {
List<Template> createTemplates(String fileName); // create a template document with the specified name
String getTemplateImageUrl(String fileName); // get the template image URL for the specified file
}

View File

@ -1,24 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.models;
import java.io.Serializable;
public abstract class AbstractModel implements Serializable {
}

View File

@ -1,51 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.models.configurations;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
/* The parameters which allow to customize the editor interface so that it looked like your
other products (if there are any) and change the presence or absence of the additional buttons,
links, change logos and editor owner details. */
public class Customization {
@Autowired
private Goback goback; // the settings for the Open file location menu button and upper right corner button
private Boolean autosave = true; // if the Autosave menu option is enabled or disabled
private Boolean comments = true; // if the Comments menu button is displayed or hidden
private Boolean compactHeader = false; /* if the additional action buttons are displayed
in the upper part of the editor window header next to the logo (false) or in the toolbar (true) */
private Boolean compactToolbar = false; // if the top toolbar type displayed is full (false) or compact (true)
private Boolean compatibleFeatures = false; // the use of functionality only compatible with the OOXML format
private Boolean forcesave = false; /* add the request for the forced file saving to the callback handler
when saving the document within the document editing service */
private Boolean help = true; // if the Help menu button is displayed or hidden
private Boolean hideRightMenu = false; // if the right menu is displayed or hidden on first loading
private Boolean hideRulers = false; // if the editor rulers are displayed or hidden
private Boolean submitForm = true; // if the Submit form button is displayed or hidden
private Boolean about = true;
private Boolean feedback = true;
}

View File

@ -1,40 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.onlyoffice.integration.documentserver.models.configurations;
import com.onlyoffice.integration.documentserver.models.enums.ToolbarDocked;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
/* The parameters which allow to change the settings
which define the behavior of the buttons in the embedded mode */
public class Embedded {
private String embedUrl; /* the absolute URL to the document serving as a source file for the document embedded
into the web page */
private String saveUrl; /* the absolute URL that will allow the document to be saved
onto the user personal computer */
private String shareUrl; // the absolute URL that will allow other users to share this document
private ToolbarDocked toolbarDocked; // the place for the embedded viewer toolbar, can be either top or bottom
}

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