Compare commits

...

175 Commits

Author SHA1 Message Date
985f96228f feat(nodejs): removed directUrl 2024-04-16 15:39:44 +07:00
e89eee7e28 Merge pull request #560 from ONLYOFFICE/bump-some-gems
build(ruby): bump gem versions as directed by dependabot
2024-04-09 11:20:35 +03:00
6a4b79fb54 build(ruby): bump gem versions as directed by dependabot 2024-04-05 17:39:48 +07:00
b1dd965590 Merge pull request #559 from ONLYOFFICE/fix/nodejs-dependencies-overrides
build(nodejs): add overrides in package.json
2024-04-05 10:25:35 +03:00
208bf086d8 Merge pull request #558 from ONLYOFFICE/feature/nodejs-navbar-update
feature/nodejs navbar update
2024-04-05 10:18:19 +03:00
ebb1179190 build(nodejs): add overrides in package.json 2024-04-04 17:32:09 +07:00
3375315cc0 feature(nodejs): show navigation bar at top even if there are no files in user directory 2024-04-04 13:08:47 +05:00
a070b6e82b nodejs: rename back (eda1876f59) 2024-04-03 14:27:57 +03:00
43d260cd7a Merge pull request #534 from ONLYOFFICE/feature/nodejs-forced-conversion
Feature/nodejs forced conversion
2024-04-03 14:05:24 +03:00
14bb9fc8a4 Merge pull request #556 from ONLYOFFICE/fix/wopi-mobile-default-action
fix(nodejs): mobileEdit default action for mobile wopi page. Fix Bug 65920
2024-04-03 13:07:02 +03:00
57ca15153f Merge pull request #551 from ONLYOFFICE/feature/fetching-formats
Feature/fetching formats
2024-04-03 12:31:53 +03:00
bbde4dc87b Merge pull request #525 from ONLYOFFICE/nodejs-update-dependencies
build(nodejs): updated dependencies
2024-04-03 12:19:33 +03:00
5b46195f72 fix(nodejs): mobileEdit default action for mobile wopi page. Fix Bug 65920 2024-04-02 12:55:33 +07:00
81c94c9fbd refactor(nodejs): load formats script and remove redundant variables 2024-04-01 12:24:14 +05:00
cc3c640868 refactor: merge format and format-manager files into formats file 2024-04-01 12:21:18 +05:00
20e6664a6b nodejs: absolute url in request to discovery (1e72167e7d)
Revert "nodejs: absolute host is not needed with urllib" (2460f2c7ac)
2024-03-28 13:35:50 +03:00
61af52a534 nodejs: fix favicon on wopi action 2024-03-28 10:53:12 +03:00
6236f90a50 Merge pull request #554 from ONLYOFFICE/feature/for-bug-59054
Feature/for bug 59054
2024-03-27 13:00:27 +03:00
5118352714 nodejs: debug mobile editors opening (Fix Bug 59054) 2024-03-27 12:57:58 +03:00
aa5a660001 nodejs: fix wopi editor size (Fix Bug 59054) 2024-03-27 12:57:52 +03:00
bf1f987333 nodejs: wopi refactoring 2024-03-27 12:56:08 +03:00
f1f834fb0c refactor: create and use new method for finding formats by extension 2024-03-26 17:57:52 +05:00
53c3e97b5c fix(nodejs): linter offence 2024-03-25 14:25:03 +05:00
eda1876f59 refactor(nodejs): rename convext variable and remove redundant internalext variable 2024-03-25 14:18:55 +05:00
64eab6c4a2 refactor(nodejs): add flag for keeping original file and replace conditional expression with it 2024-03-25 14:09:36 +05:00
acb9a0e4c9 refactor(java-spring): add formatslist dto object and replace jsonobject with it 2024-03-25 12:51:13 +05:00
909f638a92 Merge pull request #552 from ONLYOFFICE/fix/nodejs-wopi-putfile
fix(nodejs): handle document creation in putFile. Fix Bug 66817
2024-03-22 10:02:57 +03:00
6d28e3f8d8 Merge branch 'release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-03-21 14:23:41 +03:00
1b8f60d5dd nodejs: update formats 2024-03-21 14:21:29 +03:00
0414319893 nodejs: fill permission in embedded mode 2024-03-21 14:05:31 +03:00
12ad0d9e7e fix(nodejs): handle document creation in putFile. Fix Bug 66817 2024-03-21 17:18:58 +07:00
f3b35a878c refactor(java-spring): move formats method to indexcontroller and change return type to responseentity 2024-03-21 13:23:31 +05:00
c712f596e1 Merge remote-tracking branch 'remotes/origin/release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
2024-03-20 12:52:55 +03:00
ad39fb7c19 nodejs: wopi formsubmit icon
# Conflicts:
#	CHANGELOG.md
2024-03-20 12:51:24 +03:00
7d2eb086ce Merge pull request #545 from ONLYOFFICE/feature/delete-all-files
Feature/delete all files
2024-03-20 11:01:40 +03:00
0a61708f67 Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-03-20 10:58:41 +03:00
389198aec6 Merge pull request #544 from ONLYOFFICE/feature/auto-conversion-error
Feature/auto conversion error
2024-03-20 10:02:53 +03:00
0d302ee8f6 nodejs: error message when error:1 2024-03-19 18:06:43 +03:00
d3a548bf3f fix(ruby): conversion error code to integer 2024-03-19 17:19:48 +07:00
fadae60e89 fix: linter offenses 2024-03-19 13:43:17 +05:00
426b15b8f1 Merge remote-tracking branch 'origin/develop' into feature/fetching-formats 2024-03-19 13:01:48 +05:00
601146c847 refactor(nodejs): change formats retrieval method on frontend 2024-03-19 12:59:54 +05:00
c4980c19e7 Revert "docxf and oform since v7.0"
This reverts commit beb9885b03.

