Compare commits

...

425 Commits

Author SHA1 Message Date
05a3110c99 Remove workflow and disable build nodejs docker (#286)
* Remove workflow and disable build

* Remove Dockerfile
2022-05-27 15:34:59 +03:00
8bafa3ff3a Add submodule-init (#283) 2022-05-19 17:02:51 +03:00
56679a3b75 Change target repo (#282)
* Change target repo

* Add latest tag
2022-05-19 15:59:11 +03:00
d4d758770f Add docs-example multiarch build (#281)
* Add multiarch build

* Cosmetic changes

* Cosmetic changes
2022-05-19 14:17:28 +03:00
874ebff886 Fix the launch of the example container (#279)
* Fix the launch of the example container

* Change the user home directory

* Change the command for create a user
2022-05-16 17:26:24 +03:00
4f2f877f0e docxf update 2022-05-12 13:22:15 +03:00
5cc6b4cb15 Merge pull request #277 from ONLYOFFICE/develop
Release/1.2.0
2022-04-18 14:16:23 +03:00
7a70a44bcb 1.2.0 2022-04-18 13:59:07 +03:00
e42bd53664 Merge pull request #274 from ONLYOFFICE/feature/languages-fix
languages sort fix
2022-04-11 10:42:55 +03:00
23e616aade languages sort fix 2022-04-11 10:38:26 +03:00
f035da0db4 nodejs: disable X-Powered-By 2022-04-05 15:16:45 +03:00
3e12ec4ebe Merge pull request #272 from ONLYOFFICE/feature/ignore-self-signed-certificate
Feature/ignore self signed certificate
2022-03-30 14:34:02 +03:00
589ca9b601 Merge branch 'develop' into feature/ignore-self-signed-certificate 2022-03-28 16:00:59 +03:00
32f1ec82d1 Merge pull request #271 from ONLYOFFICE/feature/uid-0-fix
Feature/uid 0 fix
2022-03-28 13:26:38 +03:00
54bb5b0a24 format 2022-03-28 13:26:17 +03:00
8274c16f6d Merge pull request #273 from ONLYOFFICE/feature/update-readme
Update README.md
2022-03-28 13:09:24 +03:00
7a982fc785 format 2022-03-28 13:09:13 +03:00
6f5800fbde Updated Readme files in examples 2022-03-28 12:05:45 +03:00
8ec632eebd csharp-mvc: function created 2022-03-28 10:12:46 +03:00
b6ca4535ce csharp: function created 2022-03-28 09:58:59 +03:00
089fc8bfa0 ruby: function created 2022-03-28 09:31:01 +03:00
0b4c17ea0a Update README.md 2022-03-25 17:57:11 +03:00
405be2847b java-spring: ignoring self-signed certificate was added 2022-03-25 16:54:04 +03:00
f809c7e525 python: certificate ignore was added 2022-03-25 13:26:00 +03:00
44061c82a9 csharp-mvc: ignore certificate in config 2022-03-24 11:24:46 +03:00
ef4e283804 csharp: ignore certificate in config 2022-03-24 10:26:31 +03:00
4b0ad1a192 csharp + csharp-mvc 2022-03-23 16:56:41 +03:00
60469b0dba java: ignore certificate in config 2022-03-23 15:39:11 +03:00
f5ac95e1cc nodejs: ignore certificate in config 2022-03-23 15:11:30 +03:00
c4c2fbb945 ruby: certificate was ignored 2022-03-23 14:25:53 +03:00
99b5fcd562 python 2022-03-23 13:29:24 +03:00
7e34067410 java 2022-03-23 12:38:38 +03:00
a44787c625 java-spring 2022-03-23 11:11:03 +03:00
105afb2c34 php 2022-03-23 10:57:33 +03:00
002f9b958e nodejs 2022-03-23 10:53:51 +03:00
56d5913808 ruby 2022-03-23 10:48:28 +03:00
6664864bed nodejs 2022-03-22 13:52:28 +03:00
6c9e6e9304 Merge pull request #268 from ONLYOFFICE/feature/language-update
Feature/language update
2022-03-22 12:21:43 +03:00
416b1fde8c Merge pull request #270 from ONLYOFFICE/feature/hide-history-for-anonymous
Feature/hide history for anonymous
2022-03-22 11:54:12 +03:00
383f240825 Merge pull request #269 from ONLYOFFICE/feature/ban-renaming-for-anonymous
Feature/ban renaming for anonymous
2022-03-22 11:48:57 +03:00
642e145142 php: certificate was ignored 2022-03-22 11:15:09 +03:00
8f09dadfa0 ruby: java-spring: bugfix 2022-03-21 17:10:11 +03:00
495f1cf49a nodejs: split filename 2022-03-21 11:18:30 +03:00
cf01b5e0ae csharp: csharp-mvc: version history button was hidden 2022-03-21 09:38:48 +03:00
0673fed928 java: java-spring: version history button was hidden 2022-03-21 09:35:58 +03:00
9b0b30a0b0 nodejs: version history button was hidden 2022-03-21 09:32:27 +03:00
200187edce python: version history button was hidden 2022-03-21 09:29:32 +03:00
23176ddf07 ruby: version history button was hidden 2022-03-21 09:27:26 +03:00
9857cef8fc php: version history button was hidden 2022-03-21 09:22:31 +03:00
204f770401 java-spring: bugfix 2022-03-18 15:58:02 +03:00
61834e3ec6 Merge branch 'feature/language-update' of github.com:ONLYOFFICE/document-server-integration into feature/language-update 2022-03-18 15:24:45 +03:00
2ca6185ac4 php: bugfix 2022-03-18 15:24:30 +03:00
e818bb978b csharp: removed rename action for anonymous 2022-03-18 15:08:20 +03:00
3a4cf5e6e6 csharp-mvc: removed rename action for anonymous 2022-03-18 15:06:46 +03:00
7ec16b90e3 java: removed rename action for anonymous 2022-03-18 15:04:28 +03:00
fcfb6efda7 java-spring: removed rename action for anonymous 2022-03-18 15:02:45 +03:00
e4c72c98d1 nodejs: removed rename action for anonymous 2022-03-18 14:59:27 +03:00
c2bbda542a python: removed rename action for anonymous 2022-03-18 14:56:17 +03:00
2c12393c78 ruby: removed rename action for anonymous 2022-03-18 14:52:59 +03:00
4e93f6ebac php: fix 2022-03-18 14:47:59 +03:00
d10ba9f773 Merge branch 'develop' into feature/ban-renaming-for-anonymous 2022-03-18 14:40:38 +03:00
a0bf7db118 php: removed rename action 2022-03-18 14:36:46 +03:00
e40e7cc41c csharp-mvc: move languages to config 2022-03-18 11:25:54 +03:00
f616655f4c csharp: move languages to config 2022-03-18 11:14:49 +03:00
4ba708631e Merge pull request #266 from ONLYOFFICE/feature/renaming-files
Feature/renaming files
2022-03-18 10:31:19 +03:00
b9c1bc0f42 java-spring: changing arguments 2022-03-18 09:50:59 +03:00
215ade01a3 java: changing arguments 2022-03-18 09:32:34 +03:00
4d25418fc8 java: move languages to config 2022-03-17 14:05:56 +03:00
4539bac5db Merge pull request #267 from ONLYOFFICE/feature/customization
Feature/customization
2022-03-17 11:10:14 +03:00
eb196613e7 format 2022-03-17 10:36:38 +03:00
7ac788f589 csharp: jwt in body 2022-03-17 10:27:47 +03:00
55119458af java-spring: move languages to config 2022-03-17 10:14:02 +03:00
3c18add1fc Merge remote-tracking branch 'remotes/origin/release/v7.1.0' into develop 2022-03-17 09:56:20 +03:00
6bf63b7166 nodejs: move languages to config 2022-03-16 16:30:56 +03:00
32df2d3e34 php: move languages to config 2022-03-16 15:41:45 +03:00
97c7859db5 ruby: move languages to config 2022-03-16 15:32:47 +03:00
492f9c7baa python: config 2022-03-16 14:58:16 +03:00
e0c0595796 removed chat 2022-03-16 13:06:37 +03:00
40b8fb88a8 Merge branch 'feature/renaming-files' of github.com:ONLYOFFICE/document-server-integration into feature/renaming-files 2022-03-16 11:36:17 +03:00
b0df0d72df java-spring: refactoring 2022-03-16 10:48:43 +03:00
1053add1d9 csharp-mvc: refactoring 2022-03-16 09:47:49 +03:00
f1fc0e5fae csharp: refactoring 2022-03-16 09:38:30 +03:00
a192c6ce1f ruby: refactoring 2022-03-15 18:45:35 +03:00
e8aec0b68c java: php: python: refactoring 2022-03-15 18:10:02 +03:00
d9667f9757 nodejs: fix 2022-03-15 15:17:19 +03:00
3a985da120 Merge branch 'feature/renaming-files' of github.com:ONLYOFFICE/document-server-integration into feature/renaming-files 2022-03-15 14:19:34 +03:00
a88f84ddac nodejs: use commandRequest 2022-03-15 14:19:16 +03:00
6525d7210f micro fix 2022-03-15 13:33:33 +03:00
6b93311ce5 customization change 2022-03-15 13:10:34 +03:00
999561ffd6 Merge branch 'feature/renaming-files' of github.com:ONLYOFFICE/document-server-integration into feature/renaming-files 2022-03-15 10:51:43 +03:00
e539c1205f python: nodejs: jwt fix 2022-03-15 10:51:26 +03:00
9a52a538cb csharp-mvc: jwt fix 2022-03-15 08:24:11 +03:00
e8038a8e88 csharp: jwt fix 2022-03-15 08:18:34 +03:00
1045b314b6 Merge pull request #265 from ONLYOFFICE/bugfix/wopi
fix wopi
2022-03-14 17:50:35 +03:00
1636732521 nodejs: fix userHost in wopi 2022-03-14 17:48:32 +03:00
daa9a5f3fa fix wopi 2022-03-14 15:49:24 +03:00
9bf3973215 csharp-mvc: meta command 2022-03-14 14:00:05 +03:00
cad2a20cdf csharp: meta command 2022-03-14 13:41:12 +03:00
82a5a68e6c java: meta command 2022-03-11 14:59:10 +03:00
0e1a580a86 refactoring 2022-03-11 14:13:09 +03:00
c09f3fc4b9 Merge branch 'feature/renaming-files' of github.com:ONLYOFFICE/document-server-integration into feature/renaming-files 2022-03-11 11:02:39 +03:00
d4d7c4e222 java-spring: meta command 2022-03-11 10:58:54 +03:00
14429c5b05 php: rename refactoring 2022-03-11 09:45:42 +03:00
131e33c6af Merge pull request #264 from ONLYOFFICE/feature/fix-mentions
Feature/fix mentions
2022-03-10 16:19:50 +03:00
8a04e5fbc4 ruby:meta command 2022-03-09 13:50:47 +03:00
1b6435a7dc python:meta command 2022-03-08 10:50:05 +03:00
b8eecab45f nodejs:meta command 2022-03-07 22:01:03 +03:00
a55cb60542 nodejs: file download url was incorrectly formed when converting file 69d2e14438 2022-03-05 16:03:13 +03:00
f7259409a2 php:jwt 2022-03-04 14:34:50 +03:00
0ea9e68c7c meta command 2022-03-04 11:15:43 +03:00
4b72e0a664 php: add request rename in doceditor + add function renamefile() in webeditor 2022-03-03 14:34:57 +03:00
f4ae62e02d nodejs: missing line for 69d2e14438 2022-03-03 11:25:38 +03:00
935377a941 all: fix link in mentions 2022-03-02 17:42:12 +03:00
3690aacb66 nodejs: fix link in mentions 2022-03-02 17:10:41 +03:00
b8b375a19a Merge pull request #263 from ONLYOFFICE/feature/scroll
fixed scrolling due to footer : ab82be9b3d
2022-03-02 16:40:13 +03:00
69d2e14438 nodejs: fixed an issue when subfolders wouldn't create if storagefolder was set to an absolute path 2022-03-02 16:27:58 +03:00
fec77a9e75 fixed scrolling due to footer : ab82be9b3d 2022-03-02 14:30:57 +03:00
f0171cbb18 Merge pull request #262 from ONLYOFFICE/feature/anonymus-without-id
new branch + anonymus without id
2022-03-02 13:55:20 +03:00
fe49aeb815 Merge pull request #260 from ONLYOFFICE/feature/mobile-upload
Feature/mobile upload
2022-03-02 13:54:16 +03:00
8416f36581 mobile-upload:centering 2022-03-02 13:48:01 +03:00
b9f3bfd2e2 new branch + anonymus without id 2022-03-02 11:16:24 +03:00
02b22e9e26 Merge remote-tracking branch 'remotes/origin/develop' into feature/mobile-upload 2022-03-01 16:01:30 +03:00
f43f08012d Merge pull request #261 from ONLYOFFICE/budfix/php-device-display
Budfix/php device display
2022-03-01 15:58:40 +03:00
1c27610e8d Ruby - fix body display 2022-03-01 15:47:24 +03:00
148caf6225 Python - fix body display 2022-03-01 15:47:11 +03:00
b24e4503bc Java Spring - fix body display 2022-03-01 15:46:53 +03:00
58378827d4 Java - fix body display 2022-03-01 15:46:34 +03:00
502f14c7be C# mvc - fix body display 2022-03-01 15:46:15 +03:00
ded2d19672 C# - fix body display 2022-03-01 15:45:55 +03:00
6116f05625 Java - Add viewport device display on index page 2022-03-01 15:45:18 +03:00
1e2a9cf4f2 Java Spring - Add viewport device display on index page 2022-03-01 15:44:56 +03:00
1d7775f25b C# - Add viewport device display on index page 2022-03-01 15:44:00 +03:00
05c7a5a6db fix body display 2022-03-01 13:51:31 +03:00
c3500e39fd Add viewport device display on index page 2022-03-01 13:50:44 +03:00
23169c6fea block height fix:upload for mobile 2022-03-01 10:45:29 +03:00
f2fddc75c6 nodejs:fix 2022-02-28 18:29:54 +03:00
f542e9dcfc csharp:upload for mobile 2022-02-28 18:27:42 +03:00
6737a7e0d0 csharp-mvc:upload for mobile 2022-02-28 18:22:31 +03:00
e9c17c55da java:upload for mobile 2022-02-28 18:20:14 +03:00
f334bf4b19 java-spring:upload for mobile 2022-02-28 18:17:52 +03:00
f2139949de nodejs:upload for mobile 2022-02-28 18:14:23 +03:00
48314b2c7f ruby:upload for mobile 2022-02-28 18:09:20 +03:00
8804844281 python:upload for mobile 2022-02-28 17:59:15 +03:00
3a21d29568 php: fix centering 2022-02-28 17:17:30 +03:00
b6a08e242d Add licenses of mimemagic on ruby (7a61fac6b7)
# Conflicts:
#	web/documentserver-example/ruby/licenses/mimemagic.license
2022-02-28 16:59:02 +03:00
596235d34b php:upload for mobile 2022-02-28 16:40:55 +03:00
254fbaccea Merge pull request #259 from ONLYOFFICE/dependabot/bundler/web/documentserver-example/ruby/nokogiri-1.13.3
build(deps): bump nokogiri from 1.12.5 to 1.13.3 in /web/documentserver-example/ruby
2022-02-28 12:03:45 +03:00
69c07a30a7 Merge remote-tracking branch 'remotes/origin/develop' into dependabot/bundler/web/documentserver-example/ruby/nokogiri-1.13.3
# Conflicts:
#	web/documentserver-example/ruby/Gemfile.lock
2022-02-28 12:02:41 +03:00
6283ff934d build(deps): bump nokogiri in /web/documentserver-example/ruby
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.12.5 to 1.13.3.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.12.5...v1.13.3)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-26 03:34:12 +00:00
db231faca0 nodejs: pdf without comment and fillform permissions 2022-02-22 14:31:14 +03:00
a3dd0394d2 nodejs: remove unused code 2022-02-22 11:46:40 +03:00
f9fd73fc7e nodejs: remove unused (aadac3cca6) 2022-02-22 11:32:06 +03:00
0931936b3c nodejs: remove unused (5c1d925d42) 2022-02-22 11:29:34 +03:00
b91b49c8fa nodejs: fix (b0a0050201) 2022-02-22 11:24:19 +03:00
b0a0050201 Merge pull request #258 from ONLYOFFICE/bugfix/non-static-docmanager
Bugfix Non static Docmanager
2022-02-22 11:06:10 +03:00
1c780a639f nodejs: don't clean tmp folder while others uploads might be happening 2022-02-16 11:55:01 +03:00
ad6ac4dedd nodejs: non static docmanager 2022-02-16 11:54:22 +03:00
8ba33f524b Merge pull request #240 from ONLYOFFICE/feature/jwtHistoryFiles
Feature/jwt history files
2022-02-15 16:32:21 +03:00
2f5b25d6ab Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtHistoryFiles
# Conflicts:
#	web/documentserver-example/ruby/Gemfile.lock
2022-02-15 16:31:57 +03:00
44eef53a03 python: fixed history path building 2022-02-14 12:41:37 +03:00
08388f739c python: fixed cors issue when downloading history files 2022-02-14 12:41:14 +03:00
1d8175b88f Merge pull request #256 from ONLYOFFICE/feature/ruby-deps-version
ruby: update dependencies version
2022-02-11 13:01:44 +03:00
1400ec5a4b nodejs: fix opening history 2022-02-11 12:54:59 +03:00
e5f61ec95e php format 2022-02-11 12:34:46 +03:00
7c669cca19 mvc: fix opening history 2022-02-11 12:20:05 +03:00
81f8bd1a9b fix help 2022-02-11 11:31:00 +03:00
c4c819c513 format 2022-02-11 10:54:03 +03:00
03332b3cd9 csharp: revert coediting 2022-02-11 10:36:48 +03:00
ebc864736d Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtHistoryFiles
# Conflicts:
#	web/documentserver-example/java/README.md
2022-02-11 10:22:04 +03:00
af86ec1ca3 update submodule 2022-02-11 10:19:44 +03:00
d1d9915953 Merge pull request #257 from ONLYOFFICE/feature/userInfoGroups
Feature/user info groups
2022-02-11 10:15:35 +03:00
c663bfe464 Merge remote-tracking branch 'remotes/origin/develop' into feature/userInfoGroups
# Conflicts:
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/ExampleData.java
#	web/documentserver-example/java/src/main/java/helpers/Users.java
#	web/documentserver-example/php/users.php
#	web/documentserver-example/python/src/utils/users.py
#	web/documentserver-example/ruby/app/models/users.rb
2022-02-11 10:14:06 +03:00
1bb7dd152a Merge pull request #231 from ONLYOFFICE/feature/page-icons-layout
nodejs: change position of icons for mobile editor and filling forms
2022-02-11 10:10:37 +03:00
a52000fc97 java-spring: userInfoGroups 2022-02-11 01:22:15 +03:00
88b7fbf55c csharp: userInfoGroups 2022-02-11 00:43:01 +03:00
f9449f7742 csharp-mvc: userInfoGroups 2022-02-11 00:38:55 +03:00
9d2b8c4830 php: userInfoGroups 2022-02-11 00:28:22 +03:00
4068e23556 ruby: userInfoGroups 2022-02-11 00:20:29 +03:00
fc760af338 python: userInfoGroups 2022-02-11 00:00:58 +03:00
c55ab7cc75 java: userInfoGroups 2022-02-10 23:56:09 +03:00
00c9b3e2b9 nodejs: userInfoGroups to help 2022-02-10 15:01:21 +03:00
47074c588d nodejs: userInfoGroups 2022-02-10 14:25:51 +03:00
018d1bbead ruby: update dependencies version 2022-02-09 11:43:22 +03:00
82713572ab Merge pull request #255 from ONLYOFFICE/feature/update-readme
Update README.md
2022-02-09 10:59:07 +03:00
34d06235f4 format 2022-02-09 10:58:53 +03:00
468488c384 note to index page 2022-02-09 10:55:02 +03:00
ff4b387acf Update README.md 2022-02-09 10:50:20 +03:00
20012c7678 change note in readme 2022-02-09 10:17:36 +03:00
382160f2fc Merge remote-tracking branch 'remotes/origin/release/v7.1.0' into develop
# Conflicts:
#	web/documentserver-example/csharp-mvc/assets
#	web/documentserver-example/csharp/assets
#	web/documentserver-example/java-spring/src/main/resources/assets
#	web/documentserver-example/java/src/main/resources/assets
#	web/documentserver-example/nodejs/public/assets
#	web/documentserver-example/php/assets
#	web/documentserver-example/python/assets
#	web/documentserver-example/ruby/public/assets
2022-02-09 10:05:10 +03:00
761e578faf update submodule 2022-02-07 16:14:53 +03:00
7b7cbebc75 Merge pull request #254 from ONLYOFFICE/feature/changing-wopi-edit-view-icons
Node.js(wopi): Change wopi icons for editing and viewing actions
2022-02-07 15:53:47 +03:00
dbc5ebf098 Node.js(wopi): Change wopi icons for editing and viewing actions 2022-02-07 15:52:53 +03:00
c5d61b685b Merge pull request #253 from ONLYOFFICE/bugfix/xss
fix xss vulnerability
2022-02-06 16:32:39 +03:00
f3acca4b4b python: fix xss vulnerability 2022-02-06 16:31:16 +03:00
b92c4191f9 xss in lang 2022-02-06 16:25:52 +03:00
5b6f2696d2 xss in type 2022-02-06 16:16:51 +03:00
625df85b51 xss in actionLink 2022-02-06 15:52:58 +03:00
6716d38a40 support xlsb 2022-02-06 11:15:20 +03:00
84d574906d Python: remove unnecessary import 2022-02-03 17:32:26 +03:00
3c760c3136 Python: update pyjwt, fix jwtManager (remove decode) 2022-02-03 17:29:47 +03:00
bf28236d0d Python: fix urls (accidental deletion of a path saveus) 2022-02-01 17:13:27 +03:00
6d71a553be С#: add absolute path support for document history 2022-02-01 17:03:16 +03:00
fed5598294 С#: remove unnecessary construction 2022-02-01 16:00:50 +03:00
02351113e1 С# mvc: remove unnecessary functions and constructions 2022-02-01 15:55:36 +03:00
a07edeb5de Python: linux support (bug with json jwt decoding) 2022-02-01 15:19:15 +03:00
5bbc4c6232 Ruby: remove unnecessary action (version encoding) 2022-01-31 16:28:34 +03:00
770c2fe551 PHP: fix code 2022-01-31 15:03:41 +03:00
4916537977 Java-spring: fix the code 2022-01-31 15:01:39 +03:00
77ec1649a5 Java: fix the code and remove the encoding of the url version 2022-01-31 15:00:27 +03:00
204ff947c3 Python: fix code 2022-01-31 14:02:06 +03:00
d36fe2466a C#: add time for unique key 2022-01-27 11:53:10 +03:00
e927da28f5 C# mvc: add time for unique key 2022-01-27 11:52:49 +03:00
17b5c6e4c9 C#: Add history creation for the first version of the file 2022-01-27 11:50:30 +03:00
03f853dfef C# mvc: Add history creation for the first version of the file 2022-01-27 11:49:21 +03:00
1d7e65b2ba Python: fix bug with absolute storage path 2022-01-26 15:02:31 +03:00
8ebb67c925 Python: fix merge diff + prev 2022-01-26 14:59:40 +03:00
8524ff27ed Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtHistoryFiles 2022-01-26 13:45:33 +03:00
7bedc4b877 Merge pull request #250 from ONLYOFFICE/feature/add-wopi-users
Node.js (wopi): Add selected user to editor
2022-01-24 13:14:40 +03:00
f25c211630 Merge pull request #251 from ONLYOFFICE/feature/filetype
Feature/filetype
2022-01-24 12:12:12 +03:00
0f4785d14f python: correct code (Support old versions) 2022-01-24 11:07:28 +03:00
288add4d45 python: correct code (Support old versions) 2022-01-24 10:56:57 +03:00
1ee492838c python: correct filetype arg 2022-01-21 16:35:33 +03:00
f9ce3d1d33 nodejs: correct filetype arg 2022-01-21 15:51:16 +03:00
5f6687571a Node.js (wopi): changing the receipt of a wopi query 2022-01-20 17:11:59 +03:00
a1e5a4d48e Node.js (wopi): Add selected user to editor 2022-01-19 19:05:21 +03:00
6e9518631f Merge pull request #246 from ONLYOFFICE/feature/add-upload-wopi
Feature/add upload wopi
2022-01-19 18:07:31 +03:00
88d8086853 Node.js (wopi): Add support InternetExplorer 2022-01-19 17:59:31 +03:00
d22f4f11ca Java-Spring: jwt prev + diff 2022-01-19 17:20:48 +03:00
29cbe66d09 Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtHistoryFiles 2022-01-18 18:16:53 +03:00
c2410268eb Java: Merge jwt prev + diff 2022-01-18 17:41:59 +03:00
57cd71095d С# mvc: Merge jwt prev + diff 2022-01-18 17:00:56 +03:00
224d2bc570 С#: Merge jwt prev + diff 2022-01-18 16:25:13 +03:00
c7f18f1085 Node.js (wopi): Fix filter 2022-01-18 15:39:16 +03:00
fb05ad32ab Merge remote-tracking branch 'remotes/origin/develop' into feature/add-upload-wopi 2022-01-18 14:49:28 +03:00
bac989efd1 Node.js (wopi): Filter extensions from config that are in discovery for edit action (+ Checking the Fano condition) 2022-01-17 18:36:47 +03:00
8a203ac062 Node.js (wopi): button layout for upload 2022-01-17 18:33:49 +03:00
7e1386008b Merge pull request #249 from ONLYOFFICE/feature/wopi-layout
Feature/wopi layout
2022-01-17 15:15:10 +03:00
8ff206a411 Node.js wopi: add information when hovering over the info icon 2022-01-17 14:06:59 +03:00
83a0330725 Merge pull request #245 from ONLYOFFICE/feature/wopi-editing
Feature/wopi editing
2022-01-17 11:23:27 +03:00
c5269a53cf Merge pull request #244 from ONLYOFFICE/bugfix/customization-fix-JavaExample
fix Customization in Java and JavaSpringExample
2022-01-17 11:12:32 +03:00
f86b26928d Node.js(wopi): create a unique version code 2022-01-14 19:29:46 +03:00
f8d77947c8 Node.js(wopi): layout of the index page (delete extra info users and checkbox simple) 2022-01-14 19:28:09 +03:00
a62ac23aeb PHP: Merge jwt prev + diff (There is a bug with the history display) 2022-01-14 18:02:28 +03:00
a900183056 Merge pull request #241 from ONLYOFFICE/feature/fileTypeInsteadParsing
Feature/file type instead parsing
2022-01-14 16:52:30 +03:00
67d34f4bfa format 2022-01-14 16:52:12 +03:00
507a7f3162 Ruby: Merge jwt prev + diff 2022-01-13 18:08:40 +03:00
703281aa07 Node.js: Fix code. The direct link has been replaced with a stream output 2022-01-13 16:00:19 +03:00
aefec3e105 Python: Merge jwt prev + diff 2022-01-12 18:14:48 +03:00
8cc211b011 Node.js: Merge jwt prew + diff 2022-01-12 17:49:52 +03:00
68ec626970 C# mvc: fix code 2022-01-11 18:19:14 +03:00
065f338a79 C#: fix code 2022-01-11 18:18:54 +03:00
43548c04b9 Node.js: fix code (Made links through ready-made functions) 2022-01-11 17:52:40 +03:00
c7c95ecfbe Node.js: fix upload page (links [edit, view] ) for wopi upload files 2022-01-11 17:34:34 +03:00
064c0dcc35 C#: fix code 2022-01-11 16:42:26 +03:00
9a01f465d0 C# mvc: fix code 2022-01-11 16:42:01 +03:00
2d85a4166e Ruby: fix code 2022-01-11 15:07:19 +03:00
77c598049c I added universal content type in JavaSpringExample 2022-01-11 13:09:17 +03:00
c1baac3d6f content type Python Example FIX Commit 2022-01-11 12:58:32 +03:00
c5e30b6512 fix Application header in Node JS example 2022-01-11 12:55:19 +03:00
0fa6f43716 FixCommit content-type for Ruby 2022-01-11 12:48:28 +03:00
edc43bdf31 fix commit С# and C# MVC content type 2022-01-11 12:42:03 +03:00
f75453bf2d I fixed JWT for diff.zip Node JS Example 2022-01-11 12:35:26 +03:00
d03326a1e1 I fixed check JWT for Diff.zip in C# MVC Example 2022-01-11 11:39:43 +03:00
8be501a0ab Fix Commit for Diff.zip JWT in C# 2022-01-11 11:26:59 +03:00
a4c71eb69a JWT for diff.zip fix commit 2022-01-11 10:58:13 +03:00
132545c655 I added jwt check before giving diff in Python Example FIX Commit 2022-01-11 10:43:40 +03:00
5caaf0b1c6 Merge branch 'develop' into feature/jwtHistoryFiles 2022-01-10 19:00:27 +03:00
8f18cc8ab2 Merge branch 'feature/fileTypeInsteadParsing' of github.com:ONLYOFFICE/document-server-integration into feature/fileTypeInsteadParsing
# Conflicts:
#	web/documentserver-example/csharp-mvc/Helpers/TrackManager.cs
2022-01-10 18:49:43 +03:00
db976766cc Ruby: fix[support old version] fileType instead parsing 2022-01-10 18:47:02 +03:00
57f6028829 Python: fix[support old version] fileType instead parsing 2022-01-10 18:46:03 +03:00
05706ff038 PHP: fix[support old version] fileType instead parsing 2022-01-10 18:45:27 +03:00
9cf7ce276e Node.js: fix[support old version] fileType instead parsing 2022-01-10 18:45:03 +03:00
0b35179ef0 Java-spring: fix[support old version] fileType instead parsing 2022-01-10 18:44:35 +03:00
d396f92f4d Java : fix[support old version] fileType instead parsing 2022-01-10 18:44:01 +03:00
1e78da4cfc C#: fix[support old version] fileType instead parsing 2022-01-10 18:42:41 +03:00
a8c9c331c1 C# mvc: fix[support old version] fileType instead parsing 2022-01-10 18:41:54 +03:00
0b2e09cf1d Ruby JWT FIX for diff.zip 2022-01-10 17:40:05 +03:00
f81ae23a64 Merge branch 'feature/jwtHistoryFiles' of github.com:ONLYOFFICE/document-server-integration into feature/jwtHistoryFiles
# Conflicts:
#	web/documentserver-example/csharp-mvc/Models/FileModel.cs
#	web/documentserver-example/csharp/DocEditor.aspx.cs
#	web/documentserver-example/ruby/licenses/3rd-Party.license
2022-01-10 17:08:45 +03:00
6f90ff3391 Check JWT in JavaSpringExample 2022-01-10 16:37:54 +03:00
4f3882f892 Merge pull request #248 from ONLYOFFICE/feature/ruby-add-mimemagic
Add licenses of mimemagic on ruby
2022-01-10 16:08:31 +03:00
727418277f ruby: correct license 2022-01-10 16:08:14 +03:00
2f795de6ad Merge pull request #247 from ONLYOFFICE/feature/fileType
Feature/file type
2022-01-10 16:03:35 +03:00
bb28257a2d Merge remote-tracking branch 'remotes/origin/develop' into feature/fileType
# Conflicts:
#	web/documentserver-example/php/doceditor.php
2022-01-10 16:03:18 +03:00
379dba8b7c Merge branch 'feature/jwtForDiffZip' of https://github.com/ONLYOFFICE/document-server-integration into feature/jwtForDiffZip 2022-01-10 16:00:49 +03:00
05ea165f77 format 2022-01-10 16:00:41 +03:00
7a61fac6b7 Add licenses of mimemagic on ruby 2022-01-10 15:57:57 +03:00
31c3e050af I do check diff.zip for javaExample 2022-01-10 15:45:40 +03:00
0c677f3d65 Delete mimemagic on Ruby to do it on a new branch 2022-01-10 15:41:09 +03:00
6efa357c19 Delete mimemagic on Ruby in order to add in a new branch 2022-01-10 15:36:13 +03:00
3b33846f9d fix fileRemove and links on wopi (node.js) 2022-01-10 15:27:16 +03:00
3de8463359 Add ConverExtList and EditedExtList for wopi upload files 2022-01-10 14:18:55 +03:00
e05ead7ce6 Review and change jwt signature on python (via handler) 2022-01-10 13:01:12 +03:00
cdc8647f21 LICENSE for mimemagic on Ruby 2022-01-10 13:01:11 +03:00
c2b333fac7 fix commit 2022-01-10 13:01:11 +03:00
cae75d9888 jwt signature for prev.* files C# mvc (via handler) on Net4.8 2022-01-10 12:59:18 +03:00
ee674e6a57 jwt signature for prev.* files C# (via handler) 2022-01-10 12:57:22 +03:00
7207a9d860 jwt signature for prev.* files java-spring (via handler) 2022-01-10 12:53:41 +03:00
8cc5f685af Add link(handler) to onRequestHistoryData jwt Java 2022-01-10 12:53:41 +03:00
a61a8ccb4f jwt signature for prev.* files. Java (via handler) + README.md (Build point) 2022-01-10 12:53:41 +03:00
e857a2bed7 jwt signature for prev.* files. PHP (via handler) 2022-01-10 12:53:40 +03:00
514303d053 jwt signature for prev.* files. Ruby (by redirection) 2022-01-10 12:53:40 +03:00
7d4f511a5d jwt signature for prev.* files. Python 2022-01-10 12:53:40 +03:00
9b11e8b098 jwt signature for prev.* files node.js 2022-01-10 12:53:39 +03:00
8351905cee Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtForDiffZip 2022-01-10 12:32:09 +03:00
15b7a07963 Merge pull request #242 from ONLYOFFICE/feature/bugRubyEditor
Feature/bug ruby editor
2022-01-10 12:30:47 +03:00
ef1c53d330 ruby: fix bug of displaying the editor 2022-01-10 12:30:28 +03:00
9bcb871132 nodejs: format 2022-01-10 11:22:56 +03:00
25a4b9c97b revert assets after merge d115e4092f 2022-01-10 11:07:46 +03:00
a21fbd6802 java-spring: revert format 2022-01-10 10:58:25 +03:00
c7249ab27f Add upload files for wopi on the node.js 2021-12-30 18:28:55 +03:00
450d37161b Preparing a wopi task for PR 2021-12-30 16:53:30 +03:00
ee46a77684 Removing link to "editnew" in the file line 2021-12-29 19:20:33 +03:00
3b7e3c9258 Аdd action processing ("editnew" and "edit") and Create files only through "editnew" 2021-12-29 19:20:08 +03:00
783ad9f2de fix Customization in Java and JavaSpringExample 2021-12-29 13:30:11 +03:00
78571f6c23 FixCommit 2021-12-28 18:35:52 +03:00
a5c0b9bfb1 FixCommit 2021-12-28 18:31:48 +03:00
5047e64f3b php: revert format 2021-12-28 14:32:35 +03:00
d115e4092f Merge remote-tracking branch 'remotes/origin/develop' into feature/jwtForDiffZip
# Conflicts:
#	web/documentserver-example/csharp-mvc/Models/FileModel.cs
#	web/documentserver-example/csharp/DocEditor.aspx.cs
#	web/documentserver-example/java/src/main/java/entities/FileModel.java
#	web/documentserver-example/nodejs/app.js
#	web/documentserver-example/php/common.php
#	web/documentserver-example/php/doceditor.php
#	web/documentserver-example/php/webeditor-ajax.php
#	web/documentserver-example/ruby/Gemfile
#	web/documentserver-example/ruby/app/models/document_helper.rb
2021-12-28 14:29:37 +03:00
e7a1c2c6eb c# example check JWT for diff.zip 2021-12-28 11:34:45 +03:00
85f95ba4b9 C# MVC I Added header fileName = diff.zip 2021-12-28 11:34:16 +03:00
133013dfde Check JWT for diff.zip C# test-example 2021-12-28 11:11:58 +03:00
6acdc34e10 Start C# Example for diff.zip 2021-12-27 10:29:45 +03:00
19304920d1 fileType instead parsing url to save doc in C# MVC (take fileType out of body) 2021-12-24 18:13:12 +03:00
13b3eed5ed fileType instead parsing url to save doc in C# (take fileType out of body) 2021-12-24 18:12:40 +03:00
d9c1c7e051 fileType instead parsing url to save doc in Java-Spring (take fileType out of body) 2021-12-24 17:54:41 +03:00
2d0b17e334 fileType instead parsing url to save doc in Java (take fileType out of body) 2021-12-24 17:13:28 +03:00
384381cebc fileType instead parsing url to save doc in PHP (take fileType out of body) 2021-12-24 16:52:10 +03:00
16d830baf4 [fix] fileType instead parsing url to save doc in Python (take fileType out of body) 2021-12-24 16:51:48 +03:00
efcfaf95e8 [fix] fileType instead parsing url to save doc in node.js (take fileType out of body) 2021-12-24 16:50:23 +03:00
606f7d2d44 [fix] fileType instead parsing url to save doc in Ruby (take fileType out of body) 2021-12-24 16:47:57 +03:00
357c14b6d4 Check JWT for diff.zip in Ruby Example 2021-12-23 18:43:24 +03:00
c5a2b72b39 fileType instead parsing url to save doc in Ruby (take fileType out of body) 2021-12-23 18:29:31 +03:00
dab9e4bb16 fileType instead parsing url to save doc in Python (take fileType out of body) 2021-12-23 18:24:28 +03:00
27b6cb3293 Review and change jwt signature on python (via handler) 2021-12-23 17:49:26 +03:00
058b0c4f23 fileType in body Instead Parsing url on node.js 2021-12-22 20:21:08 +03:00
05c62bbdf3 LICENSE for mimemagic on Ruby 2021-12-22 19:01:25 +03:00
425bd81f08 fix commit 2021-12-22 18:20:29 +03:00
096102fa59 Merge branch 'develop' into feature/jwtHistoryFiles 2021-12-22 17:13:10 +03:00
c612320a65 JWT for diff.zip php example - good working example 2021-12-22 14:05:19 +03:00
e0b60a6956 JWT for diff.zip php example 2021-12-22 11:06:10 +03:00
16a0846248 jwt signature for prev.* files C# mvc (via handler) on Net4.8 2021-12-21 18:24:02 +03:00
71e1b28f47 jwt signature for prev.* files C# (via handler) 2021-12-21 17:45:42 +03:00
182f5f378e I added jwt for diff.zip 2021-12-21 13:28:05 +03:00
9d3f4b2300 jwt signature for prev.* files java-spring (via handler) 2021-12-20 18:41:38 +03:00
ab3d385c61 I added JWT validation for diff.zip in JavaSpring Example 2021-12-20 14:20:15 +03:00
8d194b78a1 Update samples 2021-12-20 11:29:02 +03:00
b8e726a7be Update pptx sample 2021-12-20 11:02:24 +03:00
dfd2d49e6c Add link(handler) to onRequestHistoryData jwt Java 2021-12-17 15:39:38 +03:00
fbe0c18315 Merge pull request #238 from ONLYOFFICE/feature/update-readme
Readme
2021-12-16 18:10:38 +03:00
ec6ea72069 small fixes for readme files 2021-12-16 17:51:01 +03:00
2accdeac3b jwt signature for prev.* files. Java (via handler) + README.md (Build point) 2021-12-16 17:43:01 +03:00
63f4b6fbb6 I added jwt check before giving diff in Python Example 2021-12-15 17:37:15 +03:00
642caddae8 jwt signature for prev.* files. PHP (via handler) 2021-12-15 16:23:23 +03:00
dac09bd1e1 jwt signature for prev.* files. Ruby (by redirection) 2021-12-14 19:26:56 +03:00
c6e3af5d3b Merge pull request #236 from ONLYOFFICE/feature/csharp-server-configuration
csharp and csharp-mvc readme
2021-12-13 16:59:39 +03:00
183fb80077 jwt signature for prev.* files. Python 2021-12-13 16:53:05 +03:00
63c3337938 Merge pull request #226 from ONLYOFFICE/bugfix/java-fixes
Bugfix/java fixes
2021-12-13 16:34:08 +03:00
0268298f2b Merge remote-tracking branch 'remotes/origin/develop' into bugfix/java-fixes
# Conflicts:
#	web/documentserver-example/java-spring/README.md
2021-12-13 16:32:54 +03:00
32ea01784c Merge pull request #234 from ONLYOFFICE/bugfix/group-fix
replace group value null with empty string
2021-12-13 16:27:14 +03:00
8e4a2c6359 I added jwt check before giving diff 2021-12-13 16:21:15 +03:00
71041fea9f Merge pull request #233 from ONLYOFFICE/feature/pptx-xpath
Feature/pptx xpath
2021-12-13 16:16:54 +03:00
8b25a7a869 ruby: v 3.0 2021-12-13 16:02:48 +03:00
dd20d79236 Merge pull request #230 from ONLYOFFICE/feature/ruby-3.0
ruby 3.0 version
2021-12-13 15:47:25 +03:00
299a68e0bd Merge pull request #229 from ONLYOFFICE/bugfix/layout-fixes
fix layout
2021-12-13 15:42:15 +03:00
9ad27d2cf0 Merge pull request #216 from ONLYOFFICE/feature/change-files-folder
Feature/change files folder
2021-12-13 15:39:26 +03:00
828115e5b0 Merge remote-tracking branch 'remotes/origin/develop' into feature/change-files-folder
# Conflicts:
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/storage/LocalFileStorage.java
2021-12-13 15:38:37 +03:00
461a005cfa Merge pull request #237 from ONLYOFFICE/develop
Release/1.1.0
2021-12-13 11:45:38 +03:00
24cfd661ef 1.1.0 2021-12-13 11:34:05 +03:00
6481ac7e13 update presentation sample 2021-12-13 11:21:56 +03:00
a194af0d19 jwt signature for prev.* files node.js 2021-12-10 20:29:15 +03:00
c0d240728d edit (fileType in setHistoryData for php) 2021-12-10 17:49:09 +03:00
89c0f03318 csharp: added information about the IIS components 2021-12-09 17:22:39 +03:00
bc1c9f455c fileType in setHistoryData for ruby (+ Gemfile) 2021-12-08 17:25:43 +03:00
df1a5f38c1 fileType in setHistoryData for python 2021-12-08 17:25:01 +03:00
6559c76fbd fileType in setHistoryData for php 2021-12-08 17:24:30 +03:00
a7db14811f fileType in setHistoryData for node.js 2021-12-08 17:23:37 +03:00
abffa3e75f fileType in setHistoryData for java 2021-12-08 17:23:00 +03:00
631f70148f fileType in setHistoryData for java-spring 2021-12-08 17:22:36 +03:00
c7e7c9c19d fileType in setHistoryData for C# 2021-12-08 17:21:54 +03:00
f2d4eb2a42 fileType in setHistoryData for C# mvc 2021-12-08 17:20:19 +03:00
778cb91317 Merge pull request #235 from ONLYOFFICE/feature/docserv_old_version
docxf and oform since v7.0
2021-12-08 14:03:12 +03:00
beb9885b03 docxf and oform since v7.0 2021-12-08 14:00:04 +03:00
65e34e52f9 nodejs: docxf and oform since v7.0 2021-12-07 18:41:42 +03:00
b453aa19f0 replace group value null with empty string 2021-12-02 17:39:48 +03:00
600570f7c7 Merge pull request #232 from ONLYOFFICE/feature/rename-master-form
Feature/rename master form
2021-12-02 11:54:00 +03:00
20f28afec1 rename master form to form template 2021-12-02 11:32:07 +03:00
2768ca5f6c nodejs: rename master form to form template 2021-12-02 11:21:53 +03:00
7841822c54 delete unused block 2021-12-02 10:37:05 +03:00
f3e24a8b5e nodejs: delete unused block 2021-12-01 22:31:08 +03:00
2425898cc8 nodejs: doc is not fillable format 2021-11-30 09:07:43 +03:00
d3b962dcb8 fix layout 2021-11-26 15:45:53 +03:00
3cee92d3a3 nodejs: change position of icons for mobile editor and filling forms 2021-11-19 16:15:58 +03:00
95ea50210f Merge remote-tracking branch 'remotes/origin/develop' into feature/change-files-folder
# Conflicts:
#	web/documentserver-example/csharp-mvc/web.appsettings.config
#	web/documentserver-example/java/src/main/java/helpers/DocumentManager.java
2021-11-18 12:54:57 +03:00
40016395a8 java-spring: update README.md, set empty server.address 2021-11-18 12:35:29 +03:00
8f2c2f96d2 java: fix docker 2021-11-17 00:10:28 +03:00
f9dbe89fd9 java-spring: fix docker, clean up application.properties 2021-11-16 18:48:52 +03:00
c3a4c0a66b java: add fields owner and uploaded for document info 2021-11-16 17:52:07 +03:00
edd423cd87 Merge remote-tracking branch 'remotes/origin/develop' into feature/change-files-folder
# Conflicts:
#	web/documentserver-example/csharp-mvc/web.appsettings.config
#	web/documentserver-example/java-spring/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java
2021-11-09 19:04:30 +03:00
e026a7027b java-spring: check if storage directory does not exist 2021-11-09 18:31:09 +03:00
11e8f40f8c ruby: fix embedded mode; fix media.css connect 2021-11-02 18:13:45 +03:00
bf18854ec0 csharp-mvc: fix embedded mode 2021-11-02 17:46:41 +03:00
08d1080527 csharp: fix embedded mode 2021-11-02 17:40:00 +03:00
9ca242fe82 python: fix storage path and embedded mode 2021-11-02 16:59:20 +03:00
b3c02a5afd php: fix embedded 2021-11-02 16:13:00 +03:00
ec65ebbfb8 php: layout fix 2021-11-02 16:01:39 +03:00
8544974202 java: layout fix 2021-11-02 16:01:16 +03:00
90eeae5334 php: fix file upload 2021-11-02 15:35:25 +03:00
970cfa6dd0 nodejs: fix embedded 2021-11-02 15:24:44 +03:00
f04a26a0f4 nodejs: fix file upload 2021-11-02 15:11:34 +03:00
53a58e2666 java: fix embedded mode 2021-11-02 14:33:29 +03:00
0ab0762aa5 java: remove urlUser param from config 2021-11-02 11:26:11 +03:00
4aeef2b873 php: fix highlighting of changes in history 2021-10-19 12:40:21 +03:00
60c03c1403 csharp-mvc: fix history 2021-10-19 11:41:28 +03:00
a597c37684 Merge branch 'develop' of https://github.com/ONLYOFFICE/document-server-integration into feature/change-files-folder 2021-10-17 15:38:48 +03:00
5206171a70 php: add ability to use custom path for files storage 2021-10-17 15:38:02 +03:00
375d916fe2 csharp-mvc: add ability to use custom path for files storage 2021-10-15 14:34:35 +03:00
35afb7a8fe csharp: add ability to custom path for files storage 2021-10-15 13:12:58 +03:00
8d1c4d8042 java-spring: add ability to use custom path for files storage 2021-10-14 12:28:36 +03:00
b969944ede python: update readme.md 2021-10-14 12:21:42 +03:00
da7450c732 ruby: add ability to use custom path for files storage 2021-10-14 12:19:45 +03:00
1db5e865a6 Merge remote-tracking branch 'remotes/origin/develop' into feature/change-files-folder 2021-10-14 12:11:38 +03:00
69ac7771d5 nodejs: add ability to use custom path for storage-folder 2021-09-24 17:53:59 +03:00
04f5cac85d java: fix; update README.md, add media.css to index.jsp 2021-09-24 17:51:43 +03:00
ccdd2a4cdc ruby 3.0 version 2021-09-20 12:29:55 +03:00
33140a2ca6 java: added ability to use absolute path for storage-folder in settings.properties, updated README.md 2021-09-13 18:49:38 +03:00
151 changed files with 3675 additions and 1556 deletions

View File

@ -1,10 +1,11 @@
## Integration examples
Test examples are simple document management systems that can be built into your
application for testing (please, do not use it for production without proper code
modifications).
Test examples are simple document management systems that can be built into your application for testing.
Do NOT use these integration examples on your own server without proper code modifications!
In case you enabled any of the test examples, disable it before going for production.
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages. The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages.
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
You should change `http://documentserver` to your server address in these files:
* [.Net (C# MVC)](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/csharp-mvc) - `web/documentserver-example/csharp-mvc/web.appsettings.config`
@ -66,6 +67,15 @@ The methods described below are available for all of the test examples.
| **Response** | **Code:** 200 OK <br />**Content on success:**<br /> `[{ "version": <file_version>, "id": <file_id>, "contentLength": <file_size_in_kilobytes>, "pureContentLength": <file_size_in_bytes>, "title": <file_name>, "updated": <last_change_date>}]`<br />**Content on error:**<br /> `"File not found"` |
| **Sample** | `curl -X GET http://localhost/files/{fileId}` |
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.
## Project Information
Official website: [https://www.onlyoffice.com](https://www.onlyoffice.com/?utm_source=github&utm_medium=cpc&utm_campaign=GitHubIntegrationEx)

View File

@ -87,10 +87,6 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -128,6 +124,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -312,6 +312,9 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -363,6 +366,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -436,6 +443,58 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,6 +22,7 @@
}
body {
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -71,6 +72,7 @@ header img {
}
.main {
display: table;
height: calc(100% - 112px);
min-height: 536px;
}
@ -97,6 +99,10 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -728,12 +734,9 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -25,6 +25,7 @@ using System.Web;
using System.Web.Configuration;
using System.Web.Script.Serialization;
using OnlineEditorsExampleMVC.Models;
using System.Net;
namespace OnlineEditorsExampleMVC.Helpers
{
@ -79,19 +80,37 @@ namespace OnlineEditorsExampleMVC.Helpers
// get the storage path of the file
public static string StoragePath(string fileName, string userAddress = null)
{
var directory = HttpRuntime.AppDomainAppPath + CurUserHostAddress(userAddress) + "\\";
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
return directory + Path.GetFileName(fileName);
return directory + (fileName.Contains("\\") ? fileName : Path.GetFileName(fileName));
}
// get the path to the forcesaved file version
public static string ForcesavePath(string fileName, string userAddress, Boolean create)
{
// create the directory to this file version
var directory = HttpRuntime.AppDomainAppPath + CurUserHostAddress(userAddress) + "\\";
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
if (!Directory.Exists(directory))
{
return "";
@ -172,7 +191,16 @@ namespace OnlineEditorsExampleMVC.Helpers
// get all the stored files from the user host address
public static List<FileInfo> GetStoredFiles()
{
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
var directory = "";
if (!string.IsNullOrEmpty(WebConfigurationManager.AppSettings["storage-path"]) && Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
}
if (!Directory.Exists(directory)) return new List<FileInfo>();
var directoryInfo = new DirectoryInfo(directory);
@ -228,8 +256,7 @@ namespace OnlineEditorsExampleMVC.Helpers
{
var uri = new UriBuilder(GetServerUrl(true))
{
Path = HttpRuntime.AppDomainAppVirtualPath + "/"
+ path,
Path = HttpRuntime.AppDomainAppVirtualPath + "/" + path,
Query = ""
};
@ -284,6 +311,24 @@ namespace OnlineEditorsExampleMVC.Helpers
return createUrl.ToString();
}
// create the public history url
public static string GetHistoryDownloadUrl(string filename, string version, string file)
{
var downloadUrl = new UriBuilder(GetServerUrl(true))
{
Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx",
Query = "type=downloadhistory"
+ "&fileName=" + HttpUtility.UrlEncode(filename)
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress)
+ "&ver=" + version
+ "&file="+ file
};
return downloadUrl.ToString();
}
// get url to download a file
public static string GetDownloadUrl(string fileName)
{
@ -372,5 +417,27 @@ namespace OnlineEditorsExampleMVC.Helpers
return files;
}
// enable certificate ignore
public static void VerifySSL()
{
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if(WebConfigurationManager.AppSettings["files.docservice.verify-peer-off"].Equals("true")) {
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}
}
public static Dictionary<string, string> GetLanguages()
{
var languages = new Dictionary<string, string>();
String[] couples = (WebConfigurationManager.AppSettings["files.docservice.languages"] ?? "").Split('|');
foreach (string couple in couples)
{
String[] tmp = couple.Split(':');
languages.Add(tmp[0],tmp[1]);
}
return languages;
}
}
}

View File

@ -143,6 +143,8 @@ namespace OnlineEditorsExampleMVC.Helpers
requestStream.Write(bytes, 0, bytes.Length); // and write the serialized body object to it
}
DocManagerHelper.VerifySSL();
string dataResponse;
using (var response = request.GetResponse())
using (var stream = response.GetResponseStream()) // get the response stream

View File

@ -76,7 +76,9 @@ namespace OnlineEditorsExampleMVC.Helpers
if (token != null && !token.Equals("")) // invalid signature error
{
fileData = (Dictionary<string, object>)jss.Deserialize<Dictionary<string, object>>(token)["payload"];
fileData = jss.Deserialize<Dictionary<string, object>>(token);
if (fileData.ContainsKey("payload"))
fileData = (Dictionary<string, object>)fileData["payload"];
}
else
{
@ -95,7 +97,11 @@ namespace OnlineEditorsExampleMVC.Helpers
}
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
string downloadExt = Path.GetExtension(downloadUri).ToLower() ?? ""; // get the extension of the downloaded file
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower() ?? ""; // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
var newFileName = fileName;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -122,6 +128,8 @@ namespace OnlineEditorsExampleMVC.Helpers
}
}
DocManagerHelper.VerifySSL();
var storagePath = DocManagerHelper.StoragePath(newFileName, userAddress); // get the file path
var histDir = DocManagerHelper.HistoryDir(storagePath); // get the path to the history directory
if (!Directory.Exists(histDir)) Directory.CreateDirectory(histDir);
@ -167,7 +175,11 @@ namespace OnlineEditorsExampleMVC.Helpers
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
string downloadExt = Path.GetExtension(downloadUri).ToLower(); // get the extension of the downloaded file
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower(); // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
Boolean newFileName = false;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -193,6 +205,8 @@ namespace OnlineEditorsExampleMVC.Helpers
}
}
DocManagerHelper.VerifySSL();
string forcesavePath = "";
Boolean isSubmitForm = fileData["forcesavetype"].ToString().Equals("3"); // SubmitForm
@ -235,8 +249,10 @@ namespace OnlineEditorsExampleMVC.Helpers
}
// create a command request
public static void commandRequest(string method, string key)
public static void commandRequest(string method, string key, object meta = null)
{
DocManagerHelper.VerifySSL();
string documentCommandUrl = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.command"];
var request = (HttpWebRequest)WebRequest.Create(documentCommandUrl);
@ -248,6 +264,11 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "key", key }
};
if (meta != null)
{
body.Add("meta", meta);
}
// check if a secret key to generate token exists or not
if (JwtManager.Enabled)
{

View File

@ -30,7 +30,8 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
"Can create files from templates using data from the editor",
"Can see the information about all users"
};
static List<string> descr_user_2 = new List<string>()
@ -39,7 +40,8 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
"Can create new files from the editor",
"Can see the information about users from Group2 and users who dont belong to any group"
};
static List<string> descr_user_3 = new List<string>()
@ -51,7 +53,8 @@ namespace OnlineEditorsExampleMVC.Helpers
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
"Can create new files from the editor",
"Can see the information about Group2 users"
};
static List<string> descr_user_0 = new List<string>()
@ -62,7 +65,9 @@ namespace OnlineEditorsExampleMVC.Helpers
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor"
};
private static List<User> users = new List<User>() {
@ -70,10 +75,11 @@ namespace OnlineEditorsExampleMVC.Helpers
"uid-1",
"John Smith",
"smith@example.com",
null,
"",
null,
new Dictionary<string, object>(),
null,
null,
new List<string>(),
descr_user_1,
true
@ -90,6 +96,7 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
new List<string>() { "group-2", "" },
true,
new List<string>(),
descr_user_2,
@ -107,6 +114,7 @@ namespace OnlineEditorsExampleMVC.Helpers
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
new List<string>() { "group-2" },
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
@ -116,9 +124,10 @@ namespace OnlineEditorsExampleMVC.Helpers
"uid-0",
null,
null,
null,
"",
null,
new Dictionary<string,object>(),
new List<string>(),
null,
new List<string>(),
descr_user_0,
@ -173,8 +182,9 @@ namespace OnlineEditorsExampleMVC.Helpers
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public List<string> userInfoGroups;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
@ -186,6 +196,7 @@ namespace OnlineEditorsExampleMVC.Helpers
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
this.userInfoGroups = userInfoGroups;
}
}
}