# Conflicts:
#	web/documentserver-example/php/doceditor.php
2024-03-18 18:24:47 +03:00
0bfb036be6 refactor(csharp-mvc): change formats retrieval method on frontend 2024-03-18 18:03:10 +05:00
88b36049d2 refactor(csharp): change formats retrieval method on frontend 2024-03-18 18:02:29 +05:00
f1a1ec15ad Merge branch 'release/v8.1.0' into develop
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/nodejs/app.js
#	web/documentserver-example/nodejs/helpers/users.js
2024-03-18 14:38:55 +03:00
495ba9814f nodejs: close editor
# Conflicts:
#	CHANGELOG.md
#	web/documentserver-example/nodejs/app.js
#	web/documentserver-example/nodejs/helpers/users.js
2024-03-18 14:35:26 +03:00
558365325c nodejs: format max length
# Conflicts:
#	web/documentserver-example/nodejs/helpers/users.js
2024-03-18 14:34:52 +03:00
683f1d33c4 nodejs: close editor 2024-03-18 14:30:25 +03:00
e8c98ba12a nodejs: format max length 2024-03-18 14:28:30 +03:00
e389cf41b8 fix(ruby): linter offence 2024-03-18 16:27:59 +05:00
80291baa40 goback: change state for users (408d80fff6) 2024-03-18 14:21:12 +03:00
b9113f93f6 fix: linter offenses 2024-03-18 16:03:00 +05:00
af778a8636 fix(ruby): linter offenses 2024-03-18 15:26:22 +05:00
47f4f022aa Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-03-15 16:48:58 +03:00
b2202111ac fix changelog 2024-03-15 16:47:29 +03:00
1da215b1eb Merge remote-tracking branch 'remotes/origin/develop' into feature/auto-conversion-error
# Conflicts:
#	CHANGELOG.md
2024-03-15 16:46:37 +03:00
8c8d14b48c refactor(java-spring): change formats retrieval method on frontend 2024-03-15 15:50:14 +05:00
5217a64e83 refactor(java): change formats retrieval method on frontend 2024-03-15 15:38:14 +05:00
456789191d build(nodejs): returned some dependencies versions with breaking changes 2024-03-15 17:33:00 +07:00
e1e9efa305 refactor(ruby): change formats retrieval method on frontend 2024-03-15 15:29:58 +05:00
a3016f3f96 Merge remote-tracking branch 'remotes/origin/master' into develop 2024-03-15 13:18:37 +03:00
333981cdad Merge pull request #549 from ONLYOFFICE/release/1.8.0
Release/1.8.0
2024-03-15 13:02:53 +03:00
cee60a340a nodejs: code alert 177 (e85cb5137b) 2024-03-15 12:55:59 +03:00
6c09b3f62a nodejs: wopi formsubmit icon 2024-03-15 11:18:45 +03:00
4b7ba35f83 nodejs: send email and image for protect request 2024-03-15 11:06:48 +03:00
abab30176f refactor(python): change formats retrieval method on frontend 2024-03-14 19:11:37 +05:00
1abcf78b85 refactor(php): change formats retrieval method on frontend 2024-03-14 19:08:12 +05:00
a952858ab8 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-03-14 15:07:47 +03:00
65ff78fba7 Merge pull request #548 from ONLYOFFICE/fix/ruby-conversion-progress
fix(ruby): conversion percent type validation. Fix Bug 66869
2024-03-14 15:07:11 +03:00
717996af87 Merge pull request #547 from ONLYOFFICE/fix/ruby-historyobj
fix(ruby): historyobj method. Fix Bug 66862
2024-03-14 15:06:45 +03:00
66389fe69c fix(ruby): conversion percent type validation. Fix Bug 66869 2024-03-14 17:24:02 +07:00
a63d8d4284 fix(ruby): previous in history data 2024-03-14 16:30:22 +07:00
ed39928d1f Merge pull request #546 from ONLYOFFICE/fix/ruby-saveas-url-in-docker
fix(ruby): replacing file_url host in saveas. Fix Bug 66874
2024-03-14 11:13:50 +03:00
5bc7ffde73 fix(ruby): historyobj method. Fix Bug 66862 2024-03-13 18:27:58 +07:00
5258fd0674 feat(csharp-mvc): handling auto-conversion error(-9) 2024-03-13 15:39:42 +05:00
ca274bc465 feat(csharp): handling auto-conversion error(-9) 2024-03-13 15:39:07 +05:00
b1d66e16a5 feat(java-spring): handling auto-conversion error(-9) 2024-03-13 15:38:24 +05:00
359cda0f67 feat(java): handling auto-conversion error(-9) 2024-03-13 15:37:13 +05:00
24a3441b1e feat(ruby): handling auto-conversion error(-9) 2024-03-13 15:36:13 +05:00
c6eff10be1 fix(ruby): replacing file_url host in saveas. Fix Bug 66874 2024-03-13 17:36:06 +07:00
a7fca1a53b feat(python): handling auto-conversion error(-9) 2024-03-13 15:35:06 +05:00
5b6a2ba318 refactor(csharp): remove console.log 2024-03-13 13:44:47 +05:00
bb4aed6efb fix(python): uncontrolled data used in path expression 2024-03-13 13:38:53 +05:00
01d8c0acde Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/ruby/Gemfile.lock
2024-03-12 11:22:07 +03:00
8fdbdb926b Merge pull request #543 from ONLYOFFICE/fix/ruby-gem-conflict
fix(ruby): resolved gem conflict. Fix Bug 66514
2024-03-12 11:21:04 +03:00
31cf6ca486 Merge pull request #529 from ONLYOFFICE/fix/ruby-gemfile-lock
build(ruby): updated gemfile.lock to 0 vulnerabilities
2024-03-12 11:20:10 +03:00
fbe24234d2 refactor(python): create method for deleting user folder and call it inside remove http method 2024-03-12 12:15:22 +05:00
ac894171fb changelog: delete all files 2024-03-12 11:23:53 +05:00
0174d2a465 fix(ruby): resolved gem conflict. Fix Bug 66514 2024-03-11 18:08:26 +07:00
0f000c1457 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-03-11 13:28:12 +03:00
97b0cdd042 fix(ruby): nginx body size 2024-03-11 13:26:29 +03:00
143c0a095f fix(python): nginx body size 2024-03-11 13:25:05 +03:00
04c004acdb fix(php): nginx body size 2024-03-11 13:25:04 +03:00
1699dc22b5 nodejs: fix rename var (9048082cb7) 2024-03-09 16:54:56 +03:00
cc62ff8a61 Merge pull request #531 from ONLYOFFICE/feature/php-forced-conversion
Feature/php forced conversion
2024-03-07 15:59:54 +03:00
fd21292dbd refactor(nodejs): change parameter name and remove redundant checking 2024-03-07 16:24:51 +05:00
d43294bd8a feat(csharp-mvc): implement delete all files method 2024-03-07 15:56:02 +05:00
81f5bdd528 feat(csharp): implement delete all files method 2024-03-07 15:42:23 +05:00
c1da8e14c3 feat(java-spring): implement delete all files method 2024-03-06 14:41:29 +05:00
767b5588ab feat(java): implement delete all files method 2024-03-06 14:27:21 +05:00
8858c3c256 feat(ruby): implement delete all files method 2024-03-06 14:24:52 +05:00
89f1c18d06 feat(python): implement delete all files method 2024-03-06 13:52:06 +05:00
81ad7f7a64 feat(php): implement delete all files method 2024-03-06 13:42:41 +05:00
23ba4ff5b3 Merge pull request #541 from ONLYOFFICE/feature/fix-domain
Feature/fix domain
2024-03-06 09:32:36 +03:00
423233e93f update submodule 2024-03-05 16:42:41 +03:00
5f3eaa05f9 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/assets/js/jscript.js
2024-03-05 16:33:14 +03:00
283d93667e ruby: change document-server to documentserver 2024-03-05 16:24:39 +03:00
158ac4161c python: change document-server to documentserver 2024-03-05 16:24:27 +03:00
bf3df5c89d php: change document-server to documentserver 2024-03-05 16:24:04 +03:00
d8251f3280 fix config paths 2024-03-05 16:16:31 +03:00
e4db31fbd5 Merge remote-tracking branch 'remotes/origin/feature/readme' into develop
# Conflicts:
#	Readme.md
2024-03-05 16:04:45 +03:00
b633f5ff19 Merge pull request #536 from Afrowave/python-example-update
CHORE: Add the Python example reference on the README.
2024-03-05 15:24:12 +03:00
0c8110d2aa Merge pull request #540 from ONLYOFFICE/fix/php-posExt-of-loaded-file
fix(php): ext of loaded file without dot. Fix Bug 66718
2024-03-05 09:51:06 +03:00
f9f8dada69 Merge pull request #539 from ONLYOFFICE/fix/php-user-in-open-source-request
fix(php): checking user in editor request. fix bug 66716
2024-03-05 09:50:33 +03:00
36535f89bb fix(php): ext of loaded file without dot. Fix Bug 66718 2024-03-05 13:46:14 +07:00
09031033aa fix(php): checking user in editor request. fix bug 66716 2024-03-05 13:30:34 +07:00
f657e5ab4a Merge pull request #537 from ONLYOFFICE/fix/csharp-mvc-document-formats-type
fix(csharp-mvc): empty strings tolerant json deserialization.
2024-03-04 15:12:50 +03:00
e42f7fd271 fix(csharp-mvc): empty strings tolerant json deserialization. Fix bug 66688 2024-03-04 13:53:31 +07:00
0f0549c535 Merge remote-tracking branch 'origin/python-example-update' into python-example-update 2024-03-02 15:53:10 +03:00
e896f03acc CHORE: Add the Python example reference on the README. 2024-03-02 15:53:06 +03:00
a74d6b8676 CHORE: Add the Python example reference on the README. 2024-03-02 15:39:19 +03:00
672aae3791 refactor(nodejs): rename variables, ids, and classes regarding forced conversion 2024-03-01 16:29:04 +05:00
999e147539 fix(nodejs): disable file type buttons after selection 2024-03-01 15:25:14 +05:00
e57ad73d4f feat(php): allow to explicitly select output file type when getting auto-conversion error(-9) 2024-03-01 13:03:59 +05:00
690ab5471b Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-28 17:40:09 +03:00
f9fa10e70a nodejs: fix when siteUrl is '/' (Fix Bug 66578) 2024-02-28 17:39:48 +03:00
2460f2c7ac nodejs: absolute host is not needed with urllib (1e72167e7d) 2024-02-28 17:22:31 +03:00
e3342a030c nodejs: fix mobile size (Fix Bug 34620) 2024-02-28 14:40:21 +03:00
47b07a5c8b Merge pull request #528 from ONLYOFFICE/fix/java-spring-document-formats-type
fix(java-spring): empty strings as null in json deserialization.
2024-02-27 15:02:14 +03:00
e7630f516d build(ruby): updated gemfile.lock to 0 vulnerabilities 2024-02-27 16:47:26 +07:00
3e6bee4cc1 fix(java-spring): empty strings as null in json deserialization. fix bug 66552 2024-02-27 15:14:16 +07:00
2b1f7b0548 Merge pull request #527 from ONLYOFFICE/fix/java-document-formats-type
fix(java): empty strings as null in json dererialization. fix bug 66534
2024-02-27 08:57:14 +03:00
ba195952b2 Merge pull request #526 from ONLYOFFICE/fix/ruby-correct-server-url
Fix/ruby correct server url
2024-02-27 08:56:10 +03:00
4ac8d9ee16 fix(ruby): correct server url for images 2024-02-27 08:55:10 +03:00
c46292c595 fix(java): empty strings as null in json dererialization. fix bug 66534 2024-02-26 17:43:55 +07:00
19a38df423 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/nodejs/app.js
2024-02-26 12:39:33 +03:00
b771b70ced Merge pull request #523 from ONLYOFFICE/fix/nodejs-editor-fileExt-vulnerability
fix(nodejs): editor fileExt validation. fix bug 66576
2024-02-26 12:37:56 +03:00
67a21fbe35 Merge pull request #524 from ONLYOFFICE/ruby-update-gemfile-lock
build(ruby): update gemfile.lock
2024-02-26 12:13:04 +03:00
08dc8ae6a7 build(ruby): updating gemfile.lock for containers 2024-02-22 17:28:13 +07:00
dcf2fb43e0 build(nodejs): updated dependencies (found 0 vulnerabilities) 2024-02-22 15:47:38 +07:00
dca6f4173e build(ruby): update gemfile.lock 2024-02-22 15:23:07 +07:00
c91d765296 fix(nodejs): editor fileExt validation. fix bug 66576 2024-02-22 14:49:46 +07:00
9615f5a93a Merge pull request #522 from ONLYOFFICE/fix/php-reference-link
fix(php): fix bug 66518
2024-02-21 15:46:08 +03:00
a9f0068600 fix(php): fix bug 66518 2024-02-21 16:53:19 +07:00
9f2a72aafa Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/templates/docEditor.tpl
2024-02-20 15:04:31 +03:00
a71e7b1896 Merge pull request #520 from ONLYOFFICE/fix/php-container-links
fix(php): nginx headers, correct serverPath and forgotten comma
2024-02-20 15:00:17 +03:00
d8cb434ad2 Merge pull request #521 from ONLYOFFICE/feat/php-make-restart
feat(php): make restart
2024-02-20 14:55:33 +03:00
96af86846b feat(php): make restart 2024-02-20 17:26:40 +07:00
a83c22e537 fix(php): nginx headers, correct serverPath and forgotten comma 2024-02-20 14:41:29 +07:00
fa5fb2f182 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-19 13:56:26 +03:00
4be1eaf917 Merge pull request #519 from ONLYOFFICE/fix/php-max-filesize
fix(php): upload file max size. fix bug 64359
2024-02-19 13:55:07 +03:00
f9bd8db640 fix(php): upload file max size. fix bug 64359 2024-02-19 13:54:25 +03:00
0ba4facdb7 Merge pull request #518 from ONLYOFFICE/fix/saveas-vulnerability
fix(nodejs): checking file domain. fix bug 65593
2024-02-19 13:51:55 +03:00
03625022ca fix(nodejs): checking file domain. fix bug 65593 2024-02-19 15:06:16 +07:00
f154ffc981 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop
# Conflicts:
#	web/documentserver-example/php/src/helpers/Users.php
2024-02-16 18:50:23 +03:00
be7ca0006a Merge pull request #517 from ONLYOFFICE/fix/php-user-image
fix(php): add image to users class
2024-02-16 18:49:07 +03:00
39a6581292 fix(php): add image to users class
Fix Bug 66516
2024-02-16 18:48:38 +03:00
90142299e5 Merge pull request #516 from ONLYOFFICE/feature/tabs-menu
feat(nodejs): move links to header
2024-02-15 15:12:37 +03:00
0f288d539e feat(nodejs): move links to header 2024-02-15 12:35:12 +03:00
d00237226b python: fix link (Fix Bug 66427) 2024-02-15 11:41:23 +03:00
2ead6e1f7e feat(nodejs): move links to header 2024-02-15 11:23:34 +03:00
98d48f373a nginx headers 2024-02-15 11:18:42 +03:00
92e7294f81 using ds v8.0 2024-02-15 11:16:46 +03:00
ea9ac4bb42 Merge pull request #506 from ONLYOFFICE/feature/delete-all-files
feat(nodejs): add a button to clear all files
2024-02-14 22:27:36 +03:00
5775f44f27 Merge remote-tracking branch 'remotes/origin/develop' into feature/delete-all-files
# Conflicts:
#	CHANGELOG.md
2024-02-14 22:26:45 +03:00
4ce10d82a1 Merge pull request #513 from ONLYOFFICE/python-reference-fix
fix(python): link in reference body
2024-02-14 22:22:38 +03:00
3e9e4281c5 Merge pull request #515 from ONLYOFFICE/fix/wopi-edit
fix(nodejs): correct edited exts from discovery info
2024-02-14 22:22:10 +03:00
3eac4912e1 Merge remote-tracking branch 'remotes/origin/release/1.8.0' into develop 2024-02-14 22:19:11 +03:00
283139450c Form template rename as PDF form 2024-02-14 16:45:07 +03:00
e8df1c2821 fix(nodejs): correct edited exts from discovery info 2024-02-14 15:29:27 +07:00
ff2bcd0ef6 feat(nodejs): add a button to clear all files 2024-02-13 11:12:36 +03:00
605c21c0be fix(python): link in reference body 2024-02-12 16:30:50 +07:00
941c00c476 nodejs: fix serbian lang 2024-02-12 10:37:27 +03:00
2459863430 Merge pull request #468 from ONLYOFFICE/release/1.7.0
Release/1.7.0
2023-10-30 12:17:35 +03:00
137 changed files with 4768 additions and 3359 deletions

View File

@ -1,9 +1,14 @@
# Change Log
- fill permission in embedded mode
- delete all files
- handling conversion -9 error
- nodejs: wopi formsubmit icon
- nodejs: tabs menu
- change insert image
- nodejs: handling conversion -9 error
- different goback for users
- nodejs: converting function on index page
- nodejs: close editor
## 1.8.0
- nodejs: pdf, djvu, xps, oxps as pdf documentType

View File

@ -1,11 +1,11 @@
## Integration examples
Test examples are simple document management systems that can be built into your application for testing.
These 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.
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Java Spring, Node.js, PHP, Python 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`
@ -13,9 +13,9 @@ You should change `http://documentserver` to your server address in these files:
* [Java](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java) - `web/documentserver-example/java/src/main/resources/settings.properties`
* [Java Spring](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java-spring) - `web/documentserver-example/java-spring/src/main/resources/application.properties`
* [Node.js](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/nodejs) - `web/documentserver-example/nodejs/config/default.json`
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/config.json`
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/config.py`
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/config/application.rb`
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/src/configuration/ConfigurationManager.php`
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/src/configuration/configuration.py`
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/app/configuration/configuration.rb`
More information on how to use these examples can be found here: [http://api.onlyoffice.com/editors/demopreview](http://api.onlyoffice.com/editors/demopreview "http://api.onlyoffice.com/editors/demopreview")

View File

@ -502,6 +502,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -592,6 +619,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -741,6 +791,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -229,6 +229,10 @@ namespace OnlineEditorsExampleMVC.Helpers
switch (errorCode)
{
case -9:
// public const int c_nErrorConversionOutputFormatError = -9;
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
break;
case -8:
// public const int c_nErrorFileVKey = -8;
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");

View File

@ -95,7 +95,7 @@ namespace OnlineEditorsExampleMVC.Helpers
descr_user_1,
true,
true,
new Goback()
new Goback(null, false)
),
new User(
"uid-2",
@ -135,7 +135,7 @@ namespace OnlineEditorsExampleMVC.Helpers
descr_user_3,
false,
false,
new Goback(null,false)
null
),
new User(
"uid-0",

View File

@ -157,7 +157,7 @@ namespace OnlineEditorsExampleMVC.Models
{ "download", !user.deniedPermissions.Contains("download") },
{ "edit", canEdit && (editorsMode == "edit" || editorsMode == "view" || editorsMode == "filter" || editorsMode == "blockcontent") },
{ "print", !user.deniedPermissions.Contains("print") },
{ "fillForms", editorsMode != "view" && editorsMode != "comment" && editorsMode != "embedded" && editorsMode != "blockcontent" },
{ "fillForms", editorsMode != "view" && editorsMode != "comment" && editorsMode != "blockcontent" },
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },

View File

@ -23,6 +23,7 @@ using System.IO;
using static OnlineEditorsExampleMVC.Models.FileUtility;
using System.Linq;
using System.Text;
using Newtonsoft.Json.Converters;
namespace OnlineEditorsExampleMVC.Models
{
@ -48,9 +49,21 @@ namespace OnlineEditorsExampleMVC.Models
}
}
public class EmptyTolerantStringEnumConverter : StringEnumConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String && string.IsNullOrWhiteSpace(reader.Value.ToString()))
return Activator.CreateInstance(objectType);
return base.ReadJson(reader, objectType, existingValue, serializer);
}
}
public class Format
{
public string Name { get; }
[JsonConverter(typeof(EmptyTolerantStringEnumConverter))]
public FileType Type { get; }
public List<string> Actions { get; }
public List<string> Convert { get; }

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch("webeditor.ashx?type=formats")
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.Name,
format.Type,
format.Actions,
format.Convert,
format.Mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({ filename: fileName, filePass: filePass }),
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")) {
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder", filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
jq("#beginView, #beginEmbedded").removeClass("disable");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillExtList.indexOf(posExt) != -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var filePass = jq("#filePass").val();
if (filePass) {
@ -294,6 +330,23 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
var requestAddress = "webeditor.ashx"
+ "?type=remove";
jq.ajax({
async: true,
contentType: "text/xml",
url: requestAddress,
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -352,12 +352,6 @@
};
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

@ -68,7 +68,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
<a class="try-editor form" data-type="docxf">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -151,7 +151,14 @@
if (storedFiles.Any())
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -295,6 +302,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -357,9 +373,6 @@
<%: Scripts.Render("~/bundles/jquery", "~/bundles/scripts") %>
<script language="javascript" type="text/javascript">
var FillExtList = '<%= string.Join(",", DocManagerHelper.FillFormExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", DocManagerHelper.ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", DocManagerHelper.EditedExts.ToArray()) %>';
var UrlConverter = '<%= Url.Content("~/webeditor.ashx?type=convert") %>';
var UrlEditor = '<%= Url.Action("editor", "Home") %>';
</script>

View File

@ -87,6 +87,9 @@ namespace OnlineEditorsExampleMVC
case "reference":
Reference(context);
break;
case "formats":
Formats(context);
break;
}
}
@ -240,7 +243,13 @@ namespace OnlineEditorsExampleMVC
var fileUri = DocManagerHelper.GetDownloadUrl(fileName);
var extension = (Path.GetExtension(fileName).ToLower() ?? "").Trim('.');
var internalExtension = "ooxml";
string conversionExtension = "ooxml";
object fileExt;
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
{
conversionExtension = fileExt.ToString();
}
// check if the file with such an extension can be converted
if (DocManagerHelper.ConvertExts.Contains("." + extension))
@ -258,7 +267,7 @@ namespace OnlineEditorsExampleMVC
// get the url and file type of the converted file
Dictionary<string, string> newFileData;
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, internalExtension, key, true, out newFileData, filePass, lang);
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, conversionExtension, key, true, out newFileData, filePass, lang);
if (result != 100)
{
context.Response.Write("{ \"step\" : \"" + result + "\", \"filename\" : \"" + fileName + "\"}");
@ -393,8 +402,17 @@ namespace OnlineEditorsExampleMVC
context.Response.ContentType = "text/plain";
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
Remove(fileName); // remove a file and its history if it exists
string fileName = context.Request["fileName"];
if (!String.IsNullOrEmpty(fileName))
{
fileName = Path.GetFileName(context.Request["fileName"]);
Remove(fileName); // remove a file and its history if it exists
}
else
{
RemoveUserDirectory(); // remove the user's directory
}
context.Response.Write("{ \"success\": true }");
}
@ -414,6 +432,14 @@ namespace OnlineEditorsExampleMVC
if (Directory.Exists(histDir)) Directory.Delete(histDir, true);
}
// remove the user's directory
private static void RemoveUserDirectory()
{
var path = DocManagerHelper.StoragePath("", null); // get the path to the user directory
if (Directory.Exists(path)) Directory.Delete(path, true);
}
// get files information
private static void Files(HttpContext context)
{
@ -951,6 +977,25 @@ namespace OnlineEditorsExampleMVC
return history;
}
// return all the supported formats
private static void Formats(HttpContext context)
{
try
{
Dictionary<string, object> data = new Dictionary<string, object>
{
{ "formats", FormatManager.All() }
};
context.Response.ContentType = "application/json";
var jss = new JavaScriptSerializer();
context.Response.Write(jss.Serialize(data));
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -502,6 +502,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -596,6 +623,29 @@ footer a:hover {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -745,6 +795,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -71,7 +71,7 @@
<a class="try-editor slide" data-type="slide">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
<a class="try-editor form" data-type="docxf">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -153,7 +153,14 @@
if (storedFiles.Any())
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr >
@ -297,6 +304,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -364,12 +380,8 @@
<script language="javascript" type="text/javascript" src="script/jquery.iframe-transport.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery.fileupload.js"></script>
<script language="javascript" type="text/javascript" src="script/jquery.dropdownToggle.js"></script>
<script language="javascript" type="text/javascript" src="script/formats.js"></script>
<script language="javascript" type="text/javascript" src="script/jscript.js"></script>
<script language="javascript" type="text/javascript">
var FillFormExtList = '<%= string.Join(",", FillFormsExts.ToArray()) %>';
var ConverExtList = '<%= string.Join(",", ConvertExts.ToArray()) %>';
var EditedExtList = '<%= string.Join(",", EditedExts.ToArray()) %>';
</script>
</body>
</html>

View File

@ -437,7 +437,14 @@ namespace OnlineEditorsExample
var lang = context.Request.Cookies.GetOrDefault("ulang", null);
var extension = (Path.GetExtension(_fileName).ToLower() ?? "").Trim('.');
var internalExtension = "ooxml";
string conversionExtension = "ooxml"; // set the default conversion extension as ooxml
object fileExt;
// change the conversion extension if it was provided in the request body
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
{
conversionExtension = fileExt.ToString();
}
// check if the file with such an extension can be converted
if (ConvertExts.Contains("." + extension))
@ -454,7 +461,7 @@ namespace OnlineEditorsExample
// get the url and file type of the converted file
Dictionary<string, string> newFileData;
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, internalExtension, key, true, out newFileData, filePass, lang);
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, conversionExtension, key, true, out newFileData, filePass, lang);
if (result != 100)
{
return "{ \"step\" : \"" + result + "\", \"filename\" : \"" + _fileName + "\"}";

View File

@ -353,12 +353,6 @@
};
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

@ -225,7 +225,7 @@ namespace OnlineEditorsExample
{ "download", !user.deniedPermissions.Contains("download") },
{ "edit", canEdit && (editorsMode == "edit" || editorsMode =="view" || editorsMode == "filter" || editorsMode == "blockcontent") },
{ "print", !user.deniedPermissions.Contains("print") },
{ "fillForms", editorsMode != "view" && editorsMode != "comment" && editorsMode != "embedded" && editorsMode != "blockcontent" },
{ "fillForms", editorsMode != "view" && editorsMode != "comment" && editorsMode != "blockcontent" },
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },

View File