View File

@ -21,6 +21,7 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using OnlineEditorsExampleMVC.Helpers;
@ -42,7 +43,7 @@ namespace OnlineEditorsExampleMVC.Models
// get file url for user
public string FileUriUser
{
get { return DocManagerHelper.GetFileUri(FileName, false); }
get { return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? DownloadUrl + "&dmode=emb" : DocManagerHelper.GetFileUri(FileName, false); }
}
public string FileName { get; set; } // file name
@ -148,7 +149,8 @@ namespace OnlineEditorsExampleMVC.Models
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups }
{ "commentGroups", user.commentGroups },
{ "userInfoGroups", user.userInfoGroups }
}
}
}
@ -166,7 +168,7 @@ namespace OnlineEditorsExampleMVC.Models
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
{
{ "id", user.id },
{ "id", !user.id.Equals("uid-0") ? user.id : null },
{ "name", user.name },
{ "group", user.group }
}
@ -186,6 +188,7 @@ namespace OnlineEditorsExampleMVC.Models
"customization", new Dictionary<string, object>
{
{ "about", true }, // the About section display
{ "comments", true },
{ "feedback", true }, // the Feedback & Support menu button display
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
@ -214,7 +217,8 @@ namespace OnlineEditorsExampleMVC.Models
// get the document history
public void GetHistory(out string history, out string historyData)
{
{
var storagePath = WebConfigurationManager.AppSettings["storage-path"];
var jss = new JavaScriptSerializer();
var histDir = DocManagerHelper.HistoryDir(DocManagerHelper.StoragePath(FileName, null));
@ -253,9 +257,22 @@ namespace OnlineEditorsExampleMVC.Models
}
}
var ext = Path.GetExtension(FileName).ToLower();
dataObj.Add("fileType", ext.Replace(".", ""));
dataObj.Add("key", key);
// write file url to the data object
dataObj.Add("url", i == currentVersion ? FileUri : DocManagerHelper.GetPathUri(Directory.GetFiles(verDir, "prev.*")[0].Substring(HttpRuntime.AppDomainAppPath.Length)));
string prevFileUrl;
if (Path.IsPathRooted(storagePath) && !string.IsNullOrEmpty(storagePath))
{
prevFileUrl = i == currentVersion ? DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext)
: DocManagerHelper.GetDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""));
}
else {
prevFileUrl = i == currentVersion ? FileUri
: DocManagerHelper.GetHistoryDownloadUrl(FileName, i.ToString(), "prev" + ext);
}
dataObj.Add("url", prevFileUrl);
dataObj.Add("version", i);
if (i > 1) // check if the version number is greater than 1 (the file was modified)
{
@ -274,11 +291,13 @@ namespace OnlineEditorsExampleMVC.Models
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
{ "fileType", prev["fileType"] },
{ "key", prev["key"] }, // write key and url information about previous file version
{ "url", prev["url"] },
});
// write the path to the diff.zip archive with differences in this file version
dataObj.Add("changesUrl", DocManagerHelper.GetPathUri(Path.Combine(DocManagerHelper.VersionDir(histDir, i - 1), "diff.zip").Substring(HttpRuntime.AppDomainAppPath.Length)));
var changesUrl = DocManagerHelper.GetHistoryDownloadUrl(FileName, (i - 1).ToString(), "diff.zip");
dataObj.Add("changesUrl", changesUrl);
}
if(JwtManager.Enabled)
{

View File

@ -55,7 +55,7 @@ namespace OnlineEditorsExampleMVC.Models
// spreadsheet extensions
public static readonly List<string> ExtsSpreadsheet = new List<string>
{
".xls", ".xlsx", ".xlsm",
".xls", ".xlsx", ".xlsm", ".xlsb",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv"
};

View File

@ -13,7 +13,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OnlineEditorsExampleMVC</RootNamespace>
<AssemblyName>OnlineEditorsExampleMVC</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />

View File

@ -2,22 +2,25 @@
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C# MVC).
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
## Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
## Step 2. Download the .Net (C# MVC) code for the editors integration
Download the [.Net (C# MVC) example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connnect the editors to your website. Specify path to the editors installation in the *settings.config* file:
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *settings.config* file:
```
<add key="storage-path" value=""/>
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-path** is the path where files will be created and stored. You can set an absolute path.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *DocEditor.aspx* file.
## Step 3. Install the prerequisites
@ -25,31 +28,41 @@ If you want to experiment with the editor configuration, modify the [parameters]
* **Microsoft .NET Framework**: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* **Internet Information Services**: version 7 or later.
Configure the IIS components for the server to work correctly:
1. Open Windows features:
**Start** -> **Control Panel** -> **Programs** -> **Programs and Features** -> **Turn Windows features on or off**
2. In the opened window, find **Internet Information Services** and choose all the necessary features. To do this, open the **World Wide Web Services** list and check the following components:
* **Application Development Features**: .NET Extensibility 4.8, ASP.NET 4.8, ISAPI Extensions, ISAPI Filters,
* **Common HTTP Features**: Default Document,
* **Security**: Request Filtering.
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) Manager:
**Start** -> **Control Panel** -> **System and Security** -> **Administrative Tools** -> **Internet Information Services (IIS) Manager**
2. Add your website in the IIS Manager.
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
3. In the **Add Website** dialog box specify the name of the folder with the .Net (C# MVC) project in the **Site name** box.
Specify the path to the folder with your project in the **Physical Path** box.
Specify the unique value used only for this website in the **Port** box.
![sitename](screenshots/sitename.png)
4. Check for the .NET platform version specified in IIS Manager for you website. Choose **v4.0.** version.
**Application Pools** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
5. Browse your website with the IIS Manager:
Right-click the site -> **Manage Website** -> **Browse**
![browse](screenshots/browse.png)
## Step 5. Check accessibility
@ -57,3 +70,12 @@ If you want to experiment with the editor configuration, modify the [parameters]
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -46,6 +46,7 @@
<script type="text/javascript" language="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
if (console && console.log)
@ -107,10 +108,14 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
};
// the user is trying to insert an image by clicking the Image from Storage button
@ -146,7 +151,7 @@
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=saveas");
xhr.setRequestHeader( 'Content-Type', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
@ -154,7 +159,25 @@
}
};
var config = <%= Model.GetDocConfig(Request, Url) %>;
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config = <%= Model.GetDocConfig(Request, Url) %>;
config.width = "100%";
config.height = "100%";
@ -174,47 +197,60 @@
<% string hist, histData; %>
<% Model.GetHistory(out hist, out histData); %>
<% if (!string.IsNullOrEmpty(hist) && !string.IsNullOrEmpty(histData))
{ %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= hist %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= histData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose '] = function () {
document.location.reload();
};
<% } %>
<% string usersForMentions; %>
<% Model.GetUsersMentions(Request, out usersForMentions); %>
<% if (!string.IsNullOrEmpty(usersForMentions))
// add mentions for not anonymous users
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= usersForMentions%>
});
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, event.data.actionLink);
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
<% } %>
if (config.editorConfig.user.id) {
<% if (!string.IsNullOrEmpty(hist) && !string.IsNullOrEmpty(histData))
{ %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= hist %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= histData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose '] = function () {
document.location.reload();
};
<% } %>
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(usersForMentions))
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= usersForMentions %>
});
};
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -4,6 +4,7 @@
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="OnlineEditorsExampleMVC.Helpers" %>
<%@ Import Namespace="OnlineEditorsExampleMVC.Models" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@ -66,7 +67,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Master form</a>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
@ -89,7 +90,7 @@
<select class="select-user" id="user">
<% foreach (User user in Users.getAllUsers())
{ %>
<option value=<%= user.id %> ><%= user.name.IsEmpty() ? "Anonymous" : user.name %></option>
<option value="<%= user.id %>"><%= user.name.IsEmpty() ? "Anonymous" : user.name %></option>
<% } %>
</select>
</td>
@ -98,37 +99,11 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
<% Dictionary<string, string> languages = DocManagerHelper.GetLanguages();
foreach (var lang in languages)
{ %>
<option value="<%= lang.Key %>"><%= lang.Value %></option>
<% } %>
</select>
</td>
</tr>
@ -139,12 +114,13 @@
<td class="section">
<div class="main-panel">
<% var storedFiles = DocManagerHelper.GetStoredFiles(); %>
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "block" %>">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<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())
{ %>
@ -222,9 +198,6 @@
</a>
</td>
<% } %>
<% if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "blockcontent" }) %>" target="_blank">
@ -328,10 +301,8 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -340,10 +311,12 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
</div>
<span id="loadScripts" data-docs="<%= WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.preloader"] %>"></span>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=152368
@ -39,7 +39,7 @@
</handlers>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800"/>
<requestLimits maxAllowedContentLength="52428800" />
</requestFiltering>
</security>
</system.webServer>

View File

@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Net;
using System.Web;
@ -46,6 +47,9 @@ namespace OnlineEditorsExampleMVC
case "download":
Download(context);
break;
case "downloadhistory":
DownloadHistory(context);
break;
case "convert":
Convert(context);
break;
@ -67,6 +71,9 @@ namespace OnlineEditorsExampleMVC
case "saveas":
SaveAs(context);
break;
case "rename":
Rename(context);
break;
}
}
@ -110,6 +117,8 @@ namespace OnlineEditorsExampleMVC
var req = (HttpWebRequest)WebRequest.Create(fileUrl);
DocManagerHelper.VerifySSL();
using (var stream = req.GetResponse().GetResponseStream())
{
@ -148,6 +157,8 @@ namespace OnlineEditorsExampleMVC
context.Response.ContentType = "text/plain";
try
{
DocManagerHelper.VerifySSL();
var httpPostedFile = context.Request.Files[0];
string fileName;
@ -247,6 +258,8 @@ namespace OnlineEditorsExampleMVC
var req = (HttpWebRequest)WebRequest.Create(newFileUri);
DocManagerHelper.VerifySSL();
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the converting file
{
if (stream == null) throw new Exception("Stream is null");
@ -300,7 +313,7 @@ namespace OnlineEditorsExampleMVC
var userAddress = context.Request["userAddress"];
var fileName = Path.GetFileName(context.Request["fileName"]);
var status = (TrackerStatus) (int) fileData["status"]; // get status from the request body
var saved = 1; // editing
var saved = 0;
switch (status)
{
case TrackerStatus.Editing:
@ -357,7 +370,7 @@ namespace OnlineEditorsExampleMVC
return;
}
context.Response.Write("{\"error\":0}");
context.Response.Write("{\"error\":" + saved + "}");
}
// remove a file
@ -443,10 +456,12 @@ namespace OnlineEditorsExampleMVC
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var fileName = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? context.Request["fileName"]
: Path.GetFileName(context.Request["fileName"]);
var userAddress = context.Request["userAddress"];
var isEmbedded = context.Request["dmode"];
if (JwtManager.Enabled)
if (JwtManager.Enabled && isEmbedded == null)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
@ -492,5 +507,80 @@ namespace OnlineEditorsExampleMVC
{
get { return false; }
}
// download a history file
private static void DownloadHistory(HttpContext context)
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var version = System.Convert.ToInt32(context.Request["ver"]);
var file = Path.GetFileName(context.Request["file"]);
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
if (context.Request.Headers.AllKeys.Contains(JWTheader, StringComparer.InvariantCultureIgnoreCase))
{
var headerToken = context.Request.Headers.Get(JWTheader).Substring("Bearer ".Length);
string token = JwtManager.Decode(headerToken);
if (token == null || token.Equals(""))
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
var histPath = DocManagerHelper.HistoryDir(DocManagerHelper.StoragePath(fileName, userAddress));
var filePath = Path.Combine(DocManagerHelper.VersionDir(histPath, version), file); // get the path to document version
download(filePath, context);
}
catch (Exception)
{
context.Response.Write("{ \"error\": \"File not found!\"}");
}
}
// rename a file
private static void Rename(HttpContext context)
{
// read request body
context.Response.ContentType = "text/plain";
string fileData;
try
{
using (var receiveStream = context.Request.InputStream)
using (var readStream = new StreamReader(receiveStream))
{
fileData = readStream.ReadToEnd();
if (string.IsNullOrEmpty(fileData)) context.Response.Write("{\"error\":\"Request stream is empty\"}");
}
}
catch (Exception e)
{
throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
}
var jss = new JavaScriptSerializer();
var body = jss.Deserialize<Dictionary<string, object>>(fileData);
var newFileName = (string) body["newfilename"];
var docKey = (string) body["dockey"];
var meta = new Dictionary<string, object>() {
{ "title", newFileName }
};
TrackManager.commandRequest("meta", docKey, meta);
context.Response.Write("{ \"result\": \"OK\"}");
}
}
}

View File

@ -1,18 +1,23 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<appSettings>
<clear />
<add key="version" value="1.0.0"/>
<add key="version" value="1.2.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
<add key="files.docservice.fillform-docs" value=".oform|.docx"/>
<add key="files.docservice.viewed-docs" value=".pdf|.djvu|.xps|.oxps"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt|.docxf"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
<add key="files.docservice.header" value="Authorization" />
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|az:Azerbaijani|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese|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|lv:Latvian|lo:Lao|nb:Norwegian|pl:Polish|pt:Portuguese|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>
<add key="files.docservice.url.converter" value="ConvertService.ashx"/>

View File

@ -87,10 +87,6 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -128,6 +124,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -312,6 +312,9 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -363,6 +366,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -436,6 +443,58 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,6 +22,7 @@ html {
}
body {
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -71,6 +72,7 @@ header img {
}
.main {
display: table;
height: calc(100% - 112px);
min-height: 536px;
}
@ -97,6 +99,10 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -732,12 +738,9 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -5,12 +5,14 @@
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="OnlineEditorsExample" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!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" />
<title>ONLYOFFICE</title>
<!--
*
@ -68,7 +70,7 @@
<a class="try-editor slide" data-type="slide">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Master form</a>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
@ -99,37 +101,11 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
<% Dictionary<string, string> languages = GetLanguages();
foreach (var lang in languages)
{ %>
<option value="<%= lang.Key %>"><%= lang.Value %></option>
<% } %>
</select>
</td>
</tr>
@ -140,12 +116,13 @@
<td class="section">
<% var storedFiles = GetStoredFiles(); %>
<div class="main-panel">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "block" %>">
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<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())
{ %>
@ -223,9 +200,6 @@
</a>
</td>
<% } %>
<%if (docType != "word" && docType != "cell") { %>
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
<% } %>
<% if (docType == "word") { %>
<td class="contentCells contentCells-icon">
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=blockcontent" %>" target="_blank">
@ -329,10 +303,8 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -341,10 +313,12 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
</div>
<span id="loadScripts" data-docs="<%= UrlPreloadScripts %>"></span>

View File

@ -35,7 +35,7 @@ namespace OnlineEditorsExample
// the spreadsheet extension list
public static readonly List<string> ExtsSpreadsheet = new List<string>
{
".xls", ".xlsx", ".xlsm",
".xls", ".xlsx", ".xlsm", ".xlsb",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv"
};
@ -78,7 +78,9 @@ namespace OnlineEditorsExample
{
get
{
return
return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ?
WebConfigurationManager.AppSettings["storage-path"] + "/"
:
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ WebConfigurationManager.AppSettings["storage-path"]
@ -144,18 +146,52 @@ namespace OnlineEditorsExample
// get the storage path of the given file
public static string StoragePath(string fileName, string userAddress)
{
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
var directory = "";
if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory); // if the file directory doesn't exist, make it
}
return directory + Path.GetFileName(fileName);
return directory + (fileName.Contains("\\") ? fileName : Path.GetFileName(fileName));
}
// get the path to the history file version
public static string HistoryPath(string fileName, string userAddress, string version, string file)
{
var directory = "";
if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
var filepath = directory + Path.GetFileName(fileName) + "-hist" + "\\" + version + "\\" + file;
return filepath;
}
// get the path to the forcesaved file version
public static string ForcesavePath(string fileName, string userAddress, Boolean create)
{
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
var directory = "";
if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(userAddress) + "\\";
}
if (!Directory.Exists(directory)) // the directory with host address doesn't exist
{
return "";
@ -317,11 +353,7 @@ namespace OnlineEditorsExample
try
{
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
VerifySSL();
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the uploading file
{
@ -384,11 +416,7 @@ namespace OnlineEditorsExample
var req = (HttpWebRequest)WebRequest.Create(fileUrl);
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
VerifySSL();
using (var stream = req.GetResponse().GetResponseStream())
{
@ -472,11 +500,7 @@ namespace OnlineEditorsExample
var req = (HttpWebRequest)WebRequest.Create(newFileUri);
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
VerifySSL();
using (var stream = req.GetResponse().GetResponseStream()) // get response stream of the converting file
{
@ -528,7 +552,16 @@ namespace OnlineEditorsExample
// get all the stored files from the folder
protected static List<FileInfo> GetStoredFiles()
{
var directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
var directory = "";
if (Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]))
{
directory = WebConfigurationManager.AppSettings["storage-path"] + "\\";
}
else
{
directory = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"] + CurUserHostAddress(null) + "\\";
}
if (!Directory.Exists(directory)) return new List<FileInfo>();
var directoryInfo = new DirectoryInfo(directory); // read the user host directory contents
@ -571,5 +604,27 @@ namespace OnlineEditorsExample
return files;
}
// enable certificate ignore
public static void VerifySSL()
{
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if(WebConfigurationManager.AppSettings["files.docservice.verify-peer-off"].Equals("true")) {
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}
}
public static Dictionary<string, string> GetLanguages()
{
var languages = new Dictionary<string, string>();
String[] couples = (WebConfigurationManager.AppSettings["files.docservice.languages"] ?? "").Split('|');
foreach (string couple in couples)
{
String[] tmp = couple.Split(':');
languages.Add(tmp[0],tmp[1]);
}
return languages;
}
}
}

View File

@ -64,6 +64,7 @@
<script type="text/javascript" language="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
if (console && console.log)
@ -125,10 +126,14 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
};
// the user is trying to insert an image by clicking the Image from Storage button
@ -158,7 +163,7 @@
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=saveas");
xhr.setRequestHeader( 'Content-Type', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
@ -166,7 +171,25 @@
}
};
var config = <%= DocConfig %>;
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "webeditor.ashx?type=rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config = <%= DocConfig %>;
config.width = "100%";
config.height = "100%";
@ -184,42 +207,53 @@
"onRequestMailMergeRecipients": onRequestMailMergeRecipients,
};
<% if (!string.IsNullOrEmpty(History) && !string.IsNullOrEmpty(HistoryData))
{ %>
config.events['onRequestHistory'] = function () { // the user is trying to show the document version history
docEditor.refreshHistory(<%= History %>); // show the document version history
};
config.events['onRequestHistoryData'] = function (event) { // the user is trying to click the specific document version in the document version history
var ver = event.data;
var histData = <%= HistoryData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
config.events['onRequestHistoryClose '] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
<% } %>
if (config.editorConfig.user.id) {
<% if (!string.IsNullOrEmpty(History) && !string.IsNullOrEmpty(HistoryData))
{ %>
config.events['onRequestHistory'] = function () { // the user is trying to show the document version history
docEditor.refreshHistory(<%= History %>); // show the document version history
};
config.events['onRequestHistoryData'] = function (event) { // the user is trying to click the specific document version in the document version history
var ver = event.data;
var histData = <%= HistoryData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
config.events['onRequestHistoryClose '] = function () { // the user is trying to go back to the document from viewing the document version history
document.location.reload();
};
<% } %>
// add mentions for not anonymous users
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= UsersForMentions %>
});
};
<% } %>
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": <%= UsersForMentions %>
});
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, event.data.actionLink);
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
<% } %>
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

52
web/documentserver-example/csharp/DocEditor.aspx.cs Normal file → Executable file
View File

@ -41,7 +41,7 @@ namespace OnlineEditorsExample
// get url to the original file for Document Server
public static string FileUriUser
{
get { return _Default.FileUri(FileName, false); }
get { return Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? getDownloadUrl(FileName) + "&dmode=emb" : _Default.FileUri(FileName, false); }
}
protected string Key
@ -100,20 +100,17 @@ namespace OnlineEditorsExample
}
// get url to download a file
public static string getDownloadUrl
public static string getDownloadUrl(string fileName)
{
get
{
var downloadUrl = new UriBuilder(_Default.GetServerUrl(true));
var downloadUrl = new UriBuilder(_Default.GetServerUrl(true));
downloadUrl.Path =
HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
downloadUrl.Query = "type=download"
+ "&fileName=" + HttpUtility.UrlEncode(FileName)
+ "&fileName=" + HttpUtility.UrlEncode(fileName)
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress);
return downloadUrl.ToString();
}
}
// loading a page
@ -195,7 +192,7 @@ namespace OnlineEditorsExample
"document", new Dictionary<string, object>
{
{ "title", FileName },
{ "url", getDownloadUrl },
{ "url", getDownloadUrl(FileName) },
{ "fileType", ext.Trim('.') },
{ "key", Key },
{
@ -220,7 +217,8 @@ namespace OnlineEditorsExample
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups }
{ "commentGroups", user.commentGroups },
{ "userInfoGroups", user.userInfoGroups }
}
}
}
@ -238,7 +236,7 @@ namespace OnlineEditorsExample
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
{
{ "id", user.id },
{ "id", !user.id.Equals("uid-0") ? user.id : null },
{ "name", user.name },
{ "group", user.group }
}
@ -258,6 +256,7 @@ namespace OnlineEditorsExample
"customization", new Dictionary<string, object>
{
{ "about", true }, // the About section display
{ "comments", true },
{ "feedback", true }, // the Feedback & Support menu button display
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
@ -318,6 +317,7 @@ namespace OnlineEditorsExample
// get the document history
private void GetHistory(out Dictionary<string, object> history, out Dictionary<string, object> historyData)
{
var storagePath = WebConfigurationManager.AppSettings["storage-path"];
var jss = new JavaScriptSerializer();
var histDir = _Default.HistoryDir(_Default.StoragePath(FileName, null));
@ -355,8 +355,17 @@ namespace OnlineEditorsExample
}
}
var ext = Path.GetExtension(FileName).ToLower();
dataObj.Add("fileType", ext.Replace(".", ""));
dataObj.Add("key", key);
dataObj.Add("url", i == currentVersion ? FileUri : MakePublicUrl(Directory.GetFiles(verDir, "prev.*")[0])); // write file url to the data object
// write file url to the data object
var prevFileUrl = i == currentVersion ? FileUri : MakePublicHistoryUrl(FileName, i.ToString(), "prev" + ext);
if (Path.IsPathRooted(storagePath))
{
prevFileUrl = i == currentVersion ? getDownloadUrl(FileName) : getDownloadUrl(Directory.GetFiles(verDir, "prev.*")[0].Replace(storagePath + "\\", ""));
}
dataObj.Add("url", prevFileUrl); // write file url to the data object
dataObj.Add("version", i);
if (i > 1) // check if the version number is greater than 1 (the file was modified)
{
@ -375,11 +384,13 @@ namespace OnlineEditorsExample
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
{ "fileType", prev["fileType"] },
{ "key", prev["key"] }, // write key and url information about previous file version
{ "url", prev["url"] },
});
// write the path to the diff.zip archive with differences in this file version
dataObj.Add("changesUrl", MakePublicUrl(Path.Combine(_Default.VersionDir(histDir, i - 1), "diff.zip")));
var changesUrl = MakePublicHistoryUrl(FileName, (i - 1).ToString(), "diff.zip");
dataObj.Add("changesUrl", changesUrl);
}
if (JwtManager.Enabled)
{
@ -503,10 +514,25 @@ namespace OnlineEditorsExample
// create the public url
private string MakePublicUrl(string fullPath)
{
var root = HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"];
var root = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? WebConfigurationManager.AppSettings["storage-path"]
: HttpRuntime.AppDomainAppPath + WebConfigurationManager.AppSettings["storage-path"];
return _Default.GetServerUrl(true) + fullPath.Substring(root.Length).Replace(Path.DirectorySeparatorChar, '/');
}
// create the public history url
private string MakePublicHistoryUrl(string filename, string version, string file)
{
var fileUrl = new UriBuilder(_Default.GetServerUrl(true));
fileUrl.Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "webeditor.ashx";
fileUrl.Query = "type=downloadhistory&fileName=" + HttpUtility.UrlEncode(filename)
+ "&ver=" + version + "&file=" + file
+ "&userAddress=" + HttpUtility.UrlEncode(HttpContext.Current.Request.UserHostAddress);
return fileUrl.ToString();
}
// create demo document
private static void Try(string type, string sample, HttpRequest request)
{

View File

@ -145,11 +145,7 @@ namespace ASC.Api.DocumentConverter
requestStream.Write(bytes, 0, bytes.Length); // and write the serialized body object to it
}
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
_Default.VerifySSL();
string dataResponse;
using (var response = request.GetResponse())

View File

@ -11,7 +11,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OnlineEditorsExample</RootNamespace>
<AssemblyName>OnlineEditorsExample</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>

View File

@ -2,11 +2,11 @@
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C#).
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
## Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
@ -14,11 +14,12 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
Download the [.Net (C#) example](https://api.onlyoffice.com/editors/demopreview) from our site.
Connect the editors to your website by specifying the path to the editors installation in the *settings.config* file:
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *settings.config* file:
```
<add key="storage-path" value=""/>
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-path** is the path where files will be created and stored. You can set an absolute path.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *DocEditor.aspx* file.
@ -28,13 +29,23 @@ Check that your system meets the requirements:
* **Microsoft .NET Framework**: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* **Internet Information Services**: version 7 or later.
Configure the IIS components for the server to work correctly:
1. Open Windows features:
**Start** -> **Control Panel** -> **Programs** -> **Programs and Features** -> **Turn Windows features on or off**
2. In the opened window, find **Internet Information Services** and choose all the necessary features. To do this, open the **World Wide Web Services** list and check the following components:
* **Application Development Features**: .NET Extensibility 4.8, ASP.NET 4.8, ISAPI Extensions, ISAPI Filters,
* **Common HTTP Features**: Default Document,
* **Security**: Request Filtering.
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) Manager:
**Start** -> **Control Panel** -> **System and Security** -> **Administrative Tools** -> **Internet Information Services (IIS) Manager**
2. Add your website in the IIS Manager.
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
@ -46,7 +57,7 @@ Check that your system meets the requirements:
![sitename](screenshots/sitename.png)
4. Check for the .NET platform version specified in IIS Manager for you website. Choose **v4.0.** version.
**Application Pools** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
@ -61,3 +72,12 @@ Check that your system meets the requirements:
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -78,7 +78,9 @@ namespace OnlineEditorsExample
if (token != null && !token.Equals("")) // invalid signature error
{
fileData = (Dictionary<string, object>)jss.Deserialize<Dictionary<string, object>>(token)["payload"];
fileData = jss.Deserialize<Dictionary<string, object>>(token);
if (fileData.ContainsKey("payload"))
fileData = (Dictionary<string, object>)fileData["payload"];
}
else
{
@ -97,7 +99,11 @@ namespace OnlineEditorsExample
}
var downloadUri = (string)fileData["url"];
var curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
var downloadExt = Path.GetExtension(downloadUri).ToLower() ?? ""; // get the extension of the downloaded file
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower() ?? ""; // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
var newFileName = fileName;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -124,11 +130,7 @@ namespace OnlineEditorsExample
}
}
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
_Default.VerifySSL();
var storagePath = _Default.StoragePath(newFileName, userAddress); // get the file path
var histDir = _Default.HistoryDir(storagePath); // get the path to the history directory
@ -175,7 +177,11 @@ namespace OnlineEditorsExample
var downloadUri = (string)fileData["url"];
string curExt = Path.GetExtension(fileName).ToLower(); // get current file extension
string downloadExt = Path.GetExtension(downloadUri).ToLower(); // get the extension of the downloaded file
var downloadExt = fileData.ContainsKey("filetype")
? "." + (string)fileData["filetype"]
: Path.GetExtension(downloadUri).ToLower(); // TODO: Delete in version 7.0 or higher. Support for versions below 7.0
Boolean newFileName = false;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -201,11 +207,7 @@ namespace OnlineEditorsExample
}
}
// hack. http://ubuntuforums.org/showthread.php?t=1841740
if (_Default.IsMono)
{
ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
}
_Default.VerifySSL();
string forcesavePath = "";
Boolean isSubmitForm = fileData["forcesavetype"].ToString().Equals("3"); // SubmitForm
@ -250,8 +252,10 @@ namespace OnlineEditorsExample
}
// create a command request
public static void commandRequest(string method, string key)
public static void commandRequest(string method, string key, object meta = null)
{
_Default.VerifySSL();
string documentCommandUrl = WebConfigurationManager.AppSettings["files.docservice.url.site"] + WebConfigurationManager.AppSettings["files.docservice.url.command"];
var request = (HttpWebRequest)WebRequest.Create(documentCommandUrl);
@ -263,13 +267,18 @@ namespace OnlineEditorsExample
{ "key", key }
};
if (meta != null)
{
body.Add("meta", meta);
}
// check if a secret key to generate token exists or not
if (JwtManager.Enabled)
{
var payload = new Dictionary<string, object>
{
{ "payload", body }
};
{
{ "payload", body }
};
var payloadToken = JwtManager.Encode(payload); // encode a payload object into a header token
var bodyToken = JwtManager.Encode(body); // encode body into a body token

View File

@ -29,7 +29,8 @@ namespace OnlineEditorsExample
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
"Can create files from templates using data from the editor",
"Can see the information about all users"
};
static List<string> descr_user_2 = new List<string>()
@ -38,19 +39,21 @@ namespace OnlineEditorsExample
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
"Can create new files from the editor",
"Can see the information about users from Group2 and users who dont belong to any group"
};
static List<string> descr_user_3 = new List<string>()
{
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
"Can create new files from the editor",
"Can see the information about Group2 users"
};
static List<string> descr_user_0 = new List<string>()
@ -61,7 +64,9 @@ namespace OnlineEditorsExample
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor"
};
private static List<User> users = new List<User>() {
@ -69,10 +74,11 @@ namespace OnlineEditorsExample
"uid-1",
"John Smith",
"smith@example.com",
null,
"",
null,
new Dictionary<string, object>(),
null,
null,
new List<string>(),
descr_user_1,
true
@ -89,6 +95,7 @@ namespace OnlineEditorsExample
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
new List<string>() { "group-2", "" },
true,
new List<string>(),
descr_user_2,
@ -106,6 +113,7 @@ namespace OnlineEditorsExample
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
new List<string>() { "group-2" },
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
@ -115,9 +123,10 @@ namespace OnlineEditorsExample
"uid-0",
null,
null,
null,
"",
null,
new Dictionary<string, object>(),
new List<string>(),
null,
new List<string>(),
descr_user_0,
@ -173,8 +182,9 @@ namespace OnlineEditorsExample
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public List<string> userInfoGroups;
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
@ -186,6 +196,7 @@ namespace OnlineEditorsExample
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
this.userInfoGroups = userInfoGroups;
}
}
}