@ -231,6 +231,10 @@ namespace ASC.Api.DocumentConverter
switch (errorCode)
{
case -9:
// public const int c_nErrorConversionOutputFormatError = -9;
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
break;
case -8:
// public const int c_nErrorFileVKey = -8;
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");

View File

@ -94,7 +94,7 @@ namespace OnlineEditorsExample
descr_user_1,
true,
true,
new Goback()
new Goback(null, false)
),
new User(
"uid-2",
@ -134,7 +134,7 @@ namespace OnlineEditorsExample
descr_user_3,
false,
false,
new Goback(null,false)
null
),
new User(
"uid-0",

View File

@ -87,6 +87,9 @@ namespace OnlineEditorsExample
case "reference":
Reference(context);
break;
case "formats":
Formats(context);
break;
}
}
@ -222,12 +225,22 @@ namespace OnlineEditorsExample
context.Response.ContentType = "text/plain";
try
{
var fileName = Path.GetFileName(context.Request["fileName"]);
var path = _Default.StoragePath(fileName, HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)));
var histDir = _Default.HistoryDir(path);
string fileName = context.Request["fileName"];
string userAddress = HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
if (File.Exists(path)) File.Delete(path); // delete file
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
if (!String.IsNullOrEmpty(fileName))
{
fileName = Path.GetFileName(fileName);
var path = _Default.StoragePath(fileName, userAddress);
var histDir = _Default.HistoryDir(path);
if (File.Exists(path)) File.Delete(path); // delete file
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
} else
{
string userDir = _Default.StoragePath("", userAddress);
if (Directory.Exists(userDir)) Directory.Delete(userDir, true); // delete the user's directory
}
context.Response.Write("{ \"success\": true }");
}
@ -778,5 +791,25 @@ namespace OnlineEditorsExample
+ userAddress;
return fileUrl.ToString();
}
// return all the supported formats
private static void Formats(HttpContext context)
{
try
{
Dictionary<string, object> data = new Dictionary<string, object>
{
{ "formats", FormatManager.All() }
};
context.Response.ContentType = "application/json";
var jss = new JavaScriptSerializer();
context.Response.Write(jss.Serialize(data));
}
catch (Exception e)
{
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
}
}
}
}

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch("webeditor.ashx?type=formats")
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.Name,
format.Type,
format.Actions,
format.Convert,
format.Mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({ filename: fileName, filePass: filePass }),
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
url: requestAddress,
complete: function (data) {
var responseText = data.responseText;
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")) {
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder", filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
jq("#beginView, #beginEmbedded").removeClass("disable");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillFormExtList.indexOf(posExt) != -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var filePass = jq("#filePass").val();
if (filePass) {
@ -293,6 +329,24 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
var requestAddress = "webeditor.ashx"
+ "?type=remove";
jq.ajax({
async: true,
contentType: "text/xml",
url: requestAddress,
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

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

View File

@ -248,15 +248,15 @@ public class FileController {
// get document type (word, cell or slide)
DocumentType type = fileUtility.getDocumentType(fileName);
// convert to .ooxml
String internalFileExt = "ooxml";
// get an auto-conversion extension from the request body or set it to the ooxml extension
String conversionExtension = body.getFileExt() != null ? body.getFileExt() : "ooxml";
try {
// check if the file with such an extension can be converted
if (fileUtility.getConvertExts().contains(fileExt)) {
String key = serviceConverter.generateRevisionId(fileUri); // generate document key
ConvertedData response = serviceConverter // get the URL to the converted file
.getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
.getConvertedData(fileUri, fileExt, conversionExtension, key, filePass, true, lang);
String newFileUri = response.getUri();
String newFileType = "." + response.getFileType();
@ -291,24 +291,33 @@ public class FileController {
return createUserMetadata(uid, fileName);
} catch (Exception e) {
e.printStackTrace();
// if the operation of file converting is unsuccessful, an error occurs
return "{ \"error\": \"" + e.getMessage() + "\"}";
}
// if the operation of file converting is unsuccessful, an error occurs
return "{ \"error\": \"" + "The file can't be converted.\"}";
}
@PostMapping("/delete")
@ResponseBody
public String delete(@RequestBody final Converter body) { // delete a file
try {
String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name
String filename = body.getFileName();
boolean success = false;
// delete a file from the storage and return the status of this operation (true or false)
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
if (filename != null) {
String fullFileName = fileUtility.getFileName(filename); // get full file name
// delete file history and return the status of this operation (true or false)
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
// delete a file from the storage and return the status of this operation (true or false)
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
return "{ \"success\": \"" + (fileSuccess && historySuccess) + "\"}";
// delete file history and return the status of this operation (true or false)
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
success = fileSuccess && historySuccess;
} else {
// delete the user's folder and return the boolean status
success = storageMutator.deleteUserFolder();
}
return "{ \"success\": \"" + (success) + "\"}";
} catch (Exception e) {
// if the operation of file deleting is unsuccessful, an error occurs
return "{ \"error\": \"" + e.getMessage() + "\"}";

View File

@ -22,8 +22,10 @@ import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.Misc;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.FormatService;
import com.onlyoffice.integration.entities.User;
import com.onlyoffice.integration.services.UserServices;
import com.onlyoffice.integration.dto.FormatsList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
@ -33,6 +35,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.ResponseEntity;
import java.util.ArrayList;
import java.util.Arrays;
@ -61,6 +64,9 @@ public class IndexController {
@Autowired
private UserServices userService;
@Autowired
private FormatService formatService;
@Value("${files.docservice.url.site}")
private String docserviceSite;
@ -136,16 +142,16 @@ public class IndexController {
@ResponseBody
public HashMap<String, String> configParameters() { // get configuration parameters
HashMap<String, String> configuration = new HashMap<>();
configuration.put("FillExtList", String.join(",", fileUtility
.getFillExts())); // put a list of the extensions that can be filled to config
configuration.put("ConverExtList", String.join(",", fileUtility
.getConvertExts())); // put a list of the extensions that can be converted to config
configuration.put("EditedExtList", String.join(",", fileUtility
.getEditedExts())); // put a list of the extensions that can be edited to config
configuration.put("UrlConverter", urlConverter);
configuration.put("UrlEditor", urlEditor);
return configuration;
}
@GetMapping("/formats")
@ResponseBody
public ResponseEntity<FormatsList> formats() { // return all the supported formats
FormatsList list = new FormatsList(formatService.getFormats());
return ResponseEntity.ok(list);
}
}

View File

@ -27,7 +27,8 @@ public enum ConvertErrorType {
UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
DATABASE_ERROR(-6, "Error database"),
DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
DOCUMENT_VKEY_ERROR(-8, "Error document VKey"),
DOCUMENT_CONVERSION_OUTPUT_ERROR(-9, "Error conversion output format");
private final int code;
private final String label;

View File

@ -31,6 +31,7 @@ public interface FileStorageMutator {
boolean createFile(Path path, InputStream stream); // create a new file if it does not exist
boolean deleteFile(String fileName); // delete a file
boolean deleteFileHistory(String fileName); // delete file history
boolean deleteUserFolder(); // delete the user's folder recursively
String updateFile(String fileName, byte[] bytes); // update a file
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

View File

@ -202,6 +202,11 @@ public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuil
return historyDeleted || historyWithoutExtDeleted;
}
// delete the user's folder recursively
public boolean deleteUserFolder() {
return FileSystemUtils.deleteRecursively(new File(getStorageLocation()));
}
// update a file
public String updateFile(final String fileName, final byte[] bytes) {
Path path = fileUtility

View File

@ -19,6 +19,7 @@
package com.onlyoffice.integration.documentserver.util.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.models.Format;
@ -41,6 +42,7 @@ public class DefaultFormatService implements FormatService {
final ObjectMapper objectMapper
) {
try {
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
File targetFile = resourceFile.getFile();
this.formats = objectMapper.readValue(targetFile, new TypeReference<List<Format>>() { });
} catch (Exception e) {

View File

@ -31,6 +31,8 @@ public class Converter {
private String fileName;
@JsonProperty("filePass")
private String filePass;
@JsonProperty("fileExt")
private String fileExt;
@JsonProperty("lang")
private String lang;
}

View File

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

View File

@ -120,7 +120,6 @@ public class DefaultFileConfigurer implements FileConfigurer<DefaultFileWrapper>
userPermissions.setFillForms(
!action.equals(Action.view)
&& !action.equals(Action.comment)
&& !action.equals(Action.embedded)
&& !action.equals(Action.blockcontent)
);

View File

@ -489,6 +489,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -595,6 +622,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -752,6 +802,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -16,18 +16,12 @@
*
*/
var ConverExtList;
var EditedExtList;
var UrlConverter;
var UrlEditor;
var FillExtList;
if (typeof jQuery !== "undefined") {
jQuery.post('/config',
function(data) {
FillExtList = data.FillExtList.split(',');
ConverExtList = data.ConverExtList.split(',');
EditedExtList = data.EditedExtList.split(',');
UrlConverter = data.UrlConverter;
UrlEditor = data.UrlEditor;
});

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch('/formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery !== "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery !== "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer !== null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (ConverExtList.includes(posExt) === -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -115,7 +136,7 @@ if (typeof jQuery !== "undefined") {
contentType: "application/json",
type: "post",
dataType: "json",
data: JSON.stringify({filename: fileName, filePass: filePass}),
data: JSON.stringify({filename: fileName, filePass: filePass, fileExt: fileType}),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -131,6 +152,12 @@ if (typeof jQuery !== "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -142,7 +169,7 @@ if (typeof jQuery !== "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -180,7 +207,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (EditedExtList.includes(posExt) !== -1 || FillExtList.includes(posExt) !== -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -218,6 +245,15 @@ if (typeof jQuery !== "undefined") {
}
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var pass = jq("#filePass").val();
if (pass) {
@ -299,6 +335,24 @@ if (typeof jQuery !== "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "application/json",
type: "post",
dataType: "json",
data: JSON.stringify({filename: null, filePass: null}),
url: "/delete",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -339,12 +339,6 @@
};
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

@ -57,7 +57,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
<a class="try-editor form" data-type="docxf">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -123,7 +123,14 @@
</div>
<th:block th:if="${not #lists.isEmpty(files)}">
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -275,6 +282,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -341,6 +357,7 @@
<script type="text/javascript" src="scripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="scripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="scripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="scripts/formats.js"></script>
<script type="text/javascript" src="scripts/jscript.js"></script>
<script type="text/javascript" src="scripts/converter.js"></script>
<script type="text/javascript">

View File

@ -29,6 +29,7 @@ import helpers.FileUtility;
import helpers.ServiceConverter;
import helpers.TrackManager;
import helpers.Users;
import format.FormatManager;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
@ -139,6 +140,9 @@ public class IndexServlet extends HttpServlet {
case "historydata":
historyData(request, response, writer);
break;
case "formats":
formats(request, response, writer);
break;
default:
break;
}
@ -283,7 +287,8 @@ public class IndexServlet extends HttpServlet {
String fileUri = DocumentManager.getDownloadUrl(fileName, true);
String fileExt = FileUtility.getFileExtension(fileName);
FileType fileType = FileUtility.getFileType(fileName);
String internalFileExt = "ooxml";
// get an auto-conversion extension from the request body or set it to the ooxml extension
String conversionExtension = body.get("fileExt") != null ? (String) body.get("fileExt") : "ooxml";
// check if the file with such an extension can be converted
if (DocumentManager.getConvertExts().contains(fileExt)) {
@ -292,7 +297,7 @@ public class IndexServlet extends HttpServlet {
// get the url and file type to the converted file
Map<String, String> newFileData = ServiceConverter
.getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
.getConvertedData(fileUri, fileExt, conversionExtension, key, filePass, true, lang);
String newFileUri = newFileData.get("fileUrl");
String newFileType = "." + newFileData.get("fileType");
@ -416,17 +421,23 @@ public class IndexServlet extends HttpServlet {
final HttpServletResponse response,
final PrintWriter writer) {
try {
String fileName = FileUtility.getFileName(request.getParameter("filename"));
String path = DocumentManager.storagePath(fileName, null);
String fileName = request.getParameter("filename");
if (fileName != null && !fileName.isEmpty()) {
fileName = FileUtility.getFileName(fileName);
String path = DocumentManager.storagePath(fileName, null);
// delete file
File f = new File(path);
delete(f);
// delete file history
File hist = new File(DocumentManager.historyDir(path));
delete(hist);
// delete file
File f = new File(path);
delete(f);
// delete file history
File hist = new File(DocumentManager.historyDir(path));
delete(hist);
} else {
// delete the user's folder and all the containing files
File userFolder = new File(DocumentManager.storagePath(null, null));
delete(userFolder);
}
writer.write("{ \"success\": true }");
} catch (Exception e) {
writer.write("{ \"error\": \"" + e.getMessage() + "\"}");
@ -1039,6 +1050,16 @@ public class IndexServlet extends HttpServlet {
writer.write("{}");
}
private static void formats(final HttpServletRequest request,
final HttpServletResponse response,
final PrintWriter writer) {
Map<String, Object> data = new HashMap<String, Object>();
data.put("formats", (new FormatManager()).getFormats());
response.setContentType("application/json");
Gson gson = new Gson();
writer.write(gson.toJson(data));
}
// process get request
@Override
protected void doGet(final HttpServletRequest request,

View File

@ -297,7 +297,7 @@ public class FileModel {
edit = canEdit && (modeParam.equals("edit") || modeParam.equals("view") || modeParam.equals("filter")
|| modeParam.equals("blockcontent"));
print = !user.getDeniedPermissions().contains("print");
fillForms = !modeParam.equals("view") && !modeParam.equals("comment") && !modeParam.equals("embedded")
fillForms = !modeParam.equals("view") && !modeParam.equals("comment")
&& !modeParam.equals("blockcontent");
modifyFilter = !modeParam.equals("filter");
modifyContentControl = !modeParam.equals("blockcontent");

View File

@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public final class FormatManager {
@ -93,6 +94,7 @@ public final class FormatManager {
private List<Format> all() {
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
Path path = this.file();
return objectMapper.readValue(Files.readAllBytes(path), new TypeReference<List<Format>>() { });
} catch (Exception e) {

View File

@ -88,7 +88,7 @@ public final class Users {
private static List<User> users = new ArrayList<User>() {{
add(new User("uid-1", "John Smith", "smith@example.com",
"", null, new CommentGroups(), null,
null, new ArrayList<String>(), descriptionUserFirst, true, true, new Goback()));
null, new ArrayList<String>(), descriptionUserFirst, true, true, new Goback(null, false)));
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")), Arrays.asList("group-2", ""),
@ -98,7 +98,7 @@ public final class Users {
"group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"),
Arrays.asList("group-2"), null), Arrays.asList("group-2"),
false, Arrays.asList("copy", "download", "print"),
descriptionUserThird, false, false, new Goback(null, false)));
descriptionUserThird, false, false, null));
add(new User("uid-0", null, null,
"", null, null, null,
null, Arrays.asList("protect"), descriptionUserZero, false, false, null));

View File

@ -27,7 +27,8 @@ public enum ConvertErrorType {
UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
DATABASE_ERROR(-6, "Error database"),
DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
DOCUMENT_VKEY_ERROR(-8, "Error document VKey"),
CONVERSION_OUTPUT_FORMAT_ERROR(-9, "Error conversion output format");
private final int code;
private final String label;

View File

@ -488,6 +488,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -230,6 +230,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -595,6 +622,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -748,6 +798,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -338,12 +338,6 @@
};
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

@ -69,7 +69,7 @@
<a class="try-editor slide" data-type="pptx">Presentation</a>
</li>
<li>
<a class="try-editor form" data-type="docxf">Form template</a>
<a class="try-editor form" data-type="docxf">PDF form</a>
</li>
</ul>
<label class="create-sample">
@ -146,7 +146,14 @@
</div>
<% if (files.length > 0) { %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -299,6 +306,15 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
<span id="step2" class="step">2. Conversion.</span>
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
@ -365,12 +381,10 @@
<script type="text/javascript" src="scripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="scripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="scripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="scripts/formats.js"></script>
<script type="text/javascript" src="scripts/jscript.js"></script>
<script language="javascript" type="text/javascript">
var FillExtList = "<%= String.join(",", DocumentManager.getFillExts()) %>".split(",");
var ConverExtList = "<%= String.join(",", DocumentManager.getConvertExts()) %>".split(",");
var EditedExtList = "<%= String.join(",", DocumentManager.getEditedExts()) %>".split(",");
var UrlConverter = "IndexServlet?type=convert";
var UrlEditor = "EditorServlet";

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch('IndexServlet?type=formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery !== "undefined") {
jq = jQuery.noConflict();
@ -87,7 +108,7 @@ if (typeof jQuery !== "undefined") {
});
var timer = null;
var checkConvert = function (filePass) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer !== null) {
clearTimeout(timer);
@ -103,7 +124,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (!ConverExtList.includes(posExt)) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -115,7 +136,7 @@ if (typeof jQuery !== "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({filename: fileName, filePass: filePass}),
data: JSON.stringify({filename: fileName, filePass: filePass, fileExt: fileType}),
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -131,6 +152,12 @@ if (typeof jQuery !== "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -142,7 +169,7 @@ if (typeof jQuery !== "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step && response.step < 100) {
checkConvert(filePass);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -180,7 +207,7 @@ if (typeof jQuery !== "undefined") {
var posExt = fileName.lastIndexOf(".") + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : "";
if (EditedExtList.includes(posExt) || FillExtList.includes(posExt)) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -212,6 +239,15 @@ if (typeof jQuery !== "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
jq(document).on("click", "#enterPass", function () {
var pass = jq("#filePass").val();
if (pass) {
@ -290,6 +326,21 @@ if (typeof jQuery !== "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "text/xml",
url: "IndexServlet?type=remove",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location.reload(true);
}
}
});
}
});
function showUserTooltip (isMobile) {
if ( jq("div#portal-info").is(":hidden") ) {
jq("div#portal-info").show();

View File

@ -93,8 +93,6 @@ app.get('/', (req, res) => { // define a handler for default page
res.render('index', { // render index template with the parameters specified
preloaderUrl: siteUrl + configServer.get('preloaderUrl'),
convertExts: fileUtility.getConvertExtensions(),
editedExts: fileUtility.getEditExtensions(),
fillExts: fileUtility.getFillExtensions(),
storedFiles: req.DocManager.getStoredFiles(),
params: req.DocManager.getCustomParams(),
@ -270,6 +268,18 @@ app.post('/create', (req, res) => {
try {
req.DocManager = new DocManager(req, res);
let host = siteUrl;
if (host.indexOf('/') === 0) {
host = req.DocManager.getServerHost();
}
if (urlModule.parse(fileUrl).host !== urlModule.parse(host).host) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ error: 'File domain is incorrect' }));
res.end();
return;
}
req.DocManager.storagePath(''); // mkdir if not exist
const fileName = req.DocManager.getCorrectName(title);
@ -321,8 +331,8 @@ app.post('/convert', (req, res) => { // define a handler for converting files
const fileUri = req.DocManager.getDownloadUrl(fileName, true);
const fileExt = fileUtility.getFileExtension(fileName, true);
const internalFileExt = 'ooxml';
let convExt = req.body.fileExt ? req.body.fileExt : internalFileExt;
if (req.body.forceConv) convExt = req.body.forceConv;
const convExt = req.body.fileExt ? req.body.fileExt : internalFileExt;
const { keepOriginal } = req.body;
const response = res;
const writeResult = function writeResult(filename, step, error) {
@ -377,14 +387,14 @@ app.post('/convert', (req, res) => { // define a handler for converting files
return;
}
// remove file with the origin extension
if (!('fileExt' in req.body)) fileSystem.unlinkSync(req.DocManager.storagePath(fileName));
if (!keepOriginal) fileSystem.unlinkSync(req.DocManager.storagePath(fileName));
const userAddress = req.DocManager.curUserHostAddress();
const historyPath = req.DocManager.historyPath(fileName, userAddress, true);
// get the history path to the file with a new extension
const correctHistoryPath = req.DocManager.historyPath(correctName, userAddress, true);
if (!('fileExt' in req.body)) {
if (!keepOriginal) {
fileSystem.renameSync(historyPath, correctHistoryPath); // change the previous history path
fileSystem.renameSync(
@ -518,7 +528,6 @@ app.post('/reference', (req, res) => { // define a handler for renaming file
if (req.body.link.indexOf(req.DocManager.getServerUrl()) === -1) {
result({
url: req.body.link,
directUrl: req.body.link,
});
return;
}
@ -548,7 +557,6 @@ app.post('/reference', (req, res) => { // define a handler for renaming file
fileType: fileUtility.getFileExtension(fileName).slice(1),
key: req.DocManager.getKey(fileName),
url: req.DocManager.getDownloadUrl(fileName, true),
directUrl: req.body.directUrl ? req.DocManager.getDownloadUrl(fileName) : null,
referenceData: {
fileKey: JSON.stringify({ fileName, userAddress: req.DocManager.curUserHostAddress() }),
instanceId: req.DocManager.getServerUrl(),
@ -645,7 +653,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
const zip = await urllib.request(downloadZip, { method: 'GET' });
const statusZip = zip.status;
const dataZip = zip.data;
if (status === 200) {
if (statusZip === 200) {
fileSystem.writeFileSync(pathChanges, dataZip); // write the document version differences to the archive
} else {
emitWarning(`Document editing service returned status: ${statusZip}`);
@ -676,7 +684,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
} catch (ex) {
console.log(ex);
response.write('{"error":1}');
response.write(`{"error":1,"message":${JSON.stringify(ex)}}`);
response.end();
return;
}
@ -688,7 +696,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
// file saving process
const processSave = async function processSave(downloadUri, body, fileName, userAddress) {
if (!downloadUri) {
response.write('{"error":1}');
response.write('{"error":1,"message":"save uri is empty"}');
response.end();
return;
}
@ -799,7 +807,8 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
}
} catch (ex) {
response.write('{"error":1}');
console.log(ex);
response.write(`{"error":1,"message":${JSON.stringify(ex)}}`);
response.end();
return;
}
@ -811,7 +820,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
// file force saving process
const processForceSave = async function processForceSave(downloadUri, body, fileName, userAddress) {
if (!downloadUri) {
response.write('{"error":1}');
response.write('{"error":1,"message":"forcesave uri is empty"}');
response.end();
return;
}
@ -903,7 +912,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
}
if (!body) {
res.write('{"error":1}');
res.write('{"error":1,"message":"body is empty"}');
res.end();
return;
}
@ -928,6 +937,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
const { name } = user;
if (fileExt) {
fileExt = fileUtility.getFileExtension(fileUtility.getFileName(fileExt), true);
// create demo document of a given extension
const fName = req.DocManager.createDemo(!!req.query.sample, fileExt, userid, name, false);
@ -940,7 +950,6 @@ app.get('/editor', (req, res) => { // define a handler for editing document
const fileName = fileUtility.getFileName(req.query.fileName);
const lang = req.DocManager.getLang();
const userDirectUrl = req.query.directUrl === 'true';
let actionData = 'null';
if (req.query.action) {
@ -983,12 +992,19 @@ app.get('/editor', (req, res) => { // define a handler for editing document
const { userInfoGroups } = user;
const usersInfo = [];
const usersForProtect = [];
if (user.id !== 'uid-0') {
users.getAllUsers().forEach((userInfo) => {
const u = userInfo;
u.image = userInfo.avatar ? `${req.DocManager.getServerUrl()}/images/${userInfo.id}.png` : null;
usersInfo.push(u);
}, usersInfo);
users.getUsersForProtect(user.id).forEach((userInfo) => {
const u = userInfo;
u.image = userInfo.avatar ? `${req.DocManager.getServerUrl()}/images/${userInfo.id}.png` : null;
usersForProtect.push(u);
}, usersForProtect);
}
fileExt = fileUtility.getFileExtension(fileName);
@ -1000,7 +1016,6 @@ app.get('/editor', (req, res) => { // define a handler for editing document
}
const key = req.DocManager.getKey(fileName);
const url = req.DocManager.getDownloadUrl(fileName, true);
const directUrl = req.DocManager.getDownloadUrl(fileName);
let mode = req.query.mode || 'edit'; // mode: view/edit/review/comment/fillForms/embedded
let canEdit = fileUtility.getEditExtensions().indexOf(fileExt.slice(1)) !== -1; // check if this file can be edited
@ -1029,8 +1044,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
name: fileName,
ext: fileUtility.getFileExtension(fileName, true),
uri: url,
directUrl: !userDirectUrl ? null : directUrl,
uriUser: directUrl,
uriUser: url,
created: new Date().toDateString(),
favorite: user.favorite != null ? user.favorite : 'null',
},
@ -1047,7 +1061,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
chat: userid !== 'uid-0',
coEditing: mode === 'view' && userid === 'uid-0' ? { mode: 'strict', change: false } : null,
comment: mode !== 'view' && mode !== 'fillForms' && mode !== 'embedded' && mode !== 'blockcontent',
fillForms: mode !== 'view' && mode !== 'comment' && mode !== 'embedded' && mode !== 'blockcontent',
fillForms: mode !== 'view' && mode !== 'comment' && mode !== 'blockcontent',
modifyFilter: mode !== 'filter',
modifyContentControl: mode !== 'blockcontent',
copy: !user.deniedPermissions.includes('copy'),
@ -1073,26 +1087,22 @@ app.get('/editor', (req, res) => { // define a handler for editing document
instanceId: userid !== 'uid-0' ? req.DocManager.getInstanceId() : null,
protect: !user.deniedPermissions.includes('protect'),
goback: user.goback != null ? user.goback : '',
close: user.close,
},
dataInsertImage: {
fileType: 'svg',
url: `${req.DocManager.getServerUrl(true)}/images/logo.svg`,
directUrl: !userDirectUrl ? null : `${req.DocManager.getServerUrl()}/images/logo.svg`,
},
dataDocument: {
fileType: 'docx',
url: `${req.DocManager.getServerUrl(true)}/assets/document-templates/sample/sample.docx`,
directUrl: !userDirectUrl
? null
: `${req.DocManager.getServerUrl()}/assets/document-templates/sample/sample.docx`,
},
dataSpreadsheet: {
fileType: 'csv',
url: `${req.DocManager.getServerUrl(true)}/csv`,
directUrl: !userDirectUrl ? null : `${req.DocManager.getServerUrl()}/csv`,
},
usersForMentions: user.id !== 'uid-0' ? users.getUsersForMentions(user.id) : null,
usersForProtect: user.id !== 'uid-0' ? users.getUsersForProtect(user.id) : null,
usersForProtect,
usersInfo,
};
@ -1158,8 +1168,7 @@ app.post('/rename', (req, res) => { // define a handler for renaming file
app.post('/historyObj', (req, res) => {
req.DocManager = new DocManager(req, res);
const { fileName } = req.body;
const { directUrl } = req.body || null;
const historyObj = req.DocManager.getHistoryObject(fileName, null, directUrl);
const historyObj = req.DocManager.getHistoryObject(fileName, null);
if (cfgSignatureEnable) {
for (let i = 0; i < historyObj.historyData.length; i++) {
@ -1179,7 +1188,9 @@ app.post('/historyObj', (req, res) => {
app.get('/formats', (req, res) => {
try {
const formats = fileUtility.getFormats();
res.json(formats);
res.json({
formats,
});
} catch (ex) {
console.log(ex); // display error message in the console
res.status(500); // write status parameter to the response

View File

@ -51,7 +51,7 @@ DocManager.prototype.createDirectory = function createDirectory(directory) {
// get the language from the request
DocManager.prototype.getLang = function getLang() {
if (/^[a-z]{2}(-[A-z]{4})?(-[A-Z]{2})?$/.test(this.req.query.lang)) {
if (/^[a-z]{2}(-[a-zA-z]{4})?(-[A-Z]{2})?$/.test(this.req.query.lang)) {
return this.req.query.lang;
} // the default language value is English
return 'en';
@ -67,9 +67,6 @@ DocManager.prototype.getCustomParams = function getCustomParams() {
const { lang } = this.req.query; // language
params += (lang ? `&lang=${this.getLang()}` : '');
const { directUrl } = this.req.query; // directUrl
params += (directUrl ? `&directUrl=${directUrl === 'true'}` : '');
const { fileName } = this.req.query; // file name
params += (fileName ? `&fileName=${fileName}` : '');
@ -446,11 +443,10 @@ DocManager.prototype.countVersion = function countVersion(directory) {
return i;
};
DocManager.prototype.getHistoryObject = function getHistoryObject(fileName, userAddr = null, userDirectUrl = null) {
DocManager.prototype.getHistoryObject = function getHistoryObject(fileName, userAddr = null) {
const userAddress = userAddr || this.curUserHostAddress();
const historyPath = this.historyPath(fileName, userAddress);
const key = this.getKey(fileName);
const directUrl = this.getDownloadUrl(fileName);
const fileExt = fileUtility.getFileExtension(fileName);
const url = this.getDownloadUrl(fileName, true);
const history = [];
@ -472,15 +468,12 @@ DocManager.prototype.getHistoryObject = function getHistoryObject(fileName, user
// write all the file history information
history.push(this.getHistory(fileName, changes, keyVersion, i));
const userUrl = i === countVersion ? directUrl : (`${this.getServerUrl(false)}/history?fileName=`
+ `${encodeURIComponent(fileName)}&file=prev${fileExt}&ver=${i}`);
const historyD = {
fileType: fileExt.slice(1),
version: i,
key: keyVersion,
url: i === countVersion ? url : (`${this.getServerUrl(true)}/history?fileName=`
+ `${encodeURIComponent(fileName)}&file=prev${fileExt}&ver=${i}&useraddress=${userAddress}`),
directUrl: !userDirectUrl ? null : userUrl,
};
// check if the path to the file with document versions differences exists
@ -489,7 +482,6 @@ DocManager.prototype.getHistoryObject = function getHistoryObject(fileName, user
fileType: historyData[i - 2].fileType,
key: historyData[i - 2].key,
url: historyData[i - 2].url,
directUrl: !userDirectUrl ? null : historyData[i - 2].directUrl,
};
const changesUrl = `${this.getServerUrl(true)}/history?fileName=`
+ `${encodeURIComponent(fileName)}&file=diff.zip&ver=${i - 1}&useraddress=${userAddress}`;
@ -512,7 +504,6 @@ DocManager.prototype.getHistoryObject = function getHistoryObject(fileName, user
version: countVersion,
key,
url,
directUrl: !userDirectUrl ? null : directUrl,
});
}

View File

@ -31,6 +31,7 @@ class User {
templates,
avatar,
goback,
close,
) {
this.id = id;
this.name = name;
@ -45,6 +46,7 @@ class User {
this.templates = templates;
this.avatar = avatar;
this.goback = goback;
this.close = close;
}
}
@ -103,7 +105,22 @@ const descrUser0 = [
];
const users = [
new User('uid-1', 'John Smith', 'smith@example.com', null, null, {}, null, null, [], descrUser1, true, true, {}),
new User(
'uid-1',
'John Smith',
'smith@example.com',
null,
null,
{},
null,
null,
[],
descrUser1,
true,
true,
{ blank: false },
{ visible: false },
),
new User(
'uid-2',
'Mark Pottato',
@ -122,6 +139,7 @@ const users = [
false,
true,
{ text: 'Go to Documents' },
{},
),
new User(
'uid-3',
@ -140,9 +158,10 @@ const users = [
descrUser3,
false,
false,
{ blank: false },
null,
{},
),
new User('uid-0', null, null, null, null, {}, [], null, ['protect'], descrUser0, false, false, null),
new User('uid-0', null, null, null, null, {}, [], null, ['protect'], descrUser0, false, false, null, null),
];
// get a list of all the users
@ -180,10 +199,7 @@ users.getUsersForProtect = function getUsersForProtect(id) {
const result = [];
this.forEach((user) => {
if (user.id !== id && user.name != null) {
result.push({
id: user.id,
name: user.name,
});
result.push(user);
}
});
return result;

View File

@ -187,13 +187,12 @@ const putFile = function putFile(wopi, req, res, userHost) {
const userAddress = req.DocManager.curUserHostAddress(userHost);
const storagePath = req.DocManager.storagePath(wopi.id, userAddress);
const fileSize = fileSystem.statSync(storagePath).size;
if (!lockManager.hasLock(storagePath)) {
// ToDo: if body length is 0 bytes => handle document creation
if (!lockManager.hasLock(storagePath) && fileSize !== 0) {
// file isn't locked => mismatch
returnLockMismatch(res, '', 'File isn\'t locked');
} else if (lockManager.getLock(storagePath) === requestLock) {
} else if (lockManager.getLock(storagePath) === requestLock || fileSize === 0) {
// lock matches current lock => put file
saveFileFromBody(req, wopi.id, userAddress, true, (err, version) => {
if (!err) {

View File

@ -27,57 +27,72 @@ const siteUrl = configServer.get('siteUrl'); // the path to the editors installa
let cache = null;
const requestDiscovery = async function requestDiscovery(url) {
const requestDiscovery = async function requestDiscovery(DocManager) {
let absSiteUrl = siteUrl;
if (absSiteUrl.indexOf('/') === 0) {
absSiteUrl = DocManager.getServerHost() + siteUrl;
}
// eslint-disable-next-line no-unused-vars
return new Promise((resolve, reject) => {
const uri = absSiteUrl + configServer.get('wopi.discovery');
const actions = [];
urllib.request(urlModule.parse(url + configServer.get('wopi.discovery')), { method: 'GET' }, (err, data) => {
if (data) {
// create the discovery XML file with the parameters from the response
const xmlParseOptions = {
attributeNamePrefix: '',
ignoreAttributes: false,
parseAttributeValue: true,
attrValueProcessor: (val) => he.decode(val, { isAttributeValue: true }),
};
const parser = new xmlParser.XMLParser(xmlParseOptions);
// create the discovery XML file with the parameters from the response
const discovery = parser.parse(data.toString());
if (discovery['wopi-discovery']) {
discovery['wopi-discovery']['net-zone'].app.forEach((app) => {
let appAction = app.action;
if (!Array.isArray(appAction)) {
appAction = [appAction];
}
appAction.forEach((action) => {
actions.push({ // write all the parameters to the actions element
app: app.name,
favIconUrl: app.favIconUrl,
checkLicense: app.checkLicense === 'true',
name: action.name,
ext: action.ext || '',
progid: action.progid || '',
isDefault: !!action.default,
urlsrc: action.urlsrc,
requires: action.requires || '',
// parse url to allow request by relative url after
// https://github.com/node-modules/urllib/pull/321/commits/514de1924bf17a38a6c2db2a22a6bc3494c0a959
urllib.request(
urlModule.parse(uri),
{
method: 'GET',
},
(err, data) => {
if (data) {
// create the discovery XML file with the parameters from the response
const xmlParseOptions = {
attributeNamePrefix: '',
ignoreAttributes: false,
parseAttributeValue: true,
attrValueProcessor: (val) => he.decode(val, { isAttributeValue: true }),
};
const parser = new xmlParser.XMLParser(xmlParseOptions);
// create the discovery XML file with the parameters from the response
const discovery = parser.parse(data.toString());
if (discovery['wopi-discovery']) {
discovery['wopi-discovery']['net-zone'].app.forEach((app) => {
let appAction = app.action;
if (!Array.isArray(appAction)) {
appAction = [appAction];
}
appAction.forEach((action) => {
actions.push({ // write all the parameters to the actions element
app: app.name,
favIconUrl: app.favIconUrl,
checkLicense: app.checkLicense === 'true',
name: action.name,
ext: action.ext || '',
progid: action.progid || '',
isDefault: !!action.default,
urlsrc: action.urlsrc,
requires: action.requires || '',
});
});
});
});
}
}
}
resolve(actions);
});
resolve(actions);
},
);
});
};
// get the wopi discovery information
const getDiscoveryInfo = async function getDiscoveryInfo(url) {
const getDiscoveryInfo = async function getDiscoveryInfo(DocManager) {
let actions = [];
if (cache) return cache;
try {
actions = await requestDiscovery(url);
actions = await requestDiscovery(DocManager);
} catch (e) {
return actions;
}
@ -91,19 +106,9 @@ const getDiscoveryInfo = async function getDiscoveryInfo(url) {
return actions;
};
const initWopi = async function initWopi(DocManager) {
let absSiteUrl = siteUrl;
if (absSiteUrl.indexOf('/') === 0) {
absSiteUrl = DocManager.getServerHost() + siteUrl;
}
// get the wopi discovery information
await getDiscoveryInfo(absSiteUrl);
};
// get actions of the specified extension
const getActions = async function getActions(ext) {
const actions = await getDiscoveryInfo(); // get the wopi discovery information
const getActions = async function getActions(DocManager, ext) {
const actions = await getDiscoveryInfo(DocManager); // get the wopi discovery information
const filtered = [];
actions.forEach((action) => { // and filter it by the specified extention
@ -116,8 +121,8 @@ const getActions = async function getActions(ext) {
};
// get an action for the specified extension and name
const getAction = async function getAction(ext, name) {
const actions = await getDiscoveryInfo();
const getAction = async function getAction(DocManager, ext, name) {
const actions = await getDiscoveryInfo(DocManager);
let act = null;
actions.forEach((action) => {
@ -130,8 +135,8 @@ const getAction = async function getAction(ext, name) {
};
// get the default action for the specified extension
const getDefaultAction = async function getDefaultAction(ext) {
const actions = await getDiscoveryInfo();
const getDefaultAction = async function getDefaultAction(DocManager, ext) {
const actions = await getDiscoveryInfo(DocManager);
let act = null;
actions.forEach((action) => {
@ -149,7 +154,6 @@ const getActionUrl = function getActionUrl(host, userAddress, action, filename)
return `${action.urlsrc.replace(/<.*&>/g, '')}WOPISrc=${encodeURIComponent(WOPISrc)}`;
};
exports.initWopi = initWopi;
exports.getDiscoveryInfo = getDiscoveryInfo;
exports.getAction = getAction;
exports.getActions = getActions;

View File

@ -45,15 +45,13 @@ exports.registerRoutes = function registerRoutes(app) {
app.get('/wopi', async (req, res) => {
req.DocManager = new DocManager(req, res);
await utils.initWopi(req.DocManager);
// get the wopi discovery information
const actions = await utils.getDiscoveryInfo();
const actions = await utils.getDiscoveryInfo(req.DocManager);
const wopiEnable = actions.length !== 0;
const docsExtEdit = []; // Supported extensions for WOPI
actions.forEach((el) => {
if (el.name === 'edit') docsExtEdit.push(`.${el.ext}`);
if (el.name === 'edit') docsExtEdit.push(`${el.ext}`);
});
// Checking supported extensions
@ -67,11 +65,13 @@ exports.registerRoutes = function registerRoutes(app) {
// run through all the files and write the corresponding information to each file
// eslint-disable-next-line no-restricted-syntax
for (const file of files) {
const mobile = new RegExp(configServer.get('mobileRegEx'), 'i').test(req.get('User-Agent'));
const ext = fileUtility.getFileExtension(file.name, true); // get an extension of each file
// eslint-disable-next-line no-await-in-loop
file.actions = await utils.getActions(ext); // get actions of the specified extension
file.actions = await utils.getActions(req.DocManager, ext); // get actions of the specified extension
// eslint-disable-next-line no-await-in-loop
file.defaultAction = await utils.getDefaultAction(ext);// get the default action of the specified extension
file.defaultAction = await utils.getDefaultAction(req.DocManager, ext);// get the default action for extension
if (mobile) file.actions.forEach((act) => { if (act.name === 'mobileEdit') file.defaultAction = act; });
}
// render wopiIndex template with the parameters specified
@ -111,14 +111,12 @@ exports.registerRoutes = function registerRoutes(app) {
try {
req.DocManager = new DocManager(req, res);
await utils.initWopi(req.DocManager);
let fileName = req.DocManager.getCorrectName(req.params.id);
const fileExt = fileUtility.getFileExtension(fileName, true); // get the file extension from the request
const user = users.getUser(req.query.userid); // get a user by the id
// get an action for the specified extension and name
const action = await utils.getAction(fileExt, req.query.action);
const action = await utils.getAction(req.DocManager, fileExt, req.query.action);
if (action && req.query.action === 'editnew') {
fileName = req.DocManager.requestEditnew(req, fileName, user);

File diff suppressed because it is too large Load Diff

View File

@ -17,17 +17,17 @@
"url": "https://github.com/ONLYOFFICE/document-server-integration/issues"
},
"dependencies": {
"body-parser": "^1.19.0",
"config": "^3.3.2",
"debug": "^4.2.0",
"ejs": "^3.1.5",
"express": "^4.17.1",
"fast-xml-parser": "^4.3.1",
"body-parser": "^1.20.2",
"config": "^3.3.11",
"debug": "^4.3.4",
"ejs": "^3.1.9",
"express": "^4.18.2",
"fast-xml-parser": "^4.3.4",
"formidable": "^1.2.2",
"he": "^1.2.0",
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.2",
"jwa": "^2.0.0",
"log4js": "^6.3.0",
"log4js": "^6.9.1",
"mime": "^2.4.6",
"serve-favicon": "^2.5.0",
"urllib": "^2.36.1"
@ -44,8 +44,16 @@
]
},
"devDependencies": {
"eslint": "^8.28.0",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.26.0"
"eslint-plugin-import": "^2.29.1"
},
"overrides": {
"semver": "7.5.2",
"word-wrap": "1.2.4",
"pac-resolver": "7.0.0",
"degenerator": "3.0.1",
"qs": "6.7.3",
"json5": "2.2.3"
}
}

View File

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

After

Width:  |  Height:  |  Size: 173 B

View File

@ -0,0 +1,4 @@
<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="M6 16V13H7V11H5C4.44772 11 4 11.4477 4 12V17C4 17.5523 4.44772 18 5 18H19C19.5523 18 20 17.5523 20 17V12C20 11.4477 19.5523 11 19 11H17V13H18V16H6Z" fill="#444444"/>
<path d="M11 15H9V13L16 6H17V7H18V8L11 15Z" fill="#444444"/>
</svg>

After

Width:  |  Height:  |  Size: 379 B

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -18,14 +18,25 @@
var language;
var userid;
var directUrl;
var Formats;
var formatManager;
window.onload = function () {
fetch('formats')
.then((response) => response.json())
.then((data) => {
Formats = data;
if (data.formats) {
let formats = [];
data.formats.forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
@ -34,7 +45,6 @@ if (typeof jQuery != "undefined") {
userid = getUrlVars()["userid"];
language = getUrlVars()["lang"];
directUrl = getUrlVars()["directUrl"] == "true";
mustReload = false;
@ -48,13 +58,6 @@ if (typeof jQuery != "undefined") {
else
userid = jq("#user").val();
if (directUrl)
jq("#directUrl").prop("checked", directUrl);
else
directUrl = jq("#directUrl").prop("checked");
jq(function () {
jq('#fileupload').fileupload({
dataType: 'json',
@ -109,7 +112,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (filePass, forceConvert) {
var checkConvert = function (filePass, fileType) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -125,22 +128,19 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
}
var convData = {filename: fileName, filePass: filePass, lang: language};
if (forceConvert) convData.forceConv = forceConvert;
timer = setTimeout(function () {
jq.ajaxSetup({ cache: false });
jq.ajax({
async: true,
type: "post",
dataType: "json",
data: convData,
data: {filename: fileName, filePass: filePass, lang: language, fileExt: fileType},
url: UrlConverter,
complete: function (data) {
var responseText = data.responseText;
@ -161,7 +161,7 @@ if (typeof jQuery != "undefined") {
return;
} else {
if (response.error.includes("-9")){
jq("#xmlError").removeClass("invisible");
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
@ -177,7 +177,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (typeof response.step != "undefined" && response.step < 100) {
checkConvert(filePass, forceConvert);
checkConvert(filePass, fileType);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -215,19 +215,16 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
var checkEdited = EditedExtList.split(",").filter(function(ext) { return ext == posExt;});
var checkFilled = FilledExtList.split(",").filter(function(ext) { return ext == posExt;});
if (checkEdited != "" || checkFilled != "") {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
jq(document).on("click", "#forceConvert:not(.disable)", function () {
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileType = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq("div[id='forceConvert']").addClass("disable, pale");
jq(".file-type").addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(filePass, fileType);
});
@ -369,10 +366,14 @@ if (typeof jQuery != "undefined") {
jq("#convertFileName").removeClass("word slide cell");
jq("#convertFileName").addClass(type);
jq("#convTypes").empty();
let convExtensions = Formats.find(format => {return format.name == fileName.split('.').pop()}).convert;
convExtensions.forEach(ext => {
jq("#convTypes").append(jq(`<td name="convertingTypeButton" id="wordTo${ext}" class="button hoar" data="${ext}">${ext}</td>`));
});
let format = formatManager.findByExtension(fileName.split('.').pop());
if (format) {
format.convert.forEach(ext => {
jq("#convTypes").append(jq(`<td name="convertingTypeButton" id="wordTo${ext}" class="button hoar" data="${ext}">${ext}</td>`));
});
}
jq("#hiddenFileName").val(fileName);
jq("#convertStep1").addClass("done");
jq("#convertStep2").addClass("waiting");
@ -410,7 +411,7 @@ if (typeof jQuery != "undefined") {
async: true,
type: "post",
dataType: "json",
data: {filename: fileName, filePass: filePass, lang: language, fileExt: fileExt},
data: {filename: fileName, filePass: filePass, lang: language, fileExt: fileExt, keepOriginal: true},
url: UrlConverter,
complete: function (data) {
try {
@ -469,6 +470,22 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "text/xml",
type: "delete",
url: "file",
complete: function (data) {
if (JSON.parse(data.responseText).success) {
window.location = collectParams();
}
}
});
}
});
jq("#createSample").click(function () {
jq(".try-editor").each(function () {
var href = jq(this).attr("href");

View File

@ -83,7 +83,9 @@
margin-left: 0;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 90%;
}
@ -106,6 +108,10 @@
.tableHeaderCellRemove {
padding-left: 0px;
}
.storedHeaderClearAll {
padding-right: 48px;
}
}
@media (max-width: 1008px) {
@ -123,7 +129,8 @@
.contentCells-icon{
width: 5%;
}
.tableRow {
.tableRow,
menu.links {
width: 55%;
}
@ -139,7 +146,7 @@
}
.scroll-table-body {
top: 31px;
top: 33px;
}
footer {
@ -179,7 +186,9 @@
}
@media (max-width: 715px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 45%;
}
}
@ -277,7 +286,9 @@
padding-left: 0;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 75%;
}
@ -298,6 +309,10 @@
.firstContentCellViewers {
margin-left: 0;
}
.storedHeaderClearAll {
padding-right: 18px;
}
}
@media (max-width: 890px) and (min-width: 769px ) {
@ -312,7 +327,9 @@
width: 580px;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 95%;
}
@ -348,6 +365,10 @@
width: 19%;
padding-right: 45px;
}
.storedHeaderClearAll {
padding-right: 8px;
}
}
@media (max-width: 890px) {
@ -373,6 +394,10 @@
.tableRow td:first-child {
max-width: 100%;
}
.storedHeaderClearAll {
padding-right: 0px;
}
}
@ -391,7 +416,7 @@
}
.scroll-table-body {
top: 31px;
top: 33px;
}
footer table tr {
@ -431,7 +456,9 @@
padding: 16px 0 6px;
}
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 40%;
}
@ -530,8 +557,8 @@
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.forceConvert:hover,
.button.forceConvert {
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
@ -571,7 +598,9 @@
}
@media (max-width: 510px) and (min-width: 470px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 35%;
}
@ -597,7 +626,9 @@
}
@media (max-width: 470px) and (min-width: 420px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 30%;
}
.tableRow td:first-child{
@ -632,7 +663,9 @@
}
@media (max-width: 420px) and (min-width: 320px) {
.tableRow {
.tableRow,
.storedHeader,
menu.links {
width: 25%;
}
@ -668,6 +701,10 @@
padding-right: 2px;
width: 11%;
}
.header-list {
font-size: 12px;
}
}
@media (max-width: 1160px) {
@ -682,7 +719,9 @@
}
}
@media (max-width: 769px) and (min-width: 715px){
.tableRow{
.tableRow,
.storedHeader,
menu.links {
width: 50%;
}
}

View File

@ -274,30 +274,30 @@ label .checkbox {
opacity: 100%;
}
.button.forceConvert {
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.forceConvert.disable {
.button.file-type.disable {
cursor: default;
}
.button.forceConvert.pale {
.button.file-type.pale {
opacity: 30%;
}
.button.forceConvert.document {
.button.file-type.document {
background: #446995;
}
.button.forceConvert.spreadsheet {
.button.file-type.spreadsheet {
background: #40865C;
}
.button.forceConvert.presentation {
.button.file-type.presentation {
background: #AA5252;
}
@ -331,24 +331,64 @@ label .checkbox {
width: 192px;
}
.create-panel,
.links-panel {
.create-panel {
float: left;
padding: 16px 0;
}
.links {
display: flex;
padding: 0;
column-gap: 30px;
align-items: center;
list-style: none;
border-bottom: 1px solid #E2E2E2;
margin: 0;
margin-bottom: 24px;
}
.links li {
padding: 4px;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.links li.active {
border-bottom: 2px solid #FF6F3D;
}
.links li.active a {
color: #FF6F3D;
}
.links li.active a img {
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
}
.links a {
display: inline-block;
padding: 2px 0;
line-height: 20px;
font-size: 13px;
text-decoration: none;
}
.home-link {
height: 24px;
padding: 0 2px 8px !important;
}
.home-link a {
padding: 0;
padding-top: 7px;
}
.upload-panel,
.create-panel {
width: 100%;
border-bottom: 1px solid #D0D5DA;
}
.links-panel-border {
margin-top: 24px;
width: 100%;
border-top: 1px solid #D0D5DA;
}
#mainProgress {
color: #333333;
display: none;
@ -740,6 +780,28 @@ footer table tr td:first-child {
margin-right: 8px;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -815,7 +877,7 @@ footer table tr td:first-child {
overflow-x: auto;
position: absolute;
right: 0;
top: 71px;
top: 75px;
scrollbar-color: #D0D5DA transparent;
scrollbar-width: thin;
}

View File

@ -1,5 +1,4 @@
"document": {
"directUrl": "<%- file.directUrl %>",
"fileType": "<%- file.ext %>",
"info": {
"owner": "Me",
@ -39,6 +38,7 @@
"customization": {
"about": true,
"comments": true,
"close": <%- JSON.stringify(editor.close) %>,
"feedback": true,
"forcesave": false,
"goback": <%- JSON.stringify(editor.goback) %>,

View File

@ -57,6 +57,11 @@
document.title = title + (event.data ? "*" : "");
};
var onRequestClose = function () { // close editor
docEditor.destroyEditor();
innerAlert("Document editor closed successfully");
};
var onMetaChange = function (event) { // the meta information of the document is changed via the meta command
if (event.data.favorite) {
var favorite = !!event.data.favorite;
@ -74,10 +79,8 @@
var onRequestHistory = function (event) { // the user is trying to show the document version history
const fileName = "<%- file.name %>" || null;
const directUrl = "<%- file.directUrl %>" || null;
const data = {
fileName: fileName,
directUrl: directUrl
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "historyObj");
@ -105,7 +108,6 @@
var onRequestRestore = function (event) { // the user is trying to restore file version
const version = event.data.version;
const fileName = "<%- file.name %>" || null;
const directUrl = "<%- file.directUrl %>" || null;
const restoreData = {
version: version,
fileName: fileName,
@ -119,7 +121,6 @@
if (response.success && !response.error) {
const dataForHistory = {
fileName: fileName,
directUrl: directUrl
};
let xhr = new XMLHttpRequest();
xhr.open("POST", "historyObj");
@ -254,8 +255,6 @@
var requestReference = function(data, callback) {
innerAlert(data);
data.directUrl = !!config.document.directUrl;
let xhr = new XMLHttpRequest();
xhr.open("POST", "reference");
xhr.setRequestHeader("Content-Type", "application/json");
@ -290,7 +289,6 @@
}
if (firstXlsxName) {
let data = {
directUrl : "<%- file.directUrl %>" || false,
path : firstXlsxName
};
let xhr = new XMLHttpRequest();
@ -370,6 +368,7 @@
};
if (<%- JSON.stringify(editor.userid) %> != null) {
config.events.onRequestClose = onRequestClose;
config.events.onRequestEditRights = onRequestEditRights;
config.events.onRequestHistory = onRequestHistory;
config.events.onRequestHistoryData = onRequestHistoryData;
@ -397,13 +396,6 @@
}
var connectEditor = 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);
fixSize();
};
@ -413,7 +405,7 @@
if (config.type !== "mobile") {
return;
}
var wrapEl = document.getElementsByClassName("form");
var wrapEl = document.getElementsByTagName("iframe");
if (wrapEl.length) {
wrapEl[0].style.height = screen.availHeight + "px";
window.scrollTo(0, -1);
@ -431,9 +423,11 @@
if (window.addEventListener) {
window.addEventListener("load", connectEditor);
window.addEventListener("resize", fixSize);
window.addEventListener("orientationchange", fixSize);
} else if (window.attachEvent) {
window.attachEvent("onload", connectEditor);
window.attachEvent("onresize", fixSize);
window.attachEvent("orientationchange", fixSize);
}
</script>

View File

@ -58,7 +58,7 @@
<a class="try-editor slide reload-page action-link" target="_blank" href="editor?fileExt=pptx" title="Create new presentation">Presentation</a>
</li>
<li>
<a class="try-editor form reload-page action-link" target="_blank" href="editor?fileExt=docxf" title="Create new form template">Form template</a>
<a class="try-editor form reload-page action-link" target="_blank" href="editor?fileExt=docxf" title="Create new PDF form">PDF form</a>
</li>
</ul>
<label class="side-option">
@ -99,22 +99,28 @@
<tr>
<td valign="middle">
<label class="side-option">
<input id="directUrl" type="checkbox" class="checkbox collectable" name="directUrl" />Try opening on client
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server." src="images/info.svg" />
<input id="" type="checkbox" class="checkbox collectable" name="" />Try opening on client
<img id="" class="info info-tooltip" data-id="" data-tooltip="Some files can be opened in the user's browser without connecting to the document server." src="images/info.svg" />
</label>
</td>
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="wopi" class="">Go to WOPI page</a>
</div>
</div>
</div>
</td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link active" >
<a href="./">
<img src="images/home.svg" alt="Home"/>
</a>
</li>
<li>
<a href="wopi">Wopi</a>
</li>
</menu>
<div id="portal-info" style="display: <%= storedFiles.length > 0 ? "none" : "table-cell" %>">
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
@ -137,7 +143,14 @@
<%if (storedFiles.length > 0)
{%>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -265,13 +278,13 @@
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
<span id="step1" class="step">1. Loading the file.</span>
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
<div id="xmlError" class="invisible">
<div id="select-file-type" class="invisible">
<br />
<span class="step">Please select the current document type</span>
<div class="buttonsMobile indent">
<div id="forceConvert" class="button forceConvert document" data="docx">Document</div>
<div id="forceConvert" class="button forceConvert spreadsheet" data="xlsx">Spreadsheet</div>
<div id="forceConvert" class="button forceConvert presentation" data="pptx">Presentation</div>
<div class="button file-type document" data="docx">Document</div>
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
<div class="button file-type presentation" data="pptx">Presentation</div>
</div>
</div>
<br />
@ -364,12 +377,10 @@
<script type="text/javascript" src="javascripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="javascripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="javascripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="javascripts/formats.js"></script>
<script type="text/javascript" src="javascripts/jscript.js"></script>
<script type="text/javascript">
var ConverExtList = "<%= convertExts %>";
var EditedExtList = "<%= editedExts %>";
var FilledExtList = "<%= fillExts %>";
var UrlConverter = "convert";
var UrlEditor = "editor";
</script>

View File

@ -23,7 +23,7 @@
*
-->
<title>ONLYOFFICE Document Editors</title>
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<style type="text/css">
body {
@ -32,7 +32,7 @@
overflow: hidden;
-ms-content-zooming: none;
}
#office_frame {
width: 100%;
height: 100%;
@ -70,6 +70,29 @@
frameholder.appendChild(office_frame);
document.getElementById('office_form').submit();
var _onMessage = function(msg) {
var data = msg.data;
if (Object.prototype.toString.apply(data) !== '[object String]' || !window.JSON) {
return;
}
var cmd = JSON.parse(data);
if (cmd) {
if ( cmd.MessageId == 'App_LoadingStatus' ) {
var fixSize = function() {
document.getElementsByTagName("iframe")[0].style.height = window.innerHeight + "px";
}
fixSize();
window.addEventListener("orientationchange", fixSize);
}
}
};
window.addEventListener('message', function (e) {
_onMessage(e);
});
</script>
</body>

View File

@ -60,7 +60,7 @@
<a class="try-editor slide reload-page action-link" target="_blank" href="wopi-new?fileExt=pptx" title="Create new presentation">Presentation</a>
</li>
<li>
<a class="try-editor form reload-page action-link" target="_blank" href="wopi-new?fileExt=docxf" title="Create new form template">Form template</a>
<a class="try-editor form reload-page action-link" target="_blank" href="wopi-new?fileExt=docxf" title="Create new PDF form">PDF form</a>
</li>
</ul>
</div>
@ -98,14 +98,20 @@
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="./" class="">Go to Index page</a>
</div>
</div>
</td>
<td class="section">
<div class="main-panel">
<menu class="links">
<li class="home-link" >
<a href="./">
<img src="images/home.svg" alt="Home"/>
</a>
</li>
<li class="active">
<a href="wopi">Wopi</a>
</li>
</menu>
<div id="portal-info" style="display: <%= storedFiles.length > 0 ? "none" : "table-cell" %>">
<% if (!wopiEnable)
{ %>
@ -129,7 +135,14 @@
<% if (storedFiles.length > 0)
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<div class="storedHeader">
<div class="storedHeaderText">
<span class="header-list">Your documents</span>
</div>
<div class="storedHeaderClearAll">
<div class="clear-all">Clear all</div>
</div>
</div>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
@ -259,12 +272,10 @@
<script type="text/javascript" src="javascripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="javascripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="javascripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="javascripts/formats.js"></script>
<script type="text/javascript" src="javascripts/jscript.js"></script>
<script type="text/javascript">
var ConverExtList = "<%= convertExts %>";
var EditedExtList = "<%= editedExts %>";
var FilledExtList = "<%= fillExts %>";
var UrlConverter = "convert";
var UrlEditor = "wopi-action";
</script>

View File

@ -61,6 +61,12 @@ compose-prod: # Up containers in a production environment.
@docker-compose build
@docker-compose up --detach
.PHONY: restart
restart: # Restart containers replacing volume files.
@docker-compose rm --stop --force proxy example
@docker volume rm php_example
@docker compose up --detach --build
.PHONY: lint
lint: # Lint the source code for the style.
@./vendor/bin/phpcs src index.php

View File

@ -504,6 +504,17 @@
justify-content: space-between;
align-items: center;
}
.buttonsMobile.indent {
margin-bottom: 0;
flex-wrap: nowrap;
}
.button.file-type:hover,
.button.file-type {
height: 28px;
width: 100px;
margin-bottom: 10px !important;
font-size: 9px;
}
.button.gray{
margin: 0;
}

View File

@ -229,6 +229,33 @@ label .checkbox {
color: #FF6F3D;
}
.button.file-type {
font-size: 11px;
color: #FFFFFF;
padding: 8px 8px;
margin-right: 10px;
}
.button.file-type.disable {
cursor: default;
}
.button.file-type.pale {
opacity: 30%;
}
.button.file-type.document {
background: #446995;
}
.button.file-type.spreadsheet {
background: #40865C;
}
.button.file-type.presentation {
background: #AA5252;
}
.upload-panel {
float: left;
padding: 24px 0;
@ -594,6 +621,29 @@ footer table tr td:first-child {
width: 4%;
}
.storedHeader {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
}
.storedHeaderClearAll {
padding-right: 52px;
}
.clear-all {
display: inline-block;
width: 100px;
padding: 2px;
outline: 1px solid #E5E5E5;
text-align: center;
cursor:pointer;
text-transform: uppercase;
background-color: #F5F5F5;
color: #666666;
}
.select-user {
color: #444444;
font-family: Open Sans;
@ -743,6 +793,16 @@ html {
margin-left: 25px;
}
.buttonsMobile.indent{
padding-left: 35px;
margin-top: 10px;
margin-bottom: 10px;
}
.invisible {
display: none;
}
.tooltip {
background: #FFFFFF;
border-radius: 5px;

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
class Format {
constructor(name, type, actions, convert, mime) {
this.name = name;
this.type = type;
this.actions = actions;
this.convert = convert;
this.mime = mime;
}
isAutoConvertible() {
return this.actions.includes('auto-convert');
}
isEditable() {
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
}
isFillable() {
return this.actions.includes('fill');
}
}
class FormatManager {
formats = [];
constructor(formats) {
if(Array.isArray(formats)) this.formats = formats;
}
findByExtension(extension) {
return this.formats.find(format => format.name == extension);
}
isAutoConvertible(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isAutoConvertible();
}
isEditable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isEditable();
}
isFillable(extension) {
let format = this.findByExtension(extension);
return format !== undefined && format.isFillable();
}
}

View File

@ -17,6 +17,27 @@
*/
var directUrl;
var formatManager;
window.onload = function () {
fetch('formats')
.then((response) => response.json())
.then((data) => {
if (data.formats) {
let formats = [];
JSON.parse(data.formats).forEach(format => {
formats.push(new Format(
format.name,
format.type,
format.actions,
format.convert,
format.mime
));
});
formatManager = new FormatManager(formats);
}
})
}
if (typeof jQuery != "undefined") {
jq = jQuery.noConflict();
@ -97,7 +118,7 @@ if (typeof jQuery != "undefined") {
});
var timer = null;
var checkConvert = function (fileUri, filePass) {
var checkConvert = function (fileUri, filePass, fileExt) {
filePass = filePass ? filePass : null;
if (timer != null) {
clearTimeout(timer);
@ -111,7 +132,7 @@ if (typeof jQuery != "undefined") {
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (ConverExtList.indexOf(posExt) == -1) {
if (!formatManager.isAutoConvertible(posExt)) {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
return;
@ -132,7 +153,7 @@ if (typeof jQuery != "undefined") {
contentType: "text/xml",
type: "post",
dataType: "json",
data: JSON.stringify({filename : fileName, fileUri : fileUri || "", filePass: filePass}),
data: JSON.stringify({filename: fileName, fileUri: fileUri || "", filePass: filePass, fileExt: fileExt}),
url: requestAddress,
complete: function (data) {
var responseText = data.responseText;
@ -153,6 +174,12 @@ if (typeof jQuery != "undefined") {
}
return;
} else {
if (response.error.includes("Error conversion output format")){
jq("#select-file-type").removeClass("invisible");
jq("#step2").removeClass("current");
jq("#hiddenFileName").attr("placeholder",filePass);
return;
}
jq(".current").removeClass("current");
jq(".step:not(.done)").addClass("error");
jq("#mainProgress .error-message").show().find("span").text(response.error);
@ -164,7 +191,7 @@ if (typeof jQuery != "undefined") {
jq("#hiddenFileName").val(response.filename);
if (response.step < 100) {
checkConvert(response.fileUri, filePass);
checkConvert(response.fileUri, filePass, fileExt);
} else {
jq("#step2").addClass("done").removeClass("current");
loadScripts();
@ -199,10 +226,10 @@ if (typeof jQuery != "undefined") {
jq("#beginView, #beginEmbedded").removeClass("disable");
var fileName = jq("#hiddenFileName").val();
var posExt = fileName.lastIndexOf('.');
posExt = 0 <= posExt ? fileName.substring(posExt + 1).trim().toLowerCase() : '';
var posExt = fileName.lastIndexOf('.') + 1;
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
if (EditedExtList.indexOf(posExt) != -1 || FillFormsExtList.indexOf(posExt) != -1) {
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
jq("#beginEdit").removeClass("disable");
}
};
@ -228,6 +255,15 @@ if (typeof jQuery != "undefined") {
});
};
jq(document).on("click", ".file-type:not(.disable)", function () {
const currentElement = jq(this);
var fileExt = currentElement.attr("data");
var filePass = jq("#hiddenFileName").attr("placeholder");
jq('.file-type').addClass(["disable", "pale"]);
currentElement.removeClass("pale");
checkConvert(null, filePass, fileExt);
});
jq(document).on("click", "#enterPass", function () {
var filePass = jq("#filePass").val();
if (filePass) {
@ -310,6 +346,22 @@ if (typeof jQuery != "undefined") {
});
});
jq(document).on("click", ".clear-all", function () {
if (confirm("Delete all the files?")) {
jq.ajax({
async: true,
contentType: "text/xml",
type: "delete",
url: "delete",
complete: function (data) {
if (JSON.parse(data.responseText).status == 'success') {
window.location.reload(true);
}
}
});
}
});
jq(document).on("click", "#createSample", function () {
jq(".try-editor").each(function () {
var href = jq(this).attr("href");

View File

@ -1,9 +1,9 @@
version: "3.8"
services:
document-server:
container_name: document-server
image: onlyoffice/documentserver:7.5
documentserver:
container_name: documentserver
image: onlyoffice/documentserver:8.0
expose:
- "80"
environment:
@ -32,7 +32,7 @@ services:
context: .
target: proxy
depends_on:
- document-server
- documentserver
- example
ports:
- "80:80"

View File

@ -76,7 +76,7 @@ function routers()
}
if (str_starts_with($path, '/convert')) {
$response = convert();
$response['status'] = 'success';
$response['status'] = isset($response['error']) ? 'error' : 'success';
echo json_encode($response);
return;
}
@ -143,6 +143,11 @@ function routers()
echo json_encode($response);
return;
}
if (str_starts_with($path, '/formats')) {
$response = formats();
echo json_encode($response);
return;
}
http_response_code(HTTPStatus::NotFound->value);
}

View File

@ -11,3 +11,5 @@ pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
clear_env = no
php_admin_value[upload_max_filesize] = 100M
php_admin_value[post_max_size] = 100M

View File

@ -24,6 +24,14 @@ http {
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass example:80;
proxy_redirect off;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Real-IP $remote_addr;
}
}
@ -34,7 +42,7 @@ http {
location / {
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_pass http://document-server;
proxy_pass http://documentserver;
proxy_redirect off;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;

View File

@ -228,6 +228,7 @@ function convert()
$lang = $_COOKIE["ulang"] ?? "";
$extension = mb_strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$internalExtension = "ooxml";
$conversionExtension = $post['fileExt'] ?? $internalExtension;
// check if the file with such an extension can be converted
if (in_array($extension, $formatManager->convertibleExtensions()) &&
@ -245,7 +246,7 @@ function convert()
$convertedData = getConvertedData(
$fileUri,
$extension,
$internalExtension,
$conversionExtension,
$key,
true,
$newFileUri,
@ -299,12 +300,15 @@ function convert()
function delete()
{
try {
$fileName = basename($_GET["fileName"]);
if (isset($_GET["fileName"]) && !empty($_GET["fileName"])) {
$fileName = basename($_GET["fileName"]);
$filePath = getStoragePath($fileName);
$filePath = getStoragePath($fileName);
unlink($filePath); // delete a file
delTree(getHistoryDir($filePath)); // delete all the elements from the history directory
unlink($filePath); // delete a file
delTree(getHistoryDir($filePath)); // delete all the elements from the history directory
} else {
delTree(getStoragePath('')); // delete the user's folder and all the containing files
}
} catch (Exception $e) {
sendlog("Deletion ".$e->getMessage(), "webedior-ajax.log");
$result["error"] = "error: " . $e->getMessage();
@ -537,7 +541,7 @@ function reference()
}
}
$link = $post["link"];
$link = $post["link"] ?? null;
if (!isset($filename) && isset($link)) {
if (strpos($link, serverPath()) === false) {
return ["url" => $link, "directUrl"=> $link];
@ -655,3 +659,19 @@ function restore()
];
}
}
function formats()
{
try {
$formatManager = new FormatManager();
$formats = $formatManager->all();
return [
'formats' => json_encode($formats)
];
} catch (Exception $error) {
return [
'error' => 'Server error'
];
}
}

View File

@ -40,7 +40,7 @@ class ConfigurationManager
public function documentServerPublicURL(): URL
{
$url = getenv('DOCUMENT_SERVER_PUBLIC_URL') ?: 'http://document-server';
$url = getenv('DOCUMENT_SERVER_PUBLIC_URL') ?: 'http://documentserver';
return new URL($url);
}

View File

@ -42,7 +42,7 @@ final class ConfigurationManagerDocumentServerAPIURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerAPIURL();
$this->assertEquals(
'http://document-server/web-apps/apps/api/documents/api.js',
'http://documentserver/web-apps/apps/api/documents/api.js',
$url->string()
);
}
@ -53,7 +53,7 @@ final class ConfigurationManagerDocumentServerAPIURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerAPIURL();
$this->assertEquals(
'http://document-server/api',
'http://documentserver/api',
$url->string()
);
}

View File

@ -42,7 +42,7 @@ final class ConfigurationManagerDocumentServerCommandURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerCommandURL();
$this->assertEquals(
'http://document-server/coauthoring/CommandService.ashx',
'http://documentserver/coauthoring/CommandService.ashx',
$url->string()
);
}
@ -53,7 +53,7 @@ final class ConfigurationManagerDocumentServerCommandURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerCommandURL();
$this->assertEquals(
'http://document-server/command',
'http://documentserver/command',
$url->string()
);
}

View File

@ -42,7 +42,7 @@ final class ConfigurationManagerDocumentServerConverterURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerConverterURL();
$this->assertEquals(
'http://document-server/ConvertService.ashx',
'http://documentserver/ConvertService.ashx',
$url->string()
);
}
@ -53,7 +53,7 @@ final class ConfigurationManagerDocumentServerConverterURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerConverterURL();
$this->assertEquals(
'http://document-server/converter',
'http://documentserver/converter',
$url->string()
);
}

View File

@ -42,7 +42,7 @@ final class ConfigurationManagerDocumentServerPreloaderURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerPreloaderURL();
$this->assertEquals(
'http://document-server/web-apps/apps/api/documents/cache-scripts.html',
'http://documentserver/web-apps/apps/api/documents/cache-scripts.html',
$url->string()
);
}
@ -53,7 +53,7 @@ final class ConfigurationManagerDocumentServerPreloaderURLTests extends TestCase
$configManager = new ConfigurationManager();
$url = $configManager->documentServerPreloaderURL();
$this->assertEquals(
'http://document-server/preloader',
'http://documentserver/preloader',
$url->string()
);
}

View File

@ -41,7 +41,7 @@ final class ConfigurationManagerDocumentServerPrivateURLTests extends TestCase
{
$configManager = new ConfigurationManager();
$url = $configManager->documentServerPrivateURL();
$this->assertEquals('http://document-server', $url->string());
$this->assertEquals('http://documentserver', $url->string());
}
public function testAssignsAValueFromTheEnvironment()

View File

@ -41,7 +41,7 @@ final class ConfigurationManagerDocumentServerPublicURLTests extends TestCase
{
$configManager = new ConfigurationManager();
$url = $configManager->documentServerPublicURL();
$this->assertEquals('http://document-server', $url->string());
$this->assertEquals('http://documentserver', $url->string());
}
public function testAssignsAValueFromTheEnvironment()

View File

@ -158,7 +158,7 @@ function getTemplateImageUrl($filename)
{
$formatManager = new FormatManager();
$ext = mb_strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$path = serverPath(true) . "/assets/images/";
$path = serverPath(false) . "/assets/images/";
foreach ($formatManager->all() as $format) {
if ($format->name === $ext) {
@ -553,6 +553,9 @@ function processConvServResponceError($errorCode)
// add the error message to the error message template depending on the error code
switch ($errorCode) {
case -9:
$errorMessage = $errorMessageTemplate . "Error conversion output format";
break;
case -8:
$errorMessage = $errorMessageTemplate . "Error document VKey";
break;

View File

@ -94,7 +94,7 @@ final class ExampleUsers
$this->user1Description,
true,
true,
[]
["blank" => false,]
),
new Users(
"uid-2",
@ -132,7 +132,7 @@ final class ExampleUsers
$this->user3Description,
false,
false,
["blank" => false,]
null
),
new Users(
"uid-0",

View File

@ -33,6 +33,7 @@ final class Users
public ?array $userInfoGroups;
public ?bool $avatar;
public ?string $image;
public ?array $goback;
/**

View File

@ -48,7 +48,7 @@ final class DocEditorView extends View
$jwtManager = new JwtManager();
$userList = new ExampleUsers();
$fileId = $request["fileID"] ?? "";
$user = $userList->getUser($request["user"]);
$user = $userList->getUser($request["user"] ?? null);
$isEnableDirectUrl = isset($request["directUrl"]) ? filter_var($request["directUrl"], FILTER_VALIDATE_BOOLEAN)
: false;
if (!empty($externalUrl)) {
@ -132,7 +132,7 @@ final class DocEditorView extends View
$editorsMode == "view" || $editorsMode == "filter" || $editorsMode == "blockcontent"),
"print" => !in_array("print", $user->deniedPermissions),
"fillForms" => $editorsMode != "view" && $editorsMode != "comment"
&& $editorsMode != "embedded" && $editorsMode != "blockcontent",
&& $editorsMode != "blockcontent",
"modifyFilter" => $editorsMode != "filter",
"modifyContentControl" => $editorsMode != "blockcontent",
"review" => $canEdit && ($editorsMode == "edit" || $editorsMode == "review"),
@ -165,7 +165,7 @@ final class DocEditorView extends View
"id" => $user->id != "uid-0" ? $user->id : null,
"name" => $user->name,
"group" => $user->group,
"image" => $user->avatar ? serverPath(true) . "/assets/images/" . $user->id . ".png" : null
"image" => $user->avatar ? serverPath(false) . "/assets/images/" . $user->id . ".png" : null
],
"embedded" => [ // the parameters for the embedded document type
// the absolute URL that will allow the document to be saved onto the user personal computer
@ -230,7 +230,7 @@ final class DocEditorView extends View
if ($user->id != 'uid-0') {
foreach ($userList->getAllUsers() as $userInfo) {
$u = $userInfo;
$u->image = $userInfo->avatar ? serverPath(true) . "/assets/images/" . $userInfo->id . ".png" : null;
$u->image = $userInfo->avatar ? serverPath(false) . "/assets/images/" . $userInfo->id . ".png" : null;
array_push($usersInfo, $u);
}
}

View File

@ -44,9 +44,6 @@ final class IndexView extends View
"editButton" => $this->getEditButton(),
"dataDocs" => $this->getPreloaderUrl(),
"date" => date("Y"),
"fillFormsExtList" => implode(",", $formatManager->fillableExtensions()),
"converExtList" => implode(",", $formatManager->convertibleExtensions()),
"editedExtList" => implode(",", $formatManager->editableExtensions()),
"serverVersion" => $configManager -> getVersion(),
];
}

View File

@ -341,12 +341,6 @@
config.events.onRequestSaveAs = onRequestSaveAs;
};
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);
};

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