View File

@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings configSource="settings.config"/>
<appSettings configSource="settings.config" />
<system.web>
<httpRuntime maxRequestLength="51200"/>
<compilation debug="true" targetFramework="4.5"/>
<authentication mode="Windows"/>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
<httpRuntime maxRequestLength="51200" />
<compilation debug="true" targetFramework="4.5" />
<authentication mode="Windows" />
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800"/>
<requestLimits maxAllowedContentLength="52428800" />
<denyUrlSequences>
<add sequence=".."/>
<add sequence=".." />
</denyUrlSequences>
<hiddenSegments>
<remove segment="App_Data"/>
<remove segment="App_Data" />
</hiddenSegments>
</requestFiltering>
</security>

View File

@ -44,6 +44,9 @@ namespace OnlineEditorsExample
case "download":
Download(context);
break;
case "downloadhistory":
DownloadHistory(context);
break;
case "convert":
Convert(context);
break;
@ -65,6 +68,9 @@ namespace OnlineEditorsExample
case "saveas":
SaveAs(context);
break;
case "rename":
Rename(context);
break;
}
}
@ -135,7 +141,7 @@ namespace OnlineEditorsExample
var userAddress = context.Request["userAddress"];
var fileName = Path.GetFileName(context.Request["fileName"]);
var status = (TrackerStatus) (int) fileData["status"]; // get status from the request body
var saved = 1; // editing
var saved = 0;
switch (status)
{
case TrackerStatus.Editing:
@ -191,7 +197,7 @@ namespace OnlineEditorsExample
context.Response.Write("{\"error\":" + saved + "}");
return;
}
context.Response.Write("{\"error\":0}");
context.Response.Write("{\"error\":" + saved + "}");
}
// remove a file
@ -271,10 +277,11 @@ namespace OnlineEditorsExample
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var fileName = Path.IsPathRooted(WebConfigurationManager.AppSettings["storage-path"]) ? context.Request["fileName"] : Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var isEmbedded = context.Request["dmode"];
if (JwtManager.Enabled)
if (JwtManager.Enabled && isEmbedded == null)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
@ -321,5 +328,77 @@ namespace OnlineEditorsExample
{
get { return false; }
}
private static void DownloadHistory(HttpContext context)
{
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var userAddress = Path.GetFileName(context.Request["userAddress"]);
var version = Path.GetFileName(context.Request["ver"]);
var file = Path.GetFileName(context.Request["file"]);
if (JwtManager.Enabled)
{
string JWTheader = WebConfigurationManager.AppSettings["files.docservice.header"].Equals("") ? "Authorization" : WebConfigurationManager.AppSettings["files.docservice.header"];
if (context.Request.Headers.AllKeys.Contains(JWTheader, StringComparer.InvariantCultureIgnoreCase))
{
var headerToken = context.Request.Headers.Get(JWTheader).Substring("Bearer ".Length);
string token = JwtManager.Decode(headerToken);
if (token == null || token.Equals(""))
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.Write("JWT validation failed");
return;
}
}
var filePath = _Default.HistoryPath(fileName, userAddress, version, file); // get the path to the force saved document version
download(filePath, context);
}
catch (Exception)
{
context.Response.Write("{ \"error\": \"File not found!\"}");
}
}
// rename a file
private static void Rename(HttpContext context)
{
string fileData;
try
{
using (var receiveStream = context.Request.InputStream)
using (var readStream = new StreamReader(receiveStream))
{
fileData = readStream.ReadToEnd();
if (string.IsNullOrEmpty(fileData)) return;
}
}
catch (Exception e)
{
throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
}
var jss = new JavaScriptSerializer();
var body = jss.Deserialize<Dictionary<string, object>>(fileData);
var newFileName = (string) body["newfilename"];
var docKey = (string) body["dockey"];
var meta = new Dictionary<string, object>() {
{ "title", newFileName }
};
TrackManager.commandRequest("meta", docKey, meta);
context.Response.Write("{ \"result\": \"OK\"}");
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<clear />
<add key="version" value="1.0.0"/>
<add key="version" value="1.2.0"/>
<add key="filesize-max" value="52428800"/>
<add key="storage-path" value=""/>
@ -9,10 +9,13 @@
<add key="files.docservice.fillform-docs" value=".oform|.docx"/>
<add key="files.docservice.viewed-docs" value=".pdf|.djvu|.xps|.oxps"/>
<add key="files.docservice.edited-docs" value=".docx|.xlsx|.csv|.pptx|.txt|.docxf"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.convert-docs" value=".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2"/>
<add key="files.docservice.timeout" value="120000" />
<add key="files.docservice.secret" value="" />
<add key="files.docservice.header" value="Authorization" />
<add key="files.docservice.verify-peer-off" value="true"/>
<add key="files.docservice.languages" value="en:English|az:Azerbaijani|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese|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|lv:Latvian|lo:Lao|nb:Norwegian|pl:Polish|pt:Portuguese|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese"/>
<add key="files.docservice.url.site" value="http://documentserver/"/>

View File

@ -1,17 +1,18 @@
## Overview
This example will help you integrate ONLYOFFICE Docs into your web application written in Java
with Spring Boot.
with Spring Boot.
Spring Boot has a lot of functionality, but its most significant features are: dependency management,
auto-configuration, and built-in servlet containers.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
## For Windows
### Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
@ -19,16 +20,15 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
Download the [Java-Spring example](https://api.onlyoffice.com/editors/demopreview) from our site.
To connect the editors to your website, specify the path to the editors installation, server address and port in the *\src\main\resources\application.properties* file:
To connect the editors to your website, specify the path to the editors installation, server port and the path to the storage folder in the *\src\main\resources\application.properties* file:
```
server.address=address
files.storage=
server.port=port
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path. For example, *D:\\\\folder*. Please note that on Windows OS the double backslash must be used as a separator.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *\src\main\resources\editor.html* file.
@ -65,11 +65,11 @@ To run the Java example code, install the Java version 11 appropriate for your O
```
echo %JAVA_HOME%
```
2. Set the **MAVEN_HOME** environment variable:
Unzip the downloaded archive with the maven to any directory, it will be something like this:
```
C:\apache-maven-3.8.1
```
@ -87,7 +87,7 @@ To run the Java example code, install the Java version 11 appropriate for your O
Add C:\apache-maven-3.8.1\bin to the PATH system variable:
In system variables, find PATH, clicks on the Edit... button. In “Edit environment variable” dialog, clicks on the New button and add this C:\apache-maven-3.8.1\bin
Check if the variable created successfully by **echo** command in the **Command Prompt**:
```
@ -112,8 +112,6 @@ To run the Java example code, install the Java version 11 appropriate for your O
```
http://server.address:server.port/
```
### Step 6. Check accessibility
@ -151,8 +149,8 @@ See the detailed guide to learn how to install Document Server [for Linux](https
```
git clone https://github.com/ONLYOFFICE/document-server-integration.git
```
3. Change the current directory for the project directory:
a) from archive
@ -173,13 +171,13 @@ See the detailed guide to learn how to install Document Server [for Linux](https
Edit the following lines:
```
server.address=address
files.storage=
server.port=port
files.docservice.url.site=https://documentserver/
```
Where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path.
5. Install **Maven**:
@ -192,19 +190,18 @@ See the detailed guide to learn how to install Document Server [for Linux](https
```
mvn package
```
7. Start Java-Spring example:
```
./mvnw spring-boot:run
```
8. Open your browser using **server.address** and **server.port**:
```
http://server.address:server.port/
```
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
@ -222,13 +219,12 @@ Make sure that the Document Server has access to the server with the example ins
2. Edit the following lines:
```
server.address=address
files.storage=
server.port=port
files.docservice.url.site=https://documentserver/
```
Where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
**address** is the address of the server or comment this line to use localhost, **port** is the any available port.
where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path.
3. Run the next command in the java example directory:
@ -236,7 +232,16 @@ Make sure that the Document Server has access to the server with the example ins
docker-compose up
```
4. Open your browser using **server.address** and **server.port**:
```
http://server.address:server.port/
```
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -7,7 +7,9 @@ services:
image: maven:3.8.1
working_dir: /java-spring
volumes:
- .:/java-spring
- .:/java-spring
ports:
- 4000:4000
command: mvn clean spring-boot:run

View File

@ -40,7 +40,9 @@ public class ExampleData {
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor"
);
List<String> description_user_1 = List.of( // the description for user 1
"File author by default",
@ -48,14 +50,16 @@ public class ExampleData {
"He can review all the changes",
"He can do everything with the comments",
"The file favorite state is undefined",
"Can create a file from a template with data from the editor"
"Can create a file from a template with data from the editor",
"Can see the information about all users"
);
List<String> description_user_2 = List.of( // the description for user 2
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"He can view every comment, edit his comments and the comments left by the users who don't belong to any of the groups and remove only his comments",
"This file is favorite",
"Can create a file from an editor"
"Can create a file from an editor",
"Can see the information about users from Group2 and users who dont belong to any group"
);
List<String> description_user_3 = List.of( // the description for user 3
"He belongs to Group3",
@ -65,21 +69,24 @@ public class ExampleData {
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file",
"Can create a file from an editor"
"Can create a file from an editor",
"Can see the information about Group2 users"
);
userService.createUser("John Smith", "smith@example.com", // create user 1 with the specified parameters
description_user_1, null, List.of(FilterState.NULL.toString()),
description_user_1, "", List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), null);
List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()),
null);
userService.createUser("Mark Pottato", "pottato@example.com", // create user 2 with the specified parameters
description_user_2, "group-2", List.of("","group-2"), List.of(FilterState.NULL.toString()),
List.of("group-2", ""), List.of("group-2"), true);
List.of("group-2", ""), List.of("group-2"), List.of("group-2", ""), true);
userService.createUser("Hamish Mitchell", "mitchell@example.com", // create user 3 with the specified parameters
description_user_3, "group-3", List.of("group-2"), List.of("group-2", "group-3"),
List.of("group-2"), new ArrayList<>(), false);
List.of("group-2"), new ArrayList<>(), List.of("group-2"), false);
userService.createUser("Anonymous",null, // create user 0 with the specified parameters
description_user_0,null, List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), null);
description_user_0,"", List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()),
List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), new ArrayList<>(),null);
}
}

View File

@ -30,15 +30,23 @@ 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();
@ -58,6 +66,17 @@ 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

View File

@ -31,6 +31,7 @@ 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 org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -61,6 +62,12 @@ public class FileController {
@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
@ -79,6 +86,8 @@ public class FileController {
private ObjectMapper objectMapper;
@Autowired
private ServiceConverter serviceConverter;
@Autowired
private CallbackManager callbackManager;
// create user metadata
private String createUserMetadata(String uid, String fullFileName) {
@ -104,6 +113,18 @@ public class FileController {
.body(resource);
}
// download data from the specified history file
private ResponseEntity<Resource> downloadFileHistory(String fileName, String version, String file){
Resource resource = storageMutator.loadFileAsResourceHistory(fileName,version,file); // load the specified file as a resource
String contentType = "application/octet-stream";
// create a response with the content type, header and body with the file data
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
@PostMapping("/upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file, // upload a file
@ -202,6 +223,29 @@ public class FileController {
}
}
@GetMapping("/downloadhistory")
public ResponseEntity<Resource> downloadHistory(HttpServletRequest request,// download a file
@RequestParam("fileName") String fileName,
@RequestParam("ver") String version,
@RequestParam("file") String file){ // history file
try{
// check if a token is enabled or not
if(jwtManager.tokenEnabled()){
String header = request.getHeader(documentJwtHeader == null // get the document JWT header
|| documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
if(header != null && !header.isEmpty()){
String token = header.replace("Bearer ", ""); // token is the header without the Bearer prefix
jwtManager.readToken(token); // read the token
}else {
return null;
}
}
return downloadFileHistory(fileName,version,file); // download data from the specified file
} catch(Exception e){
return null;
}
}
@GetMapping(path = "${url.download}")
public ResponseEntity<Resource> download(HttpServletRequest request, // download a file
@RequestParam("fileName") String fileName){
@ -321,4 +365,22 @@ public class FileController {
return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
}
}
@PostMapping("/rename")
@ResponseBody
public String rename(@RequestBody JSONObject body) {
String newfilename = (String) body.get("newfilename");
String dockey = (String) body.get("dockey");
HashMap<String, String> meta = new HashMap<>();
meta.put("title", newfilename);
try {
callbackManager.commandRequest("meta", dockey, meta);
return "result ok";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}

View File

@ -64,6 +64,9 @@ public class IndexController {
@Value("${url.editor}")
private String urlEditor;
@Value("${files.docservice.languages}")
private String langs;
@GetMapping("${url.index}")
public String index(Model model){
java.io.File[] files = storageMutator.getStoredFiles(); // get all the stored files from the storage
@ -71,6 +74,14 @@ public class IndexController {
List<Boolean> filesEditable = new ArrayList<>();
List<String> versions = new ArrayList<>();
List<Boolean> isFillFormDoc = new ArrayList<>();
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
Map<String, String> languages = new HashMap<>();
langsAndKeys.forEach((str) -> {
String[] couple = str.split(":");
languages.put(couple[0], couple[1]);
});
List<User> users = userService.findAll(); // get a list of all the users
@ -95,6 +106,7 @@ public class IndexController {
model.addAttribute("datadocs", docserviceSite+docservicePreloader);
model.addAttribute("tooltip", tooltip);
model.addAttribute("users", users);
model.addAttribute("languages", languages);
return "index.html";
}

View File

@ -39,7 +39,7 @@ public class EditCallback implements Callback {
if (!body.getUsers().contains(user)) { // if this user is not specified in the body
String key = body.getKey(); // get document key
try {
callbackManager.commandRequest("forcesave", key); // create a command request to forcibly save the document being edited without closing it
callbackManager.commandRequest("forcesave", key, null); // create a command request to forcibly save the document being edited without closing it
} catch (Exception e) {
e.printStackTrace();
result = 1;

View File

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

View File

@ -94,7 +94,10 @@ public class DefaultCallbackManager implements CallbackManager {
String newFileName = fileName;
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = fileUtility.getFileExtension(downloadUri); // get an extension of the downloaded file
String downloadExt = "." + body.getFiletype(); // get an extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt != "." + null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
//TODO: Refactoring
if (!curExt.equals(downloadExt)) { // convert downloaded file to the file with the current extension if these extensions aren't equal
@ -150,16 +153,20 @@ public class DefaultCallbackManager implements CallbackManager {
//TODO: Replace (String method) with (Enum method)
@SneakyThrows
public void commandRequest(String method, String key) { // create a command request
public void commandRequest(String method, String key, HashMap meta) { // create a command request
String DocumentCommandUrl = docserviceUrlSite + docserviceUrlCommand;
URL url = new URL(DocumentCommandUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
HashMap<String, Object> params = new HashMap<>();
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;
if (jwtManager.tokenEnabled()) // check if a secret key to generate token exists or not
{
@ -212,7 +219,11 @@ public class DefaultCallbackManager implements CallbackManager {
String downloadUri = body.getUrl();
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
String downloadExt = fileUtility.getFileExtension(downloadUri); // get an extension of the downloaded file
String downloadExt = "."+body.getFiletype(); // get an extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt != "."+null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
Boolean newFileName = false;
// convert downloaded file to the file with the current extension if these extensions aren't equal

View File

@ -45,6 +45,8 @@ 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}")
@ -93,6 +95,9 @@ public class DefaultDocumentManager implements DocumentManager {
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());
@ -104,6 +109,27 @@ public class DefaultDocumentManager implements DocumentManager {
}
}
// get file URL
public String getHistoryFileUrl(String fileName, Integer version, String file, 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 filePath = serverPath + "/downloadhistory?fileName=" + URLEncoder.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString())
+ "&ver=" + version + "&file="+file
+ "&userAddress" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
return filePath;
}
catch (UnsupportedEncodingException | UnknownHostException e)
{
return "";
}
}
// get the callback URL
public String getCallback(String fileName)
{

View File

@ -25,6 +25,7 @@ import java.util.Map;
public interface DocumentManager {
String getCorrectName(String fileName); // get a file name with an index if the file with such a name already exists
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); // get URL to download a file
ArrayList<Map<String, Object>> getFilesInfo(); // get file information

View File

@ -87,9 +87,10 @@ public class DefaultHistoryManager implements HistoryManager {
obj.put("user", user);
}
dataObj.put("fileType", fileUtility.getFileExtension(document.getTitle()).replace(".", ""));
dataObj.put("key", key);
dataObj.put("url", i == curVer ? document.getUrl() :
documentManager.getFileUri(documentManager.versionDir(histDir, i, true) + File.separator + "prev" + fileUtility.getFileExtension(document.getTitle()), true));
documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility.getFileExtension(document.getTitle()), true));
dataObj.put("version", i);
if (i > 1) { //check if the version number is greater than 1
@ -105,11 +106,13 @@ public class DefaultHistoryManager implements HistoryManager {
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version
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"));
dataObj.put("previous", prevInfo); // write information about previous file version to the data object
// write the path to the diff.zip archive with differences in this file version
dataObj.put("changesUrl", documentManager.getFileUri(documentManager.versionDir(histDir, i - 1, true) + File.separator + "diff.zip", true));
Integer verdiff = i - 1;
dataObj.put("changesUrl", documentManager.getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true));
}
if (jwtManager.tokenEnabled()) dataObj.put("token", jwtManager.createToken(dataObj));

View File

@ -34,7 +34,6 @@ public class Customization { // the parameters which allow to customize the edi
@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 chat = true; // if the Chat menu button is displayed or hidden
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)
@ -44,4 +43,6 @@ public class Customization { // the parameters which allow to customize the edi
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 = false; // if the Submit form button is displayed or hidden
private Boolean about = true;
private Boolean feedback =true;
}

View File

@ -20,7 +20,6 @@ package com.onlyoffice.integration.documentserver.models.configurations;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
@ -30,8 +29,6 @@ import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
@Getter
@Setter
public class Goback { // the settings for the Open file location menu button and upper right corner button
@Autowired
@ -39,10 +36,12 @@ public class Goback { // the settings for the Open file location menu button an
@Value("${url.index}")
private String indexMapping;
@Getter
private String url; // the absolute URL to the website address which will be opened when clicking the Open file location menu button
@PostConstruct
private void init(){
this.url = storagePathBuilder.getServerUrl(false)+indexMapping;
private void init() {
this.url = storagePathBuilder.getServerUrl(false) + indexMapping;
}
}

View File

@ -49,5 +49,7 @@ public enum Language {
es,
tr,
uk,
vi
vi,
gl,
az
}

View File

@ -47,4 +47,6 @@ public class Permission extends AbstractModel { // the permission for the docum
private List<String> reviewGroups; // the groups whose changes the user can accept/reject
@Autowired
private CommentGroup commentGroups; // the groups whose comments the user can edit, remove and/or view
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> userInfoGroups;
}

View File

@ -16,6 +16,7 @@ public interface FileStorageMutator {
boolean writeToFile(String pathName, String payload); // write the payload to the file
boolean moveFile(Path source, Path destination); // move a file to the specified destination
Resource loadFileAsResource(String fileName); // load file as a resource
Resource loadFileAsResourceHistory(String fileName,String version,String file); // load file as a resource
File[] getStoredFiles(); // get a collection of all the stored files
void createMeta(String fileName, String uid, String uname); // create the file meta information
boolean createOrUpdateFile(Path path, InputStream stream); // create or update a file

View File

@ -85,10 +85,18 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
// get the storage directory
public String getStorageLocation(){
String serverPath = System.getProperty("user.dir"); // get the path to the server
String directory = serverPath // create the storage directory
+ File.separator + storageFolder
+ File.separator + this.storageAddress
+ File.separator;
String directory; // create the storage directory
if (Paths.get(this.storageAddress).isAbsolute()) {
directory = this.storageAddress + File.separator;
} else {
directory = serverPath
+ File.separator + storageFolder
+ File.separator + this.storageAddress
+ File.separator;
}
if (!Files.exists(Paths.get(directory))) {
createDirectory(Paths.get(directory));
}
return directory;
}
@ -238,6 +246,20 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return null;
}
public Resource loadFileAsResourceHistory(String fileName,String version,String file){
String fileLocation = getStorageLocation() + fileName + "-hist" + File.separator + version + File.separator + file; // get it by the file name
try {
Path filePath = Paths.get(fileLocation); // get the path to the file location
Resource resource = new UrlResource(filePath.toUri()); // convert the file path to URL
if(resource.exists()) return resource;
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
// get a collection of all the stored files
public File[] getStoredFiles()
{

View File

@ -0,0 +1,59 @@
package com.onlyoffice.integration.documentserver.util;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.springframework.stereotype.Component;
/**
* Disables and enables certificate and host-name checking in
* HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
* Has no effect on implementations such as Apache Http Client, Ok Http.
*/
@Component
public final class SSLUtils {
private final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
private final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
};
private final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
public void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
}

View File

@ -59,7 +59,7 @@ public class DefaultFileUtility implements FileUtility {
// spreadsheet extensions
private List<String> ExtsSpreadsheet = Arrays.asList(
".xls", ".xlsx", ".xlsm",
".xls", ".xlsx", ".xlsm", ".xlsb",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv");

View File

@ -47,4 +47,6 @@ public class Permission extends AbstractEntity {
private List<Group> commentsEditGroups;
@ManyToMany
private List<Group> commentsRemoveGroups;
@ManyToMany
private List<Group> userInfoGroups;
}

View File

@ -54,5 +54,6 @@ public class PermissionsMapper extends AbstractMapper<Permission, com.onlyoffice
source.getCommentsRemoveGroups().stream().map(g -> g.getName()).collect(Collectors.toList())
)
);
destination.setUserInfoGroups(source.getUserInfoGroups().stream().map(g -> g.getName()).collect(Collectors.toList()));
}
}

View File

@ -36,13 +36,15 @@ public class PermissionServices {
public Permission createPermission(List<Group> reviewGroups,
List<Group> commentViewGroups,
List<Group> commentEditGroups,
List<Group> commentRemoveGroups){
List<Group> commentRemoveGroups,
List<Group> userInfoGroups){
Permission permission = new Permission();
permission.setReviewGroups(reviewGroups); // define the groups whose changes the user can accept/reject
permission.setCommentsViewGroups(commentViewGroups); // defines the groups whose comments the user can view
permission.setCommentsEditGroups(commentEditGroups); // defines the groups whose comments the user can edit
permission.setCommentsRemoveGroups(commentRemoveGroups); // defines the groups whose comments the user can remove
permission.setUserInfoGroups(userInfoGroups);
permissionRepository.save(permission); // save new permissions

View File

@ -56,7 +56,7 @@ public class UserServices {
List<String> reviewGroups,
List<String> viewGroups,
List<String> editGroups,
List<String> removeGroups, Boolean favoriteDoc){
List<String> removeGroups, List<String> userInfoGroups, Boolean favoriteDoc){
User newUser = new User();
newUser.setName(name); // set the user name
newUser.setEmail(email); // set the user email
@ -68,9 +68,10 @@ public class UserServices {
List<Group> commentGroupsView = groupServices.createGroups(viewGroups); // defines the groups whose comments the user can view
List<Group> commentGroupsEdit = groupServices.createGroups(editGroups); // defines the groups whose comments the user can edit
List<Group> commentGroupsRemove = groupServices.createGroups(removeGroups); // defines the groups whose comments the user can remove
List<Group> usInfoGroups = groupServices.createGroups(userInfoGroups);
Permission permission = permissionService
.createPermission(groupsReview, commentGroupsView, commentGroupsEdit, commentGroupsRemove); // specify permissions for the current user
.createPermission(groupsReview, commentGroupsView, commentGroupsEdit, commentGroupsRemove, usInfoGroups); // specify permissions for the current user
newUser.setPermissions(permission);
userRepository.save(newUser); // save a new user

View File

@ -85,7 +85,7 @@ public class DefaultEditorConfigConfigurer implements EditorConfigConfigurer<Def
defaultCustomizationConfigurer.configure(config.getCustomization(), DefaultCustomizationWrapper.builder() // define the customization configurer
.action(action)
.user(wrapper.getUser())
.user(userIsAnon ? null : wrapper.getUser())
.build());
config.setMode(canEdit && !action.equals(Action.view) ? Mode.edit : Mode.view);
config.setUser(mapper.toModel(wrapper.getUser()));

View File

@ -1,6 +1,6 @@
server.version=1.0.0
server.version=1.2.0
server.address=127.0.0.1
server.address=
server.port=4000
filesize-max=5242880
@ -11,7 +11,7 @@ files.storage.folder=documents
files.docservice.fillforms-docs=.oform|.docx
files.docservice.viewed-docs=.pdf|.djvu|.xps|.oxps
files.docservice.edited-docs=.docx|.xlsx|.csv|.pptx|.txt|.docxf
files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2
files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2
files.docservice.timeout=120000
files.docservice.history.postfix=-hist
@ -25,6 +25,10 @@ files.docservice.url.example=
files.docservice.secret=
files.docservice.header=Authorization
files.docservice.verify-peer-off=true
files.docservice.languages=en:English|az:Azerbaijani|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese|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|lv:Latvian|lo:Lao|nb:Norwegian|pl:Polish|pt:Portuguese|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese
spring.datasource.url=jdbc:h2:mem:usersdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa

View File

@ -129,6 +129,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.left-panel {
width: 90%;
}
@ -367,6 +371,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -440,6 +448,58 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,7 +22,7 @@ html {
}
body {
display: inline-table;
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -98,6 +98,10 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -740,12 +744,9 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -30,6 +30,7 @@
<script th:inline="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
if (console && console.log)
@ -90,10 +91,13 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite);
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite);
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
};
@ -115,7 +119,7 @@
docEditor.setMailMergeRecipients([[${dataMailMergeRecipients}]]);
};
var config = [[${model}]];
config = [[${model}]];
if (config.editorConfig.user.name == "Anonymous") {
config.editorConfig.user.name = "";
@ -130,7 +134,7 @@
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "saveas");
xhr.setRequestHeader( 'Content-Type', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
@ -138,6 +142,23 @@
}
};
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config.width = "100%";
config.height = "100%";
config.events = {
@ -158,24 +179,23 @@
var historyData = histArray[1];
var usersForMentions = [[${usersForMentions}]];
if (hist && historyData) {
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(JSON.parse(hist)); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = historyData;
docEditor.setHistoryData(JSON.parse(histData)[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
}
if(usersForMentions){
if (config.editorConfig.user.id != 4) {
if (hist && historyData) {
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(JSON.parse(hist)); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = historyData;
docEditor.setHistoryData(JSON.parse(histData)[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
}
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
@ -184,10 +204,12 @@
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, event.data.actionLink);
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
if (config.editorConfig.createUrl) {
@ -195,6 +217,12 @@
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -2,6 +2,7 @@
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width" />
<!--
*
* (c) Copyright Ascensio System SIA 2021
@ -55,7 +56,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Master form</a>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
@ -86,37 +87,9 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<option value="en" selected="selected">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
<option th:each="language: ${languages}"
th:value="${language.key}"
th:text="${language.value}"/>
</select>
</td>
</tr>
@ -127,12 +100,13 @@
</td>
<td class="section">
<div class="main-panel">
<div id="portal-info" th:attr="tooltip=${tooltip}" th:style="${not #lists.isEmpty(files)} ? 'display: none' : 'display: block' ">
<div id="portal-info" th:attr="tooltip=${tooltip}" th:style="${not #lists.isEmpty(files)} ? 'display: none' : 'display: table-cell' ">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<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>
</div>
<th:block th:if="${not #lists.isEmpty(files)}">
@ -189,9 +163,6 @@
</a>
</td>
</div>
<div th:if="${docTypes[iState.index]} eq 'slide'">
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
</div>
<div th:if="${docTypes[iState.index]} eq 'word'">
<td class="contentCells contentCells-icon">
<a th:href="@{/editor(fileName=${files[iState.index].getName()},type='desktop',action='blockcontent')}" target="_blank">
@ -298,10 +269,8 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -310,10 +279,12 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
</div>
<span id="loadScripts" th:attr="data-docs=${datadocs}"></span>
@ -346,5 +317,10 @@
<script type="text/javascript" src="scripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="scripts/jscript.js"></script>
<script type="text/javascript" src="scripts/converter.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function(){
document.getElementById("language").value="en";
});
</script>
</body>
</html>

View File

@ -0,0 +1,9 @@
FROM maven:3.6.1-jdk-8-alpine AS MVN_BLDR
COPY pom.xml /tmp/
COPY src /tmp/src/
WORKDIR /tmp/
RUN mvn package
FROM tomcat:alpine
RUN rm -fr /usr/local/tomcat/webapps/ROOT
COPY --from=MVN_BLDR /tmp/target/*.war $CATALINA_HOME/webapps/ROOT.war

View File

@ -1,14 +1,14 @@
## Overview
This example will help you integrate ONLYOFFICE Docs into your web application written in Java.
This example will help you integrate ONLYOFFICE Docs into your web application written in Java.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
## For Windows
### Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to [install Document Server for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
@ -16,13 +16,14 @@ See the detailed guide to learn how to [install Document Server for Windows](htt
Download the [Java example](https://api.onlyoffice.com/editors/demopreview) from our site.
To connect the editors to your website, specify the path to the editors installation in the *\src\main\resources\settings.properties* file:
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *\src\main\resources\settings.properties* file:
```
storage-folder = app_data
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-folder** is the path where files will be created and stored. You can set an absolute path. For example, *D:\\\\folder*. Please note that on Windows OS the double backslash must be used as a separator.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *\src\main\webapp\editor.jsp* file.
@ -96,7 +97,7 @@ To run the Java example code, install the Java version appropriate for your OS a
2. Tomcat Web Application Manager will request the **username** and the **password:**
![author](screenshots/author.jpg)
Specify user data in *tomcat-users.xml* file in the Apache Tomcat installation folder. Define the **manager-gui** user role, specify the **user name** and **password** values:
@ -106,18 +107,22 @@ To run the Java example code, install the Java version appropriate for your OS a
<user username="tomcat" password="tomcat" roles="manager-gui"/>
</tomcat-users>
```
3. Upload the Java project in Tomcat Web Application Manager. For that click **Choose File** in the **WAR file to deploy** section and find the *.war* file in the Java project folder, then click **Deploy**.
3. Build the project using the following commands
```
mvn clean
mvn package
```
4. Upload the Java project in Tomcat Web Application Manager. For that click **Choose File** in the **WAR file to deploy** section and find the *.war* file in the Java project folder, then click **Deploy**.
![upload-app](screenshots/upload-app.jpg)
![war-file](screenshots/war-file.jpg)
4. You will see the project in the **Application List**:
5. You will see the project in the **Application List**:
![manager-app](screenshots/manager-app.jpg)
5. Click the link with the application name to run it.
6. Click the link with the application name to run it.
### Step 6. Check accessibility
@ -163,13 +168,17 @@ See the detailed guide to learn how to [install Document Server for Linux](https
nano src/main/resources/settings.properties
```
Edit the following line:
Edit the following lines:
```
storage-folder = app_data
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-folder** is the path where files will be created and stored. Please note that you must have read and write permissions to the folder. If you do not have them, please use the next command:
```
sudo chmod -R ugo+rw /{path}
```
5. Install **Maven**:
@ -238,13 +247,14 @@ Make sure that the Document Server has access to the server with the example ins
nano src/main/resources/settings.properties
```
2. Edit the following line:
2. Edit the following lines:
```
storage-folder = app_data
files.docservice.url.site=https://documentserver/
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed and the **storage-folder** is the path where files will be created and stored.
3. Run the next command in the Java example directory:
@ -253,3 +263,12 @@ Make sure that the Document Server has access to the server with the example ins
```
4. After it, all the *bin* files will be passed to the *./target* folder.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

View File

@ -1,7 +1,9 @@
version: '3'
services:
build:
image: maven:3.6
volumes:
- .:/java
command: mvn -f /java package
java-intg-ex:
build:
context: ./
dockerfile: Dockerfile
ports:
- 8080:8080

View File

@ -45,8 +45,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<source>8</source>
<target>8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>

View File

@ -72,7 +72,7 @@ public class EditorServlet extends HttpServlet
// create file model (get all the necessary parameters from cookies)
FileModel file = new FileModel(fileName, cm.getCookie("ulang"), request.getParameter("actionLink"), user);
// change type parameter if needed
file.changeType(request.getParameter("mode"), request.getParameter("type"), user);
file.changeType(request.getParameter("mode"), request.getParameter("type"), user, fileName);
// an image that will be inserted into the document
Map<String, Object> dataInsertImage = new HashMap<>();

View File

@ -29,6 +29,7 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import helpers.*;
public class GlobalServletContextListener implements ServletContextListener
{
@ -70,16 +71,19 @@ public class GlobalServletContextListener implements ServletContextListener
SSLContext sc;
try
{
// register the all-trusting trust manager for HTTPS
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
catch (NoSuchAlgorithmException | KeyManagementException ex)
{
if(!ConfigManager.GetProperty("files.docservice.verify-peer-off").isEmpty()) {
try
{
// register the all-trusting trust manager for HTTPS
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
catch (NoSuchAlgorithmException | KeyManagementException ex)
{
}
}
// create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier()

View File

@ -29,6 +29,8 @@ import java.util.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
@ -36,7 +38,9 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import entities.FileType;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@ -45,6 +49,7 @@ import org.primeframework.jwt.Verifier;
import org.primeframework.jwt.domain.JWT;
import org.primeframework.jwt.hmac.HMACVerifier;
@WebServlet(name = "IndexServlet", urlPatterns = {"/IndexServlet"})
@MultipartConfig
public class IndexServlet extends HttpServlet
@ -72,6 +77,10 @@ public class IndexServlet extends HttpServlet
break;
case "download":
Download(request, response, writer);
break;
case "downloadhistory":
DownloadHistory(request, response, writer);
break;
case "convert":
Convert(request, response, writer);
break;
@ -93,6 +102,9 @@ public class IndexServlet extends HttpServlet
case "saveas":
SaveAs(request, response, writer);
break;
case "rename":
Rename(request, response, writer);
break;
}
}
@ -317,7 +329,7 @@ public class IndexServlet extends HttpServlet
if (users.indexOf(user) == -1) {
String key = (String) body.get("key");
try {
TrackManager.commandRequest("forcesave", key); // create a command request with the forcesave method
TrackManager.commandRequest("forcesave", key, null); // create a command request with the forcesave method
} catch (Exception e) {
e.printStackTrace();
}
@ -430,14 +442,53 @@ public class IndexServlet extends HttpServlet
download(filePath.toString(), response, writer);
}
// download a file from history
private static void DownloadHistory(HttpServletRequest request, HttpServletResponse response, PrintWriter writer)
{
try {
if (DocumentManager.TokenEnabled()) {
String DocumentJwtHeader = ConfigManager.GetProperty("files.docservice.header");
String header = (String) request.getHeader(DocumentJwtHeader == null || DocumentJwtHeader.isEmpty() ? "Authorization" : DocumentJwtHeader);
if (header != null && !header.isEmpty()) {
String token = header.startsWith("Bearer ") ? header.substring(7) : header;
try {
Verifier verifier = HMACVerifier.newVerifier(DocumentManager.GetTokenSecret());
JWT jwt = JWT.getDecoder().decode(token, verifier);
} catch (Exception e) {
response.sendError(403, "JWT validation failed");
return;
}
} else {
response.sendError(403, "JWT validation failed");
return;
}
}
String fileName = FileUtility.GetFileName(request.getParameter("fileName"));
String userAddress = request.getParameter("userAddress");
String ver = request.getParameter("ver"); // Document version
String file = request.getParameter("file"); // File. If not defined, then Prev.*
String filePath = DocumentManager.HistoryPath(fileName, userAddress, ver, file);
download(filePath, response, writer);
} catch (Exception e) {
writer.write("{ \"error\": \"File not found\"}");
}
}
// download a file
private static void Download(HttpServletRequest request, HttpServletResponse response, PrintWriter writer)
{
try {
String fileName = FileUtility.GetFileName(request.getParameter("fileName"));
String userAddress = request.getParameter("userAddress");
String isEmbedded = request.getParameter("dmode");
if (DocumentManager.TokenEnabled()) {
if (DocumentManager.TokenEnabled() && isEmbedded == null) {
String DocumentJwtHeader = ConfigManager.GetProperty("files.docservice.header");
@ -508,6 +559,32 @@ public class IndexServlet extends HttpServlet
}
}
// rename a file
private static void Rename(HttpServletRequest request, HttpServletResponse response, PrintWriter writer) {
try {
Scanner scanner = new Scanner(request.getInputStream());
scanner.useDelimiter("\\A");
String bodyString = scanner.hasNext() ? scanner.next() : "";
scanner.close();
JSONParser parser = new JSONParser();
JSONObject body = (JSONObject) parser.parse(bodyString);
String newfilename = (String) body.get("newfilename");
String dockey = (String) body.get("dockey");
HashMap<String, String> meta = new HashMap<>();
meta.put("title", newfilename);
TrackManager.commandRequest("meta", dockey, meta);
} catch (Exception e) {
e.printStackTrace();
writer.write("{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}");
}
}
// process get request
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

View File

@ -20,16 +20,14 @@ package entities;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import helpers.DocumentManager;
import helpers.FileUtility;
import helpers.ServiceConverter;
import helpers.Users;
import helpers.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.*;
public class FileModel
@ -54,7 +52,6 @@ public class FileModel
document = new Document();
document.title = fileName;
document.url = DocumentManager.GetDownloadUrl(fileName); // get file url
document.urlUser = DocumentManager.GetFileUri(fileName, false);
document.fileType = FileUtility.GetFileExtension(fileName).replace(".", ""); // get file extension from the file name
// generate document key
document.key = ServiceConverter.GenerateRevisionId(DocumentManager.CurUserHostAddress(null) + "/" + fileName + "/" + Long.toString(new File(DocumentManager.StoragePath(fileName, null)).lastModified()));
@ -87,18 +84,18 @@ public class FileModel
editorConfig.templates = user.templates ? templates : null;
// write user information to the config (id, name and group)
editorConfig.user.id = user.id;
editorConfig.user.id = !user.id.equals("uid-0") ? user.id : null;
editorConfig.user.name = user.name;
editorConfig.user.group = user.group;
// write the absolute URL to the file location
editorConfig.customization.goback.url = DocumentManager.GetServerUrl(false) + "/IndexServlet";
changeType(mode, type, user);
changeType(mode, type, user, fileName);
}
// change the document type
public void changeType(String _mode, String _type, User user)
public void changeType(String _mode, String _type, User user, String fileName)
{
if (_mode != null) mode = _mode;
if (_type != null) type = _type;
@ -119,12 +116,12 @@ public class FileModel
// set document permissions
document.permissions = new Permissions(mode, type, canEdit, user);
if (type.equals("embedded")) InitDesktop(); // set parameters for the embedded document
if (type.equals("embedded")) InitDesktop(fileName); // set parameters for the embedded document
}
public void InitDesktop()
public void InitDesktop(String fileName)
{
editorConfig.InitDesktop(document.urlUser);
editorConfig.InitDesktop(DocumentManager.GetDownloadUrl(fileName) + "&dmode=emb");
}
// generate document token
@ -167,7 +164,7 @@ public class FileModel
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
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)
@ -178,8 +175,9 @@ public class FileModel
obj.put("user", user);
}
dataObj.put("fileType", FileUtility.GetFileExtension(document.title).substring(1));
dataObj.put("key", key);
dataObj.put("url", i == curVer ? document.url : DocumentManager.GetPathUri(verDir + File.separator + "prev" + FileUtility.GetFileExtension(document.title)));
dataObj.put("url", i == curVer ? document.url : DocumentManager.GetDownloadHistoryUrl(document.title, i, "prev" + FileUtility.GetFileExtension(document.title)));
dataObj.put("version", i);
if (i > 1) { //check if the version number is greater than 1
@ -195,11 +193,14 @@ public class FileModel
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version
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"));
dataObj.put("previous", prevInfo); // write information about previous file version to the data object
// write the path to the diff.zip archive with differences in this file version
dataObj.put("changesUrl", DocumentManager.GetPathUri(DocumentManager.VersionDir(histDir, i - 1) + File.separator + "diff.zip"));
Integer verdiff = i - 1;
String changesUrl = DocumentManager.GetDownloadHistoryUrl(document.title, verdiff, "diff.zip");
dataObj.put("changesUrl", changesUrl);
}
if (DocumentManager.TokenEnabled())
@ -246,7 +247,6 @@ public class FileModel
{
public String title;
public String url;
public String urlUser;
public String fileType;
public String key;
public Info info;
@ -267,6 +267,7 @@ public class FileModel
public Boolean review;
public List<String> reviewGroups;
public CommentGroups commentGroups;
public List<String> userInfoGroups;
// defines what can be done with a document
public Permissions(String mode, String type, Boolean canEdit, User user)
@ -282,13 +283,21 @@ public class FileModel
review = canEdit && (mode.equals("edit") || mode.equals("review"));
reviewGroups = user.reviewGroups;
commentGroups = user.commentGroups;
userInfoGroups = user.userInfoGroups;
}
}
// the Favorite icon state
public class Info
{
public String owner = "Me";
public Boolean favorite;
public String uploaded = getDate();
private String getDate() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);
return simpleDateFormat.format(new Date());
}
}
// the editor config parameters
public class EditorConfig
@ -338,9 +347,15 @@ public class FileModel
public Goback goback;
public Boolean forcesave;
public Boolean submitForm;
public Boolean about;
public Boolean comments;
public Boolean feedback;
public Customization()
{
about = true;
comments = true;
feedback = true;
forcesave = false;
goback = new Goback();
}

View File

@ -31,8 +31,9 @@ public class User {
public List<String> deniedPermissions;
public List<String> descriptions;
public Boolean templates;
public List<String> userInfoGroups;
public User(String id, String name, String email, String group, List<String> reviewGroups, CommentGroups commentGroups,
public User(String id, String name, String email, String group, List<String> reviewGroups, CommentGroups commentGroups, List<String> userInfoGroups,
Boolean favorite, List<String> deniedPermissions, List<String> descriptions, Boolean templates) {
this.id = id;
this.name = name;
@ -44,5 +45,6 @@ public class User {
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
this.userInfoGroups = userInfoGroups;
}
}

View File

@ -130,7 +130,20 @@ public class DocumentManager
String hostAddress = CurUserHostAddress(userAddress); // get current user host address
String serverPath = request.getSession().getServletContext().getRealPath(""); // get the server url
String storagePath = ConfigManager.GetProperty("storage-folder"); // get the storage directory
String directory = serverPath + storagePath + File.separator + hostAddress + File.separator;
File f = new File(storagePath);
if (f.isAbsolute()) {
if (!f.exists()) {
if (Files.isWritable(Paths.get(storagePath.substring(0, storagePath.lastIndexOf(File.separator))))) {
f.mkdirs();
} else {
throw new SecurityException("No write permission to path: " + f.toPath());
}
} else if (f.exists() && f.isFile()) {
throw new SecurityException("The path to the file is specified instead of the folder");
}
}
String directory = !f.isAbsolute() ? serverPath + storagePath + File.separator + hostAddress + File.separator : storagePath + File.separator;
File file = new File(directory);
@ -151,6 +164,22 @@ public class DocumentManager
return directory + FileUtility.GetFileName(fileName);
}
// get the path to history file
public static String HistoryPath(String fileName, String userAddress, String version, String file)
{
String hostAddress = CurUserHostAddress(userAddress);
String serverPath = request.getSession().getServletContext().getRealPath("");
String storagePath = ConfigManager.GetProperty("storage-folder");
String directory = serverPath + storagePath + File.separator + hostAddress + File.separator;
if (new File(storagePath).isAbsolute()) {
directory = FilesRootPath(userAddress);
}
directory = directory + fileName + "-hist" + File.separator + version + File.separator + file;
return directory;
}
// get the path to the forcesaved file version
public static String ForcesavePath(String fileName, String userAddress, Boolean create)
{
@ -320,13 +349,20 @@ public class DocumentManager
{
String serverPath = GetServerUrl(forDocumentServer);
String storagePath = ConfigManager.GetProperty("storage-folder");
File f = new File(storagePath);
String hostAddress = CurUserHostAddress(null);
String filePath = serverPath + "/" + storagePath + "/" + hostAddress + "/" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()).replace("+", "%20");
if (f.isAbsolute() && f.isFile()) {
filePath = GetDownloadUrl(fileName);
if (!Files.isWritable(f.toPath())) {
throw new SecurityException("No write permission to path: " + f.toPath());
}
}
return filePath;
}
catch (UnsupportedEncodingException e)
catch (Exception e)
{
return "";
}
@ -429,6 +465,23 @@ public class DocumentManager
}
}
// get url to download a file to History prev.*
public static String GetDownloadHistoryUrl(String fileName, Integer version, String file) {
String serverPath = GetServerUrl(true);
String hostAddress = CurUserHostAddress(null);
try
{
String query = "?type=downloadhistory&fileName=" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) + "&userAddress=" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
query = query + "&ver=" + version + "&file=" + URLEncoder.encode(file, java.nio.charset.StandardCharsets.UTF_8.toString());
return serverPath + "/IndexServlet" + query;
}
catch (UnsupportedEncodingException e)
{
return "";
}
}
// get an editor internal extension
public static String GetInternalExtension(FileType fileType)
{
@ -515,4 +568,19 @@ public class DocumentManager
{
return ConfigManager.GetProperty("files.docservice.secret");
}
// get languages
public static Map<String, String> GetLanguages()
{
String langs = ConfigManager.GetProperty("files.docservice.languages");
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
Map<String, String> languages = new HashMap<>();
langsAndKeys.forEach((str) -> {
String[] couple = str.split(":");
languages.put(couple[0], couple[1]);
});
return languages;
}
}

View File

@ -63,7 +63,7 @@ public class FileUtility
// spreadsheet extensions
public static List<String> ExtsSpreadsheet = Arrays.asList
(
".xls", ".xlsx", ".xlsm",
".xls", ".xlsx", ".xlsm", ".xlsb",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv"
);

View File

@ -127,7 +127,10 @@ public class TrackManager {
String newFileName = fileName;
String curExt = FileUtility.GetFileExtension(fileName); // get current file extension
String downloadExt = FileUtility.GetFileExtension(downloadUri); // get the extension of the downloaded file
String downloadExt = "." + (String) body.get("filetype"); // get the extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt == "." + null) downloadExt = FileUtility.GetFileExtension(downloadUri); // Support for versions below 7.0
// convert downloaded file to the file with the current extension if these extensions aren't equal
if (!curExt.equals(downloadExt)) {
@ -188,7 +191,11 @@ public class TrackManager {
String downloadUri = (String) body.get("url");
String curExt = FileUtility.GetFileExtension(fileName); // get current file extension
String downloadExt = FileUtility.GetFileExtension(downloadUri); // get the extension of the downloaded file
String downloadExt = "."+(String) body.get("filetype"); // get the extension of the downloaded file
// Todo [Delete in version 7.0 or higher]
if (downloadExt == "."+null) downloadExt = FileUtility.GetFileExtension(downloadUri); // Support for versions below 7.0
Boolean newFileName = false;
// convert downloaded file to the file with the current extension if these extensions aren't equal
@ -270,7 +277,7 @@ public class TrackManager {
}
// create a command request
public static void commandRequest(String method, String key) throws Exception {
public static void commandRequest(String method, String key, HashMap meta) throws Exception {
String DocumentCommandUrl = ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.command");
URL url = new URL(DocumentCommandUrl);
@ -280,6 +287,10 @@ public class TrackManager {
params.put("c", method);
params.put("key", key);
if (meta != null) {
params.put("meta", meta);
}
String headerToken = "";
if (DocumentManager.TokenEnabled()) // check if a secret key to generate token exists or not
{
@ -307,7 +318,7 @@ public class TrackManager {
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte); // write bytes to the output stream
}
InputStream stream = connection.getInputStream();; // get input stream
InputStream stream = connection.getInputStream(); // get input stream
if (stream == null)
throw new Exception("Could not get an answer");

View File

@ -31,6 +31,7 @@ public class Users {
add("Can perform all actions with comments");
add("The file favorite state is undefined");
add("Can create files from templates using data from the editor");
add("Can see the information about all users");
}};
static List<String> descr_user_2 = new ArrayList<String>() {{
@ -39,17 +40,19 @@ public class Users {
add("Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only");
add("This file is marked as favorite");
add("Can create new files from the editor");
add("Can see the information about users from Group2 and users who dont belong to any group");
}};
static List<String> descr_user_3 = new ArrayList<String>() {{
add("Belongs to Group3");
add("Can review changes made by Group2 users");
add("Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users");
add("Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users");
add("This file isnt marked as favorite");
add("Cant copy data from the file to clipboard");
add("Cant download the file");
add("Cant print the file");
add("Can create new files from the editor");
add("Can see the information about Group2 users");
}};
static List<String> descr_user_0 = new ArrayList<String>() {{
@ -60,20 +63,22 @@ public class Users {
add("The file favorite state is undefined");
add("Can't mention others in comments");
add("Can't create new files from the editor");
add("Cant see anyones information");
add("Can't rename files from the editor");
}};
private static List<User> users = new ArrayList<User>() {{
add(new User("uid-1", "John Smith", "smith@example.com",
null, null, new CommentGroups(),
"", null, new CommentGroups(), null,
null, new ArrayList<String>(), descr_user_1, true));
add(new User("uid-2", "Mark Pottato", "pottato@example.com",
"group-2", Arrays.asList("group-2", ""), new CommentGroups(null, Arrays.asList("group-2", ""), Arrays.asList("group-2")),
"group-2", Arrays.asList("group-2", ""), new CommentGroups(null, Arrays.asList("group-2", ""), Arrays.asList("group-2")), Arrays.asList("group-2", ""),
true, new ArrayList<String>(), descr_user_2, false));
add(new User("uid-3", "Hamish Mitchell", "mitchell@example.com",
"group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"), Arrays.asList("group-2"), new ArrayList<String>()),
"group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"), Arrays.asList("group-2"), new ArrayList<String>()), Arrays.asList("group-2"),
false, Arrays.asList("copy", "download", "print"), descr_user_3, false));
add(new User("uid-0", null, null,
null, null, new CommentGroups(),
"", null, new CommentGroups(), new ArrayList<String>(),
null, new ArrayList<String>(), descr_user_0, false));
}};

View File

@ -1,4 +1,4 @@
version=1.0.0
version=1.2.0
filesize-max=5242880
storage-folder=app_data
@ -6,7 +6,7 @@ storage-folder=app_data
files.docservice.fill-docs=.oform|.docx
files.docservice.viewed-docs=.pdf|.djvu|.xps|.oxps
files.docservice.edited-docs=.docx|.xlsx|.csv|.pptx|.txt|.docxf
files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2
files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2
files.docservice.timeout=120000
files.docservice.url.site=http://documentserver/
@ -16,5 +16,9 @@ files.docservice.url.api=web-apps/apps/api/documents/api.js
files.docservice.url.preloader=web-apps/apps/api/documents/cache-scripts.html
files.docservice.url.example=
files.docservice.languages=en:English|az:Azerbaijani|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese|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|lv:Latvian|lo:Lao|nb:Norwegian|pl:Polish|pt:Portuguese|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese
files.docservice.secret=
files.docservice.header=Authorization
files.docservice.header=Authorization
files.docservice.verify-peer-off=TRUE

View File

@ -86,10 +86,6 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -127,6 +123,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -299,6 +299,9 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -353,6 +356,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -422,6 +429,58 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -22,6 +22,7 @@ html {
}
body {
display: block;
background: #FFFFFF;
color: #333333;
font-family: Open Sans;
@ -71,6 +72,7 @@ header img {
}
.main{
display: table;
height: calc(100% - 112px);
min-height: 536px;
}
@ -97,6 +99,10 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -735,12 +741,9 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

View File

@ -36,6 +36,7 @@
<script type="text/javascript" language="javascript">
var docEditor;
var config;
var innerAlert = function (message, inEditor) {
if (console && console.log)
@ -97,10 +98,14 @@
// the meta information of the document is changed via the meta command
var onMetaChange = function (event) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
if (event.data.favorite) {
var favorite = !!event.data.favorite;
var title = document.title.replace(/^\☆/g, "");
document.title = (favorite ? "☆" : "") + title;
docEditor.setFavorite(favorite); // change the Favorite icon state
}
innerAlert("onMetaChange: " + JSON.stringify(event.data));
};
// the user is trying to insert an image by clicking the Image from Storage button
@ -130,7 +135,7 @@
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "IndexServlet?type=saveas");
xhr.setRequestHeader( 'Content-Type', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
@ -138,7 +143,24 @@
}
};
var config = JSON.parse('<%= FileModel.Serialize(Model) %>');
var onRequestRename = function(event) { // the user is trying to rename file by clicking Rename... button
innerAlert("onRequestRename: " + JSON.stringify(event.data));
var newfilename = event.data;
var data = {
newfilename: newfilename,
dockey: config.document.key,
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "IndexServlet?type=rename");
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
xhr.onload = function () {
innerAlert(xhr.responseText);
}
};
config = JSON.parse('<%= FileModel.Serialize(Model) %>');
config.width = "100%";
config.height = "100%";
config.events = {
@ -161,43 +183,50 @@
String usersForMentions = (String) request.getAttribute("usersForMentions");
%>
<% if (!history.isEmpty() && !historyData.isEmpty()) { %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= history %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= historyData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
<% } %>
<% if (usersForMentions != null) { %>
if (config.editorConfig.user.id) {
<% if (!history.isEmpty() && !historyData.isEmpty()) { %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= history %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= historyData %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
config.events['onRequestHistoryClose'] = function () {
document.location.reload();
};
<% } %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({ // set a list of users to mention in the comments
"users": ${usersForMentions}
"users": <%=usersForMentions%>
});
};
// the user is mentioned in a comment
config.events['onRequestSendNotify'] = function (event) {
event.data.actionLink = replaceActionLink(location.href, event.data.actionLink);
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
var data = JSON.stringify(event.data);
innerAlert("onRequestSendNotify: " + data);
};
<% } %>
// prevent file renaming for anonymous users
config.events['onRequestRename'] = onRequestRename;
}
if (config.editorConfig.createUrl) {
config.events.onRequestSaveAs = onRequestSaveAs;
};
var сonnectEditor = function () {
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
return;
}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -4,6 +4,8 @@
<%@page import="java.util.Calendar"%>
<%@page import="java.io.File"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.util.Map.Entry"%>
<%@page import="java.util.Map"%>
<%@page import="helpers.Users"%>
<%@page import="entities.User"%>
@ -13,6 +15,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width" />
<!--
*
* (c) Copyright Ascensio System SIA 2021
@ -65,7 +68,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Master form</a>
<a class="try-editor form" data-type="docxf">Form template</a>
</li>
</ul>
<label class="create-sample">
@ -96,37 +99,10 @@
<td valign="middle">
<span class="select-user">Language editors interface</span>
<select class="select-user" id="language">
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
<% Map<String, String> languages = DocumentManager.GetLanguages(); %>
<% for (Map.Entry<String, String> language : languages.entrySet()) { %>
<option value="<%=language.getKey()%>"><%=language.getValue()%></option>
<% } %>
</select>
</td>
</tr>
@ -139,12 +115,13 @@
<% DocumentManager.Init(request, response); %>
<% File[] files = DocumentManager.GetStoredFiles(null); %>
<div class="main-panel">
<div id="portal-info" style="display: <%= files.length > 0 ? "none" : "block" %>">
<div id="portal-info" style="display: <%= files.length > 0 ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
<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>
<% for (User user : Users.getAllUsers()) { %>
<div class="user-descr">
@ -180,7 +157,7 @@
Boolean canEdit = DocumentManager.GetEditedExts().contains(FileUtility.GetFileExtension(files[i].getName()));
String version=" ["+DocumentManager.GetFileVersion(DocumentManager.HistoryDir(DocumentManager.StoragePath(files[i].getName(), null)))+"]";
%>
<tr class="tableRow" title="<%= files[i].getName() %> [<%= version %>]">
<tr class="tableRow" title="<%= files[i].getName() %><%= version %>">
<td class="contentCells">
<a class="stored-edit <%= docType %>" href="EditorServlet?fileName=<%= URLEncoder.encode(files[i].getName(), "UTF-8") %>" target="_blank">
<span><%= files[i].getName() %></span>
@ -215,9 +192,6 @@
</a>
</td>
<% } %>
<% if (!docType.equals("cell") && !docType.equals("word")) { %>
<td class="contentCells contentCells-icon contentCellsEmpty"></td>
<% } %>
<% if (docType.equals("word")) { %>
<td class="contentCells contentCells-icon">
<a href="EditorServlet?fileName=<%= URLEncoder.encode(files[i].getName(), "UTF-8") %>&type=desktop&mode=blockcontent" target="_blank">
@ -320,10 +294,8 @@
<span class="step-descr">They are loaded only once, they will be cached on your computer.</span>
<input type="hidden" name="hiddenFileName" id="hiddenFileName" />
<br />
<br />
<span class="progress-descr">Note the speed of all operations depends on your connection quality and server location.</span>
<br />
<br />
<div class="error-message">
<b>Upload error: </b><span></span>
<br />
@ -332,10 +304,12 @@
</div>
<iframe id="embeddedView" src="" height="345px" width="432px" frameborder="0" scrolling="no" allowtransparency></iframe>
<br />
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
<div class="buttonsMobile">
<div id="beginEdit" class="button orange disable">Edit</div>
<div id="beginView" class="button gray disable">View</div>
<div id="beginEmbedded" class="button gray disable">Embedded view</div>
<div id="cancelEdit" class="button gray">Cancel</div>
</div>
</div>
<span id="loadScripts" data-docs="<%= ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.preloader") %>"></span>
@ -374,7 +348,10 @@
var EditedExtList = "<%= String.join(",", DocumentManager.GetEditedExts()) %>";
var UrlConverter = "IndexServlet?type=convert";
var UrlEditor = "EditorServlet";
</script>
document.addEventListener('DOMContentLoaded', function(){
document.getElementById("language").value="en";
});
</script>
</body>
</html>

View File

@ -66,7 +66,7 @@ function key(k) {
var getDocumentType = function (ext) {
if (".doc.docx.docm.dot.dotx.dotm.odt.fodt.ott.rtf.txt.html.htm.mht.xml.pdf.djvu.fb2.epub.xps.oxps".indexOf(ext) != -1) return "text";
if (".xls.xlsx.xlsm.xlt.xltx.xltm.ods.fods.ots.csv".indexOf(ext) != -1) return "spreadsheet";
if (".xls.xlsx.xlsm.xlsb.xlt.xltx.xltm.ods.fods.ots.csv".indexOf(ext) != -1) return "spreadsheet";
if (".pps.ppsx.ppsm.ppt.pptx.pptm.pot.potx.potm.odp.fodp.otp".indexOf(ext) != -1) return "presentation";
return null;
};

View File

@ -1,28 +0,0 @@
FROM node:buster
LABEL maintainer Ascensio System SIA <support@onlyoffice.com>
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
NODE_ENV=production-linux \
NODE_CONFIG_DIR=/etc/onlyoffice/documentserver-example/
WORKDIR /var/www/onlyoffice/documentserver-example/
COPY . /var/www/onlyoffice/documentserver-example/
RUN groupadd --system --gid 1001 ds && \
useradd --system -g ds --no-create-home --shell /sbin/nologin --uid 1001 ds && \
chown -R ds:ds /var/www/onlyoffice/documentserver-example/ && \
mkdir -p /var/lib/onlyoffice/documentserver-example/ && \
chown -R ds:ds /var/lib/onlyoffice/ && \
mv files /var/lib/onlyoffice/documentserver-example/ && \
mkdir -p /etc/onlyoffice/documentserver-example/ && \
chown -R ds:ds /etc/onlyoffice/ && \
mv config/* /etc/onlyoffice/documentserver-example/ && \
npm install
EXPOSE 3000
USER ds
ENTRYPOINT /var/www/onlyoffice/documentserver-example/docker-entrypoint.sh npm start

View File

@ -2,13 +2,13 @@
This example will help you integrate ONLYOFFICE Docs into your web application on Node.js.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production.
## For Windows
### Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to [install Document Server for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
@ -16,13 +16,15 @@ See the detailed guide to learn how to [install Document Server for Windows](htt
Download the [Node.js example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connect the editors to your website. Specify the path to the editors installation in the *config/default.json* file:
To connect the editors to your website, specify the path to the editors installation and the path to the storage folder in the *config/default.json* file:
```
"storageFolder": "./files"
"storagePath": "/files"
"siteUrl": "https://documentserver/"
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed, the **storageFolder** and **storagePath** are the paths where files will be created and stored. You can set an absolute path. For example, *D:\\\\folder*. Please note that on Windows OS the double backslash must be used as a separator.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *\views\editor.ejs* file.
@ -114,13 +116,18 @@ See the detailed guide to learn how to [install Document Server for Linux](https
nano config/default.json
```
Edit the following line:
Edit the following lines:
```
"storageFolder": "./files"
"storagePath": "/files"
"siteUrl": "https://documentserver/"
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed, the **storageFolder** and **storagePath** are the paths where files will be created and stored. Please note that you must have read and write permissions to the folder. If you do not have them, please use the next command:
```
sudo chmod -R ugo+rw /{path}
```
6. Run the project with Node.js:
@ -139,3 +146,12 @@ See the detailed guide to learn how to [install Document Server for Linux](https
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Important security info
Please keep in mind the following security aspects when you are using test examples:
* There is no protection of the storage from unauthorized access since there is no need for authorization.
* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts.
* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server.
* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain.

303
web/documentserver-example/nodejs/app.js Normal file → Executable file
View File

@ -44,9 +44,11 @@ const cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizat
const cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn');
const cfgSignatureSecret = configServer.get('token.secret');
const urllib = require("urllib");
const verifyPeerOff = configServer.get('verify_peer_off');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
if(verifyPeerOff) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
String.prototype.hashCode = function () {
const len = this.length;
@ -70,6 +72,7 @@ String.prototype.format = function () {
const app = express(); // create an application object
app.disable("x-powered-by");
app.set("views", path.join(__dirname, "views")); // specify the path to the main template
app.set("view engine", "ejs"); // specify which template engine is used
@ -97,17 +100,18 @@ app.use(bodyParser.urlencoded({ extended: false })); // connect middleware that
app.get("/", function (req, res) { // define a handler for default page
try {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
res.render("index", { // render index template with the parameters specified
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
convertExts: configServer.get('convertedDocs').join(","),
editedExts: configServer.get('editedDocs').join(","),
fillExts: configServer.get("fillDocs").join(","),
storedFiles: docManager.getStoredFiles(),
params: docManager.getCustomParams(),
convertExts: configServer.get('convertedDocs'),
editedExts: configServer.get('editedDocs'),
fillExts: configServer.get("fillDocs"),
storedFiles: req.docManager.getStoredFiles(),
params: req.docManager.getCustomParams(),
users: users,
serverUrl: docManager.getServerUrl(),
serverUrl: req.docManager.getServerUrl(),
languages: configServer.get('languages'),
});
}
@ -120,12 +124,13 @@ app.get("/", function (req, res) { // define a handler for default page
});
app.get("/download", function(req, res) { // define a handler for downloading files
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
var fileName = fileUtility.getFileName(req.query.fileName);
var userAddress = req.query.useraddress;
var isEmbedded = req.query.dmode;
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
if ((cfgSignatureEnable && cfgSignatureUseForRequest) && isEmbedded == null ) {
var authorization = req.get(cfgSignatureAuthorizationHeader);
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
var token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
@ -139,9 +144,9 @@ app.get("/download", function(req, res) { // define a handler for downloading f
}
}
var path = docManager.forcesavePath(fileName, userAddress, false); // get the path to the force saved document version
var path = req.docManager.forcesavePath(fileName, userAddress, false); // get the path to the force saved document version
if (path == "") {
path = docManager.storagePath(fileName, userAddress); // or to the original document
path = req.docManager.storagePath(fileName, userAddress); // or to the original document
}
res.setHeader("Content-Length", fileSystem.statSync(path).size); // add headers to the response to specify the page parameters
@ -153,15 +158,56 @@ app.get("/download", function(req, res) { // define a handler for downloading f
filestream.pipe(res); // send file information to the response by streams
});
app.get("/history", function (req, res) {
req.docManager = new docManager(req, res);
if (cfgSignatureEnable && cfgSignatureUseForRequest) {
var authorization = req.get(cfgSignatureAuthorizationHeader);
if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
var token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
try {
var decoded = jwt.verify(token, cfgSignatureSecret);
} catch (err) {
console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token);
res.sendStatus(403);
return;
}
} else {
res.sendStatus(403);
return;
}
}
var fileName = req.query.fileName;
var userAddress = req.query.useraddress;
var ver = req.query.ver;
var file = req.query.file;
if (file.includes("diff")) {
var Path = req.docManager.diffPath(fileName, userAddress, ver);
} else if (file.includes("prev")) {
var Path = req.docManager.prevFilePath(fileName, userAddress, ver);
} else {
res.sendStatus(403);
return;
}
res.setHeader("Content-Length", fileSystem.statSync(Path).size); // add headers to the response to specify the page parameters
res.setHeader("Content-Type", mime.getType(Path));
res.setHeader("Content-Disposition", "attachment; filename*=UTF-8\'\'" + encodeURIComponent(file));
var filestream = fileSystem.createReadStream(Path);
filestream.pipe(res); // send file information to the response by streams
})
app.post("/upload", function (req, res) { // define a handler for uploading files
docManager.init(storageFolder, req, res);
docManager.storagePath(""); // mkdir if not exist
req.docManager = new docManager(req, res);
req.docManager.storagePath(""); // mkdir if not exist
const userIp = docManager.curUserHostAddress(); // get the path to the user host
const uploadDir = path.join(storageFolder, userIp);
const userIp = req.docManager.curUserHostAddress(); // get the path to the user host
const uploadDir = req.docManager.storageRootPath(userIp);
const uploadDirTmp = path.join(uploadDir, 'tmp'); // and create directory for temporary files if it doesn't exist
docManager.createDirectory(uploadDirTmp);
req.docManager.createDirectory(uploadDirTmp);
const form = new formidable.IncomingForm(); // create a new incoming form
form.uploadDir = uploadDirTmp; // and write there all the necessary parameters
@ -170,7 +216,7 @@ app.post("/upload", function (req, res) { // define a handler for uploading fil
form.parse(req, function (err, fields, files) { // parse this form
if (err) { // if an error occurs
docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
//docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
res.writeHead(200, { "Content-Type": "text/plain" }); // and write the error status and message to the response
res.write("{ \"error\": \"" + err.message + "\"}");
res.end();
@ -186,10 +232,10 @@ app.post("/upload", function (req, res) { // define a handler for uploading fil
return;
}
file.name = docManager.getCorrectName(file.name);
file.name = req.docManager.getCorrectName(file.name);
if (configServer.get('maxFileSize') < file.size || file.size <= 0) { // check if the file size exceeds the maximum file size
docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
//docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
res.writeHead(200, { "Content-Type": "text/plain" });
res.write("{ \"error\": \"File size is incorrect\"}");
res.end();
@ -201,7 +247,7 @@ app.post("/upload", function (req, res) { // define a handler for uploading fil
const documentType = fileUtility.getFileType(file.name);
if (exts.indexOf(curExt) == -1) { // check if the file extension is supported
docManager.cleanFolderRecursive(uploadDirTmp, true); // if not, clean the folder with temporary files
//docManager.cleanFolderRecursive(uploadDirTmp, true); // if not, clean the folder with temporary files
res.writeHead(200, { "Content-Type": "text/plain" }); // and write the error status and message to the response
res.write("{ \"error\": \"File type is not supported\"}");
res.end();
@ -209,7 +255,7 @@ app.post("/upload", function (req, res) { // define a handler for uploading fil
}
fileSystem.rename(file.path, uploadDir + "/" + file.name, function (err) { // rename a file
docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
//docManager.cleanFolderRecursive(uploadDirTmp, true); // clean the folder with temporary files
res.writeHead(200, { "Content-Type": "text/plain" });
if (err) { // if an error occurs
res.write("{ \"error\": \"" + err + "\"}"); // write an error message to the response
@ -218,7 +264,7 @@ app.post("/upload", function (req, res) { // define a handler for uploading fil
var user = users.getUser(req.query.userid); // get user id and name parameters or set them to the default values
docManager.saveFileData(file.name, user.id, user.name);
req.docManager.saveFileData(file.name, user.id, user.name);
}
res.end();
});
@ -230,12 +276,12 @@ app.post("/create", function (req, res) {
var fileUrl = req.body.url;
try {
docManager.init(storageFolder, req, res);
docManager.storagePath(""); // mkdir if not exist
req.docManager = new docManager(req, res);
req.docManager.storagePath(""); // mkdir if not exist
var fileName = docManager.getCorrectName(title);
var userAddress = docManager.curUserHostAddress();
docManager.historyPath(fileName, userAddress, true);
var fileName = req.docManager.getCorrectName(title);
var userAddress = req.docManager.curUserHostAddress();
req.docManager.historyPath(fileName, userAddress, true);
urllib.request(fileUrl, {method: "GET"},function(err, data) {
if (configServer.get("maxFileSize") < data.length || data.length <= 0) { // check if the file size exceeds the maximum file size
@ -255,7 +301,7 @@ app.post("/create", function (req, res) {
return;
}
fileSystem.writeFileSync(docManager.storagePath(fileName), data);
fileSystem.writeFileSync(req.docManager.storagePath(fileName), data);
res.writeHead(200, { "Content-Type": "application/json" });
res.write(JSON.stringify({ "file" : fileName }));
@ -274,14 +320,15 @@ app.post("/create", function (req, res) {
});
app.post("/convert", function (req, res) { // define a handler for converting files
req.docManager = new docManager(req, res);
var fileName = fileUtility.getFileName(req.body.filename);
var filePass = req.body.filePass ? req.body.filePass : null;
var lang = req.body.lang ? req.body.lang : null;
var fileUri = docManager.getFileUri(fileName);
var fileUri = req.docManager.getFileUri(fileName);
var fileExt = fileUtility.getFileExtension(fileName);
var fileType = fileUtility.getFileType(fileName);
var internalFileExt = docManager.getInternalExtension(fileType);
var internalFileExt = req.docManager.getInternalExtension(fileType);
var response = res;
var writeResult = function (filename, step, error) {
@ -322,17 +369,17 @@ app.post("/convert", function (req, res) { // define a handler for converting f
return;
}
var correctName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + internalFileExt); // get the file name with a new extension
var correctName = req.docManager.getCorrectName(fileUtility.getFileName(fileName, true) + internalFileExt); // get the file name with a new extension
urllib.request(newFileUri, {method: "GET"},function(err, data) {
fileSystem.writeFileSync(docManager.storagePath(correctName), data); // write a file with a new extension, but with the content from the origin file
fileSystem.writeFileSync(req.docManager.storagePath(correctName), data); // write a file with a new extension, but with the content from the origin file
});
fileSystem.unlinkSync(docManager.storagePath(fileName)); // remove file with the origin extension
fileSystem.unlinkSync(req.docManager.storagePath(fileName)); // remove file with the origin extension
var userAddress = docManager.curUserHostAddress();
var historyPath = docManager.historyPath(fileName, userAddress, true);
var correctHistoryPath = docManager.historyPath(correctName, userAddress, true); // get the history path to the file with a new extension
var userAddress = req.docManager.curUserHostAddress();
var historyPath = req.docManager.historyPath(fileName, userAddress, true);
var correctHistoryPath = req.docManager.historyPath(correctName, userAddress, true); // get the history path to the file with a new extension
fileSystem.renameSync(historyPath, correctHistoryPath); // change the previous history path
@ -347,7 +394,7 @@ app.post("/convert", function (req, res) { // define a handler for converting f
try {
if (configServer.get('convertedDocs').indexOf(fileExt) != -1) { // check if the file with such an extension can be converted
let storagePath = docManager.storagePath(fileName);
let storagePath = req.docManager.storagePath(fileName);
const stat = fileSystem.statSync(storagePath);
let key = fileUri + stat.mtime.getTime();
@ -364,8 +411,8 @@ app.post("/convert", function (req, res) { // define a handler for converting f
app.get("/files", function(req, res) { // define a handler for getting files information
try {
docManager.init(storageFolder, req, res);
const filesInDirectoryInfo = docManager.getFilesInfo(); // get the information about the files from the storage path
req.docManager = new docManager(req, res);
const filesInDirectoryInfo = req.docManager.getFilesInfo(); // get the information about the files from the storage path
res.setHeader("Content-Type", "application/json");
res.write(JSON.stringify(filesInDirectoryInfo)); // transform files information into the json string
} catch (ex) {
@ -377,9 +424,9 @@ app.get("/files", function(req, res) { // define a handler for getting files in
app.get("/files/file/:fileId", function(req, res) { // define a handler for getting file information by its id
try {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
const fileId = req.params.fileId;
const fileInfoById = docManager.getFilesInfo(fileId); // get the information about the file specified by a file id
const fileInfoById = req.docManager.getFilesInfo(fileId); // get the information about the file specified by a file id
res.setHeader("Content-Type", "application/json");
res.write(JSON.stringify(fileInfoById));
} catch (ex) {
@ -391,19 +438,14 @@ app.get("/files/file/:fileId", function(req, res) { // define a handler for get
app.delete("/file", function (req, res) { // define a handler for removing file
try {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
let fileName = req.query.filename;
if (fileName) { // if the file name is defined
fileName = fileUtility.getFileName(fileName); // get its part without an extension
const filePath = docManager.storagePath(fileName); // get the path to this file
fileSystem.unlinkSync(filePath); // and delete it
const userAddress = docManager.curUserHostAddress();
const historyPath = docManager.historyPath(fileName, userAddress, true);
docManager.cleanFolderRecursive(historyPath, true); // clean all the files from the history folder
req.docManager.fileRemove(fileName); // delete file and his history
} else {
docManager.cleanFolderRecursive(docManager.storagePath(''), false); // if the file name is undefined, clean the storage folder
req.docManager.cleanFolderRecursive(req.docManager.storagePath(''), false); // if the file name is undefined, clean the storage folder
}
res.write("{\"success\":true}");
@ -429,7 +471,7 @@ app.get("/csv", function (req, res) { // define a handler for downloading csv f
app.post("/track", function (req, res) { // define a handler for tracking file changes
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
var userAddress = req.query.useraddress;
var fileName = fileUtility.getFileName(req.query.filename);
@ -441,22 +483,22 @@ app.post("/track", function (req, res) { // define a handler for tracking file
// callback file saving process
var callbackProcessSave = function (downloadUri, body, fileName, userAddress, newFileName) {
try {
var storagePath = docManager.storagePath(newFileName, userAddress);
var storagePath = req.docManager.storagePath(newFileName, userAddress);
var historyPath = docManager.historyPath(newFileName, userAddress); // get the path to the history data
var historyPath = req.docManager.historyPath(newFileName, userAddress); // get the path to the history data
if (historyPath == "") { // if the history path doesn't exist
historyPath = docManager.historyPath(newFileName, userAddress, true); // create it
docManager.createDirectory(historyPath); // and create a directory for the history data
historyPath = req.docManager.historyPath(newFileName, userAddress, true); // create it
req.docManager.createDirectory(historyPath); // and create a directory for the history data
}
var count_version = docManager.countVersion(historyPath); // get the next file version number
var count_version = req.docManager.countVersion(historyPath); // get the next file version number
version = count_version + 1;
var versionPath = docManager.versionPath(newFileName, userAddress, version); // get the path to the specified file version
docManager.createDirectory(versionPath); // create a directory to the specified file version
var versionPath = req.docManager.versionPath(newFileName, userAddress, version); // get the path to the specified file version
req.docManager.createDirectory(versionPath); // create a directory to the specified file version
var downloadZip = body.changesurl;
if (downloadZip) {
var path_changes = docManager.diffPath(newFileName, userAddress, version); // get the path to the file with document versions differences
var path_changes = req.docManager.diffPath(newFileName, userAddress, version); // get the path to the file with document versions differences
urllib.request(downloadZip, {method: "GET"},function(err, data) {
fileSystem.writeFileSync(path_changes, data); // write the document version differences to the archive
});
@ -464,21 +506,21 @@ app.post("/track", function (req, res) { // define a handler for tracking file
var changeshistory = body.changeshistory || JSON.stringify(body.history);
if (changeshistory) {
var path_changes_json = docManager.changesPath(newFileName, userAddress, version); // get the path to the file with document changes
var path_changes_json = req.docManager.changesPath(newFileName, userAddress, version); // get the path to the file with document changes
fileSystem.writeFileSync(path_changes_json, changeshistory); // and write this data to the path in json format
}
var path_key = docManager.keyPath(newFileName, userAddress, version); // get the path to the key.txt file
var path_key = req.docManager.keyPath(newFileName, userAddress, version); // get the path to the key.txt file
fileSystem.writeFileSync(path_key, body.key); // write the key value to the key.txt file
var path_prev = path.join(versionPath, "prev" + fileUtility.getFileExtension(fileName)); // get the path to the previous file version
fileSystem.renameSync(docManager.storagePath(fileName, userAddress), path_prev); // and write it to the current path
fileSystem.renameSync(req.docManager.storagePath(fileName, userAddress), path_prev); // and write it to the current path
urllib.request(downloadUri, {method: "GET"},function(err, data) {
fileSystem.writeFileSync(storagePath, data);
});
var forcesavePath = docManager.forcesavePath(newFileName, userAddress, false); // get the path to the forcesaved file
var forcesavePath = req.docManager.forcesavePath(newFileName, userAddress, false); // get the path to the forcesaved file
if (forcesavePath != "") { // if this path is empty
fileSystem.unlinkSync(forcesavePath); // remove it
}
@ -503,13 +545,17 @@ app.post("/track", function (req, res) { // define a handler for tracking file
}
var curExt = fileUtility.getFileExtension(fileName); // get current file extension
var downloadExt = fileUtility.getFileExtension(downloadUri); // get the extension of the downloaded file
var downloadExt = "." + body.filetype; // get the extension of the downloaded file
// TODO [Delete in version 7.0 or higher]
if (downloadExt == ".") downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
var newFileName = fileName;
// convert downloaded file to the file with the current extension if these extensions aren't equal
if (downloadExt != curExt) {
var key = documentService.generateRevisionId(downloadUri);
newFileName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + downloadExt, userAddress); // get the correct file name if it already exists
newFileName = req.docManager.getCorrectName(fileUtility.getFileName(fileName, true) + downloadExt, userAddress); // get the correct file name if it already exists
try {
documentService.getConvertedUriSync(downloadUri, downloadExt, curExt, key, function (err, data) {
if (err) {
@ -537,26 +583,30 @@ app.post("/track", function (req, res) { // define a handler for tracking file
// callback file force saving process
var callbackProcessForceSave = function (downloadUri, body, fileName, userAddress, newFileName = false){
try {
var downloadExt = fileUtility.getFileExtension(downloadUri);
var downloadExt = "." + body.fileType;
/// TODO [Delete in version 7.0 or higher]
if (downloadExt == ".") downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
var isSubmitForm = body.forcesavetype === 3; // SubmitForm
if (isSubmitForm) {
// new file
if (newFileName){
fileName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + "-form" + downloadExt, userAddress);
fileName = req.docManager.getCorrectName(fileUtility.getFileName(fileName, true) + "-form" + downloadExt, userAddress);
} else {
var ext = fileUtility.getFileExtension(fileName);
fileName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + "-form" + ext, userAddress);
fileName = req.docManager.getCorrectName(fileUtility.getFileName(fileName, true) + "-form" + ext, userAddress);
}
var forcesavePath = docManager.storagePath(fileName, userAddress);
var forcesavePath = req.docManager.storagePath(fileName, userAddress);
} else {
if (newFileName){
fileName = docManager.getCorrectName(fileUtility.getFileName(fileName, true) + downloadExt, userAddress);
fileName = req.docManager.getCorrectName(fileUtility.getFileName(fileName, true) + downloadExt, userAddress);
}
// create forcesave path if it doesn't exist
forcesavePath = docManager.forcesavePath(fileName, userAddress, false);
forcesavePath = req.docManager.forcesavePath(fileName, userAddress, false);
if (forcesavePath == "") {
forcesavePath = docManager.forcesavePath(fileName, userAddress, true);
forcesavePath = req.docManager.forcesavePath(fileName, userAddress, true);
}
}
@ -566,7 +616,7 @@ app.post("/track", function (req, res) { // define a handler for tracking file
if (isSubmitForm) {
var uid =body.actions[0].userid
docManager.saveFileData(fileName, uid, "Filling Form", userAddress);
req.docManager.saveFileData(fileName, uid, "Filling Form", userAddress);
}
} catch (ex) {
response.write("{\"error\":1}");
@ -588,7 +638,10 @@ app.post("/track", function (req, res) { // define a handler for tracking file
}
var curExt = fileUtility.getFileExtension(fileName);
var downloadExt = fileUtility.getFileExtension(downloadUri);
var downloadExt = "." + body.filetype;
// TODO [Delete in version 7.0 or higher]
if (downloadExt == ".") downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0
// convert downloaded file to the file with the current extension if these extensions aren't equal
if (downloadExt != curExt) {
@ -695,21 +748,30 @@ app.post("/track", function (req, res) { // define a handler for tracking file
app.get("/editor", function (req, res) { // define a handler for editing document
try {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
var fileName = fileUtility.getFileName(req.query.fileName);
var fileExt = req.query.fileExt;
var history = [];
var historyData = [];
var lang = docManager.getLang();
var lang = req.docManager.getLang();
var user = users.getUser(req.query.userid);
var userid = user.id;
var name = user.name;
var actionData = req.query.action ? req.query.action : "null";
var templatesImageUrl = docManager.getTemplateImageUrl(fileUtility.getFileType(fileName));
var createUrl = docManager.getCreateUrl(fileUtility.getFileType(fileName), userid, type, lang);
var actionData = "null";
if (req.query.action){
try {
actionData = JSON.stringify(JSON.parse(req.query.action));
}
catch (ex) {
console.log(ex);
}
}
var templatesImageUrl = req.docManager.getTemplateImageUrl(fileUtility.getFileType(fileName));
var createUrl = req.docManager.getCreateUrl(fileUtility.getFileType(fileName), userid, type, lang);
var templates = [
{
"image": "",
@ -726,81 +788,92 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
var userGroup = user.group;
var reviewGroups = user.reviewGroups;
var commentGroups = user.commentGroups;
var userInfoGroups = user.userInfoGroups;
if (fileExt != null) {
var fileName = docManager.createDemo(!!req.query.sample, fileExt, userid, name); // create demo document of a given extension
var fileName = req.docManager.createDemo(!!req.query.sample, fileExt, userid, name, false); // create demo document of a given extension
// get the redirect path
var redirectPath = docManager.getServerUrl() + "/editor?fileName=" + encodeURIComponent(fileName) + docManager.getCustomParams();
var redirectPath = req.docManager.getServerUrl() + "/editor?fileName=" + encodeURIComponent(fileName) + req.docManager.getCustomParams();
res.redirect(redirectPath);
return;
}
fileExt = fileUtility.getFileExtension(fileName);
var userAddress = docManager.curUserHostAddress();
if (!docManager.existsSync(docManager.storagePath(fileName, userAddress))) { // if the file with a given name doesn't exist
var userAddress = req.docManager.curUserHostAddress();
if (!req.docManager.existsSync(req.docManager.storagePath(fileName, userAddress))) { // if the file with a given name doesn't exist
throw {
"message": "File not found: " + fileName // display error message
};
}
var key = docManager.getKey(fileName);
var url = docManager.getDownloadUrl(fileName);
var urlUser = docManager.getlocalFileUri(fileName, 0, false)
var key = req.docManager.getKey(fileName);
var url = req.docManager.getDownloadUrl(fileName);
var urlUser = path.isAbsolute(storageFolder) ? req.docManager.getDownloadUrl(fileName) + "&dmode=emb" : req.docManager.getlocalFileUri(fileName, 0, false);
var mode = req.query.mode || "edit"; // mode: view/edit/review/comment/fillForms/embedded
var type = req.query.type || ""; // type: embedded/mobile/desktop
if (type == "") {
type = new RegExp(configServer.get("mobileRegEx"), "i").test(req.get('User-Agent')) ? "mobile" : "desktop";
}
type = new RegExp(configServer.get("mobileRegEx"), "i").test(req.get('User-Agent')) ? "mobile" : "desktop";
} else if (type != "mobile"
&& type != "embedded") {
type = "desktop";
}
var canEdit = configServer.get('editedDocs').indexOf(fileExt) != -1; // check if this file can be edited
if ((!canEdit && mode == "edit" || mode == "fillForms") && configServer.get('fillDocs').indexOf(fileExt) != -1) {
mode = "fillForms";
canEdit = true;
}
if (!canEdit && mode == "edit") {
mode = "view";
}
var submitForm = mode == "fillForms" && userid == "uid-1" && !1;
var countVersion = 1;
var historyPath = docManager.historyPath(fileName, userAddress);
var historyPath = req.docManager.historyPath(fileName, userAddress);
var changes = null;
var keyVersion = key;
if (historyPath != '') {
countVersion = docManager.countVersion(historyPath) + 1; // get the number of file versions
countVersion = req.docManager.countVersion(historyPath) + 1; // get the number of file versions
for (var i = 1; i <= countVersion; i++) { // get keys to all the file versions
if (i < countVersion) {
var keyPath = docManager.keyPath(fileName, userAddress, i);
var keyPath = req.docManager.keyPath(fileName, userAddress, i);
if (!fileSystem.existsSync(keyPath)) continue;
keyVersion = "" + fileSystem.readFileSync(keyPath);
} else {
keyVersion = key;
}
history.push(docManager.getHistory(fileName, changes, keyVersion, i)); // write all the file history information
history.push(req.docManager.getHistory(fileName, changes, keyVersion, i)); // write all the file history information
var historyD = {
fileType: fileExt.slice(1),
version: i,
key: keyVersion,
url: i == countVersion ? url : (docManager.getlocalFileUri(fileName, i, true) + "/prev" + fileExt),
url: i == countVersion ? url : (`${req.docManager.getServerUrl(false)}/history?fileName=${encodeURIComponent(fileName)}&file=prev${fileExt}&ver=${i}&useraddress=${userAddress}`),
};
if (i > 1 && docManager.existsSync(docManager.diffPath(fileName, userAddress, i-1))) { // check if the path to the file with document versions differences exists
if (i > 1 && req.docManager.existsSync(req.docManager.diffPath(fileName, userAddress, i-1))) { // check if the path to the file with document versions differences exists
historyD.previous = { // write information about previous file version
fileType: historyData[i-2].fileType,
key: historyData[i-2].key,
url: historyData[i-2].url,
};
historyD.changesUrl = docManager.getlocalFileUri(fileName, i-1) + "/diff.zip"; // get the path to the diff.zip file and write it to the history object
let changesUrl = `${req.docManager.getServerUrl(false)}/history?fileName=${encodeURIComponent(fileName)}&file=diff.zip&ver=${i-1}&useraddress=${userAddress}`;
historyD.changesUrl = changesUrl; // get the path to the diff.zip file and write it to the history object
}
historyData.push(historyD);
if (i < countVersion) {
var changesFile = docManager.changesPath(fileName, userAddress, i); // get the path to the file with document changes
changes = docManager.getChanges(changesFile); // get changes made in the file
var changesFile = req.docManager.changesPath(fileName, userAddress, i); // get the path to the file with document changes
changes = req.docManager.getChanges(changesFile); // get changes made in the file
}
}
} else { // if history path is empty
history.push(docManager.getHistory(fileName, changes, keyVersion, countVersion)); // write the history information about the last file version
history.push(req.docManager.getHistory(fileName, changes, keyVersion, countVersion)); // write the history information about the last file version
historyData.push({
version: countVersion,
key: key,
@ -831,7 +904,7 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
documentType: fileUtility.getFileType(fileName),
key: key,
token: "",
callbackUrl: docManager.getCallback(fileName),
callbackUrl: req.docManager.getCallback(fileName),
createUrl: userid != "uid-0" ? createUrl : null,
templates: user.templates ? templates : null,
isEdit: canEdit && (mode == "edit" || mode == "view" || mode == "filter" || mode == "blockcontent"),
@ -843,16 +916,17 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
copy: !user.deniedPermissions.includes("copy"),
download: !user.deniedPermissions.includes("download"),
print: !user.deniedPermissions.includes("print"),
mode: canEdit && mode != "view" ? "edit" : "view",
mode: mode != "view" ? "edit" : "view",
canBackToFolder: type != "embedded",
backUrl: docManager.getServerUrl() + "/",
curUserHostAddress: docManager.curUserHostAddress(),
backUrl: req.docManager.getServerUrl() + "/",
curUserHostAddress: req.docManager.curUserHostAddress(),
lang: lang,
userid: userid,
userid: userid != "uid-0" ? userid : null,
name: name,
userGroup: userGroup,
reviewGroups: JSON.stringify(reviewGroups),
commentGroups: JSON.stringify(commentGroups),
userInfoGroups: JSON.stringify(userInfoGroups),
fileChoiceUrl: fileChoiceUrl,
submitForm: submitForm,
plugins: JSON.stringify(plugins),
@ -862,15 +936,15 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
historyData: historyData,
dataInsertImage: {
fileType: "png",
url: docManager.getServerUrl(true) + "/images/logo.png"
url: req.docManager.getServerUrl(true) + "/images/logo.png"
},
dataCompareFile: {
fileType: "docx",
url: docManager.getServerUrl(true) + "/assets/sample/sample.docx"
url: req.docManager.getServerUrl(true) + "/assets/sample/sample.docx"
},
dataMailMergeRecipients: {
fileType: "csv",
url: docManager.getServerUrl(true) + "/csv"
url: req.docManager.getServerUrl(true) + "/csv"
},
usersForMentions: user.id != "uid-0" ? users.getUsersForMentions(user.id) : null,
};
@ -899,6 +973,21 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
}
});
app.post("/rename", function (req, res) { //define a handler for renaming file
var newfilename = req.body.newfilename;
var dockey = req.body.dockey;
var meta = {title: newfilename};
var result = function(err, data, ress) {
res.writeHead(200, {"Content-Type": "application/json" });
res.write(JSON.stringify({ "result": ress }));
res.end();
};
documentService.commandRequest("meta", dockey, meta, result);
});
wopiApp.registerRoutes(app);
// "Not found" error with 404 status

View File

@ -1,5 +1,5 @@
{
"version": "1.0.0",
"version": "1.2.0",
"log": {
"appenders": [
{
@ -25,7 +25,7 @@
"viewedDocs": [".pdf", ".djvu", ".xps", ".oxps"],
"editedDocs": [".docx", ".xlsx", ".csv", ".pptx", ".txt", ".docxf"],
"fillDocs": [".docx", ".oform"],
"convertedDocs": [".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".rtf", ".mht", ".html", ".htm", ".xml", ".epub", ".fb2"],
"convertedDocs": [".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".xlsm", ".xlsb", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".rtf", ".mht", ".html", ".htm", ".xml", ".epub", ".fb2"],
"storageFolder": "./files",
"storagePath": "/files",
"maxFileSize": 1073741824,
@ -44,6 +44,42 @@
"authorizationHeaderPrefix": "Bearer ",
"secret": "secret",
"expiresIn": "5m"
},
"verify_peer_off": true,
"languages": {
"en": "English",
"az": "Azerbaijani",
"be": "Belarusian",
"bg": "Bulgarian",
"ca": "Catalan",
"zh": "Chinese",
"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",
"lv": "Latvian",
"lo": "Lao",
"nb": "Norwegian",
"pl": "Polish",
"pt": "Portuguese",
"ro": "Romanian",
"ru": "Russian",
"sk": "Slovak",
"sl": "Slovenian",
"es": "Spanish",
"sv": "Swedish",
"tr": "Turkish",
"uk": "Ukrainian",
"vi": "Vietnamese"
}
},
"plugins": {

View File

@ -21,19 +21,16 @@ const path = require("path");
const fileSystem = require("fs");
const fileUtility = require("./fileUtility");
const documentService = require("./documentService");
const cacheManager = require("./cacheManager");
const guidManager = require("./guidManager");
const configServer = require('config').get('server');
const os = require("os");
const storageConfigFolder = configServer.get("storageFolder");
let docManager = {};
docManager.dir = null;
docManager.req = null;
docManager.res = null;
function docManager(req, res) {
this.req = req;
this.res = res;
}
// check if the path exists or not
docManager.existsSync = function(path) {
docManager.prototype.existsSync = function(path) {
let res = true;
try {
fileSystem.accessSync(path, fileSystem.F_OK); // synchronously test the user's permissions for the directory specified by path; the directory is visible to the calling process
@ -44,57 +41,51 @@ docManager.existsSync = function(path) {
};
// create a new directory if it doesn't exist
docManager.createDirectory = function(path) {
docManager.prototype.createDirectory = function(path) {
if (!this.existsSync(path)) {
fileSystem.mkdirSync(path);
}
};
docManager.init = function (dir, req, res) {
docManager.dir = dir;
docManager.req = req;
docManager.res = res;
};
// get the language from the request
docManager.getLang = function () {
if (docManager.req.query.lang) {
return docManager.req.query.lang;
docManager.prototype.getLang = function () {
if (new RegExp("^[a-z]{2}(-[A-Z]{2})?$", "i").test(this.req.query.lang)) {
return this.req.query.lang;
} else { // the default language value is English
return "en"
}
};
// get customization parameters
docManager.getCustomParams = function () {
docManager.prototype.getCustomParams = function () {
let params = "";
const userid = docManager.req.query.userid; // user id
const userid = this.req.query.userid; // user id
params += (userid ? "&userid=" + userid : "");
const lang = docManager.req.query.lang; // language
params += (lang ? "&lang=" + docManager.getLang() : "");
const lang = this.req.query.lang; // language
params += (lang ? "&lang=" + this.getLang() : "");
const fileName = docManager.req.query.fileName; // file name
const fileName = this.req.query.fileName; // file name
params += (fileName ? "&fileName=" + fileName : "");
const mode = docManager.req.query.mode; // mode: view/edit/review/comment/fillForms/embedded
const mode = this.req.query.mode; // mode: view/edit/review/comment/fillForms/embedded
params += (mode ? "&mode=" + mode : "");
const type = docManager.req.query.type; // type: embedded/mobile/desktop
const type = this.req.query.type; // type: embedded/mobile/desktop
params += (type ? "&type=" + type : "");
return params;
};
// get the correct file name if such a name already exists
docManager.getCorrectName = function (fileName, userAddress) {
docManager.prototype.getCorrectName = function (fileName, userAddress) {
const baseName = fileUtility.getFileName(fileName, true); // get file name from the url without extension
const ext = fileUtility.getFileExtension(fileName); // get file extension from the url
let name = baseName + ext; // get full file name
let index = 1;
while (this.existsSync(docManager.storagePath(name, userAddress))) { // if the file with such a name already exists in this directory
while (this.existsSync(this.storagePath(name, userAddress))) { // if the file with such a name already exists in this directory
name = baseName + " (" + index + ")" + ext; // add an index after its base name
index++;
}
@ -102,39 +93,69 @@ docManager.getCorrectName = function (fileName, userAddress) {
return name;
};
// processes a request editnew
docManager.prototype.RequestEditnew = function (req, fileName, user) {
if (req.params['id'] != fileName){ // processes a repeated request editnew
this.fileRemove(req.params['id']);
fileName = this.getCorrectName(req.params['id']);
}
this.fileSizeZero(fileName);
this.saveFileData(fileName, user.id, user.name);
return fileName;
}
// delete a file with its history
docManager.prototype.fileRemove = function (fileName) {
const filePath = this.storagePath(fileName); // get the path to this file
fileSystem.unlinkSync(filePath); // and delete it
const userAddress = this.curUserHostAddress();
const historyPath = this.historyPath(fileName, userAddress, true);
this.cleanFolderRecursive(historyPath, true); // clean all the files from the history folder
}
// create a zero-size file
docManager.prototype.fileSizeZero = function (fileName) {
var path = this.storagePath(fileName);
var fh = fileSystem.openSync(path, 'w');
fileSystem.closeSync(fh);
}
// create demo document
docManager.createDemo = function (isSample, fileExt, userid, username) {
docManager.prototype.createDemo = function (isSample, fileExt, userid, username, wopi) {
const demoName = (isSample ? "sample" : "new") + "." + fileExt;
const fileName = docManager.getCorrectName(demoName); // get the correct file name if such a name already exists
const fileName = this.getCorrectName(demoName); // get the correct file name if such a name already exists
docManager.copyFile(path.join(__dirname, "..","public", "assets", isSample ? "sample" : "new", demoName), docManager.storagePath(fileName)); // copy sample document of a necessary extension to the storage path
this.copyFile(path.join(__dirname, "..","public", "assets", isSample ? "sample" : "new", demoName), this.storagePath(fileName)); // copy sample document of a necessary extension to the storage path
docManager.saveFileData(fileName, userid, username); // save file data to the file
this.saveFileData(fileName, userid, username); // save file data to the file
return fileName;
};
// save file data to the file
docManager.saveFileData = function (fileName, userid, username, userAddress) {
docManager.prototype.saveFileData = function (fileName, userid, username, userAddress) {
if (!userAddress) {
userAddress = docManager.curUserHostAddress(); // get current user host address
userAddress = this.curUserHostAddress(); // get current user host address
}
// get full creation date of the document
const date_create = fileSystem.statSync(docManager.storagePath(fileName, userAddress)).mtime;
const date_create = fileSystem.statSync(this.storagePath(fileName, userAddress)).mtime;
const minutes = (date_create.getMinutes() < 10 ? '0' : '') + date_create.getMinutes().toString();
const month = (date_create.getMonth() < 10 ? '0' : '') + (parseInt(date_create.getMonth().toString()) + 1);
const sec = (date_create.getSeconds() < 10 ? '0' : '') + date_create.getSeconds().toString();
const date_format = date_create.getFullYear() + "-" + month + "-" + date_create.getDate() + " " + date_create.getHours() + ":" + minutes + ":" + sec;
const file_info = docManager.historyPath(fileName, userAddress, true); // get file history information
const file_info = this.historyPath(fileName, userAddress, true); // get file history information
this.createDirectory(file_info); // create a new history directory if it doesn't exist
fileSystem.writeFileSync(path.join(file_info, fileName + ".txt"), date_format + "," + userid + "," + username); // write all the file information to a new txt file
};
// get file data
docManager.getFileData = function (fileName, userAddress) {
const history = path.join(docManager.historyPath(fileName, userAddress, true), fileName + ".txt"); // get the path to the file with file information
docManager.prototype.getFileData = function (fileName, userAddress) {
const history = path.join(this.historyPath(fileName, userAddress, true), fileName + ".txt"); // get the path to the file with file information
if (!this.existsSync(history)) { // if such a file doesn't exist
return ["2017-01-01", "uid-1", "John Smith"]; // return default information
}
@ -143,15 +164,15 @@ docManager.getFileData = function (fileName, userAddress) {
};
// get url to the original file
docManager.getFileUri = function (fileName) {
return docManager.getlocalFileUri(fileName, 0, true);
docManager.prototype.getFileUri = function (fileName) {
return this.getlocalFileUri(fileName, 0, true);
};
// get local file url
docManager.getlocalFileUri = function (fileName, version, forDocumentServer) {
const serverPath = docManager.getServerUrl(forDocumentServer);
const hostAddress = docManager.curUserHostAddress();
const url = serverPath + configServer.get("storagePath") + "/" + hostAddress + "/" + encodeURIComponent(fileName); // get full url address to the file
docManager.prototype.getlocalFileUri = function (fileName, version, forDocumentServer) {
const serverPath = this.getServerUrl(forDocumentServer);
const hostAddress = this.curUserHostAddress();
let url = serverPath + configServer.get("storagePath") + "/" + hostAddress + "/" + encodeURIComponent(fileName); // get full url address to the file
if (!version) {
return url;
}
@ -159,63 +180,67 @@ docManager.getlocalFileUri = function (fileName, version, forDocumentServer) {
};
// get server url
docManager.getServerUrl = function (forDocumentServer) {
return (forDocumentServer && !!configServer.get("exampleUrl")) ? configServer.get("exampleUrl") : docManager.getServerPath();
docManager.prototype.getServerUrl = function (forDocumentServer) {
return (forDocumentServer && !!configServer.get("exampleUrl")) ? configServer.get("exampleUrl") : this.getServerPath();
};
// get server address from the request
docManager.getServerPath = function () {
return docManager.getServerHost() + (docManager.req.headers["x-forwarded-path"] || docManager.req.baseUrl);
docManager.prototype.getServerPath = function () {
return this.getServerHost() + (this.req.headers["x-forwarded-path"] || this.req.baseUrl);
};
// get host address from the request
docManager.getServerHost = function () {
return docManager.getProtocol() + "://" + (docManager.req.headers["x-forwarded-host"] || docManager.req.headers["host"]);
docManager.prototype.getServerHost = function () {
return this.getProtocol() + "://" + (this.req.headers["x-forwarded-host"] || this.req.headers["host"]);
};
// get protocol from the request
docManager.getProtocol = function () {
return docManager.req.headers["x-forwarded-proto"] || docManager.req.protocol;
docManager.prototype.getProtocol = function () {
return this.req.headers["x-forwarded-proto"] || this.req.protocol;
};
// get callback url
docManager.getCallback = function (fileName) {
const server = docManager.getServerUrl(true);
const hostAddress = docManager.curUserHostAddress();
docManager.prototype.getCallback = function (fileName) {
const server = this.getServerUrl(true);
const hostAddress = this.curUserHostAddress();
const handler = "/track?filename=" + encodeURIComponent(fileName) + "&useraddress=" + encodeURIComponent(hostAddress); // get callback handler
return server + handler;
};
// get url to the created file
docManager.getCreateUrl = function (docType, userid, type, lang) {
const server = docManager.getServerUrl();
var ext = docManager.getInternalExtension(docType).replace(".", "");
docManager.prototype.getCreateUrl = function (docType, userid, type, lang) {
const server = this.getServerUrl();
var ext = this.getInternalExtension(docType).replace(".", "");
const handler = "/editor?fileExt=" + ext + "&userid=" + userid + "&type=" + type + "&lang=" + lang;
return server + handler;
}
// get url to download a file
docManager.getDownloadUrl = function (fileName) {
const server = docManager.getServerUrl(true);
const hostAddress = docManager.curUserHostAddress();
docManager.prototype.getDownloadUrl = function (fileName) {
const server = this.getServerUrl(true);
const hostAddress = this.curUserHostAddress();
const handler = "/download?fileName=" + encodeURIComponent(fileName) + "&useraddress=" + encodeURIComponent(hostAddress);
return server + handler;
};
docManager.prototype.storageRootPath = function (userAddress) {
return path.join(storageConfigFolder, this.curUserHostAddress(userAddress)); // get the path to the directory for the host address
}
// get the storage path of the given file
docManager.storagePath = function (fileName, userAddress) {
docManager.prototype.storagePath = function (fileName, userAddress) {
fileName = fileUtility.getFileName(fileName); // get the file name with extension
const directory = path.join(docManager.dir, docManager.curUserHostAddress(userAddress)); // get the path to the directory for the host address
const directory = this.storageRootPath(userAddress);
this.createDirectory(directory); // create a new directory if it doesn't exist
return path.join(directory, fileName); // put the given file to this directory
};
// get the path to the forcesaved file version
docManager.forcesavePath = function (fileName, userAddress, create) {
let directory = path.join(docManager.dir, docManager.curUserHostAddress(userAddress));
docManager.prototype.forcesavePath = function (fileName, userAddress, create) {
let directory = this.storageRootPath(userAddress);
if (!this.existsSync(directory)) { // the directory with host address doesn't exist
return "";
}
@ -232,8 +257,8 @@ docManager.forcesavePath = function (fileName, userAddress, create) {
};
// create the path to the file history
docManager.historyPath = function (fileName, userAddress, create) {
let directory = path.join(docManager.dir, docManager.curUserHostAddress(userAddress));
docManager.prototype.historyPath = function (fileName, userAddress, create) {
let directory = this.storageRootPath(userAddress);
if (!this.existsSync(directory)) {
return "";
}
@ -245,40 +270,40 @@ docManager.historyPath = function (fileName, userAddress, create) {
};
// get the path to the specified file version
docManager.versionPath = function (fileName, userAddress, version) {
const historyPath = docManager.historyPath(fileName, userAddress, true); // get the path to the history of a given file or create it if it doesn't exist
docManager.prototype.versionPath = function (fileName, userAddress, version) {
const historyPath = this.historyPath(fileName, userAddress, true); // get the path to the history of a given file or create it if it doesn't exist
return path.join(historyPath, "" + version);
};
// get the path to the previous file version
docManager.prevFilePath = function (fileName, userAddress, version) {
return path.join(docManager.versionPath(fileName, userAddress, version), "prev" + fileUtility.getFileExtension(fileName));
docManager.prototype.prevFilePath = function (fileName, userAddress, version) {
return path.join(this.versionPath(fileName, userAddress, version), "prev" + fileUtility.getFileExtension(fileName));
};
// get the path to the file with document versions differences
docManager.diffPath = function (fileName, userAddress, version) {
return path.join(docManager.versionPath(fileName, userAddress, version), "diff.zip");
docManager.prototype.diffPath = function (fileName, userAddress, version) {
return path.join(this.versionPath(fileName, userAddress, version), "diff.zip");
};
// get the path to the file with document changes
docManager.changesPath = function (fileName, userAddress, version) {
return path.join(docManager.versionPath(fileName, userAddress, version), "changes.txt");
docManager.prototype.changesPath = function (fileName, userAddress, version) {
return path.join(this.versionPath(fileName, userAddress, version), "changes.txt");
};
// get the path to the file with key value in it
docManager.keyPath = function (fileName, userAddress, version) {
return path.join(docManager.versionPath(fileName, userAddress, version), "key.txt");
docManager.prototype.keyPath = function (fileName, userAddress, version) {
return path.join(this.versionPath(fileName, userAddress, version), "key.txt");
};
// get the path to the file with the user information
docManager.changesUser = function (fileName, userAddress, version) {
return path.join(docManager.versionPath(fileName, userAddress, version), "user.txt");
docManager.prototype.changesUser = function (fileName, userAddress, version) {
return path.join(this.versionPath(fileName, userAddress, version), "user.txt");
};
// get all the stored files
docManager.getStoredFiles = function () {
const userAddress = docManager.curUserHostAddress();
const directory = path.join(docManager.dir, userAddress);
docManager.prototype.getStoredFiles = function () {
const userAddress = this.curUserHostAddress();
const directory = this.storageRootPath(userAddress);
this.createDirectory(directory);
const result = [];
const storedFiles = fileSystem.readdirSync(directory); // read the user host directory contents
@ -286,10 +311,10 @@ docManager.getStoredFiles = function () {
const stats = fileSystem.lstatSync(path.join(directory, storedFiles[i])); // save element parameters
if (!stats.isDirectory()) { // if the element isn't a directory
let historyPath = docManager.historyPath(storedFiles[i], userAddress); // get the path to the file history
let historyPath = this.historyPath(storedFiles[i], userAddress); // get the path to the file history
let version = 0;
if (historyPath != "") { // if the history path exists
version = docManager.countVersion(historyPath); // get the last file version
version = this.countVersion(historyPath); // get the last file version
}
const time = stats.mtime.getTime(); // get the time of element modification
@ -318,20 +343,20 @@ docManager.getStoredFiles = function () {
};
// get current user host address
docManager.curUserHostAddress = function (userAddress) {
docManager.prototype.curUserHostAddress = function (userAddress) {
if (!userAddress) // if user address isn't passed to the function
userAddress = docManager.req.headers["x-forwarded-for"] || docManager.req.connection.remoteAddress; // take it from the header or use the remote address
userAddress = this.req.headers["x-forwarded-for"] || this.req.connection.remoteAddress; // take it from the header or use the remote address
return userAddress.replace(new RegExp("[^0-9a-zA-Z.=]", "g"), "_");
};
// copy file
docManager.copyFile = function (exist, target) {
docManager.prototype.copyFile = function (exist, target) {
fileSystem.writeFileSync(target, fileSystem.readFileSync(exist));
};
// get an internal extension
docManager.getInternalExtension = function (fileType) {
docManager.prototype.getInternalExtension = function (fileType) {
if (fileType == fileUtility.fileType.word) // .docx for word type
return ".docx";
@ -345,8 +370,8 @@ docManager.getInternalExtension = function (fileType) {
};
// get the template image url
docManager.getTemplateImageUrl = function (fileType) {
let path = docManager.getServerUrl(true);
docManager.prototype.getTemplateImageUrl = function (fileType) {
let path = this.getServerUrl(true);
if (fileType == fileUtility.fileType.word) // for word type
return path + "/images/file_docx.svg";
@ -360,16 +385,16 @@ docManager.getTemplateImageUrl = function (fileType) {
}
// get document key
docManager.getKey = function (fileName) {
const userAddress = docManager.curUserHostAddress();
let key = userAddress + docManager.getlocalFileUri(fileName); // get document key by adding local file url to the current user host address
docManager.prototype.getKey = function (fileName, userAddress) {
userAddress = userAddress || this.curUserHostAddress();
let key = userAddress + this.getlocalFileUri(fileName); // get document key by adding local file url to the current user host address
let historyPath = docManager.historyPath(fileName, userAddress); // get the path to the file history
let historyPath = this.historyPath(fileName, userAddress); // get the path to the file history
if (historyPath != ""){ // if the path to the file history exists
key += docManager.countVersion(historyPath); // add file version number to the document key
key += this.countVersion(historyPath); // add file version number to the document key
}
let storagePath = docManager.storagePath(fileName, userAddress); // get the storage path to the given file
let storagePath = this.storagePath(fileName, userAddress); // get the storage path to the given file
const stat = fileSystem.statSync(storagePath); // get file information
key += stat.mtime.getTime(); // and add creation time to the document key
@ -377,13 +402,13 @@ docManager.getKey = function (fileName) {
};
// get current date
docManager.getDate = function (date) {
docManager.prototype.getDate = function (date) {
const minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes().toString();
return date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear() + " " + date.getHours() + ":" + minutes;
};
// get changes made in the file
docManager.getChanges = function (fileName) {
docManager.prototype.getChanges = function (fileName) {
if (this.existsSync(fileName)) { // if the directory with such a file exists
return JSON.parse(fileSystem.readFileSync(fileName)); // read this file and parse it
}
@ -391,7 +416,7 @@ docManager.getChanges = function (fileName) {
};
// get the last file version
docManager.countVersion = function(directory) {
docManager.prototype.countVersion = function(directory) {
let i = 0;
while (this.existsSync(path.join(directory, '' + (i + 1)))) { // run through all the file versions
i++; // and count them
@ -400,7 +425,7 @@ docManager.countVersion = function(directory) {
};
// get file history information
docManager.getHistory = function (fileName, content, keyVersion, version) {
docManager.prototype.getHistory = function (fileName, content, keyVersion, version) {
let oldVersion = false;
let contentJson = null;
if (content) { // if content is defined
@ -414,10 +439,10 @@ docManager.getHistory = function (fileName, content, keyVersion, version) {
}
}
const userAddress = docManager.curUserHostAddress();
const username = content ? (oldVersion ? contentJson.username : contentJson.user.name) : (docManager.getFileData(fileName, userAddress))[2];
const userid = content ? (oldVersion ? contentJson.userid : contentJson.user.id) : (docManager.getFileData(fileName, userAddress))[1];
const created = content ? (oldVersion ? contentJson.date : contentJson.created) : (docManager.getFileData(fileName, userAddress))[0];
const userAddress = this.curUserHostAddress();
const username = content ? (oldVersion ? contentJson.username : contentJson.user.name) : (this.getFileData(fileName, userAddress))[2];
const userid = content ? (oldVersion ? contentJson.userid : contentJson.user.id) : (this.getFileData(fileName, userAddress))[1];
const created = content ? (oldVersion ? contentJson.date : contentJson.created) : (this.getFileData(fileName, userAddress))[0];
const res = (content && !oldVersion) ? content : {changes: content};
res.key = keyVersion; // write the information about the user, creation time, key and version to the result object
res.version = version;
@ -431,7 +456,7 @@ docManager.getHistory = function (fileName, content, keyVersion, version) {
};
// clean folder
docManager.cleanFolderRecursive = function (folder, me) {
docManager.prototype.cleanFolderRecursive = function (folder, me) {
if (fileSystem.existsSync(folder)) { // if the given folder exists
const files = fileSystem.readdirSync(folder);
files.forEach((file) => { // for each file from the folder
@ -449,9 +474,9 @@ docManager.cleanFolderRecursive = function (folder, me) {
};
// get files information
docManager.getFilesInfo = function (fileId) {
const userAddress = docManager.curUserHostAddress();
const directory = path.join(docManager.dir, userAddress);
docManager.prototype.getFilesInfo = function (fileId) {
const userAddress = this.curUserHostAddress();
const directory = this.storageRootPath(userAddress);
const filesInDirectory = this.getStoredFiles(); // get all the stored files from the folder
let responseArray = [];
let responseObject;

View File

@ -17,11 +17,9 @@
*/
// get all the necessary values and modules
var path = require("path");
var urlModule = require("url");
var urllib = require("urllib");
var jwt = require("jsonwebtoken");
var jwa = require("jwa");
var fileUtility = require("./fileUtility");
var guidManager = require("./guidManager");
var configServer = require('config').get('server');
@ -170,13 +168,18 @@ documentService.getResponseUri = function (json) {
};
// create a command request
documentService.commandRequest = function (method, documentRevisionId, callback) {
documentService.commandRequest = function (method, documentRevisionId, meta = null, callback) {
documentRevisionId = documentService.generateRevisionId(documentRevisionId); // generate the document key value
var params = { // create a parameter object with command method and the document key value in it
params = { // create a parameter object with command method and the document key value in it
c: method,
key: documentRevisionId
};
if (meta) {
params.meta = meta;
}
var uri = siteUrl + configServer.get('commandUrl'); // get the absolute command url
var headers = { // create a headers object
'Content-Type': 'application/json'

View File

@ -22,7 +22,9 @@ var fileUtility = {};
fileUtility.getFileName = function (url, withoutExtension) {
if (!url) return "";
var parts = url.split("/");
var parts = url.split("\\");
parts = parts.pop();
parts = parts.split("/");
var fileName = parts.pop(); // get the file name from the last part of the url
fileName = fileName.split("?")[0];
@ -66,7 +68,7 @@ fileUtility.fileType = {
fileUtility.documentExts = [".doc", ".docx", ".oform", ".docm", ".dot", ".dotx", ".dotm", ".odt", ".fodt", ".ott", ".rtf", ".txt", ".html", ".htm", ".mht", ".xml", ".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps"];
// the spreadsheet extension list
fileUtility.spreadsheetExts = [".xls", ".xlsx", ".xlsm", ".xlt", ".xltx", ".xltm", ".ods", ".fods", ".ots", ".csv"];
fileUtility.spreadsheetExts = [".xls", ".xlsx", ".xlsm", ".xlsb", ".xlt", ".xltx", ".xltm", ".ods", ".fods", ".ots", ".csv"];
// the presentation extension list
fileUtility.presentationExts = [".pps", ".ppsx", ".ppsm", ".ppt", ".pptx", ".pptm", ".pot", ".potx", ".potm", ".odp", ".fodp", ".otp"];

View File

@ -23,6 +23,7 @@ var descr_user_1 = [
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor",
"Can see the information about all users",
//"Can submit forms"
];
@ -32,6 +33,7 @@ var descr_user_2 = [
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor",
"Can see the information about users from Group2 and users who dont belong to any group",
//"Cant submit forms"
];
@ -44,6 +46,7 @@ var descr_user_3 = [
"Cant download the file",
"Cant print the file",
"Can create new files from the editor",
"Can see the information about Group2 users",
//"Cant submit forms"
];
@ -55,39 +58,42 @@ var descr_user_0 = [
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor",
"Cant see anyones information",
"Can't rename files from the editor",
//"Cant submit forms"
];
var users = [
new User("uid-1", "John Smith", "smith@example.com",
null, null, {},
null, null, {}, null,
null, [], descr_user_1, true),
new User("uid-2", "Mark Pottato", "pottato@example.com",
"group-2", ["group-2", ""], {
view: "",
edit: ["group-2", ""],
remove: ["group-2"]
},
}, ["group-2", ""],
true, [], descr_user_2, false), // own and without group
new User("uid-3", "Hamish Mitchell", "mitchell@example.com",
"group-3", ["group-2"], {
view: ["group-3", "group-2"],
edit: ["group-2"],
remove: []
},
}, ["group-2"],
false, ["copy", "download", "print"], descr_user_3, false), // other group only
new User("uid-0", null, null,
null, null, {},
null, null, {}, [],
null, [], descr_user_0, false),
];
function User(id, name, email, group, reviewGroups, commentGroups, favorite, deniedPermissions, descriptions, templates) {
function User(id, name, email, group, reviewGroups, commentGroups, userInfoGroups, favorite, deniedPermissions, descriptions, templates) {
this.id = id;
this.name = name;
this.email = email;
this.group = group;
this.reviewGroups = reviewGroups;
this.commentGroups = commentGroups;
this.userInfoGroups = userInfoGroups;
this.favorite = favorite;
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;

View File

@ -17,14 +17,13 @@
*/
const reqConsts = require('./request');
const docManager = require("../docManager");
const fileUtility = require("../fileUtility");
const lockManager = require("./lockManager");
const utils = require("./utils");
const fileSystem = require("fs");
const mime = require("mime");
const path = require("path");
const users = require("../users");
const docManager = require("../docManager");
const actionMapping = {};
actionMapping[reqConsts.requestType.GetFile] = getFile;
@ -105,8 +104,8 @@ function parseWopiRequest(req) {
function lock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost); // get current user host address
let filePath = docManager.storagePath(wopi.id, userAddress); // get the storage path of the given file
let userAddress = req.docManager.curUserHostAddress(userHost); // get current user host address
let filePath = req.docManager.storagePath(wopi.id, userAddress); // get the storage path of the given file
if (!lockManager.hasLock(filePath)) {
// file isn't locked => lock
@ -125,8 +124,8 @@ function lock(wopi, req, res, userHost) {
// retrieve a lock on a file
function getLock(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let filePath = req.docManager.storagePath(wopi.id, userAddress);
// get the lock of the specified file and set it as the X-WOPI-Lock header
res.setHeader(reqConsts.requestHeaders.lock, lockManager.getLock(filePath));
@ -137,8 +136,8 @@ function getLock(wopi, req, res, userHost) {
function refreshLock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let filePath = req.docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
@ -157,8 +156,8 @@ function refreshLock(wopi, req, res, userHost) {
function unlock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let filePath = req.docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
@ -178,8 +177,8 @@ function unlockAndRelock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let oldLock = req.headers[reqConsts.requestHeaders.oldLock.toLowerCase()]; // get the X-WOPI-OldLock header
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let filePath = req.docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
@ -196,9 +195,9 @@ function unlockAndRelock(wopi, req, res, userHost) {
// request a message to retrieve a file
function getFile(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let userAddress = req.docManager.curUserHostAddress(userHost);
let path = docManager.storagePath(wopi.id, userAddress);
let path = req.docManager.storagePath(wopi.id, userAddress);
res.setHeader("Content-Length", fileSystem.statSync(path).size);
res.setHeader("Content-Type", mime.getType(path));
@ -213,8 +212,8 @@ function getFile(wopi, req, res, userHost) {
function putFile(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let storagePath = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let storagePath = req.docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(storagePath)) {
// ToDo: if body length is 0 bytes => handle document creation
@ -224,20 +223,20 @@ function putFile(wopi, req, res, userHost) {
} else if (lockManager.getLock(storagePath) == requestLock) {
// lock matches current lock => put file
if (req.body) {
var historyPath = docManager.historyPath(wopi.id, userAddress); // get the path to the file history
var historyPath = req.docManager.historyPath(wopi.id, userAddress); // get the path to the file history
if (historyPath == "") { // if it is empty
historyPath = docManager.historyPath(wopi.id, userAddress, true); // create it
docManager.createDirectory(historyPath); // and create a new directory for the history
historyPath = req.docManager.historyPath(wopi.id, userAddress, true); // create it
req.docManager.createDirectory(historyPath); // and create a new directory for the history
}
var count_version = docManager.countVersion(historyPath); // get the last file version
var count_version = req.docManager.countVersion(historyPath); // get the last file version
version = count_version + 1; // get a number of a new file version
res.setHeader(reqConsts.requestHeaders.ItemVersion, version + 1); // set the X-WOPI-ItemVersion header
var versionPath = docManager.versionPath(wopi.id, userAddress, version); // get the path to the specified file version
docManager.createDirectory(versionPath); // and create a new directory for the specified version
var versionPath = req.docManager.versionPath(wopi.id, userAddress, version); // get the path to the specified file version
req.docManager.createDirectory(versionPath); // and create a new directory for the specified version
var path_prev = path.join(versionPath, "prev" + fileUtility.getFileExtension(wopi.id)); // get the path to the previous file version
fileSystem.renameSync(docManager.storagePath(wopi.id, userAddress), path_prev); // synchronously rename the given file as the previous file version
fileSystem.renameSync(req.docManager.storagePath(wopi.id, userAddress), path_prev); // synchronously rename the given file as the previous file version
let filestream = fileSystem.createWriteStream(storagePath);
req.pipe(filestream);
@ -256,20 +255,18 @@ function putFile(wopi, req, res, userHost) {
// return information about the file properties, access rights and editor settings
function checkFileInfo(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let historyPath = docManager.historyPath(wopi.id, userAddress); // get the path to the file history
let version = 1;
if (historyPath != "") { // if it isn't empty
version = docManager.countVersion(historyPath) + 1; // get a number of a new file version
}
let path = docManager.storagePath(wopi.id, userAddress);
let userAddress = req.docManager.curUserHostAddress(userHost);
let version = req.docManager.getKey(wopi.id, userAddress);
let user = users.getUser(req.query.userid);
let path = req.docManager.storagePath(wopi.id, userAddress);
// add wopi query
var query = new URLSearchParams(wopi.accessToken);
let user = users.getUser(query.get("userid"));
// create the file information object
let fileInfo = {
"BaseFileName": wopi.id,
"OwnerId": docManager.getFileData(wopi.id, userAddress)[1],
"OwnerId": req.docManager.getFileData(wopi.id, userAddress)[1],
"Size": fileSystem.statSync(path).size,
"UserId": user.id,
"UserFriendlyName": user.name,
@ -293,6 +290,7 @@ function returnLockMismatch(res, lock, reason) {
exports.fileRequestHandler = (req, res) => {
let userAddress = null;
req.docManager = new docManager(req, res);
if (req.params['id'].includes("@")) { // if there is the "@" sign in the id parameter
let split = req.params['id'].split("@"); // split this parameter by "@"
req.params['id'] = split[0]; // rewrite id with the first part of the split parameter
@ -314,5 +312,5 @@ exports.fileRequestHandler = (req, res) => {
return;
}
action(wopiData, req, res);
action(wopiData, req, res, userAddress);
}

View File

@ -24,7 +24,6 @@ const fileUtility = require("../fileUtility");
const config = require('config');
const configServer = config.get('server');
const siteUrl = configServer.get('siteUrl'); // the path to the editors installation
const storageFolder = configServer.get("storageFolder");
const users = require("../users");
exports.registerRoutes = function(app) {
@ -32,11 +31,11 @@ exports.registerRoutes = function(app) {
// define a handler for the default wopi page
app.get("/wopi", async function(req, res) {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
let absSiteUrl = siteUrl;
if (absSiteUrl.indexOf("/") === 0) {
absSiteUrl = docManager.getServerHost() + siteUrl;
absSiteUrl = req.docManager.getServerHost() + siteUrl;
//todo: remove
if (absSiteUrl.indexOf("example") !== -1) {
@ -46,17 +45,25 @@ exports.registerRoutes = function(app) {
{
host = host.substring(0, pos);
}
absSiteUrl = docManager.getProtocol() + "://" + host + siteUrl;
absSiteUrl = req.docManager.getProtocol() + "://" + host + siteUrl;
}
}
// get the wopi discovery information
let actions = await utils.getDiscoveryInfo(absSiteUrl);
let wopiEnable = actions.length != 0 ? true : false;
let docsExtEdit = []; // Supported extensions for WOPI
actions.forEach(el => {
if (el.name == "edit") docsExtEdit.push("."+el.ext);
});
let editedExts = configServer.get('editedDocs').filter(i => docsExtEdit.includes(i)); // Checking supported extensions
let fillExts = configServer.get("fillDocs").filter(i => docsExtEdit.includes(i));
try {
// get all the stored files
let files = docManager.getStoredFiles();
let files = req.docManager.getStoredFiles();
// run through all the files and write the corresponding information to each file
for (var file of files) {
@ -69,9 +76,14 @@ exports.registerRoutes = function(app) {
res.render("wopiIndex", {
wopiEnable : wopiEnable,
storedFiles: wopiEnable ? files : [],
params: docManager.getCustomParams(),
params: req.docManager.getCustomParams(),
users: users,
serverUrl: docManager.getServerUrl(),
serverUrl: req.docManager.getServerUrl(),
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
convertExts: configServer.get('convertedDocs'),
editedExts: editedExts,
fillExts: fillExts,
languages: configServer.get('languages'),
});
} catch (ex) {
@ -84,11 +96,12 @@ exports.registerRoutes = function(app) {
// define a handler for creating a new wopi editing session
app.get("/wopi-new", function(req, res) {
var fileExt = req.query.fileExt; // get the file extension from the request
var user = users.getUser(req.query.userid); // get a user by the id
req.docManager = new docManager(req, res);
if (fileExt != null) { // if the file extension exists
var fileName = docManager.createDemo(!!req.query.sample, fileExt, user.id, user.name); // create demo document of the given extension
var redirectPath = docManager.getServerUrl(true) + "/wopi-action/" + encodeURIComponent(fileName) + "?action=edit" + docManager.getCustomParams(); // get the redirect path
var fileName = req.docManager.getCorrectName("new." + fileExt)
var redirectPath = req.docManager.getServerUrl(true) + "/wopi-action/" + encodeURIComponent(fileName) + "?action=editnew" + req.docManager.getCustomParams(); // get the redirect path
res.redirect(redirectPath);
return;
}
@ -96,17 +109,25 @@ exports.registerRoutes = function(app) {
// define a handler for getting wopi action information by its id
app.get("/wopi-action/:id", async function(req, res) {
try {
docManager.init(storageFolder, req, res);
req.docManager = new docManager(req, res);
var fileName = req.docManager.getCorrectName(req.params['id'])
var fileExt = fileUtility.getFileExtension(fileName, true); // get the file extension from the request
var user = users.getUser(req.query.userid); // get a user by the id
// get an action for the specified extension and name
let action = await utils.getAction(fileUtility.getFileExtension(req.params['id'], true), req.query["action"]);
let action = await utils.getAction(fileExt, req.query["action"]);
if (action != null && req.query["action"] == "editnew") {
fileName = req.docManager.RequestEditnew(req, fileName, user);
}
// render wopiAction template with the parameters specified
res.render("wopiAction", {
actionUrl: utils.getActionUrl(docManager.getServerUrl(true), docManager.curUserHostAddress(), action, req.params['id']),
actionUrl: utils.getActionUrl(req.docManager.getServerUrl(true), req.docManager.curUserHostAddress(), action, req.params['id']),
token: "test",
tokenTtl: Date.now() + 1000 * 60 * 60 * 10,
params: docManager.getCustomParams(),
params: req.docManager.getCustomParams(),
});
} catch (ex) {
@ -140,4 +161,11 @@ exports.registerRoutes = function(app) {
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
// define a handler for upload files
app.route('/wopi/upload')
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
};

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="M5 19H8.11111L8.84845 18.2627L5.73734 15.1516L5 15.8889V19ZM10.2627 16.8484L19 8.11111V6.55556H17.4444V5H15.8889L7.15155 13.7373L10.2627 16.8484Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 316 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="M12 6C8.17879 6 4.71351 8.10432 2.15649 11.5223C1.94784 11.8023 1.94784 12.1935 2.15649 12.4736C4.71351 15.8957 8.17879 18 12 18C15.8212 18 19.2865 15.8957 21.8435 12.4777C22.0522 12.1977 22.0522 11.8065 21.8435 11.5264C19.2865 8.10432 15.8212 6 12 6ZM12.2607 15.9919C9.84844 16.1436 7.8564 14.1554 8.00813 11.7393C8.13264 9.74729 9.74728 8.13265 11.7393 8.00815C14.1516 7.85641 16.1436 9.84456 15.9919 12.2607C15.8635 14.2488 14.2488 15.8635 12.2607 15.9919ZM12.1282 13.9959C10.9219 14.0718 9.92498 13.0783 10.0044 11.8718C10.0658 10.8747 10.8749 10.0691 11.8718 10.0041C13.0781 9.92821 14.075 10.9217 13.9956 12.1282C13.9305 13.1289 13.1215 13.9345 12.1282 13.9959Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 838 B

View File

@ -198,8 +198,10 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1
|| FilledExtList.indexOf(posExt) != -1) {
var checkEdited = EditedExtList.split(",").filter(function(ext) { return ext == posExt;});
var checkFilled = FilledExtList.split(",").filter(function(ext) { return ext == posExt;});
if (checkEdited != "" || checkFilled != "") {
jq("#beginEdit").removeClass("disable");
}
};
@ -223,7 +225,11 @@ if (typeof jQuery != "undefined") {
jq(document).on("click", "#beginEdit:not(.disable)", function () {
var fileId = encodeURIComponent(jq('#hiddenFileName').val());
var url = UrlEditor + "?fileName=" + fileId + "&lang=" + language + "&userid=" + userid;
if (UrlEditor == "wopi-action"){
var url = UrlEditor + "/" + fileId + "?action=edit";
}else{
var url = UrlEditor + "?fileName=" + fileId + "&lang=" + language + "&userid=" + userid;
}
window.open(url, "_blank");
jq('#hiddenFileName').val("");
jq.unblockUI();
@ -232,7 +238,11 @@ if (typeof jQuery != "undefined") {
jq(document).on("click", "#beginView:not(.disable)", function () {
var fileId = encodeURIComponent(jq('#hiddenFileName').val());
var url = UrlEditor + "?mode=view&fileName=" + fileId + "&lang=" + language + "&userid=" + userid;
if (UrlEditor == "wopi-action"){
var url = UrlEditor + "/" + fileId + "?action=view";
}else{
var url = UrlEditor + "?mode=view&fileName=" + fileId + "&lang=" + language + "&userid=" + userid;
}
window.open(url, "_blank");
jq('#hiddenFileName').val("");
jq.unblockUI();

View File

@ -87,10 +87,6 @@
}
@media (max-width: 1008px) {
#portal-info {
width: 65vw;
}
.left-panel {
margin-left: 0;
}
@ -128,6 +124,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.main-panel {
left: 0;
padding: 48px 18px 24px;
@ -312,6 +312,9 @@
.tableRow td:first-child {
max-width: 17%;
}
#portal-info {
max-width: 60vw;
}
}
.downloadContentCellShift:after {
@ -363,6 +366,10 @@
height: 80px;
}
.main {
height: calc(100% - 128px);
}
.copy {
width: 100%;
text-align: center;
@ -436,6 +443,58 @@
display: none;
width: 1%;
}
/* Mobile Upload*/
.blockUI.blockMsg.blockPage.ui-dialog.ui-widget.ui-corner-all.ui-widget-content.ui-draggable {
width: 344px !important;
box-shadow: 0px 7px 15px rgba(85, 85, 85, 0.1);
border-radius: 2px;
top: 10% !important;
margin-left: -172px !important;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0;
}
.ui-dialog .ui-dialog-content {
padding: 0 !important;
}
#mainProgress {
margin: 24px 16px 0 !important;
}
.blockTitle {
padding: 10px 10px 6px 16px !important;
font-size: 14px !important;
}
#mainProgress .describeUpload {
padding: 8px 0 !important;
}
.dialog-close {
margin: 0 !important;
}
.step-descr{
line-height: 150%;
}
.step {
line-height: 160%;
}
.buttonsMobile{
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.button.gray{
margin: 0;
}
.button, .button:hover{
display: flex;
justify-content: center;
padding: 0 !important;
width: 144px;
height: 56px;
margin-bottom: 24px !important;
}
}
@media (max-width: 560px) and (min-width: 510px) {

View File

@ -97,6 +97,10 @@ header img {
width: 896px;
}
#portal-info {
max-width: 65vw;
}
.portal-name {
color: #FF6F3D;
font-size: 24px;
@ -748,12 +752,9 @@ html {
width: 30vw;
min-width: 200px;
max-width: 400px;
margin-top: 20px;
}
.user-descr > b {
margin-left: 25px;
}
.portal-descr:nth-child(3) {
margin-bottom: 20px;
}

4
web/documentserver-example/nodejs/views/config.ejs Normal file → Executable file
View File

@ -24,7 +24,8 @@
"modifyContentControl": <%- editor.modifyContentControl %>,
"review": <%- editor.review %>,
"reviewGroups": <%- editor.reviewGroups %>,
"commentGroups": <%- editor.commentGroups %>
"commentGroups": <%- editor.commentGroups %>,
"userInfoGroups": <%- editor.userInfoGroups %>
}
},
"editorConfig": {
@ -47,7 +48,6 @@
},
"customization": {
"about": true,
"chat": true,
"comments": true,
"feedback": true,
"forcesave": false,

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