diff --git a/.gitmodules b/.gitmodules index 5db5fbe9..fe80f429 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,8 @@ -[submodule "src/main/resources/app_data"] - path = src/main/resources/app_data +[submodule "src/main/resources/app_data/document-templates"] + path = src/main/resources/app_data/document-templates url = https://github.com/ONLYOFFICE/document-templates branch = main/new +[submodule "src/main/resources/app_data/document-formats"] + path = src/main/resources/app_data/document-formats + url = https://github.com/ONLYOFFICE/document-formats + branch = master diff --git a/3rd-Party.license b/3rd-Party.license index b6f1b966..5569e79c 100644 --- a/3rd-Party.license +++ b/3rd-Party.license @@ -1,29 +1,13 @@ Confluence ONLYOFFICE integration app uses code from the following 3rd party projects: -atlassian-plugins-osgi-testrunner - Atlassian Plugins TestRunner (https://maven.atlassian.com/public/licenses/license.txt) -License: The 3-Clause BSD License -License File: atlassian-plugins-osgi-testrunner.license +com.auth0.java-jwt - Java implementation of JSON Web Token (JWT) (https://github.com/auth0/java-jwt/blob/master/LICENSE) +License: MIT License +License File: com.auth0.java-jwt.license -atlassian-spring-scanner-annotation - Atlassian Spring Scanner Annotations (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: atlassian-spring-scanner-annotation.license - -commons-collections - Types that extend and augment the Java Collections Framework. (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: commons-collections.license - -commons-httpclient - The HttpClient component supports the client-side of RFC 1945 (HTTP/1.0) and RFC 2616 (HTTP/1.1) , several related specifications (RFC 2109 (Cookies) , RFC 2617 (HTTP Authentication) , etc.), and provides a framework by which new request types (methods) or HTTP extensions can be created easily. (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: commons-httpclient.license - -javax.inject - The javax.inject API (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: javax.inject.license - -javax.enterprise.cdi-api - Contexts and Dependency Injection for Java (https://github.com/eclipse-ee4j/cdi/blob/master/LICENSE.txt) -License: Apache 2.0 -License File javax.enterprise.cdi-api.license +com.fasterxml.jackson.core.jackson-databind - General data-binding functionality for Jackson: works on core streaming API (https://github.com/FasterXML/jackson-databind/blob/2.16/LICENSE) +License: Apache License 2.0 +License File: com.fasterxml.jackson.core.jackson-databind.license javax.servlet-api - Java Servlet API (https://opensource.org/licenses/CDDL-1.0 https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) License: CDDL, GPL 2.0 @@ -32,7 +16,3 @@ License File: javax.servlet-api.license JSON - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (http://json.org/license.html) License: JSON License File: JSON.license - -SAL API - A plugin that provides API for Shared Application Access Layer (https://opensource.org/licenses/BSD-3-Clause) -License: The 3-Clause BSD License -License File: SAL API.license diff --git a/CHANGELOG.md b/CHANGELOG.md index 8975bc55..55b3276a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## 4.3.0 +## Added +- compatible with Confluence 8.4.0 +- extended list of supported formats +- document server v6.4 and earlier is no longer supported +- macros for view documents +- improvement of jwt signature +- download as +- Paste Special to add a link between files + ## 4.2.0 ## Changed - compatible with Confluence 8.1.1 diff --git a/README.md b/README.md index 51b06605..6bdfb565 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,32 @@ The app allows to: Supported formats: -* For viewing and editing: DOCX, XLSX, PPTX, DOCXF, OFORM. -* For conversion to Office Open XML: ODT, DOC, ODP, PPT, ODS, XLS. +**For viewing:** +* **WORD:** DJVU, DOC, DOCM, DOCX, DOCXF, DOT, DOTM, DOTX, EPUB, FB2, FODT, HTM, HTML, MHT, ODT, OFORM, OTT, OXPS, PDF, RTF, TXT, XML, XPS +* **CELL:** CSV, FODS, ODS, OTS, XLS, XLSM, XLSX, XLT, XLTM, XLTX +* **SLIDE:** FODP, ODP, OTP, POT, POTM, POTX, PPS, PPSM, PPSX, PPT, PPTM, PPTX + +**For editing:** + +* **WORD:** DOCM, DOCX, DOCXF, DOTM, DOTX, HTM, XML +* **CELL:** XLSM, XLSX, XLTM, XLTX +* **SLIDE:** POTM, POTX, PPSM, PPSX, PPTM, PPTX + +**For editing with possible loss of information:** + +* **WORD:** EPUB, FB2, HTML, ODT, OTT, RTF, TXT +* **CELL:** CSV, ODS, OTS +* **SLIDE:** ODP, OTP + +**For filling:** + +* **WORD:** OFORM + +**For converting to Office Open XML formats:** + +* **WORD:** DOC, DOCM, DOCXF, DOT, DOTM, DOTX, EPUB, FB2, FODT, HTM, HTML, MHT, ODT, OTT, OXPS, PDF, RTF, XML, XPS +* **CELL:** FODS, ODS, OTS, XLS, XLSM, XLT, XLTM, XLTX +* **SLIDE:** FODP, ODP, OTP, POT, POTM, POTX, PPS, PPSM, PPSX, PPT, PPTM ## Installing ONLYOFFICE Docs diff --git a/licenses/3rd-Party.license b/licenses/3rd-Party.license index b6f1b966..5569e79c 100644 --- a/licenses/3rd-Party.license +++ b/licenses/3rd-Party.license @@ -1,29 +1,13 @@ Confluence ONLYOFFICE integration app uses code from the following 3rd party projects: -atlassian-plugins-osgi-testrunner - Atlassian Plugins TestRunner (https://maven.atlassian.com/public/licenses/license.txt) -License: The 3-Clause BSD License -License File: atlassian-plugins-osgi-testrunner.license +com.auth0.java-jwt - Java implementation of JSON Web Token (JWT) (https://github.com/auth0/java-jwt/blob/master/LICENSE) +License: MIT License +License File: com.auth0.java-jwt.license -atlassian-spring-scanner-annotation - Atlassian Spring Scanner Annotations (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: atlassian-spring-scanner-annotation.license - -commons-collections - Types that extend and augment the Java Collections Framework. (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: commons-collections.license - -commons-httpclient - The HttpClient component supports the client-side of RFC 1945 (HTTP/1.0) and RFC 2616 (HTTP/1.1) , several related specifications (RFC 2109 (Cookies) , RFC 2617 (HTTP Authentication) , etc.), and provides a framework by which new request types (methods) or HTTP extensions can be created easily. (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: commons-httpclient.license - -javax.inject - The javax.inject API (https://www.apache.org/licenses/LICENSE-2.0) -License: Apache 2.0 -License File: javax.inject.license - -javax.enterprise.cdi-api - Contexts and Dependency Injection for Java (https://github.com/eclipse-ee4j/cdi/blob/master/LICENSE.txt) -License: Apache 2.0 -License File javax.enterprise.cdi-api.license +com.fasterxml.jackson.core.jackson-databind - General data-binding functionality for Jackson: works on core streaming API (https://github.com/FasterXML/jackson-databind/blob/2.16/LICENSE) +License: Apache License 2.0 +License File: com.fasterxml.jackson.core.jackson-databind.license javax.servlet-api - Java Servlet API (https://opensource.org/licenses/CDDL-1.0 https://www.gnu.org/licenses/old-licenses/gpl-2.0.html) License: CDDL, GPL 2.0 @@ -32,7 +16,3 @@ License File: javax.servlet-api.license JSON - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. It also includes the capability to convert between JSON and XML, HTTP headers, Cookies, and CDL. This is a reference implementation. (http://json.org/license.html) License: JSON License File: JSON.license - -SAL API - A plugin that provides API for Shared Application Access Layer (https://opensource.org/licenses/BSD-3-Clause) -License: The 3-Clause BSD License -License File: SAL API.license diff --git a/licenses/SAL API.license b/licenses/SAL API.license deleted file mode 100644 index ae69751d..00000000 --- a/licenses/SAL API.license +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (c) , -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/atlassian-plugins-osgi-testrunner.license b/licenses/atlassian-plugins-osgi-testrunner.license deleted file mode 100644 index ae69751d..00000000 --- a/licenses/atlassian-plugins-osgi-testrunner.license +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (c) , -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/com.auth0.java-jwt.license b/licenses/com.auth0.java-jwt.license new file mode 100644 index 00000000..72de587f --- /dev/null +++ b/licenses/com.auth0.java-jwt.license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Auth0, Inc. (http://auth0.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/licenses/atlassian-spring-scanner-annotation.license b/licenses/com.fasterxml.jackson.core.jackson-databind.license similarity index 100% rename from licenses/atlassian-spring-scanner-annotation.license rename to licenses/com.fasterxml.jackson.core.jackson-databind.license diff --git a/licenses/commons-collections.license b/licenses/commons-collections.license deleted file mode 100644 index d6456956..00000000 --- a/licenses/commons-collections.license +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. diff --git a/licenses/commons-httpclient.license b/licenses/commons-httpclient.license deleted file mode 100644 index d6456956..00000000 --- a/licenses/commons-httpclient.license +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. diff --git a/licenses/javax.enterprise.cdi-api.license b/licenses/javax.enterprise.cdi-api.license deleted file mode 100644 index 56ee3c8c..00000000 --- a/licenses/javax.enterprise.cdi-api.license +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. \ No newline at end of file diff --git a/licenses/javax.inject.license b/licenses/javax.inject.license deleted file mode 100644 index d6456956..00000000 --- a/licenses/javax.inject.license +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. diff --git a/pom.xml b/pom.xml index 075aa43c..97b61bb7 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 onlyoffice onlyoffice-confluence-plugin - 4.2.0 + 4.3.0 Ascensio System SIA @@ -17,22 +17,6 @@ Confluence ONLYOFFICE integration app Confluence ONLYOFFICE integration app allows you to work on all kinds of office documents within Confluence using ONLYOFFICE Online Editors with the enhanced formatting toolset. View, create and co-edit the documents in real-time. atlassian-plugin - - - - commons-httpclient - commons-httpclient - 3.1 - provided - - - commons-collections - commons-collections - 3.2.2 - provided - - - @@ -41,45 +25,27 @@ ${confluence.version} provided - - com.atlassian.plugin - atlassian-spring-scanner-annotation - ${atlassian.spring.scanner.version} - provided - - - com.atlassian.plugins - atlassian-plugins-osgi-testrunner - ${plugin.testrunner.version} - test - javax.servlet javax.servlet-api - 3.1.0 + 4.0.1 provided org.json json - 20090211 + 20230227 provided - com.atlassian.sal - sal-api - 2.0.17 - provided + com.auth0 + java-jwt + 4.0.0 - javax.inject - javax.inject - 1 - - - javax.enterprise - cdi-api - 1.0 + com.fasterxml.jackson.core + jackson-databind + 2.13.3 @@ -87,7 +53,7 @@ com.atlassian.maven.plugins - maven-confluence-plugin + confluence-maven-plugin ${amps.version} true @@ -99,58 +65,20 @@ ${confluence.version} ${confluence.data.version} false - false - false - - ${atlassian.plugin.key} - - - - onlyoffice, - com.atlassian.confluence.pages, - com.atlassian.confluence.renderer, - com.atlassian.confluence.setup, - com.atlassian.confluence.spaces, - com.atlassian.spring.container, - javax.servlet,javax.servlet.http";version="1.0.0", - * - - - - - * - - - * - - -com.atlassian.plugin.spring.scanner.annotation.* + false - - com.atlassian.plugin - atlassian-spring-scanner-maven-plugin - ${atlassian.spring.scanner.version} - - - - atlassian-spring-scanner - - process-classes - - - - false - - org.apache.maven.plugins maven-compiler-plugin + 3.11.0 8 8 + org.apache.maven.plugins maven-checkstyle-plugin @@ -211,11 +139,10 @@ 8.0.1 8.0.1 - 6.3.21 - 1.2.3 - 2.2.3 + 8.10.0 ${project.groupId}.${project.artifactId} + UTF-8 diff --git a/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java b/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java index 17ef7f15..57a147d3 100644 --- a/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeAPIServlet.java @@ -18,6 +18,8 @@ package onlyoffice; +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.status.service.SystemInformationService; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.google.gson.Gson; @@ -39,7 +41,6 @@ import org.json.JSONArray; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -57,18 +58,19 @@ public class OnlyOfficeAPIServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeAPIServlet"); + private final SystemInformationService sysInfoService; private final JwtManager jwtManager; private final DocumentManager documentManager; - private final AttachmentUtil attachmentUtil; private final ParsingUtil parsingUtil; private final UrlManager urlManager; private final ConfigurationManager configurationManager; - @Inject - public OnlyOfficeAPIServlet(final JwtManager jwtManager, final DocumentManager documentManager, - final AttachmentUtil attachmentUtil, final ParsingUtil parsingUtil, - final UrlManager urlManager, final ConfigurationManager configurationManager) { + public OnlyOfficeAPIServlet(final SystemInformationService sysInfoService, final JwtManager jwtManager, + final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final ParsingUtil parsingUtil, final UrlManager urlManager, + final ConfigurationManager configurationManager) { + this.sysInfoService = sysInfoService; this.jwtManager = jwtManager; this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; @@ -89,6 +91,9 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r case "attachment-data": attachmentData(request, response); break; + case "reference-data": + referenceData(request, response); + break; default: response.sendError(HttpServletResponse.SC_NOT_FOUND); return; @@ -183,8 +188,7 @@ private void attachmentData(final HttpServletRequest request, final HttpServletR if (attachmentUtil.checkAccess(attachmentId, user, false)) { Map data = new HashMap<>(); - String fileName = attachmentUtil.getFileName(attachmentId); - String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).trim().toLowerCase(); + String fileType = attachmentUtil.getFileExt(attachmentId); if (bodyJson.has("command")) { data.put("command", bodyJson.getString("command")); @@ -207,4 +211,73 @@ private void attachmentData(final HttpServletRequest request, final HttpServletR throw new IOException(e.getMessage()); } } + + private void referenceData(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + if (user == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + InputStream requestStream = request.getInputStream(); + String body = parsingUtil.getBody(requestStream); + + try { + JSONObject bodyJson = new JSONObject(body); + JSONObject referenceData = new JSONObject(); + Long attachmentId = null; + + if (bodyJson.has("referenceData")) { + referenceData = bodyJson.getJSONObject("referenceData"); + if (referenceData.getString("instanceId").equals(sysInfoService.getConfluenceInfo().getBaseUrl())) { + attachmentId = referenceData.getLong("fileKey"); + } + } + + Attachment attachment = attachmentUtil.getAttachment(attachmentId); + + if (attachment == null) { + String pageIdString = request.getParameter("pageId"); + + if (pageIdString != null && !pageIdString.isEmpty()) { + Long pageId = Long.parseLong(pageIdString); + attachment = attachmentUtil.getAttachmentByName(bodyJson.getString("path"), pageId); + if (attachment != null) { + attachmentId = attachment.getId(); + referenceData.put("fileKey", attachment.getId()); + referenceData.put("instanceId", sysInfoService.getConfluenceInfo().getBaseUrl()); + } + } + } + + if (attachment == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } + + if (!attachmentUtil.checkAccess(attachmentId, user, false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + JSONObject responseJson = new JSONObject(); + + responseJson.put("fileType", attachmentUtil.getFileExt(attachmentId)); + responseJson.put("path", attachmentUtil.getFileName(attachmentId)); + responseJson.put("referenceData", referenceData); + responseJson.put("url", urlManager.getFileUri(attachmentId)); + + if (jwtManager.jwtEnabled()) { + responseJson.put("token", jwtManager.createToken(responseJson)); + } + + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(responseJson.toString()); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } } diff --git a/src/main/java/onlyoffice/OnlyOfficeConfServlet.java b/src/main/java/onlyoffice/OnlyOfficeConfServlet.java index 09c73e85..89fa9483 100644 --- a/src/main/java/onlyoffice/OnlyOfficeConfServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeConfServlet.java @@ -21,7 +21,6 @@ import com.atlassian.confluence.renderer.radeox.macros.MacroUtils; import com.atlassian.confluence.setup.settings.SettingsManager; import com.atlassian.confluence.util.velocity.VelocityUtils; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.atlassian.sal.api.user.UserManager; @@ -42,7 +41,6 @@ import org.json.JSONArray; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -58,18 +56,12 @@ public class OnlyOfficeConfServlet extends HttpServlet { private final long serialVersionUID = 1L; private static final int ERROR_INVALID_TOKEN = 6; - @ComponentImport private final UserManager userManager; - @ComponentImport private final PluginSettingsFactory pluginSettingsFactory; - private final JwtManager jwtManager; private final ConfigurationManager configurationManager; - private final ParsingUtil parsingUtil; - - @Inject public OnlyOfficeConfServlet(final UserManager userManager, final PluginSettingsFactory pluginSettingsFactory, final JwtManager jwtManager, final ConfigurationManager configurationManager, final ParsingUtil parsingUtil) { diff --git a/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java b/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java index f5d1a245..a88c5b25 100644 --- a/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeConvertServlet.java @@ -24,7 +24,7 @@ import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.velocity.VelocityUtils; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; +import onlyoffice.managers.auth.AuthContext; import onlyoffice.managers.configuration.ConfigurationManager; import onlyoffice.managers.convert.ConvertManager; import onlyoffice.managers.document.DocumentManager; @@ -40,7 +40,6 @@ import org.apache.log4j.Logger; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -57,16 +56,13 @@ public class OnlyOfficeConvertServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeConvertServlet"); - @ComponentImport private final AttachmentManager attachmentManager; - private final AttachmentUtil attachmentUtil; private final ConvertManager convertManager; private final AuthContext authContext; private final DocumentManager documentManager; private final ConfigurationManager configurationManager; - @Inject public OnlyOfficeConvertServlet(final AttachmentManager attachmentManager, final AttachmentUtil attachmentUtil, final ConvertManager convertManager, final AuthContext authContext, final DocumentManager documentManager, @@ -82,7 +78,7 @@ public OnlyOfficeConvertServlet(final AttachmentManager attachmentManager, final @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - if (!authContext.checkUserAuthorisation(request, response)) { + if (!authContext.checkUserAuthorization(request, response)) { return; } String pageIdString = request.getParameter("pageId"); @@ -99,7 +95,7 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re Long pageId = attachment.getContainer().getId(); String fileName = attachment.getFileName(); String ext = attachment.getFileExtension(); - String newExt = convertManager.convertsTo(ext); + String newExt = convertManager.getTargetExt(ext); String title = fileName.substring(0, fileName.lastIndexOf(".")); if (pageIdString != null && !pageIdString.isEmpty()) { @@ -127,7 +123,7 @@ private String getTemplate(final Map map) throws UnsupportedEnco @Override public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - if (!authContext.checkUserAuthorisation(request, response)) { + if (!authContext.checkUserAuthorization(request, response)) { return; } @@ -163,11 +159,12 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r pageId = attachment.getContainer().getId(); } + String convertToExt = convertManager.getTargetExt(ext); + if (attachmentUtil.checkAccess(attachmentId, user, false) && attachmentUtil.checkAccessCreate(user, pageId)) { - if (convertManager.isConvertable(ext)) { - String convertToExt = convertManager.convertsTo(ext); - json = convertManager.convert(attachmentId, ext, convertToExt, user); + if (convertToExt != null) { + json = convertManager.convert(attachmentId, ext, convertToExt, user, null); if (json.has("endConvert") && json.getBoolean("endConvert")) { String newFileName = documentManager.getCorrectName(title, convertToExt, pageId); diff --git a/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java b/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java index 5cf05e8b..0e51d74c 100644 --- a/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeEditorServlet.java @@ -18,107 +18,79 @@ package onlyoffice; -import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.pages.BlogPost; import com.atlassian.confluence.renderer.radeox.macros.MacroUtils; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.velocity.VelocityUtils; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; -import com.atlassian.plugin.webresource.UrlMode; -import com.atlassian.plugin.webresource.WebResourceUrlProvider; +import com.atlassian.sal.api.message.I18nResolver; +import onlyoffice.managers.auth.AuthContext; +import com.atlassian.confluence.pages.Attachment; +import onlyoffice.managers.config.ConfigManager; import onlyoffice.managers.configuration.ConfigurationManager; import onlyoffice.managers.document.DocumentManager; -import onlyoffice.managers.jwt.JwtManager; import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.config.DocumentType; +import onlyoffice.model.config.Type; +import onlyoffice.model.config.editor.Mode; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.json.JSONArray; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.HashMap; import java.util.Map; -import java.util.Properties; public class OnlyOfficeEditorServlet extends HttpServlet { private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeEditorServlet"); private final long serialVersionUID = 1L; - private Properties properties; - - @ComponentImport - private final LocaleManager localeManager; - @ComponentImport - private final WebResourceUrlProvider webResourceUrlProvider; - - private final JwtManager jwtManager; + private final I18nResolver i18n; private final UrlManager urlManager; private final ConfigurationManager configurationManager; private final AuthContext authContext; private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; + private final ConfigManager configManager; - - @Inject - public OnlyOfficeEditorServlet(final LocaleManager localeManager, - final WebResourceUrlProvider webResourceUrlProvider, - final UrlManager urlManager, final JwtManager jwtManager, - final ConfigurationManager configurationManager, - final AuthContext authContext, final DocumentManager documentManager, - final AttachmentUtil attachmentUtil) { - this.localeManager = localeManager; - this.webResourceUrlProvider = webResourceUrlProvider; + public OnlyOfficeEditorServlet(final I18nResolver i18n, final UrlManager urlManager, + final ConfigurationManager configurationManager, final AuthContext authContext, + final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final ConfigManager configManager) { + this.i18n = i18n; this.urlManager = urlManager; - this.jwtManager = jwtManager; this.configurationManager = configurationManager; this.authContext = authContext; this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; + this.configManager = configManager; } @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - if (!authContext.checkUserAuthorisation(request, response)) { + if (!authContext.checkUserAuthorization(request, response)) { return; } - String apiUrl = urlManager.getPublicDocEditorUrl(); - if (apiUrl == null || apiUrl.isEmpty()) { - apiUrl = ""; - } - - properties = configurationManager.getProperties(); - - String type = ""; - String callbackUrl = ""; - String fileUrl = ""; - String gobackUrl = ""; - String key = ""; - String fileName = ""; - String errorMessage = ""; - ConfluenceUser user = null; + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); String attachmentIdString = request.getParameter("attachmentId"); - String actionData = request.getParameter("actionData"); + String actionDataString = request.getParameter("actionData"); + String referer = request.getHeader("referer"); - if (attachmentIdString == null) { - fileName = request.getParameter("fileName"); + if (attachmentIdString == null || attachmentIdString.isEmpty()) { + String fileName = request.getParameter("fileName"); String fileExt = request.getParameter("fileExt"); String pageId = request.getParameter("pageId"); if (pageId != null && !pageId.equals("")) { - user = AuthenticatedUserThreadLocal.get(); if (!attachmentUtil.checkAccessCreate(user, Long.parseLong(pageId))) { response.sendError(HttpServletResponse.SC_FORBIDDEN); @@ -133,162 +105,64 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re } } - Long attachmentId = null; - try { - attachmentId = Long.parseLong(attachmentIdString); - log.info("attachmentId " + attachmentId); - - user = AuthenticatedUserThreadLocal.get(); - log.info("user " + user); - if (attachmentUtil.checkAccess(attachmentId, user, false)) { - type = documentManager.getEditorType(request.getHeader("USER-AGENT")); - - key = documentManager.getKeyOfFile(attachmentId); - - fileName = attachmentUtil.getFileName(attachmentId); - - fileUrl = urlManager.getFileUri(attachmentId); - - gobackUrl = urlManager.getGobackUrl(attachmentId, request); - - if (attachmentUtil.checkAccess(attachmentId, user, true)) { - callbackUrl = urlManager.getCallbackUrl(attachmentId); - } - } else { - log.error("access deny"); - errorMessage = "You don not have enough permission to view the file"; + Long attachmentId = Long.parseLong(attachmentIdString); + Long pageId = attachmentUtil.getAttachmentPageId(attachmentId); + Attachment attachment = attachmentUtil.getAttachment(attachmentId); + String extension = attachmentUtil.getFileExt(attachmentId); + DocumentType documentType = documentManager.getDocType(extension); + + if (attachment == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; } - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - String error = ex.toString() + "\n" + sw.toString(); - log.error(error); - errorMessage = ex.toString(); - } - - response.setContentType("text/html;charset=UTF-8"); - PrintWriter writer = response.getWriter(); - writer.write(getTemplate(attachmentId, type, apiUrl, callbackUrl, fileUrl, key, fileName, user, gobackUrl, - actionData, errorMessage)); - } - - private String getTemplate(final Long attachmentId, final String type, final String apiUrl, - final String callbackUrl, final String fileUrl, final String key, final String fileName, - final ConfluenceUser user, final String gobackUrl, final String actionData, - final String errorMessage) throws - UnsupportedEncodingException { - Map defaults = MacroUtils.defaultVelocityContext(); - Map config = new HashMap(); - - String docTitle = fileName.trim(); - String docExt = attachmentUtil.getFileExt(attachmentId); - boolean canEdit = documentManager.isEditable(docExt) || documentManager.isFillForm(docExt); - String documentType = documentManager.getDocType(docExt); - Long pageId = attachmentUtil.getAttachmentPageId(attachmentId); - - config.put("docserviceApiUrl", apiUrl + properties.getProperty("files.docservice.url.api")); - config.put("errorMessage", errorMessage); - config.put("docTitle", docTitle); - config.put("favicon", webResourceUrlProvider.getStaticPluginResourceUrl( - "onlyoffice.onlyoffice-confluence-plugin:onlyoffice-confluence-plugin-resources-editor", - documentType + ".ico", - UrlMode.ABSOLUTE) - ); - - JSONObject responseJson = new JSONObject(); - JSONObject documentObject = new JSONObject(); - JSONObject editorConfigObject = new JSONObject(); - JSONObject userObject = new JSONObject(); - JSONObject permObject = new JSONObject(); - JSONObject customizationObject = new JSONObject(); - JSONObject gobackObject = new JSONObject(); - - try { - responseJson.put("type", type); - responseJson.put("width", "100%"); - responseJson.put("height", "100%"); - responseJson.put("documentType", documentType); - - responseJson.put("document", documentObject); - documentObject.put("title", docTitle); - documentObject.put("url", fileUrl); - documentObject.put("fileType", docExt); - documentObject.put("key", key); - documentObject.put("permissions", permObject); - responseJson.put("editorConfig", editorConfigObject); - - if (canEdit && callbackUrl != null && !callbackUrl.isEmpty()) { - permObject.put("edit", true); - editorConfigObject.put("mode", "edit"); - editorConfigObject.put("callbackUrl", callbackUrl); - } else { - permObject.put("edit", false); - editorConfigObject.put("mode", "view"); + if (!attachmentUtil.checkAccess(attachmentId, user, false)) { + response.sendRedirect(attachment.getContainer().getUrlPath()); + return; } - if (actionData != null && !actionData.isEmpty()) { - editorConfigObject.put("actionLink", new JSONObject(actionData)); - } + Map context = MacroUtils.defaultVelocityContext(); + context.put("docserviceApiUrl", urlManager.getDocServiceApiUrl()); + context.put("docTitle", attachmentUtil.getFileName(attachmentId)); + context.put("favicon", urlManager.getFaviconUrl(documentType)); + context.put("pageId", pageId); + context.put("pageTitle", attachmentUtil.getAttachmentPageTitle(attachmentId)); + context.put("spaceKey", attachmentUtil.getAttachmentSpaceKey(attachmentId)); + context.put("spaceName", attachmentUtil.getAttachmentSpaceName(attachmentId)); + context.put("isBlogPost", String.valueOf(attachmentUtil.getContainer(pageId) instanceof BlogPost)); - if (attachmentUtil.checkAccessCreate(user, pageId)) { - editorConfigObject.put("createUrl", urlManager.getCreateUri(pageId, docExt)); - } + if (documentType != null) { + Type type = documentManager.getEditorType(request.getHeader("USER-AGENT")); - editorConfigObject.put("lang", localeManager.getLocale(user).toLanguageTag()); - editorConfigObject.put("customization", customizationObject); + JSONObject actionData = null; - customizationObject.put("forcesave", configurationManager.forceSaveEnabled()); - customizationObject.put("chat", configurationManager.getBooleanPluginSetting("chat", true)); - customizationObject.put("compactHeader", - configurationManager.getBooleanPluginSetting("compactHeader", false)); - customizationObject.put("feedback", configurationManager.getBooleanPluginSetting("feedback", false)); - customizationObject.put("help", configurationManager.getBooleanPluginSetting("helpMenu", true)); - customizationObject.put("toolbarNoTabs", - configurationManager.getBooleanPluginSetting("toolbarNoTabs", false)); - if (!configurationManager.getStringPluginSetting("reviewDisplay", "original").equals("original")) { - customizationObject.put("reviewDisplay", - configurationManager.getStringPluginSetting("reviewDisplay", "original")); - } - customizationObject.put("goback", gobackObject); - gobackObject.put("url", gobackUrl); + if (actionDataString != null && !actionDataString.isEmpty()) { + actionData = new JSONObject(actionDataString); + } - if (user != null) { - editorConfigObject.put("user", userObject); - userObject.put("id", user.getName()); - userObject.put("name", user.getFullName()); + String config = configManager.createConfig(attachmentId, Mode.EDIT, type, actionData, referer); + context.put("configAsHtml", config); + context.put("historyInfoUriAsHtml", urlManager.getHistoryInfoUri(attachmentId)); + context.put("historyDataUriAsHtml", urlManager.getHistoryDataUri(attachmentId)); + context.put("attachmentDataAsHtml", urlManager.getAttachmentDataUri()); + context.put("saveAsUriAsHtml", urlManager.getSaveAsUri()); + context.put("referenceDataUriAsHtml", urlManager.getReferenceDataUri(pageId)); + context.put("insertImageTypesAsHtml", new JSONArray(documentManager.getInsertImageTypes()).toString()); + context.put("compareFileTypesAsHtml", new JSONArray(documentManager.getCompareFileTypes()).toString()); + context.put("mailMergeTypesAsHtml", new JSONArray(documentManager.getMailMergeTypes()).toString()); + context.put("demo", configurationManager.demoActive()); + } else { + context.put("errorMessage", i18n.getText("onlyoffice.editor.message.error.unsupported") + "(." + + attachmentUtil.getFileExt(attachmentId) + ")"); } - if (jwtManager.jwtEnabled()) { - responseJson.put("token", jwtManager.createToken(responseJson)); - } + response.setContentType("text/html;charset=UTF-8"); + PrintWriter writer = response.getWriter(); + writer.write(VelocityUtils.getRenderedTemplate("templates/editor.vm", context)); - // AsHtml at the end disables automatic html encoding - config.put("jsonAsHtml", responseJson.toString()); - config.put("pageId", pageId.toString()); - config.put("pageTitle", attachmentUtil.getAttachmentPageTitle(attachmentId)); - config.put("spaceKey", attachmentUtil.getAttachmentSpaceKey(attachmentId)); - config.put("spaceName", attachmentUtil.getAttachmentSpaceName(attachmentId)); - config.put("isBlogPost", String.valueOf(attachmentUtil.getContainer(pageId) instanceof BlogPost)); - config.put("historyInfoUriAsHtml", urlManager.getHistoryInfoUri(attachmentId)); - config.put("historyDataUriAsHtml", urlManager.getHistoryDataUri(attachmentId)); - config.put("attachmentDataAsHtml", urlManager.getAttachmentDataUri()); - config.put("saveAsUriAsHtml", urlManager.getSaveAsUri()); - config.put("insertImageTypesAsHtml", new JSONArray(documentManager.getInsertImageTypes()).toString()); - config.put("compareFileTypesAsHtml", new JSONArray(documentManager.getCompareFileTypes()).toString()); - config.put("mailMergeTypesAsHtml", new JSONArray(documentManager.getMailMergeTypes()).toString()); - } catch (Exception ex) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - ex.printStackTrace(pw); - String error = ex.toString() + "\n" + sw.toString(); - log.error(error); + } catch (Exception e) { + throw new ServletException(e.getMessage(), e); } - - defaults.putAll(config); - defaults.put("demo", configurationManager.demoActive()); - return VelocityUtils.getRenderedTemplate("templates/editor.vm", defaults); } } diff --git a/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java b/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java index 37644c51..27c0f825 100644 --- a/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeFileProviderServlet.java @@ -18,13 +18,14 @@ package onlyoffice; -import onlyoffice.managers.document.DocumentManager; +import com.atlassian.confluence.user.ConfluenceUser; +import com.atlassian.confluence.user.UserAccessor; +import com.atlassian.sal.api.user.UserKey; +import com.atlassian.spring.container.ContainerManager; import onlyoffice.managers.jwt.JwtManager; import onlyoffice.utils.attachment.AttachmentUtil; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; +import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -35,19 +36,14 @@ public class OnlyOfficeFileProviderServlet extends HttpServlet { private static final long serialVersionUID = 1L; - private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeFileProviderServlet"); private static final int BUFFER_SIZE = 10240; private final AttachmentUtil attachmentUtil; private final JwtManager jwtManager; - private final DocumentManager documentManager; - @Inject - public OnlyOfficeFileProviderServlet(final AttachmentUtil attachmentUtil, final JwtManager jwtManager, - final DocumentManager documentManager) { + public OnlyOfficeFileProviderServlet(final AttachmentUtil attachmentUtil, final JwtManager jwtManager) { this.attachmentUtil = attachmentUtil; this.jwtManager = jwtManager; - this.documentManager = documentManager; } @Override @@ -64,17 +60,46 @@ public void doGet(final HttpServletRequest request, final HttpServletResponse re throw new SecurityException("Expected JWT"); } - if (!jwtManager.verify(token)) { - throw new SecurityException("JWT verification failed"); + try { + String payload = jwtManager.verify(token); + } catch (Exception e) { + throw new SecurityException("JWT verification failed!"); } } - String vkey = request.getParameter("vkey"); - log.info("vkey = " + vkey); - String attachmentIdString = documentManager.readHash(vkey); + String token = request.getParameter("token"); + String payload; + JSONObject bodyFromToken; + try { + payload = jwtManager.verifyInternalToken(token); + bodyFromToken = new JSONObject(payload); + + if (!bodyFromToken.getString("action").equals("download")) { + throw new SecurityException(); + } + } catch (Exception e) { + throw new SecurityException("Invalid link token!"); + } + + String userKeyString = bodyFromToken.getString("userKey"); + String attachmentIdString = bodyFromToken.getString("attachmentId"); + + UserAccessor userAccessor = (UserAccessor) ContainerManager.getComponent("userAccessor"); + + UserKey userKey = new UserKey(userKeyString); + ConfluenceUser user = userAccessor.getUserByKey(userKey); Long attachmentId = Long.parseLong(attachmentIdString); - log.info("attachmentId " + attachmentId); + + if (attachmentUtil.getAttachment(attachmentId) == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } + + if (!attachmentUtil.checkAccess(attachmentId, user, false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } String contentType = attachmentUtil.getMediaType(attachmentId); response.setContentType(contentType); diff --git a/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java b/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java new file mode 100644 index 00000000..bce10e48 --- /dev/null +++ b/src/main/java/onlyoffice/OnlyOfficeFormatsServlet.java @@ -0,0 +1,62 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice; + +import com.google.gson.Gson; +import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.model.Format; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class OnlyOfficeFormatsServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeFormatsServlet"); + + private final ConfigurationManager configurationManager; + + public OnlyOfficeFormatsServlet(final ConfigurationManager configurationManager) { + this.configurationManager = configurationManager; + } + + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + List supportedFormats = configurationManager.getSupportedFormats(); + List result = new ArrayList<>(); + + for (Format format : supportedFormats) { + if (format.getActions().contains("view")) { + result.add(format.getName()); + } + } + + Gson gson = new Gson(); + + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(gson.toJson(result)); + } +} diff --git a/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java b/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java index 531fb2a5..286a7879 100644 --- a/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeHistoryServlet.java @@ -26,9 +26,9 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.user.ConfluenceUserPreferences; import com.atlassian.confluence.user.UserAccessor; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.spring.container.ContainerManager; import com.google.gson.Gson; +import onlyoffice.managers.auth.AuthContext; import onlyoffice.managers.document.DocumentManager; import onlyoffice.managers.jwt.JwtManager; import onlyoffice.managers.url.UrlManager; @@ -39,7 +39,6 @@ import org.json.JSONException; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -59,11 +58,8 @@ public class OnlyOfficeHistoryServlet extends HttpServlet { private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeHistoryServlet"); private static final int BUFFER_SIZE = 10240; - @ComponentImport private final LocaleManager localeManager; - @ComponentImport private final FormatSettingsManager formatSettingsManager; - private final AuthContext authContext; private final DocumentManager documentManager; private final AttachmentUtil attachmentUtil; @@ -71,7 +67,6 @@ public class OnlyOfficeHistoryServlet extends HttpServlet { private final JwtManager jwtManager; private final ParsingUtil parsingUtil; - @Inject public OnlyOfficeHistoryServlet(final LocaleManager localeManager, final FormatSettingsManager formatSettingsManager, final AuthContext authContext, final DocumentManager documentManager, @@ -151,7 +146,7 @@ private void getAttachmentDiff(final HttpServletRequest request, final HttpServl private void getAttachmentHistoryInfo(final HttpServletRequest request, final HttpServletResponse response) throws IOException { - if (!authContext.checkUserAuthorisation(request, response)) { + if (!authContext.checkUserAuthorization(request, response)) { return; } @@ -184,7 +179,7 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht for (Attachment attachment : attachments) { Version version = new Version(); version.setVersion(attachment.getVersion()); - version.setKey(documentManager.getKeyOfFile(attachment.getId())); + version.setKey(documentManager.getKeyOfFile(attachment.getId(), false)); version.setCreated(dateFormatter.formatDateTime(attachment.getCreationDate())); version.setUser(attachment.getCreator().getName(), attachment.getCreator().getFullName()); @@ -197,7 +192,9 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht try { changesJSON = new JSONObject(changesString); version.setServerVersion(changesJSON.getString("serverVersion")); - version.setChanges(gson.fromJson(changesJSON.getString("changes"), Object.class)); + version.setChanges( + gson.fromJson(changesJSON.getJSONArray("changes").toString(), Object.class) + ); } catch (JSONException e) { throw new IOException(e.getMessage()); } @@ -225,7 +222,7 @@ private void getAttachmentHistoryInfo(final HttpServletRequest request, final Ht private void getAttachmentHistoryData(final HttpServletRequest request, final HttpServletResponse response) throws IOException { - if (!authContext.checkUserAuthorisation(request, response)) { + if (!authContext.checkUserAuthorization(request, response)) { return; } @@ -259,7 +256,7 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht if (attachment.getVersion() == version) { versionData = new VersionData(); versionData.setVersion(attachment.getVersion()); - versionData.setKey(documentManager.getKeyOfFile(attachment.getId())); + versionData.setKey(documentManager.getKeyOfFile(attachment.getId(), false)); versionData.setUrl(urlManager.getFileUri(attachment.getId())); versionData.setFileType(attachment.getFileExtension()); @@ -268,7 +265,7 @@ private void getAttachmentHistoryData(final HttpServletRequest request, final Ht boolean adjacentVersions = (attachment.getVersion() - prevVersion.getVersion()) == 1; if (adjacentVersions) { versionData.setChangesUrl(urlManager.getAttachmentDiffUri(attachment.getId())); - versionData.setPrevious(documentManager.getKeyOfFile(prevVersion.getId()), + versionData.setPrevious(documentManager.getKeyOfFile(prevVersion.getId(), false), urlManager.getFileUri(prevVersion.getId()), prevVersion.getFileExtension()); } } diff --git a/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java b/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java index ddcc34c2..5e102fa2 100644 --- a/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java +++ b/src/main/java/onlyoffice/OnlyOfficeSaveFileServlet.java @@ -20,10 +20,10 @@ import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.user.UserAccessor; +import com.atlassian.sal.api.user.UserKey; import com.atlassian.spring.container.ContainerManager; import onlyoffice.managers.configuration.ConfigurationManager; import onlyoffice.managers.convert.ConvertManager; -import onlyoffice.managers.document.DocumentManager; import onlyoffice.managers.jwt.JwtManager; import onlyoffice.managers.url.UrlManager; import onlyoffice.utils.attachment.AttachmentUtil; @@ -38,10 +38,8 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -52,7 +50,6 @@ import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Base64; public class OnlyOfficeSaveFileServlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -66,21 +63,17 @@ public class OnlyOfficeSaveFileServlet extends HttpServlet { private static final int STATUS_CORRUPTED_FORCE_SAVE = 7; private final JwtManager jwtManager; - private final DocumentManager documentManager; - private final AttachmentUtil attachmentUtil; private final ParsingUtil parsingUtil; private final UrlManager urlManager; private final ConfigurationManager configurationManager; private final ConvertManager convertManager; - @Inject - public OnlyOfficeSaveFileServlet(final JwtManager jwtManager, final DocumentManager documentManager, - final AttachmentUtil attachmentUtil, final ParsingUtil parsingUtil, - final UrlManager urlManager, final ConfigurationManager configurationManager, + public OnlyOfficeSaveFileServlet(final JwtManager jwtManager, final AttachmentUtil attachmentUtil, + final ParsingUtil parsingUtil, final UrlManager urlManager, + final ConfigurationManager configurationManager, final ConvertManager convertManager) { this.jwtManager = jwtManager; - this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; this.parsingUtil = parsingUtil; this.urlManager = urlManager; @@ -93,13 +86,38 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r throws ServletException, IOException { response.setContentType("text/plain; charset=utf-8"); - String vkey = request.getParameter("vkey"); - log.info("vkey = " + vkey); - String attachmentIdString = documentManager.readHash(vkey); + String token = request.getParameter("token"); + String payload; + JSONObject bodyFromToken; + + try { + payload = jwtManager.verifyInternalToken(token); + bodyFromToken = new JSONObject(payload); + + if (!bodyFromToken.getString("action").equals("callback")) { + throw new SecurityException(); + } + } catch (Exception e) { + throw new SecurityException("Invalid link token!"); + } + + String userKeyString = bodyFromToken.getString("userKey"); + String attachmentIdString = bodyFromToken.getString("attachmentId"); + + UserAccessor userAccessor = (UserAccessor) ContainerManager.getComponent("userAccessor"); + + UserKey userKey = new UserKey(userKeyString); + ConfluenceUser user = userAccessor.getUserByKey(userKey); + Long attachmentId = Long.parseLong(attachmentIdString); + + if (attachmentUtil.getAttachment(attachmentId) == null) { + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } String error = ""; try { - processData(attachmentIdString, request); + processData(attachmentId, user, request); } catch (Exception e) { error = e.getMessage(); } @@ -115,16 +133,12 @@ public void doPost(final HttpServletRequest request, final HttpServletResponse r log.info("error = " + error); } - private void processData(final String attachmentIdString, final HttpServletRequest request) throws Exception { - log.info("attachmentId = " + attachmentIdString); + private void processData(final Long attachmentId, final ConfluenceUser user, final HttpServletRequest request) + throws Exception { + log.info("attachmentId = " + attachmentId.toString()); InputStream requestStream = request.getInputStream(); - if (attachmentIdString.isEmpty()) { - throw new IllegalArgumentException("attachmentId is empty"); - } try { - Long attachmentId = Long.parseLong(attachmentIdString); - String body = parsingUtil.getBody(requestStream); log.info("body = " + body); if (body.isEmpty()) { @@ -135,6 +149,7 @@ private void processData(final String attachmentIdString, final HttpServletReque if (jwtManager.jwtEnabled()) { String token = jsonObj.optString("token"); + String payload = null; Boolean inBody = true; if (token == null || token == "") { @@ -150,12 +165,13 @@ private void processData(final String attachmentIdString, final HttpServletReque throw new SecurityException("Try save without JWT"); } - if (!jwtManager.verify(token)) { + try { + payload = jwtManager.verify(token); + } catch (Exception e) { throw new SecurityException("Try save with wrong JWT"); } - JSONObject bodyFromToken = new JSONObject( - new String(Base64.getUrlDecoder().decode(token.split("\\.")[1]), "UTF-8")); + JSONObject bodyFromToken = new JSONObject(payload); if (inBody) { jsonObj = bodyFromToken; @@ -166,8 +182,6 @@ private void processData(final String attachmentIdString, final HttpServletReque long status = jsonObj.getLong("status"); log.info("status = " + status); - - ConfluenceUser user = getConfluenceUserFromJSON(jsonObj); log.info("user = " + user); if (status == STATUS_EDITING) { @@ -192,12 +206,15 @@ private void processData(final String attachmentIdString, final HttpServletReque if (status == STATUS_MUST_SAVE || status == STATUS_CORRUPTED) { if (user != null && attachmentUtil.checkAccess(attachmentId, user, true)) { + String fileType = jsonObj.getString("filetype"); String downloadUrl = jsonObj.getString("url"); downloadUrl = urlManager.replaceDocEditorURLToInternal(downloadUrl); log.info("downloadUri = " + downloadUrl); - String history = jsonObj.getString("history"); - String changesUrl = urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")); + JSONObject history = jsonObj.getJSONObject("history"); + String changesUrl = !jsonObj.isNull("changesurl") + ? urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")) + : null; log.info("changesUri = " + changesUrl); Boolean forceSaveVersion = @@ -206,7 +223,7 @@ private void processData(final String attachmentIdString, final HttpServletReque attachmentUtil.setCollaborativeEditingKey(attachmentId, null); if (forceSaveVersion) { - saveAttachmentFromUrl(attachmentId, downloadUrl, user, false); + saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, false); attachmentUtil.removeProperty(attachmentId, "onlyoffice-force-save"); attachmentUtil.removeAttachmentChanges(attachmentId); @@ -215,10 +232,10 @@ private void processData(final String attachmentIdString, final HttpServletReque convertedFile.delete(); } } else { - saveAttachmentFromUrl(attachmentId, downloadUrl, user, true); + saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, true); } - attachmentUtil.saveAttachmentChanges(attachmentId, history, changesUrl); + attachmentUtil.saveAttachmentChanges(attachmentId, history.toString(), changesUrl); } else { throw new SecurityException("Try save without access: " + user); } @@ -231,30 +248,33 @@ private void processData(final String attachmentIdString, final HttpServletReque if (status == STATUS_FORCE_SAVE || status == STATUS_CORRUPTED_FORCE_SAVE) { if (user != null && attachmentUtil.checkAccess(attachmentId, user, true)) { if (configurationManager.forceSaveEnabled()) { + String fileType = jsonObj.getString("filetype"); String downloadUrl = jsonObj.getString("url"); downloadUrl = urlManager.replaceDocEditorURLToInternal(downloadUrl); log.info("downloadUri = " + downloadUrl); - String history = jsonObj.getString("history"); - String changesUrl = urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")); + JSONObject history = jsonObj.getJSONObject("history"); + String changesUrl = !jsonObj.isNull("changesurl") + ? urlManager.replaceDocEditorURLToInternal(jsonObj.getString("changesurl")) + : null; log.info("changesUri = " + downloadUrl); Boolean forceSaveVersion = attachmentUtil.getPropertyAsBoolean(attachmentId, "onlyoffice-force-save"); if (forceSaveVersion) { - saveAttachmentFromUrl(attachmentId, downloadUrl, user, false); + saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, false); attachmentUtil.removeAttachmentChanges(attachmentId); } else { String key = attachmentUtil.getCollaborativeEditingKey(attachmentId); attachmentUtil.setCollaborativeEditingKey(attachmentId, null); - saveAttachmentFromUrl(attachmentId, downloadUrl, user, true); + saveAttachmentFromUrl(attachmentId, downloadUrl, fileType, user, true); attachmentUtil.setCollaborativeEditingKey(attachmentId, key); attachmentUtil.setProperty(attachmentId, "onlyoffice-force-save", "true"); } - attachmentUtil.saveAttachmentChanges(attachmentId, history, changesUrl); + attachmentUtil.saveAttachmentChanges(attachmentId, history.toString(), changesUrl); File convertedFile = attachmentUtil.getConvertedFile(attachmentId); if (convertedFile.exists()) { @@ -278,15 +298,14 @@ private void processData(final String attachmentIdString, final HttpServletReque } } - private void saveAttachmentFromUrl(final Long attachmentId, final String downloadUrl, final ConfluenceUser user, - final boolean newVersion) throws Exception { + private void saveAttachmentFromUrl(final Long attachmentId, final String downloadUrl, final String fileType, + final ConfluenceUser user, final boolean newVersion) throws Exception { String attachmentExt = attachmentUtil.getFileExt(attachmentId); - String extDownloadUrl = downloadUrl.substring(downloadUrl.lastIndexOf(".") + 1); String url = downloadUrl; - if (!attachmentExt.equals(extDownloadUrl)) { + if (!attachmentExt.equals(fileType)) { JSONObject response = - convertManager.convert(attachmentId, extDownloadUrl, attachmentExt, downloadUrl, null, false); + convertManager.convert(attachmentId, fileType, attachmentExt, downloadUrl, null, false, null); url = response.getString("fileUrl"); } @@ -312,17 +331,4 @@ private void saveAttachmentFromUrl(final Long attachmentId, final String downloa } } } - - private ConfluenceUser getConfluenceUserFromJSON(final JSONObject jsonObj) throws JSONException { - ConfluenceUser confluenceUser = null; - if (jsonObj.has("users")) { - JSONArray users = jsonObj.getJSONArray("users"); - if (users.length() > 0) { - String userName = users.getString(0); - UserAccessor userAccessor = (UserAccessor) ContainerManager.getComponent("userAccessor"); - confluenceUser = userAccessor.getUserByName(userName); - } - } - return confluenceUser; - } } diff --git a/src/main/java/onlyoffice/action/DownloadAsAction.java b/src/main/java/onlyoffice/action/DownloadAsAction.java new file mode 100644 index 00000000..922f4d86 --- /dev/null +++ b/src/main/java/onlyoffice/action/DownloadAsAction.java @@ -0,0 +1,155 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.action; + +import com.atlassian.confluence.core.ConfluenceActionSupport; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.core.filters.ServletContextThreadLocal; +import com.atlassian.xwork.HttpMethod; +import com.atlassian.xwork.PermittedMethods; +import onlyoffice.managers.convert.ConvertManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import com.atlassian.confluence.user.ConfluenceUser; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; + +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.util.List; + +public class DownloadAsAction extends ConfluenceActionSupport { + + private AttachmentUtil attachmentUtil; + private ConvertManager convertManager; + + private String attachmentId; + private String fileName; + private String targetFileType; + private static final char[] INVALID_CHARS; + + public DownloadAsAction(final AttachmentUtil attachmentUtil, final ConvertManager convertManager) { + this.attachmentUtil = attachmentUtil; + this.convertManager = convertManager; + } + + @PermittedMethods({ HttpMethod.GET }) + public String doDefault() { + return ConfluenceActionSupport.INPUT; + } + + @Override + public void validate() { + super.validate(); + + Long attachmentId = Long.parseLong(this.attachmentId); + String ext = attachmentUtil.getFileExt(attachmentId); + + if (!attachmentUtil.checkAccess(attachmentId, getAuthenticatedUser(), false)) { + addActionError(getText("onlyoffice.connector.dialog.conversion.message.error.permission")); + ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + + if (fileName == null || fileName.isEmpty()) { + addActionError(getText("onlyoffice.connector.error.Unknown")); + ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + + if (StringUtils.containsAny((CharSequence) this.fileName, DownloadAsAction.INVALID_CHARS)) { + addActionError(getText("filename.contain.invalid.character")); + ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + + if (targetFileType == null || targetFileType.isEmpty()) { + addActionError(getText("onlyoffice.connector.error.Unknown")); + ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + + if (convertManager.getTargetExtList(ext) == null + || convertManager.getTargetExtList(ext).isEmpty() + || !convertManager.getTargetExtList(ext).contains(targetFileType) + ) { + addActionError(getText("onlyoffice.connector.error.Unknown")); + ServletContextThreadLocal.getResponse().setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); + } + } + + @PermittedMethods({ HttpMethod.POST }) + public String execute() throws Exception { + Long attachmentId = Long.parseLong(this.attachmentId); + String ext = attachmentUtil.getFileExt(attachmentId); + String targetExt = convertManager.getTargetExt(ext); + + if (!this.targetFileType.isEmpty()) { + targetExt = this.targetFileType; + } + + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + JSONObject convertResult = + convertManager.convert(attachmentId, ext, targetExt, user, this.fileName + "." + targetExt); + HttpServletResponse response = ServletContextThreadLocal.getResponse(); + response.setContentType("application/json"); + PrintWriter writer = response.getWriter(); + writer.write(convertResult.toString()); + response.setStatus(HttpServletResponse.SC_OK); + return "none"; + } + + public void setAttachmentId(final String attachmentId) { + this.attachmentId = attachmentId; + } + + public void setFileName(final String fileName) { + this.fileName = fileName; + } + + public void setTargetFileType(final String targetFileType) { + this.targetFileType = targetFileType; + } + + public String getAttachmentId() { + return attachmentId; + } + + public String getFileName() { + Long attachmentId = Long.parseLong(this.attachmentId); + String fileName = attachmentUtil.getFileName(attachmentId); + + return fileName.substring(0, fileName.lastIndexOf(".")); + } + + public String getFileType() { + Long attachmentId = Long.parseLong(this.attachmentId); + return attachmentUtil.getFileExt(attachmentId); + } + + public String getTargetFileType() { + return convertManager.getTargetExt(getFileType()); + } + + public List getTargetFileTypeList() { + return convertManager.getTargetExtList(getFileType()); + } + + static { + INVALID_CHARS = new char[] {'\\', '/', '\"', ':', '?', '*', '<', '|', '>'}; + } +} diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java index d2dfbbe9..82b08188 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileAttachment.java @@ -26,7 +26,6 @@ import onlyoffice.managers.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; -import javax.inject.Inject; import java.util.Map; public class IsOfficeFileAttachment implements Condition { @@ -35,7 +34,6 @@ public class IsOfficeFileAttachment implements Condition { private DocumentManager documentManager; private AttachmentUtil attachmentUtil; - @Inject public IsOfficeFileAttachment(final DocumentManager documentManager, final AttachmentUtil attachmentUtil) { this.documentManager = documentManager; this.attachmentUtil = attachmentUtil; diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java index 3161b1bd..140bb73f 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileConvertAttachment.java @@ -27,7 +27,6 @@ import onlyoffice.managers.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; -import javax.inject.Inject; import java.util.Map; public class IsOfficeFileConvertAttachment implements Condition { @@ -38,7 +37,6 @@ public class IsOfficeFileConvertAttachment implements Condition { private final AttachmentUtil attachmentUtil; private final ConvertManager convertManager; - @Inject public IsOfficeFileConvertAttachment(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, final ConvertManager convertManager) { this.documentManager = documentManager; @@ -67,7 +65,7 @@ public boolean shouldDisplay(final Map context) { ConfluenceUser user = AuthenticatedUserThreadLocal.get(); boolean accessEdit = attachmentUtil.checkAccess(attachment, user, true); - if (!accessEdit || !convertManager.isConvertable(ext) || ext.equals("docx")) { + if (!accessEdit || convertManager.getTargetExt(ext) == null || ext.equals("docx")) { return false; } diff --git a/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java b/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java new file mode 100644 index 00000000..a4e867fb --- /dev/null +++ b/src/main/java/onlyoffice/conditions/IsOfficeFileDownloadAsAttachment.java @@ -0,0 +1,73 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.conditions; + +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; +import com.atlassian.plugin.PluginParseException; +import com.atlassian.plugin.web.Condition; +import onlyoffice.managers.convert.ConvertManager; +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import java.util.Map; + +public class IsOfficeFileDownloadAsAttachment implements Condition { + + private final DocumentManager documentManager; + private final AttachmentUtil attachmentUtil; + private final ConvertManager convertManager; + + public IsOfficeFileDownloadAsAttachment(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final ConvertManager convertManager) { + this.documentManager = documentManager; + this.attachmentUtil = attachmentUtil; + this.convertManager = convertManager; + } + private final Logger log = LogManager.getLogger("onlyoffice.OnlyOfficeSaveFileServlet"); + + @Override + public void init(final Map map) throws PluginParseException { + } + + @Override + public boolean shouldDisplay(final Map map) { + Attachment attachment = (Attachment) map.get("attachment"); + + if (attachment == null) { + return false; + } + + String ext = attachment.getFileExtension(); + + if (attachment.getFileSize() > documentManager.getConvertationFileSizeMax()) { + return false; + } + + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + boolean access = attachmentUtil.checkAccess(attachment, user, false); + + return access + && convertManager.getTargetExtList(ext) != null + && convertManager.getTargetExtList(ext).size() > 0; + } +} diff --git a/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java b/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java index 7bbfedc5..6e91f96a 100644 --- a/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java +++ b/src/main/java/onlyoffice/conditions/IsOfficePageAttachments.java @@ -25,7 +25,6 @@ import com.atlassian.plugin.web.Condition; import onlyoffice.utils.attachment.AttachmentUtil; -import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import java.util.Map; import java.util.regex.Matcher; @@ -33,10 +32,8 @@ public class IsOfficePageAttachments implements Condition { private String pageAttachments = "viewpageattachments.action"; - private final AttachmentUtil attachmentUtil; - @Inject public IsOfficePageAttachments(final AttachmentUtil attachmentUtil) { this.attachmentUtil = attachmentUtil; } diff --git a/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java b/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java index 0dd7929d..d733a350 100644 --- a/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java +++ b/src/main/java/onlyoffice/conditions/confluence/previews/plugin/OnlyofficeButton.java @@ -22,13 +22,11 @@ import com.atlassian.confluence.pages.AttachmentManager; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import onlyoffice.managers.document.DocumentManager; import onlyoffice.utils.attachment.AttachmentUtil; import onlyoffice.utils.parsing.ParsingUtil; import org.json.JSONObject; -import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -38,14 +36,11 @@ import java.io.PrintWriter; public class OnlyofficeButton extends HttpServlet { - @ComponentImport private AttachmentManager attachmentManager; - private final ParsingUtil parsingUtil; private final AttachmentUtil attachmentUtil; private final DocumentManager documentManager; - @Inject public OnlyofficeButton(final AttachmentManager attachmentManager, final ParsingUtil parsingUtil, final AttachmentUtil attachmentUtil, final DocumentManager documentManager) { this.attachmentManager = attachmentManager; diff --git a/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java b/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java new file mode 100644 index 00000000..640e8052 --- /dev/null +++ b/src/main/java/onlyoffice/macro/OnlyOfficePreviewMacro.java @@ -0,0 +1,194 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.macro; + +import com.atlassian.confluence.content.render.image.ImageDimensions; +import com.atlassian.confluence.content.render.xhtml.ConversionContext; +import com.atlassian.confluence.core.ContentEntityObject; + +import com.atlassian.confluence.macro.Macro; +import com.atlassian.confluence.macro.EditorImagePlaceholder; +import com.atlassian.confluence.macro.ResourceAware; +import com.atlassian.confluence.macro.MacroExecutionException; +import com.atlassian.confluence.macro.ImagePlaceholder; +import com.atlassian.confluence.macro.DefaultImagePlaceholder; +import com.atlassian.confluence.pages.Attachment; +import com.atlassian.confluence.pages.AttachmentManager; +import com.atlassian.confluence.plugin.services.VelocityHelperService; +import com.atlassian.confluence.util.HtmlUtil; +import onlyoffice.macro.components.ContentResolver; +import onlyoffice.managers.config.ConfigManager; +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.config.DocumentType; +import onlyoffice.model.config.Type; +import onlyoffice.model.config.editor.Mode; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +public class OnlyOfficePreviewMacro implements Macro, EditorImagePlaceholder, ResourceAware { + + private final Logger log = LogManager.getLogger("onlyoffice.macro.OnlyOfficePreviewMacro"); + + public static final int DOT_INDEX = 46; + public static final int DEFAULT_PLACEHOLDER_WIDTH = 380; + public static final int DEFAULT_PLACEHOLDER_HEIGHT = 300; + public static final String DEFAULT_WIDTH = "100%"; + public static final String DEFAULT_HEIGHT = "720"; + private String resourcePath; + + private final AttachmentManager attachmentManager; + private final VelocityHelperService velocityHelperService; + private final ContentResolver contentResolver; + private final ConfigManager configManager; + private final UrlManager urlManager; + private final DocumentManager documentManager; + + public OnlyOfficePreviewMacro(final AttachmentManager attachmentManager, + final VelocityHelperService velocityHelperService, + final ContentResolver contentResolver, + final ConfigManager configManager, final UrlManager urlManager, + final DocumentManager documentManager) { + this.attachmentManager = attachmentManager; + this.velocityHelperService = velocityHelperService; + this.contentResolver = contentResolver; + this.configManager = configManager; + this.urlManager = urlManager; + this.documentManager = documentManager; + } + + @Override + public String execute(final Map args, final String s, final ConversionContext conversionContext) + throws MacroExecutionException { + final String file = this.getFileName(args); + final String pageName = args.get("page"); + final String space = args.get("space"); + final String date = args.get("date"); + String width = args.get("width"); + String height = args.get("height"); + + final ContentEntityObject page = this.contentResolver.getContent(pageName, space, date, + conversionContext.getPageContext().getEntity()); + final Attachment attachment = this.attachmentManager.getAttachment(page, file); + + if (attachment == null) { + throw new MacroExecutionException("The viewfile macro is unable to locate the attachment \"" + + file + "\" on " + ((pageName == null) + ? "this page" : ("the page \"" + pageName + "\" in space \"" + space + "\""))); + } + + width = normalizeSize((width == null) ? DEFAULT_WIDTH : width); + height = normalizeSize((height == null) ? DEFAULT_HEIGHT : height); + + try { + String config = configManager.createConfig( + attachment.getId(), + Mode.VIEW, + Type.EMBEDDED, + null, + null, + width, + height + ); + + final Map context = this.velocityHelperService.createDefaultVelocityContext(); + context.put("id", documentManager.getKeyOfFile(attachment.getId(), true)); + context.put("docServiceApiUrl", urlManager.getDocServiceApiUrl()); + context.put("configAsHtml", config); + + return this.velocityHelperService.getRenderedTemplate("templates/preview.vm", context); + } catch (Exception e) { + throw new MacroExecutionException(e.getMessage(), e); + } + } + + @Override + public BodyType getBodyType() { + return BodyType.NONE; + } + + @Override + public OutputType getOutputType() { + return OutputType.BLOCK; + } + + @Override + public String getResourcePath() { + return this.resourcePath; + } + + @Override + public void setResourcePath(final String resourcePath) { + this.resourcePath = resourcePath; + } + + @Override + public ImagePlaceholder getImagePlaceholder(final Map args, + final ConversionContext conversionContext) { + String name = (String) args.get("name"); + if (name == null) { + name = (String) args.get("0"); + } + + String documentType = DocumentType.WORD.name().toLowerCase(); + + if (!StringUtils.isBlank(name)) { + int dotIdx = name.lastIndexOf(DOT_INDEX); + if (dotIdx != -1) { + String fileExt = name.substring(dotIdx + 1).toLowerCase(); + if (documentManager.getDocType(fileExt) != null) { + documentType = documentManager.getDocType(fileExt).name().toLowerCase(); + if (fileExt.equals("oform")) { + documentType = "form"; + } + } + } + } + + return new DefaultImagePlaceholder(this.resourcePath + "/images/preview-placeholder-" + + documentType + ".svg", + true, new ImageDimensions(DEFAULT_PLACEHOLDER_WIDTH, DEFAULT_PLACEHOLDER_HEIGHT)); + } + + private String getFileName(final Map args) throws MacroExecutionException { + String file = args.get("0"); + if (file == null) { + file = args.get("filename"); + if (file == null) { + file = args.get("name"); + if (file == null || file.trim().length() == 0) { + throw new MacroExecutionException("No attachment name specified"); + } + } + } + return file; + } + + private String normalizeSize(final String attr) { + String size = attr; + if (!attr.endsWith("px") && !attr.endsWith("%")) { + size += "px"; + } + + return HtmlUtil.htmlEncode(size); + } +} diff --git a/src/main/java/onlyoffice/macro/components/ContentResolver.java b/src/main/java/onlyoffice/macro/components/ContentResolver.java new file mode 100644 index 00000000..ae667aef --- /dev/null +++ b/src/main/java/onlyoffice/macro/components/ContentResolver.java @@ -0,0 +1,27 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.macro.components; + +import com.atlassian.confluence.core.ContentEntityObject; +import com.atlassian.confluence.macro.MacroExecutionException; + +public interface ContentResolver { + ContentEntityObject getContent(String page, String spaceKey, String date, + ContentEntityObject context) throws MacroExecutionException; +} diff --git a/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java b/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java new file mode 100644 index 00000000..1235a653 --- /dev/null +++ b/src/main/java/onlyoffice/macro/components/DefaultContentResolver.java @@ -0,0 +1,103 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.macro.components; + +import com.atlassian.confluence.core.ContentEntityObject; +import com.atlassian.confluence.core.SpaceContentEntityObject; +import com.atlassian.confluence.macro.MacroExecutionException; +import com.atlassian.confluence.pages.Comment; +import com.atlassian.confluence.pages.Draft; +import com.atlassian.confluence.pages.PageManager; +import org.apache.commons.lang3.StringUtils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +public class DefaultContentResolver implements ContentResolver { + private final PageManager pageManager; + + public DefaultContentResolver(final PageManager pageManager) { + this.pageManager = pageManager; + } + + @Override + public ContentEntityObject getContent(final String page, final String sk, final String date, + final ContentEntityObject context) throws MacroExecutionException { + ContentEntityObject content = null; + String spaceKey = sk; + + try { + if (StringUtils.isBlank((CharSequence) page)) { + return context; + } + if (StringUtils.isBlank((CharSequence) spaceKey)) { + spaceKey = this.getSpaceKey(context); + } + if (StringUtils.isBlank((CharSequence) spaceKey)) { + throw new IllegalArgumentException( + "No spaceKey parameter was supplied and it could not be deduced from the context parameter." + ); + } + + if (StringUtils.isNotBlank((CharSequence) date)) { + final DateFormat dateFormat = DateFormat.getDateInstance(3, Locale.US); + final Date parsedDate = dateFormat.parse(date); + final Calendar cal = Calendar.getInstance(); + cal.setTime(parsedDate); + content = (ContentEntityObject) this.pageManager.getBlogPost(spaceKey, page, cal); + } else { + content = (ContentEntityObject) this.pageManager.getPage(spaceKey, page); + } + } catch (ParseException ex) { + throw new MacroExecutionException("Unrecognized date string, please use mm/dd/yyyy"); + } catch (IllegalArgumentException ex2) { + throw new MacroExecutionException("The space key could not be found."); + } + + if (content == null) { + throw new MacroExecutionException("The viewfile macro is unable to locate the page \"" + + page + "\" in space \"" + spaceKey + "\""); + } + + return content; + } + + private String getSpaceKey(final ContentEntityObject contentObject) { + if (contentObject == null) { + return null; + } + + ContentEntityObject ceo = contentObject; + + String spaceKey = null; + if (ceo instanceof Comment) { + ceo = ((Comment) ceo).getContainer(); + } + + if (ceo instanceof SpaceContentEntityObject) { + spaceKey = ((SpaceContentEntityObject) ceo).getSpaceKey(); + } else if (ceo instanceof Draft) { + spaceKey = ((Draft) ceo).getDraftSpaceKey(); + } + return spaceKey; + } +} diff --git a/src/main/java/onlyoffice/managers/auth/AuthContext.java b/src/main/java/onlyoffice/managers/auth/AuthContext.java new file mode 100644 index 00000000..c596d50a --- /dev/null +++ b/src/main/java/onlyoffice/managers/auth/AuthContext.java @@ -0,0 +1,9 @@ +package onlyoffice.managers.auth; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public interface AuthContext { + boolean checkUserAuthorization(HttpServletRequest request, HttpServletResponse response) throws IOException; +} diff --git a/src/main/java/onlyoffice/AuthContext.java b/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java similarity index 91% rename from src/main/java/onlyoffice/AuthContext.java rename to src/main/java/onlyoffice/managers/auth/AuthContextImpl.java index 0e90fce2..1f045205 100644 --- a/src/main/java/onlyoffice/AuthContext.java +++ b/src/main/java/onlyoffice/managers/auth/AuthContextImpl.java @@ -16,23 +16,21 @@ * */ -package onlyoffice; +package onlyoffice.managers.auth; import com.atlassian.confluence.util.GeneralUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import javax.inject.Named; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.Principal; -@Named -public class AuthContext { - private final Logger log = LogManager.getLogger("onlyoffice.AuthContext"); +public class AuthContextImpl implements AuthContext { + private final Logger log = LogManager.getLogger("onlyoffice.managers.auth.AuthContext"); - public boolean checkUserAuthorisation(final HttpServletRequest request, final HttpServletResponse response) + public boolean checkUserAuthorization(final HttpServletRequest request, final HttpServletResponse response) throws IOException { Principal principal = request.getUserPrincipal(); if (principal == null) { diff --git a/src/main/java/onlyoffice/managers/config/ConfigManager.java b/src/main/java/onlyoffice/managers/config/ConfigManager.java new file mode 100644 index 00000000..ad40d420 --- /dev/null +++ b/src/main/java/onlyoffice/managers/config/ConfigManager.java @@ -0,0 +1,14 @@ +package onlyoffice.managers.config; + +import onlyoffice.model.config.Type; +import onlyoffice.model.config.editor.Mode; +import org.json.JSONObject; + +import java.io.Serializable; + +public interface ConfigManager extends Serializable { + String createConfig(Long attachmentId, Mode mode, Type type, JSONObject actionLink, String referer) + throws Exception; + String createConfig(Long attachmentId, Mode mode, Type type, JSONObject actionLink, String referer, + String width, String height) throws Exception; +} diff --git a/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java b/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java new file mode 100644 index 00000000..7a34b470 --- /dev/null +++ b/src/main/java/onlyoffice/managers/config/ConfigManagerImpl.java @@ -0,0 +1,100 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.managers.config; + +import com.atlassian.confluence.languages.LocaleManager; +import com.atlassian.confluence.status.service.SystemInformationService; +import com.google.gson.Gson; +import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.managers.jwt.JwtManager; +import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.config.Config; +import onlyoffice.model.config.Type; +import onlyoffice.model.config.editor.Mode; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.json.JSONObject; + +public class ConfigManagerImpl implements ConfigManager { + private final Logger log = LogManager.getLogger("onlyoffice.ConfigManagerImpl"); + + private final LocaleManager localeManager; + private final SystemInformationService sysInfoService; + + private final DocumentManager documentManager; + private final AttachmentUtil attachmentUtil; + private final UrlManager urlManager; + private final ConfigurationManager configurationManager; + private final JwtManager jwtManager; + + public ConfigManagerImpl(final LocaleManager localeManager, final SystemInformationService sysInfoService, + final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final UrlManager urlManager, final ConfigurationManager configurationManager, + final JwtManager jwtManager) { + this.localeManager = localeManager; + this.sysInfoService = sysInfoService; + this.documentManager = documentManager; + this.attachmentUtil = attachmentUtil; + this.urlManager = urlManager; + this.configurationManager = configurationManager; + this.jwtManager = jwtManager; + + } + + public String createConfig(final Long attachmentId, final Mode mode, final Type type, final JSONObject actionLink, + final String referer) + throws Exception { + return this.createConfig(attachmentId, mode, type, actionLink, referer, null, null); + } + + public String createConfig(final Long attachmentId, final Mode mode, final Type type, final JSONObject actionLink, + final String referer, final String width, final String height) throws Exception { + Gson gson = new Gson(); + + Config config = new Config( + localeManager, + documentManager, + attachmentUtil, + urlManager, + configurationManager, + attachmentId, + mode, + type, + actionLink, + referer, + sysInfoService.getConfluenceInfo().getBaseUrl() + ); + + if (width != null) { + config.setWidth(width); + } + + if (height != null) { + config.setHeight(height); + } + + if (jwtManager.jwtEnabled()) { + config.setToken(jwtManager.createToken(config)); + } + + return gson.toJson(config); + } +} diff --git a/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java b/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java index c40a3d35..4d18f508 100644 --- a/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java +++ b/src/main/java/onlyoffice/managers/configuration/ConfigurationManager.java @@ -1,5 +1,6 @@ package onlyoffice.managers.configuration; +import onlyoffice.model.Format; import org.apache.http.impl.client.CloseableHttpClient; import java.io.IOException; @@ -29,11 +30,9 @@ public interface ConfigurationManager extends Serializable { String getStringPluginSetting(String key, String defaultValue); - List getDefaultEditingTypes(); - - List getFillFormTypes(); - Map getCustomizableEditingTypes(); CloseableHttpClient getHttpClient() throws Exception; + + List getSupportedFormats(); } diff --git a/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java b/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java index a3fbc83e..acdd8cf4 100644 --- a/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java +++ b/src/main/java/onlyoffice/managers/configuration/ConfigurationManagerImpl.java @@ -20,6 +20,9 @@ import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import onlyoffice.model.Format; import org.apache.http.client.config.RequestConfig; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; @@ -30,9 +33,6 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; import java.io.IOException; @@ -44,7 +44,6 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -54,18 +53,18 @@ import java.util.Properties; import java.util.concurrent.TimeUnit; -@Named -@Default public class ConfigurationManagerImpl implements ConfigurationManager { private final Logger log = LogManager.getLogger("onlyoffice.managers.configuration.ConfigurationManager"); private final PluginSettings pluginSettings; private final String configurationPath = "onlyoffice-config.properties"; + private final String formatsPath = "app_data/document-formats/onlyoffice-docs-formats.json"; private final String pluginDemoName = "onlyoffice.demo"; private final String pluginDemoNameStart = "onlyoffice.demoStart"; + private Map demoData; + private List supportedFormats; - @Inject public ConfigurationManagerImpl(final PluginSettingsFactory pluginSettingsFactory) { pluginSettings = pluginSettingsFactory.createGlobalSettings(); @@ -74,6 +73,15 @@ public ConfigurationManagerImpl(final PluginSettingsFactory pluginSettingsFactor demoData.put("header", "AuthorizationJWT"); demoData.put("secret", "sn2puSUF7muF5Jas"); demoData.put("trial", "30"); + + InputStream inputStream = getClass().getClassLoader().getResourceAsStream(formatsPath); + + ObjectMapper objectMapper = new ObjectMapper(); + try { + supportedFormats = objectMapper.readValue(inputStream, new TypeReference>() { }); + } catch (IOException e) { + log.error(e.getMessage(), e); + } } public Properties getProperties() throws IOException { @@ -170,19 +178,9 @@ public String getStringPluginSetting(final String key, final String defaultValue return setting; } - public List getDefaultEditingTypes() { - String editableTypes = getProperty("docservice.type.edit"); - return new ArrayList<>(Arrays.asList(editableTypes.split("\\|"))); - } - - public List getFillFormTypes() { - String editableTypes = getProperty("docservice.type.fill-form"); - return new ArrayList<>(Arrays.asList(editableTypes.split("\\|"))); - } - public Map getCustomizableEditingTypes() { Map customizableEditingTypes = new HashMap<>(); - List editingTypes = null; + List editingTypes; String editingTypesString = (String) pluginSettings.get("onlyoffice.editingTypes"); @@ -193,10 +191,12 @@ public Map getCustomizableEditingTypes() { editingTypes = Arrays.asList("csv", "txt"); } - List availableTypes = Arrays.asList(getProperty("docservice.type.edit.customizable").split("\\|")); + List formats = this.getSupportedFormats(); - for (String type : availableTypes) { - customizableEditingTypes.put(type, editingTypes.contains(type)); + for (Format format : formats) { + if (format.getActions().contains("lossy-edit")) { + customizableEditingTypes.put(format.getName(), editingTypes.contains(format.getName())); + } } return customizableEditingTypes; @@ -236,5 +236,9 @@ public boolean verify(final String hostname, final SSLSession session) { return httpClient; } + + public List getSupportedFormats() { + return supportedFormats; + } } diff --git a/src/main/java/onlyoffice/managers/convert/ConvertManager.java b/src/main/java/onlyoffice/managers/convert/ConvertManager.java index 3f46c383..a466aeb2 100644 --- a/src/main/java/onlyoffice/managers/convert/ConvertManager.java +++ b/src/main/java/onlyoffice/managers/convert/ConvertManager.java @@ -2,16 +2,17 @@ import com.atlassian.confluence.user.ConfluenceUser; import org.json.JSONObject; - +import java.util.List; import java.io.Serializable; public interface ConvertManager extends Serializable { - boolean isConvertable(String ext); + JSONObject convert(Long attachmentId, String ext, String convertToExt, ConfluenceUser user, + String title) throws Exception; - String convertsTo(String ext); + JSONObject convert(Long attachmentId, String currentExt, String convertToExt, String url, String region, + boolean async, String title) throws Exception; - JSONObject convert(Long attachmentId, String ext, String convertToExt, ConfluenceUser user) throws Exception; + String getTargetExt(String ext); - JSONObject convert(Long attachmentId, String currentExt, String convertToExt, String url, String region, - boolean async) throws Exception; + List getTargetExtList(String ext); } diff --git a/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java b/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java index 7d729de8..75f552a6 100644 --- a/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java +++ b/src/main/java/onlyoffice/managers/convert/ConvertManagerImpl.java @@ -20,13 +20,12 @@ import com.atlassian.confluence.languages.LocaleManager; import com.atlassian.confluence.user.ConfluenceUser; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import onlyoffice.managers.configuration.ConfigurationManager; import onlyoffice.managers.document.DocumentManager; import onlyoffice.managers.jwt.JwtManager; import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.Format; import org.apache.commons.io.IOUtils; -import org.apache.http.HttpException; import org.apache.http.HttpStatus; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; @@ -37,28 +36,22 @@ import org.apache.log4j.Logger; import org.json.JSONObject; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; -@Named -@Default public class ConvertManagerImpl implements ConvertManager { private final Logger log = LogManager.getLogger("onlyoffice.managers.convert.ConvertManager"); - @ComponentImport - private final LocaleManager localeManager; + private static final int NOT_REACHED_STATUS = -10; + private final LocaleManager localeManager; private final UrlManager urlManager; private final JwtManager jwtManager; private final ConfigurationManager configurationManager; private final DocumentManager documentManager; - @Inject public ConvertManagerImpl(final UrlManager urlManager, final JwtManager jwtManager, final ConfigurationManager configurationManager, final DocumentManager documentManager, final LocaleManager localeManager) { @@ -69,60 +62,39 @@ public ConvertManagerImpl(final UrlManager urlManager, final JwtManager jwtManag this.localeManager = localeManager; } - public boolean isConvertable(final String ext) { - String convertableTypes = configurationManager.getProperty("docservice.type.convert"); - if (convertableTypes == null) { - return false; - } - List exts = Arrays.asList(convertableTypes.split("\\|")); - return exts.contains(ext); - } - - public String convertsTo(final String ext) { - String docType = documentManager.getDocType(ext); - if (docType != null) { - if (ext.equals("docx")) { - return "docxf"; - } - if (ext.equals("docxf")) { - return "oform"; - } - - if (docType.equals("word")) { - return "docx"; - } - if (docType.equals("cell")) { - return "xlsx"; - } - if (docType.equals("slide")) { - return "pptx"; - } - } - return null; - } - public JSONObject convert(final Long attachmentId, final String ext, final String convertToExt, - final ConfluenceUser user) throws Exception { + final ConfluenceUser user, final String title) throws Exception { String url = urlManager.getFileUri(attachmentId); String region = localeManager.getLocale(user).toLanguageTag(); - return convert(attachmentId, ext, convertToExt, url, region, true); + return convert(attachmentId, ext, convertToExt, url, region, true, title); } public JSONObject convert(final Long attachmentId, final String currentExt, final String convertToExt, - final String url, final String region, final boolean async) throws Exception { + final String url, final String region, final boolean async, + final String title) throws Exception { try (CloseableHttpClient httpClient = configurationManager.getHttpClient()) { JSONObject body = new JSONObject(); body.put("async", async); body.put("embeddedfonts", true); body.put("filetype", currentExt); body.put("outputtype", convertToExt); - body.put("key", documentManager.getKeyOfFile(attachmentId)); + body.put("key", documentManager.getKeyOfFile(attachmentId, false)); body.put("url", url); body.put("region", region); + body.put("title", title); + + if (Arrays.asList("bmp", "gif", "jpg", "png").contains(convertToExt)) { + JSONObject thumbnail = new JSONObject(); + thumbnail.put("first", false); + body.put("thumbnail", thumbnail); + } StringEntity requestEntity = new StringEntity(body.toString(), ContentType.APPLICATION_JSON); - HttpPost request = new HttpPost(urlManager.getInnerDocEditorUrl() - + configurationManager.getProperties().getProperty("files.docservice.url.convert")); + String conversionServiceUrl = urlManager.getInnerDocEditorUrl() + configurationManager + .getProperties() + .getProperty("files.docservice.url.convert"); + + HttpPost request = new HttpPost(conversionServiceUrl); request.setEntity(requestEntity); request.setHeader("Accept", "application/json"); @@ -137,31 +109,75 @@ public JSONObject convert(final Long attachmentId, final String currentExt, fina } log.debug("Sending POST to Docserver: " + body.toString()); + JSONObject callBackJson = new JSONObject(); try (CloseableHttpResponse response = httpClient.execute(request)) { int status = response.getStatusLine().getStatusCode(); if (status != HttpStatus.SC_OK) { - throw new HttpException("Docserver returned code " + status); + log.error("Conversion service returned code " + status + ". URL: " + conversionServiceUrl); + callBackJson.put("error", NOT_REACHED_STATUS); } else { InputStream is = response.getEntity().getContent(); String content = IOUtils.toString(is, StandardCharsets.UTF_8); log.debug("Docserver returned: " + content); - JSONObject callBackJson = null; + try { callBackJson = new JSONObject(content); } catch (Exception e) { throw new Exception("Couldn't convert JSON from docserver: " + e.getMessage()); } + } + + return callBackJson; + } + } + } - return callBackJson; + public String getTargetExt(final String ext) { + List supportedFormats = configurationManager.getSupportedFormats(); + + for (Format format : supportedFormats) { + if (format.getName().equals(ext)) { + switch (format.getType()) { + case WORD: + if (format.getName().equals("docxf") && format.getConvert().contains("oform")) { + return "oform"; + } + if (format.getConvert().contains("docx")) { + return "docx"; + } + break; + case CELL: + if (format.getConvert().contains("xlsx")) { + return "xlsx"; + } + break; + case SLIDE: + if (format.getConvert().contains("pptx")) { + return "pptx"; + } + break; + default: + break; } } } + + return null; } - private String trimDot(final String input) { - return input.startsWith(".") ? input.substring(1) : input; + public List getTargetExtList(final String ext) { + List supportedFormats = configurationManager.getSupportedFormats(); + + for (Format format : supportedFormats) { + if (format.getName().equals(ext)) { + return format.getConvert(); + } + } + + return null; } + } diff --git a/src/main/java/onlyoffice/managers/document/DocumentManager.java b/src/main/java/onlyoffice/managers/document/DocumentManager.java index a5920720..5e826f99 100644 --- a/src/main/java/onlyoffice/managers/document/DocumentManager.java +++ b/src/main/java/onlyoffice/managers/document/DocumentManager.java @@ -1,6 +1,8 @@ package onlyoffice.managers.document; import com.atlassian.confluence.user.ConfluenceUser; +import onlyoffice.model.config.DocumentType; +import onlyoffice.model.config.Type; import java.io.IOException; import java.io.Serializable; @@ -9,7 +11,9 @@ public interface DocumentManager extends Serializable { long getMaxFileSize(); - String getKeyOfFile(Long attachmentId); + long getConvertationFileSizeMax(); + + String getKeyOfFile(Long attachmentId, boolean embedded); String createHash(String str); @@ -19,9 +23,9 @@ public interface DocumentManager extends Serializable { Long createDemo(String fileName, String fileExt, Long pageID, ConfluenceUser user) throws IOException; - String getDocType(String ext); + DocumentType getDocType(String ext); - String getEditorType(String userAgent); + Type getEditorType(String userAgent); String getMimeType(String name); diff --git a/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java b/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java index d970b1a4..cd89cf26 100644 --- a/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java +++ b/src/main/java/onlyoffice/managers/document/DocumentManagerImpl.java @@ -26,32 +26,30 @@ import com.atlassian.confluence.pages.AttachmentManager; import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.plugin.PluginAccessor; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.message.I18nResolver; import com.atlassian.spring.container.ContainerManager; import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.model.Format; +import onlyoffice.model.config.DocumentType; +import onlyoffice.model.config.Type; import onlyoffice.utils.attachment.AttachmentUtil; import org.apache.commons.codec.binary.Hex; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; +import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.Map; import java.util.regex.Pattern; -@Named -@Default public class DocumentManagerImpl implements DocumentManager { private final Logger log = LogManager.getLogger("onlyoffice.managers.document.DocumentManager"); private static final String USER_AGENT_MOBILE = "android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec" @@ -61,15 +59,13 @@ public class DocumentManagerImpl implements DocumentManager { private static final int DEFAULT_MAX_FILE_SIZE = 5242880; private static final int MAX_KEY_LENGTH = 20; - @ComponentImport - private final I18nResolver i18n; + private final I18nResolver i18nResolver; private final ConfigurationManager configurationManager; private final AttachmentUtil attachmentUtil; - @Inject - public DocumentManagerImpl(final I18nResolver i18n, final ConfigurationManager configurationManager, + public DocumentManagerImpl(final I18nResolver i18nResolver, final ConfigurationManager configurationManager, final AttachmentUtil attachmentUtil) { - this.i18n = i18n; + this.i18nResolver = i18nResolver; this.configurationManager = configurationManager; this.attachmentUtil = attachmentUtil; } @@ -86,14 +82,26 @@ public long getMaxFileSize() { return size > 0 ? size : DEFAULT_MAX_FILE_SIZE; } - public String getKeyOfFile(final Long attachmentId) { + public String getKeyOfFile(final Long attachmentId, final boolean embedded) { String key = attachmentUtil.getCollaborativeEditingKey(attachmentId); if (key == null) { String hashCode = attachmentUtil.getHashCode(attachmentId); key = generateRevisionId(hashCode); } - return key; + return embedded ? key + "_embedded" : key; + } + + public long getConvertationFileSizeMax() { + long size; + try { + String filesizeMax = configurationManager.getProperty("convertation-filesize-max"); + size = Long.parseLong(filesizeMax); + } catch (Exception ex) { + size = 0; + } + + return size > 0 ? size : DEFAULT_MAX_FILE_SIZE; } private String generateRevisionId(final String expectedKey) { @@ -183,7 +191,10 @@ private InputStream getDemoFile(final ConfluenceUser user, final String fileExt) LocaleManager localeManager = (LocaleManager) ContainerManager.getComponent("localeManager"); PluginAccessor pluginAccessor = (PluginAccessor) ContainerManager.getComponent("pluginAccessor"); - String pathToDemoFile = "app_data/" + localeManager.getLocale(user).toString().replace("_", "-"); + String pathToDemoFile = "app_data/document-templates/" + localeManager + .getLocale(user) + .toString() + .replace("_", "-"); if (pluginAccessor.getDynamicResourceAsStream(pathToDemoFile) == null) { pathToDemoFile = "app_data/en-US"; @@ -199,7 +210,7 @@ public Long createDemo(final String fileName, final String fileExt, final Long p fileExt == null || !fileExt.equals("xlsx") && !fileExt.equals("pptx") && !fileExt.equals("docxf") ? "docx" : fileExt.trim(); String name = fileName == null || fileName.equals("") - ? i18n.getText("onlyoffice.editor.dialog.filecreate." + extension) : fileName; + ? i18nResolver.getText("onlyoffice.editor.dialog.filecreate." + extension) : fileName; InputStream demoFile = getDemoFile(user, extension); @@ -212,20 +223,14 @@ public Long createDemo(final String fileName, final String fileExt, final Long p return attachment.getContentId().asLong(); } - public String getDocType(final String ext) { - List wordFormats = Arrays.asList(configurationManager.getProperty("docservice.type.word").split("\\|")); - List cellFormats = Arrays.asList(configurationManager.getProperty("docservice.type.cell").split("\\|")); - List slideFormats = - Arrays.asList(configurationManager.getProperty("docservice.type.slide").split("\\|")); + public DocumentType getDocType(final String ext) { + List supportedFormats = configurationManager.getSupportedFormats(); - if (wordFormats.contains(ext)) { - return "word"; - } - if (cellFormats.contains(ext)) { - return "cell"; - } - if (slideFormats.contains(ext)) { - return "slide"; + for (Format format : supportedFormats) { + if (format.getName().equals(ext)) { + + return format.getType(); + } } return null; @@ -242,37 +247,57 @@ public String getMimeType(final String name) { return mimeType != null ? mimeType : "application/octet-stream"; } - public String getEditorType(final String userAgent) { + public Type getEditorType(final String userAgent) { Pattern pattern = Pattern.compile(USER_AGENT_MOBILE, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); if (userAgent != null && pattern.matcher(userAgent).find()) { - return "mobile"; + return Type.MOBILE; } else { - return "desktop"; + return Type.DESKTOP; } } - public boolean isEditable(final String fileExtension) { - List editingTypes = configurationManager.getDefaultEditingTypes(); + public boolean isEditable(final String ext) { + List supportedFormats = configurationManager.getSupportedFormats(); + + for (Format format : supportedFormats) { + if (format.getName().equals(ext) && format.getActions().contains("edit")) { + return true; + } + } Map customizableEditingTypes = configurationManager.getCustomizableEditingTypes(); for (Map.Entry customizableEditingType : customizableEditingTypes.entrySet()) { - if (customizableEditingType.getValue()) { - editingTypes.add(customizableEditingType.getKey()); + if (customizableEditingType.getKey().equals(ext) && customizableEditingType.getValue()) { + return true; } } - return editingTypes.contains(fileExtension); + return false; } - public boolean isFillForm(final String fileExtension) { - List fillFormTypes = configurationManager.getFillFormTypes(); - return configurationManager.getFillFormTypes().contains(fileExtension); + public boolean isFillForm(final String ext) { + List supportedFormats = configurationManager.getSupportedFormats(); + + for (Format format : supportedFormats) { + if (format.getName().equals(ext) && format.getActions().contains("fill")) { + return true; + } + } + + return false; } public boolean isViewable(final String fileExtension) { - String docType = getDocType(fileExtension); - return docType != null; + List supportedFormats = configurationManager.getSupportedFormats(); + + for (Format format : supportedFormats) { + if (format.getName().equals(fileExtension) && format.getActions().contains("view")) { + return true; + } + } + + return false; } public List getInsertImageTypes() { @@ -280,10 +305,28 @@ public List getInsertImageTypes() { } public List getCompareFileTypes() { - return Arrays.asList(configurationManager.getProperty("docservice.type.word").split("\\|")); + List supportedFormats = configurationManager.getSupportedFormats(); + List result = new ArrayList<>(); + + for (Format format : supportedFormats) { + if (format.getType().equals(DocumentType.WORD)) { + result.add(format.getName()); + } + } + + return result; } public List getMailMergeTypes() { - return Arrays.asList(configurationManager.getProperty("docservice.type.cell").split("\\|")); + List supportedFormats = configurationManager.getSupportedFormats(); + List result = new ArrayList<>(); + + for (Format format : supportedFormats) { + if (format.getType().equals(DocumentType.CELL)) { + result.add(format.getName()); + } + } + + return result; } } diff --git a/src/main/java/onlyoffice/managers/jwt/JwtManager.java b/src/main/java/onlyoffice/managers/jwt/JwtManager.java index a7ba7de7..fb87286d 100644 --- a/src/main/java/onlyoffice/managers/jwt/JwtManager.java +++ b/src/main/java/onlyoffice/managers/jwt/JwtManager.java @@ -3,13 +3,21 @@ import org.json.JSONObject; import java.io.Serializable; +import java.util.Map; public interface JwtManager extends Serializable { - Boolean jwtEnabled(); + + String createToken(Object payload) throws Exception; String createToken(JSONObject payload) throws Exception; - Boolean verify(String token); + String verify(String token); + + String createInternalToken(Map payloadMap); + + String verifyInternalToken(String token); + + Boolean jwtEnabled(); String getJwtHeader(); } diff --git a/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java b/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java index 5dcfe9a9..ae9c0f27 100644 --- a/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java +++ b/src/main/java/onlyoffice/managers/jwt/JwtManagerImpl.java @@ -19,86 +19,65 @@ package onlyoffice.managers.jwt; import com.atlassian.config.ApplicationConfiguration; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.fasterxml.jackson.databind.ObjectMapper; import onlyoffice.managers.configuration.ConfigurationManager; import org.json.JSONObject; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; import java.util.Base64; -import java.util.Base64.Encoder; +import java.util.Map; +import java.util.Random; -@Named -@Default public class JwtManagerImpl implements JwtManager { - private static final int NUMBER_PARTS_TOKEN = 3; + private static final long ACCEPT_LEEWAY = 3; + private static final int PLUGIN_SECRET_LENGTH = 32; - @ComponentImport - private final PluginSettingsFactory pluginSettingsFactory; - @ComponentImport private final ApplicationConfiguration applicationConfiguration; - private final ConfigurationManager configurationManager; private final PluginSettings settings; - @Inject public JwtManagerImpl(final PluginSettingsFactory pluginSettingsFactory, final ApplicationConfiguration applicationConfiguration, final ConfigurationManager configurationManager) { - this.pluginSettingsFactory = pluginSettingsFactory; settings = pluginSettingsFactory.createGlobalSettings(); this.applicationConfiguration = applicationConfiguration; this.configurationManager = configurationManager; } - public Boolean jwtEnabled() { - return configurationManager.demoActive() || settings.get("onlyoffice.jwtSecret") != null - && !((String) settings.get("onlyoffice.jwtSecret")).isEmpty(); + public String createToken(final Object payload) { + ObjectMapper objectMapper = new ObjectMapper(); + Map payloadMap = objectMapper.convertValue(payload, Map.class); + + return createToken(payloadMap, getJwtSecret()); } public String createToken(final JSONObject payload) throws Exception { - JSONObject header = new JSONObject(); - header.put("alg", "HS256"); - header.put("typ", "JWT"); - - Encoder enc = Base64.getUrlEncoder(); - - String encHeader = enc.encodeToString(header.toString().getBytes("UTF-8")) - .replace("=", ""); - String encPayload = enc.encodeToString(payload.toString().getBytes("UTF-8")) - .replace("=", ""); - - String hash = calculateHash(encHeader, encPayload); + ObjectMapper objectMapper = new ObjectMapper(); + Map payloadMap = objectMapper.readValue(payload.toString(), Map.class); - return encHeader + "." + encPayload + "." + hash; + return createToken(payloadMap, getJwtSecret()); } - public Boolean verify(final String token) { - if (!jwtEnabled()) { - return false; - } + public String verify(final String token) { + return verifyToken(token, getJwtSecret()); + } - String[] jwt = token.split("\\."); - if (jwt.length != NUMBER_PARTS_TOKEN) { - return false; - } + public String createInternalToken(final Map payloadMap) { + return createToken(payloadMap, getPluginSecret()); + } - try { - String hash = calculateHash(jwt[0], jwt[1]); - if (!hash.equals(jwt[2])) { - return false; - } - } catch (Exception ex) { - return false; - } + public String verifyInternalToken(final String token) { + return verifyToken(token, getPluginSecret()); + } - return true; + public Boolean jwtEnabled() { + return configurationManager.demoActive() || settings.get("onlyoffice.jwtSecret") != null + && !((String) settings.get("onlyoffice.jwtSecret")).isEmpty(); } public String getJwtHeader() { @@ -108,20 +87,50 @@ public String getJwtHeader() { return header == null || header.isEmpty() ? "Authorization" : header; } - private String calculateHash(final String header, final String payload) throws Exception { - Mac hasher = getHasher(); - return Base64.getUrlEncoder().encodeToString(hasher.doFinal((header + "." + payload).getBytes("UTF-8"))) - .replace("=", ""); + private String getJwtSecret() { + return configurationManager.demoActive() + ? configurationManager.getDemo("secret") : (String) settings.get("onlyoffice.jwtSecret"); } - private Mac getHasher() throws Exception { - String jwts = configurationManager.demoActive() - ? configurationManager.getDemo("secret") : (String) settings.get("onlyoffice.jwtSecret"); + private String createToken(final Map payloadMap, final String key) { + Algorithm algorithm = Algorithm.HMAC256(key); + + String token = JWT.create() + .withPayload(payloadMap) + .sign(algorithm); + + return token; + } + + private String verifyToken(final String token, final String key) { + Algorithm algorithm = Algorithm.HMAC256(key); + Base64.Decoder decoder = Base64.getUrlDecoder(); - Mac sha256 = Mac.getInstance("HmacSHA256"); - SecretKeySpec secretKey = new SecretKeySpec(jwts.getBytes("UTF-8"), "HmacSHA256"); - sha256.init(secretKey); + DecodedJWT jwt = JWT.require(algorithm) + .acceptLeeway(ACCEPT_LEEWAY) + .build() + .verify(token); - return sha256; + return new String(decoder.decode(jwt.getPayload())); + } + + private String getPluginSecret() { + if (settings.get("onlyoffice.plugin-secret") == null || settings.get("onlyoffice.plugin-secret").equals("")) { + Random random = new Random(); + char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + + char[] randBuffer = new char[PLUGIN_SECRET_LENGTH]; + for (int i = 0; i < randBuffer.length; i++) { + randBuffer[i] = numbersAndLetters[random.nextInt(numbersAndLetters.length)]; + } + + String secret = new String(randBuffer); + + settings.put("onlyoffice.plugin-secret", secret); + + return secret; + } else { + return (String) settings.get("onlyoffice.plugin-secret"); + } } } diff --git a/src/main/java/onlyoffice/managers/url/UrlManager.java b/src/main/java/onlyoffice/managers/url/UrlManager.java index cb9e68ab..de89e877 100644 --- a/src/main/java/onlyoffice/managers/url/UrlManager.java +++ b/src/main/java/onlyoffice/managers/url/UrlManager.java @@ -1,6 +1,7 @@ package onlyoffice.managers.url; -import javax.servlet.http.HttpServletRequest; +import onlyoffice.model.config.DocumentType; + import java.io.Serializable; public interface UrlManager extends Serializable { @@ -20,11 +21,17 @@ public interface UrlManager extends Serializable { String getSaveAsUri(); + String getReferenceDataUri(Long pageId); + String getCallbackUrl(Long attachmentId); - String getGobackUrl(Long attachmentId, HttpServletRequest request); + String getGobackUrl(Long attachmentId, String referer); String getCreateUri(Long pageId, String ext); String replaceDocEditorURLToInternal(String url); + + String getDocServiceApiUrl(); + + String getFaviconUrl(DocumentType documentType); } diff --git a/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java b/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java index 5fbbc94f..45907c07 100644 --- a/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java +++ b/src/main/java/onlyoffice/managers/url/UrlManagerImpl.java @@ -20,24 +20,25 @@ import com.atlassian.confluence.pages.Attachment; import com.atlassian.confluence.pages.AttachmentManager; +import com.atlassian.plugin.webresource.UrlMode; +import com.atlassian.plugin.webresource.WebResourceUrlProvider; import com.atlassian.confluence.setup.settings.SettingsManager; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; import com.atlassian.confluence.util.GeneralUtil; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.atlassian.spring.container.ContainerManager; import onlyoffice.managers.configuration.ConfigurationManager; import onlyoffice.managers.document.DocumentManager; +import onlyoffice.model.config.DocumentType; +import onlyoffice.managers.jwt.JwtManager; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; -import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; -@Named -@Default public class UrlManagerImpl implements UrlManager { private final Logger log = LogManager.getLogger("onlyoffice.managers.url.UrlManager"); private final String docEditorServlet = "plugins/servlet/onlyoffice/doceditor"; @@ -46,22 +47,21 @@ public class UrlManagerImpl implements UrlManager { private final String fileProviderServlet = "plugins/servlet/onlyoffice/file-provider"; private final String apiServlet = "plugins/servlet/onlyoffice/api"; - @ComponentImport - private final PluginSettingsFactory pluginSettingsFactory; - @ComponentImport + private final WebResourceUrlProvider webResourceUrlProvider; private final SettingsManager settingsManager; - private final PluginSettings pluginSettings; private final ConfigurationManager configurationManager; private final DocumentManager documentManager; + private final JwtManager jwtManager; - @Inject - public UrlManagerImpl(final PluginSettingsFactory pluginSettingsFactory, final SettingsManager settingsManager, - final ConfigurationManager configurationManager, final DocumentManager documentManager) { - this.pluginSettingsFactory = pluginSettingsFactory; - this.settingsManager = settingsManager; + public UrlManagerImpl(final WebResourceUrlProvider webResourceUrlProvider, + final PluginSettingsFactory pluginSettingsFactory, final SettingsManager settingsManager, + final ConfigurationManager configurationManager, final DocumentManager documentManager, + final JwtManager jwtManager) { + this.webResourceUrlProvider = webResourceUrlProvider; this.settingsManager = settingsManager; this.configurationManager = configurationManager; this.documentManager = documentManager; + this.jwtManager = jwtManager; pluginSettings = pluginSettingsFactory.createGlobalSettings(); } @@ -86,10 +86,15 @@ public String getInnerDocEditorUrl() { } public String getFileUri(final Long attachmentId) { - String hash = documentManager.createHash(Long.toString(attachmentId)); + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); - String fileUri = getConfluenceBaseUrl() + fileProviderServlet + "?vkey=" + GeneralUtil.urlEncode(hash); - log.info("fileUrl " + fileUri); + Map params = new HashMap<>(); + params.put("userKey", user.getKey().getStringValue()); + params.put("attachmentId", attachmentId.toString()); + params.put("action", "download"); + + String fileUri = + getConfluenceBaseUrl() + fileProviderServlet + "?token=" + jwtManager.createInternalToken(params); return fileUri; } @@ -130,18 +135,29 @@ public String getSaveAsUri() { return saveAsUri; } + public String getReferenceDataUri(final Long pageId) { + String referenceDataUri = getConfluenceBaseUrl() + apiServlet + "?type=reference-data&pageId=" + pageId; + + return referenceDataUri; + } + public String getCallbackUrl(final Long attachmentId) { - String hash = documentManager.createHash(Long.toString(attachmentId)); + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + + Map params = new HashMap<>(); + params.put("userKey", user.getKey().getStringValue()); + params.put("attachmentId", attachmentId.toString()); + params.put("action", "callback"); - String callbackUrl = getConfluenceBaseUrl() + callbackServlet + "?vkey=" + GeneralUtil.urlEncode(hash); + String callbackUrl = + getConfluenceBaseUrl() + callbackServlet + "?token=" + jwtManager.createInternalToken(params); log.info("callbackUrl " + callbackUrl); return callbackUrl; } - public String getGobackUrl(final Long attachmentId, final HttpServletRequest request) { + public String getGobackUrl(final Long attachmentId, final String referer) { String gobackUrl = ""; - String referer = request.getHeader("referer"); if (referer != null && referer.contains("/display/")) { gobackUrl = referer; @@ -164,13 +180,13 @@ public String getCreateUri(final Long pageId, final String ext) { String targetExt = "docx"; switch (documentManager.getDocType(ext)) { - case "word": + case WORD: targetExt = ext.equals("docxf") ? "docxf" : "docx"; break; - case "cell": + case CELL: targetExt = "xlsx"; break; - case "slide": + case SLIDE: targetExt = "pptx"; break; default: @@ -198,4 +214,22 @@ public String replaceDocEditorURLToInternal(final String url) { } return result; } + + public String getDocServiceApiUrl() { + return getPublicDocEditorUrl() + configurationManager.getProperty("files.docservice.url.api"); + } + + public String getFaviconUrl(final DocumentType documentType) { + String nameIcon = "word"; + + if (documentType != null) { + nameIcon = documentType.name().toLowerCase(); + } + + return webResourceUrlProvider.getStaticPluginResourceUrl( + "onlyoffice.onlyoffice-confluence-plugin:onlyoffice-confluence-plugin-resources-editor", + nameIcon + ".ico", + UrlMode.ABSOLUTE + ); + } } diff --git a/src/main/java/onlyoffice/model/Format.java b/src/main/java/onlyoffice/model/Format.java new file mode 100644 index 00000000..d99b824c --- /dev/null +++ b/src/main/java/onlyoffice/model/Format.java @@ -0,0 +1,72 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model; + +import onlyoffice.model.config.DocumentType; + +import java.util.List; + +public class Format { + private String name; + private DocumentType type; + private List actions; + private List convert; + private List mime; + + public String getName() { + return name; + } + + public DocumentType getType() { + return type; + } + + public List getActions() { + return actions; + } + + public List getConvert() { + return convert; + } + + public List getMime() { + return mime; + } + + public void setName(final String name) { + this.name = name; + } + + public void setType(final DocumentType type) { + this.type = type; + } + + public void setAction(final List actions) { + this.actions = actions; + } + + public void setConvert(final List convert) { + this.convert = convert; + } + + public void setMime(final List mime) { + this.mime = mime; + } + +} diff --git a/src/main/java/onlyoffice/model/config/Config.java b/src/main/java/onlyoffice/model/config/Config.java new file mode 100644 index 00000000..f5f69bdf --- /dev/null +++ b/src/main/java/onlyoffice/model/config/Config.java @@ -0,0 +1,114 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config; + +import com.atlassian.confluence.languages.LocaleManager; +import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.config.document.Document; +import onlyoffice.model.config.editor.EditorConfig; +import onlyoffice.model.config.editor.Mode; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.json.JSONObject; + +public class Config { + private Type type; + private DocumentType documentType; + private EditorConfig editorConfig; + private Document document; + private String token; + private String height = "100%"; + private String width = "100%"; + + public Config(final LocaleManager localeManager, final DocumentManager documentManager, + final AttachmentUtil attachmentUtil, final UrlManager urlManager, + final ConfigurationManager configurationManager, final Long attachmentId, final Mode mode, + final Type type, final JSONObject actionLink, final String referer, final String instanceId) { + this.type = type; + this.documentType = documentManager.getDocType(attachmentUtil.getFileExt(attachmentId)); + this.document = new Document(documentManager, attachmentUtil, urlManager, attachmentId, type, instanceId); + this.editorConfig = new EditorConfig( + localeManager, + attachmentUtil, + urlManager, + configurationManager, + attachmentId, + mode, + actionLink, + referer + ); + } + + public String getToken() { + return token; + } + + public void setToken(final String token) { + this.token = token; + } + + public String getHeight() { + return height; + } + + public void setHeight(final String height) { + this.height = height; + } + + public String getWidth() { + return width; + } + + public void setWidth(final String width) { + this.width = width; + } + + public Type getType() { + return type; + } + + public void setType(final Type type) { + this.type = type; + } + + public DocumentType getDocumentType() { + return documentType; + } + + public void setDocumentType(final DocumentType documentType) { + this.documentType = documentType; + } + + public EditorConfig getEditorConfig() { + return editorConfig; + } + + public void setEditorConfig(final EditorConfig editorConfig) { + this.editorConfig = editorConfig; + } + + public Document getDocument() { + return document; + } + + public void setDocument(final Document document) { + this.document = document; + } +} diff --git a/src/main/java/onlyoffice/model/config/DocumentType.java b/src/main/java/onlyoffice/model/config/DocumentType.java new file mode 100644 index 00000000..ebb0a343 --- /dev/null +++ b/src/main/java/onlyoffice/model/config/DocumentType.java @@ -0,0 +1,34 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; + +public enum DocumentType { + @JsonProperty("word") + @SerializedName("word") + WORD, + @JsonProperty("cell") + @SerializedName("cell") + CELL, + @JsonProperty("slide") + @SerializedName("slide") + SLIDE +} diff --git a/src/main/java/onlyoffice/model/config/Type.java b/src/main/java/onlyoffice/model/config/Type.java new file mode 100644 index 00000000..33c31c8a --- /dev/null +++ b/src/main/java/onlyoffice/model/config/Type.java @@ -0,0 +1,30 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config; + +import com.google.gson.annotations.SerializedName; + +public enum Type { + @SerializedName("desktop") + DESKTOP, + @SerializedName("mobile") + MOBILE, + @SerializedName("embedded") + EMBEDDED +} diff --git a/src/main/java/onlyoffice/model/config/document/Document.java b/src/main/java/onlyoffice/model/config/document/Document.java new file mode 100644 index 00000000..cfb4cf2a --- /dev/null +++ b/src/main/java/onlyoffice/model/config/document/Document.java @@ -0,0 +1,83 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.document; + +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.managers.url.UrlManager; +import onlyoffice.model.config.Type; +import onlyoffice.utils.attachment.AttachmentUtil; + +public class Document { + private String key; + private String title; + private String url; + private String fileType; + private Permissions permissions; + private ReferenceData referenceData; + + public Document(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final UrlManager urlManager, final Long attachmentId, final Type type, final String instanceId) { + key = documentManager.getKeyOfFile(attachmentId, type.equals(Type.EMBEDDED)); + title = attachmentUtil.getFileName(attachmentId); + fileType = attachmentUtil.getFileExt(attachmentId); + url = urlManager.getFileUri(attachmentId); + permissions = new Permissions(documentManager, attachmentUtil, attachmentId); + referenceData = new ReferenceData(attachmentId, instanceId); + } + + public String getKey() { + return key; + } + + public void setKey(final String key) { + this.key = key; + } + + public String getTitle() { + return title; + } + + public void setTitle(final String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + + public String getFileType() { + return fileType; + } + + public void setFileType(final String fileType) { + this.fileType = fileType; + } + + public Permissions getPermissions() { + return permissions; + } + + public void setPermissions(final Permissions permissions) { + this.permissions = permissions; + } +} diff --git a/src/main/java/onlyoffice/model/config/document/Permissions.java b/src/main/java/onlyoffice/model/config/document/Permissions.java new file mode 100644 index 00000000..b37b9c48 --- /dev/null +++ b/src/main/java/onlyoffice/model/config/document/Permissions.java @@ -0,0 +1,42 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.document; + +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import onlyoffice.managers.document.DocumentManager; +import onlyoffice.utils.attachment.AttachmentUtil; + +public class Permissions { + private boolean edit; + + public Permissions(final DocumentManager documentManager, final AttachmentUtil attachmentUtil, + final Long attachmentId) { + String fileExt = attachmentUtil.getFileExt(attachmentId); + boolean isEditable = documentManager.isEditable(fileExt) || documentManager.isFillForm(fileExt); + edit = attachmentUtil.checkAccess(attachmentId, AuthenticatedUserThreadLocal.get(), true) && isEditable; + } + + public boolean isEdit() { + return edit; + } + + public void setEdit(final boolean edit) { + this.edit = edit; + } +} diff --git a/src/main/java/onlyoffice/model/config/document/ReferenceData.java b/src/main/java/onlyoffice/model/config/document/ReferenceData.java new file mode 100644 index 00000000..352e7f40 --- /dev/null +++ b/src/main/java/onlyoffice/model/config/document/ReferenceData.java @@ -0,0 +1,45 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.document; + +public class ReferenceData { + private long fileKey; + private String instanceId; + + public ReferenceData(final long fileKey, final String instanceId) { + this.fileKey = fileKey; + this.instanceId = instanceId; + } + + public long getFileKey() { + return fileKey; + } + + public void setFileKey(final long fileKey) { + this.fileKey = fileKey; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(final String instanceId) { + this.instanceId = instanceId; + } +} diff --git a/src/main/java/onlyoffice/model/config/editor/Customization.java b/src/main/java/onlyoffice/model/config/editor/Customization.java new file mode 100644 index 00000000..20ec88fe --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/Customization.java @@ -0,0 +1,120 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.managers.url.UrlManager; + +public class Customization { + private boolean forcesave; + private boolean chat; + private boolean compactHeader; + private boolean feedback; + private boolean help; + private boolean toolbarNoTabs; + private ReviewDisplay reviewDisplay; + private Goback goback; + + public Customization(final UrlManager urlManager, final ConfigurationManager configurationManager, + final Long attachmentId, final String referer) { + this.forcesave = configurationManager.forceSaveEnabled(); + this.chat = configurationManager.getBooleanPluginSetting("chat", true); + this.compactHeader = configurationManager.getBooleanPluginSetting("compactHeader", false); + this.feedback = configurationManager.getBooleanPluginSetting("feedback", false); + this.help = configurationManager.getBooleanPluginSetting("helpMenu", true); + this.toolbarNoTabs = configurationManager.getBooleanPluginSetting("toolbarNoTabs", false); + if (!configurationManager.getStringPluginSetting("reviewDisplay", "original").equals("original")) { + switch (configurationManager.getStringPluginSetting("reviewDisplay", "original")) { + case "markup": + this.reviewDisplay = ReviewDisplay.MARKUP; + break; + case "final": + this.reviewDisplay = ReviewDisplay.FINAL; + break; + case "original": + default: + this.reviewDisplay = ReviewDisplay.ORIGINAL; + } + } + this.goback = new Goback(urlManager, attachmentId, referer); + } + + public boolean isForcesave() { + return forcesave; + } + + public void setForcesave(final boolean forcesave) { + this.forcesave = forcesave; + } + + public boolean isChat() { + return chat; + } + + public void setChat(final boolean chat) { + this.chat = chat; + } + + public boolean isCompactHeader() { + return compactHeader; + } + + public void setCompactHeader(final boolean compactHeader) { + this.compactHeader = compactHeader; + } + + public boolean isFeedback() { + return feedback; + } + + public void setFeedback(final boolean feedback) { + this.feedback = feedback; + } + + public boolean isHelp() { + return help; + } + + public void setHelp(final boolean help) { + this.help = help; + } + + public boolean isToolbarNoTabs() { + return toolbarNoTabs; + } + + public void setToolbarNoTabs(final boolean toolbarNoTabs) { + this.toolbarNoTabs = toolbarNoTabs; + } + + public ReviewDisplay getReviewDisplay() { + return reviewDisplay; + } + + public void setReviewDisplay(final ReviewDisplay reviewDisplay) { + this.reviewDisplay = reviewDisplay; + } + + public Goback getGoback() { + return goback; + } + + public void setGoback(final Goback goback) { + this.goback = goback; + } +} diff --git a/src/main/java/onlyoffice/model/config/editor/EditorConfig.java b/src/main/java/onlyoffice/model/config/editor/EditorConfig.java new file mode 100644 index 00000000..081273b1 --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/EditorConfig.java @@ -0,0 +1,118 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import com.atlassian.confluence.languages.LocaleManager; +import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; +import com.atlassian.confluence.user.ConfluenceUser; +import onlyoffice.managers.configuration.ConfigurationManager; +import onlyoffice.managers.url.UrlManager; +import onlyoffice.utils.attachment.AttachmentUtil; +import org.json.JSONObject; + +public class EditorConfig { + private Mode mode; + private String createUrl; + private String callbackUrl; + private String lang; + private JSONObject actionLink; + private Customization customization; + private User user; + + public EditorConfig(final LocaleManager localeManager, final AttachmentUtil attachmentUtil, + final UrlManager urlManager, final ConfigurationManager configurationManager, + final Long attachmentId, final Mode mode, final JSONObject actionLink, final String referer) { + ConfluenceUser user = AuthenticatedUserThreadLocal.get(); + Long pageId = attachmentUtil.getAttachmentPageId(attachmentId); + String fileExt = attachmentUtil.getFileExt(attachmentId); + + this.mode = mode; + this.actionLink = actionLink; + this.lang = localeManager.getLocale(user).toLanguageTag(); + this.customization = new Customization(urlManager, configurationManager, attachmentId, referer); + + if (user != null) { + this.user = new User(user); + } + + if (attachmentUtil.checkAccessCreate(user, pageId)) { + this.createUrl = urlManager.getCreateUri(pageId, fileExt); + } + + if (attachmentUtil.checkAccess(attachmentId, user, true)) { + this.callbackUrl = urlManager.getCallbackUrl(attachmentId); + } + } + + public Mode getMode() { + return mode; + } + + public void setMode(final Mode mode) { + this.mode = mode; + } + + public String getCreateUrl() { + return createUrl; + } + + public void setCreateUrl(final String createUrl) { + this.createUrl = createUrl; + } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(final String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public String getLang() { + return lang; + } + + public void setLang(final String lang) { + this.lang = lang; + } + + public JSONObject getActionLink() { + return actionLink; + } + + public void setActionLink(final JSONObject actionLink) { + this.actionLink = actionLink; + } + + public Customization getCustomization() { + return customization; + } + + public void setCustomization(final Customization customization) { + this.customization = customization; + } + + public User getUser() { + return user; + } + + public void setUser(final User user) { + this.user = user; + } +} diff --git a/src/main/java/onlyoffice/model/config/editor/Goback.java b/src/main/java/onlyoffice/model/config/editor/Goback.java new file mode 100644 index 00000000..f095d40a --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/Goback.java @@ -0,0 +1,37 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import onlyoffice.managers.url.UrlManager; + +public class Goback { + private String url; + + public Goback(final UrlManager urlManager, final Long attachmentId, final String referer) { + this.url = urlManager.getGobackUrl(attachmentId, referer); + } + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } +} diff --git a/src/main/java/onlyoffice/model/config/editor/Mode.java b/src/main/java/onlyoffice/model/config/editor/Mode.java new file mode 100644 index 00000000..2d5d7dad --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/Mode.java @@ -0,0 +1,28 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import com.google.gson.annotations.SerializedName; + +public enum Mode { + @SerializedName("view") + VIEW, + @SerializedName("edit") + EDIT +} diff --git a/src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java b/src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java new file mode 100644 index 00000000..be09896d --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/ReviewDisplay.java @@ -0,0 +1,30 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import com.google.gson.annotations.SerializedName; + +public enum ReviewDisplay { + @SerializedName("markup") + MARKUP, + @SerializedName("final") + FINAL, + @SerializedName("original") + ORIGINAL +} diff --git a/src/main/java/onlyoffice/model/config/editor/User.java b/src/main/java/onlyoffice/model/config/editor/User.java new file mode 100644 index 00000000..21852e7f --- /dev/null +++ b/src/main/java/onlyoffice/model/config/editor/User.java @@ -0,0 +1,47 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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 onlyoffice.model.config.editor; + +import com.atlassian.confluence.user.ConfluenceUser; + +public class User { + private String id; + private String name; + + public User(final ConfluenceUser user) { + this.id = user.getName(); + this.name = user.getFullName(); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setId(final String id) { + this.id = id; + } + + public void setName(final String name) { + this.name = name; + } +} diff --git a/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java b/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java index b6167905..b92f3a38 100644 --- a/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java +++ b/src/main/java/onlyoffice/utils/attachment/AttachmentUtil.java @@ -12,6 +12,10 @@ import java.util.List; public interface AttachmentUtil extends Serializable { + Attachment getAttachment(Long attachmentId); + + Attachment getAttachmentByName(String fileName, Long pageId); + boolean checkAccess(Long attachmentId, User user, boolean forEdit); boolean checkAccess(Attachment attachment, User user, boolean forEdit); diff --git a/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java b/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java index eb3c690e..985cde21 100644 --- a/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java +++ b/src/main/java/onlyoffice/utils/attachment/AttachmentUtilImpl.java @@ -19,6 +19,7 @@ package onlyoffice.utils.attachment; import com.atlassian.confluence.content.ContentProperties; +import com.atlassian.confluence.core.ContentEntityManager; import com.atlassian.confluence.core.ContentEntityObject; import com.atlassian.confluence.pages.Attachment; import com.atlassian.confluence.pages.AttachmentManager; @@ -30,7 +31,6 @@ import com.atlassian.confluence.setup.BootstrapManager; import com.atlassian.confluence.user.AuthenticatedUserThreadLocal; import com.atlassian.confluence.user.ConfluenceUser; -import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import com.atlassian.sal.api.transaction.TransactionCallback; import com.atlassian.sal.api.transaction.TransactionTemplate; import com.atlassian.spring.container.ContainerManager; @@ -46,9 +46,6 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; -import javax.enterprise.inject.Default; -import javax.inject.Inject; -import javax.inject.Named; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -58,25 +55,18 @@ import java.util.Date; import java.util.List; -@Named -@Default public class AttachmentUtilImpl implements AttachmentUtil { private final Logger log = LogManager.getLogger("onlyoffice.utils.attachment.AttachmentUtil"); private static final HierarchicalContentFileSystemHelper FILE_SYSTEM_HELPER = new HierarchicalContentFileSystemHelper(); - @ComponentImport private final AttachmentManager attachmentManager; - @ComponentImport private final TransactionTemplate transactionTemplate; - @ComponentImport private final PageManager pageManager; - @ComponentImport private final BootstrapManager bootstrapManager; private final ConfigurationManager configurationManager; - @Inject public AttachmentUtilImpl(final AttachmentManager attachmentManager, final TransactionTemplate transactionTemplate, final ConfigurationManager configurationManager, final PageManager pageManager, final BootstrapManager bootstrapManager) { @@ -87,6 +77,30 @@ public AttachmentUtilImpl(final AttachmentManager attachmentManager, final Trans this.bootstrapManager = bootstrapManager; } + public Attachment getAttachment(final Long attachmentId) { + try { + return attachmentManager.getAttachment(attachmentId); + } catch (NullPointerException e) { + return null; + } + } + + public Attachment getAttachmentByName(final String fileName, final Long pageId) { + ContentEntityManager contentEntityManager = + (ContentEntityManager) ContainerManager.getComponent("contentEntityManager"); + ContentEntityObject contentEntityObject = contentEntityManager.getById(pageId); + + List attachments = attachmentManager.getLatestVersionsOfAttachments(contentEntityObject); + + for (Attachment attachment : attachments) { + if (attachment.getFileName().equals(fileName)) { + return attachment; + } + } + + return null; + } + public boolean checkAccess(final Long attachmentId, final User user, final boolean forEdit) { if (user == null) { return false; @@ -415,5 +429,4 @@ public ContentEntityObject getContainer(final Long containerId) { return container; } - } diff --git a/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java b/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java index b8222dc7..3e8bf310 100644 --- a/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java +++ b/src/main/java/onlyoffice/utils/parsing/ParsingUtilImpl.java @@ -1,12 +1,8 @@ package onlyoffice.utils.parsing; -import javax.enterprise.inject.Default; -import javax.inject.Named; import java.io.InputStream; import java.util.Scanner; -@Named -@Default public class ParsingUtilImpl implements ParsingUtil { public String getBody(final InputStream stream) { Scanner scanner = null; diff --git a/src/main/resources/app_data b/src/main/resources/app_data deleted file mode 160000 index 4b96e283..00000000 --- a/src/main/resources/app_data +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4b96e283924e0481299b6400520829649634c23e diff --git a/src/main/resources/app_data/document-formats b/src/main/resources/app_data/document-formats new file mode 160000 index 00000000..6c4927a0 --- /dev/null +++ b/src/main/resources/app_data/document-formats @@ -0,0 +1 @@ +Subproject commit 6c4927a0d153350202492e6f6b5e434faf1e80d2 diff --git a/src/main/resources/app_data/document-templates b/src/main/resources/app_data/document-templates new file mode 160000 index 00000000..f00ab3a3 --- /dev/null +++ b/src/main/resources/app_data/document-templates @@ -0,0 +1 @@ +Subproject commit f00ab3a3efe6e2f8542ba026d1fc1d72df7dfd5f diff --git a/src/main/resources/atlassian-plugin-marketing.xml b/src/main/resources/atlassian-plugin-marketing.xml index 182ace91..a93e7646 100644 --- a/src/main/resources/atlassian-plugin-marketing.xml +++ b/src/main/resources/atlassian-plugin-marketing.xml @@ -1,6 +1,6 @@ - + diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index 5f53366c..6c23883f 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -16,6 +16,11 @@ + + + + + @@ -29,6 +34,16 @@ + + com.atlassian.auiplugin:ajs + com.atlassian.auiplugin:dialog2 + + + + + page + + com.atlassian.auiplugin:ajs @@ -80,6 +95,29 @@ + + + confluence.editor.actions:editor-macro-browser + macro-browser + + + + onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc + + + + + + + + + + + + + @@ -131,6 +169,59 @@ onlyoffice-doceditor + + + Link and text for this link used to where a document is available for download in various formats. + + + + onlyoffice.managers.auth.AuthContext + + + onlyoffice.managers.configuration.ConfigurationManager + + + onlyoffice.managers.convert.ConvertManager + + + onlyoffice.managers.document.DocumentManager + + + onlyoffice.managers.jwt.JwtManager + + + onlyoffice.managers.url.UrlManager + + + onlyoffice.utils.attachment.AttachmentUtil + + + onlyoffice.utils.parsing.ParsingUtil + + + onlyoffice.managers.config.ConfigManager + + + onlyoffice.macro.components.ContentResolver + + + + + + + + + + + + + + + + A full-featured editor for the most known formats of text documents, spreadsheets and presentations that can open these types of documents for editing or preview. @@ -164,4 +255,24 @@ Conditions for displaying ONLYOFFICE button in confluence preview. /onlyoffice/confluence/previews/plugin/access + + The ONLYOFFICE Formats. + /onlyoffice/formats + + + + + + /templates/download-as.vm + /templates/download-as.vm + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/images/preview-macros-logo.png b/src/main/resources/images/preview-macros-logo.png new file mode 100644 index 00000000..0e0e67a7 Binary files /dev/null and b/src/main/resources/images/preview-macros-logo.png differ diff --git a/src/main/resources/images/preview-placeholder-cell.svg b/src/main/resources/images/preview-placeholder-cell.svg new file mode 100644 index 00000000..007a4cb7 --- /dev/null +++ b/src/main/resources/images/preview-placeholder-cell.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/images/preview-placeholder-form.svg b/src/main/resources/images/preview-placeholder-form.svg new file mode 100644 index 00000000..003c5f1e --- /dev/null +++ b/src/main/resources/images/preview-placeholder-form.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/main/resources/images/preview-placeholder-slide.svg b/src/main/resources/images/preview-placeholder-slide.svg new file mode 100644 index 00000000..e7c43715 --- /dev/null +++ b/src/main/resources/images/preview-placeholder-slide.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/main/resources/images/preview-placeholder-word.svg b/src/main/resources/images/preview-placeholder-word.svg new file mode 100644 index 00000000..9212f3b7 --- /dev/null +++ b/src/main/resources/images/preview-placeholder-word.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/js/confluence-previews-plugin/onlyoffice-button.js b/src/main/resources/js/confluence-previews-plugin/onlyoffice-button.js index ff50446b..27f8b178 100644 --- a/src/main/resources/js/confluence-previews-plugin/onlyoffice-button.js +++ b/src/main/resources/js/confluence-previews-plugin/onlyoffice-button.js @@ -66,6 +66,10 @@ define('cp/component/onlyoffice-button', [ if ($.fn.tooltip) { this.$('a').tooltip({gravity: 'n'}); } + + this.$('a').on("click", function() { + this.blur(); + }); } return this; diff --git a/src/main/resources/js/onlyoffice-download-as.js b/src/main/resources/js/onlyoffice-download-as.js new file mode 100644 index 00000000..a0f4f255 --- /dev/null +++ b/src/main/resources/js/onlyoffice-download-as.js @@ -0,0 +1,154 @@ +(function ($) { + const dialogId = "#onlyoffice-download-as-dialog"; + const buttonCloseId = "#dialog-close-button"; + const buttonDownloadAsId = "#dialog-download-as-button"; + + $(function () { + AJS.$(".onlyoffice-download-as-action").unbind("click"); + AJS.$(".onlyoffice-download-as-action").bind("click", function (e) { + e.preventDefault(); + + var link = AJS.$(this); + + AJS.$.get(link.attr('href'), function (response) { + AJS.$('.aui-page-panel').after(response); + AJS.dialog2(dialogId).show(); + + Confluence.Binder.autocompletePage(AJS.$("#onlyoffice-download-as-binder")); + $(".aui-message-context").html(""); + + AJS.$(buttonCloseId).bind("click", function (e) { + e.preventDefault(); + AJS.dialog2(dialogId).hide(); + }); + + AJS.$(buttonDownloadAsId).bind("click", function (e) { + e.preventDefault(); + downloadAsAction(); + }); + }); + + return false; + }); + }); + + function downloadAsAction(url) { + var actionUrl = Confluence.getBaseUrl() + "/" + $(dialogId).find("form").attr("action"); + var data = { + "fileName": $(dialogId).find("#file-name").val(), + "targetFileType": $(dialogId).find("#target-file-type").val() + }; + + $(dialogId).find(buttonDownloadAsId)[0].busy(); + $(dialogId + " form").find("input,select").not(".disabled").attr("disabled","disabled"); + + conversionRequest( + actionUrl, + data, + function(response) { + $("#onlyoffice-download-as-iframe").remove(); + $("body").append(""); + $("#onlyoffice-download-as-iframe").attr("src", response.fileUrl); + AJS.dialog2(dialogId).hide(); + }, + function(errorMessage) { + $(dialogId).find(buttonDownloadAsId)[0].idle(); + $(".aui-message-context").html("
" + errorMessage + "
"); + $(dialogId + " form").find("input,select").not(".disabled").attr("disabled", null); + } + ) + } + + function conversionRequest(url, data, onSuccess, onError) { + if ($(dialogId).length <= 0) return; + + if (data.fileName == "") { + onError(AJS.I18n.getText("fileName.required")); + return; + } + + if (/[\/:*?"<>|]/.test(data.fileName)) { + onError(AJS.I18n.getText("filename.contain.invalid.character")); + return; + } + + $.ajax({ + type: "POST", + url: url, + data: data, + success: function (response) { + if (response.error) { + var errorMessage = getErrorMessage(response); + onError(errorMessage); + return; + } + + if (response.endConvert) { + onSuccess(response); + } else { + setTimeout(function() { + conversionRequest(url, data, onSuccess, onError); + }, 1000); + } + }, + error: function (xhr) { + if (xhr.status == 403) { + onError(AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.permission")); + } else { + onError(AJS.I18n.getText("onlyoffice.connector.error.Unknown")); + } + } + }); + } + + function getErrorMessage(response) { + var errorMessage; + var servicePrefix = false; + + switch (response.error) { + case -1: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.unknown"); + servicePrefix = true; + break; + case -2: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.timeout"); + servicePrefix = true; + break; + case -3: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.conversion"); + servicePrefix = true; + break; + case -4: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.download"); + servicePrefix = true; + break; + case -5: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.password"); + servicePrefix = true; + break; + case -6: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.database"); + servicePrefix = true; + break; + case -7: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.input"); + servicePrefix = true; + break; + case -8: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.token"); + servicePrefix = true; + break; + case -10: + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.not-reached"); + break; + default: + errorMessage = AJS.I18n.getText("onlyoffice.connector.error.Unknown"); + } + + if (servicePrefix) { + errorMessage = AJS.I18n.getText("onlyoffice.connector.dialog.conversion.message.error.service-prefix").replace("$", errorMessage); + } + + return errorMessage; + } +})(AJS.$); \ No newline at end of file diff --git a/src/main/resources/js/onlyoffice-preview-macro-fields.js b/src/main/resources/js/onlyoffice-preview-macro-fields.js new file mode 100644 index 00000000..afb59a45 --- /dev/null +++ b/src/main/resources/js/onlyoffice-preview-macro-fields.js @@ -0,0 +1,23 @@ +/** + * + * (c) Copyright Ascensio System SIA 2023 + * + * 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. + * + */ + +(function($) { + $.getJSON("/plugins/servlet/onlyoffice/formats", function(data) { + AJS.MacroBrowser.activateSmartFieldsAttachmentsOnPage("onlyoffice-preview", data); + }); +})(AJS.$); diff --git a/src/main/resources/lang-resource.properties b/src/main/resources/lang-resource.properties index 20ab32ab..ba0dd706 100644 --- a/src/main/resources/lang-resource.properties +++ b/src/main/resources/lang-resource.properties @@ -56,7 +56,34 @@ onlyoffice.editor.message.demo=You are using public demo ONLYOFFICE Document Ser onlyoffice.editor.message.docs-api-undefined=ONLYOFFICE cannot be reached. Please contact admin onlyoffice.editor.message.docs-api-unsupported=Not supported version DocumentServer. onlyoffice.editor.message.forms.error.version=Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online. +onlyoffice.editor.message.error.unsupported=Sorry, this file format isn't supported onlyoffice.convert.link=Convert using ONLYOFFICE -onlyoffice.convert.label=Converting {0} to {1}.. +onlyoffice.convert.label=Converting {0} to {1}... onlyoffice.convert.message.error=Error\: onlyoffice.form.create.link=Create form using ONLYOFFICE +onlyoffice.connector.download-as.link=Download As +onlyoffice.connector.dialog.conversion.header.title=Download As with ONLYOFFICE +onlyoffice.connector.dialog.conversion.field.current-type=Current type +onlyoffice.connector.dialog.conversion.field.target-type=Target type +onlyoffice.connector.dialog.conversion.message.error.service-prefix=ONLYOFFICE conversion service returned error ($). +onlyoffice.connector.dialog.conversion.message.error.unknown=Unknown error +onlyoffice.connector.dialog.conversion.message.error.timeout=Conversion timeout error +onlyoffice.connector.dialog.conversion.message.error.conversion=Conversion error +onlyoffice.connector.dialog.conversion.message.error.download=Error while downloading the document file to be converted +onlyoffice.connector.dialog.conversion.message.error.password=Incorrect password +onlyoffice.connector.dialog.conversion.message.error.database=Error while accessing the conversion result database +onlyoffice.connector.dialog.conversion.message.error.input=Input error +onlyoffice.connector.dialog.conversion.message.error.token=Invalid token +onlyoffice.connector.dialog.conversion.message.error.not-reached=ONLYOFFICE Conversion service cannot be reached. Please contact admin. +onlyoffice.connector.dialog.conversion.message.error.permission=User does not have rights to perform this operation. +onlyoffice.connector.error.Unknown=An unknown error occurred during the operation. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.label=ONLYOFFICE Preview +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc=Insert an ONLYOFFICE preview into the page. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.label=Page Name +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.desc=Published Confluence page containing the attached file. If not specified, the current page is assumed. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.label=File Name +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.desc=Name of the attached file to view in this page. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.label=Width +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.desc=Specified either in pixels (default or ''px'') or as a ''%'' of page width. Examples: 200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=Height +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=Specified either in pixels (default or ''px'') or as a ''%'' of page height. Examples: 200, 200px, 10% diff --git a/src/main/resources/lang-resource_de.properties b/src/main/resources/lang-resource_de.properties index 68f9032f..cec5f6d2 100644 --- a/src/main/resources/lang-resource_de.properties +++ b/src/main/resources/lang-resource_de.properties @@ -54,8 +54,36 @@ onlyoffice.editor.dialog.create.form.button.create-blank=Leere Datei erstellen onlyoffice.editor.dialog.create.form.message.error=Die ausgew\u00e4hlte Datei ist nicht im DOCX-Format onlyoffice.editor.message.demo=Du verwendest den \u00f6ffentlichen Demo ONLYOFFICE Document Server. Bitte benutze ihn nicht zum Speichern von Deinen privaten sensiblen Daten. onlyoffice.editor.message.docs-api-undefined=ONLYOFFICE kann nicht erreicht werden. Bitte kontaktieren Sie Ihren Administrator. +onlyoffice.editor.message.docs-api-unsupported=Nicht unterst\u00fctzte Version von DocumentServer. onlyoffice.editor.message.forms.error.version=F\u00fcr Online-Arbeit mit Formularen ist Version 7.0 von ONLYOFFICE Docs erforderlich. +onlyoffice.editor.message.error.unsupported=Leider wird dieses Dateiformat nicht unterst\u00fctzt onlyoffice.convert.link=Mit ONLYOFFICE konvertieren -onlyoffice.convert.label=Konvertieren von {0} in {1}.. +onlyoffice.convert.label=Konvertieren von {0} in {1}... onlyoffice.convert.message.error=Fehler\: onlyoffice.form.create.link=Formular in ONLYOFFICE erstellen +onlyoffice.connector.download-as.link=Herunterladen als +onlyoffice.connector.dialog.conversion.header.title=Herunterladen Als mit ONLYOFFICE +onlyoffice.connector.dialog.conversion.field.current-type=Originalformat +onlyoffice.connector.dialog.conversion.field.target-type=Ausgabeformat +onlyoffice.connector.dialog.conversion.message.error.service-prefix=Der ONLYOFFICE-Konvertierungsdienst hat einen Fehler zur\u00fcckgegeben ($). +onlyoffice.connector.dialog.conversion.message.error.unknown=Unbekannter Fehler +onlyoffice.connector.dialog.conversion.message.error.timeout=Timeout-Fehler bei der Konvertierung +onlyoffice.connector.dialog.conversion.message.error.conversion=Fehler bei der Umwandlung +onlyoffice.connector.dialog.conversion.message.error.download=Fehler beim Herunterladen der Datei, die konvertiert werden muss +onlyoffice.connector.dialog.conversion.message.error.password=Ung\u00fcltiges Passwort +onlyoffice.connector.dialog.conversion.message.error.database=Fehler beim Zugriff auf die Datenbank der Ergebnisse der Konvertierung +onlyoffice.connector.dialog.conversion.message.error.input=Eingabefehler +onlyoffice.connector.dialog.conversion.message.error.token=Ung\u00fcltiges Token +onlyoffice.connector.dialog.conversion.message.error.not-reached=Der ONLYOFFICE-Konvertierungsdienst ist nicht erreichbar. Bitte kontaktieren Sie den Administrator. +onlyoffice.connector.dialog.conversion.message.error.permission=Benutzer hat keine Berechtigungen, diesen Vorgang auszuf\u00fchren. +onlyoffice.connector.error.Unknown=Ein unbekannter Fehler ist w\u00e4hrend des Vorgangs aufgetreten. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.label=Vorschau in ONLYOFFICE +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc=Vorschau in ONLYOFFICE auf der Seite einf\u00fcgen. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.label=Seitenname +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.desc=Ver\u00f6ffentlichte Confluence-Seite mit der angeh\u00e4ngten Datei. Falls nicht angegeben, wird die aktuelle Seite angenommen. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.label=Dateiname +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.desc=Name der angeh\u00e4ngten Datei, die auf dieser Seite angezeigt werden soll. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.label=Breite +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.desc=Wird entweder in Pixel (standardm\u00e4\u00dfig oder ''px'') oder als ''%'' der Seitenbreite angegeben. Beispiele: 200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=H\u00f6he +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=Wird entweder in Pixel (standardm\u00e4\u00dfig oder ''px'') oder als ''%'' der Seitenh\u00f6he angegeben. Beispiele: 200, 200px, 10% diff --git a/src/main/resources/lang-resource_es.properties b/src/main/resources/lang-resource_es.properties index c69f591c..2962d9cf 100644 --- a/src/main/resources/lang-resource_es.properties +++ b/src/main/resources/lang-resource_es.properties @@ -54,8 +54,36 @@ onlyoffice.editor.dialog.create.form.button.create-blank=Crear desde cero onlyoffice.editor.dialog.create.form.message.error=El archivo seleccionado no es de formato DOCX onlyoffice.editor.message.demo=Est\u00e1s usando el ONLYOFFICE Document Server de demostraci\u00f3n. Por favor, no almacenes tus datos confidenciales aqu\u00ed. onlyoffice.editor.message.docs-api-undefined=No se puede establecer contacto con ONLYOFFICE. Por favor, p\u00f3ngase en contacto con el administrador. +onlyoffice.editor.message.docs-api-unsupported=Versi\u00f3n del DocumentServer no soportada. onlyoffice.editor.message.forms.error.version=Por favor, actualice ONLYOFFICE Docs a la versi\u00f3n 7.0 para poder trabajar con formularios rellenables en l\u00ednea. +onlyoffice.editor.message.error.unsupported=Lo sentimos, este formato de archivo no es compatible onlyoffice.convert.link=Convierta usando ONLYOFFICE -onlyoffice.convert.label=Convirtiendo {0} a {1}.. +onlyoffice.convert.label=Convirtiendo {0} a {1}... onlyoffice.convert.message.error=Error\: onlyoffice.form.create.link=Crear formulario utilizando ONLYOFFICE +onlyoffice.connector.download-as.link=Descargar como +onlyoffice.connector.dialog.conversion.header.title=Descargar Como con ONLYOFFICE +onlyoffice.connector.dialog.conversion.field.current-type=Tipo presente +onlyoffice.connector.dialog.conversion.field.target-type=Tipo di obiettivo +onlyoffice.connector.dialog.conversion.message.error.service-prefix=El servicio de conversi\u00f3n de ONLYOFFICE devolvi\u00f3 un error ($). +onlyoffice.connector.dialog.conversion.message.error.unknown=Error desconocido +onlyoffice.connector.dialog.conversion.message.error.timeout=Error de tiempo de espera +onlyoffice.connector.dialog.conversion.message.error.conversion=Error de conversi\u00f3n +onlyoffice.connector.dialog.conversion.message.error.download=Error al descargar el archivo para su conversi\u00f3n +onlyoffice.connector.dialog.conversion.message.error.password=Contrase\u00f1a incorrecta +onlyoffice.connector.dialog.conversion.message.error.database=Error al acceder la base de datos de resultados de conversi\u00f3n +onlyoffice.connector.dialog.conversion.message.error.input=Error de entrada +onlyoffice.connector.dialog.conversion.message.error.token=Token inv\u00e1lido +onlyoffice.connector.dialog.conversion.message.error.not-reached=No se puede acceder al servicio de conversi\u00f3n de ONLYOFFICE. Por favor, p\u00f3ngase en contacto con el administrador. +onlyoffice.connector.dialog.conversion.message.error.permission=El usuario no tiene derechos a realizar esta operaci\u00f3n. +onlyoffice.connector.error.Unknown=Se produjo un error desconocido durante la operaci\u00f3n. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.label=Vista previa de ONLYOFFICE +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc=Inserte una vista previa de ONLYOFFICE en la p\u00e1gina. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.label=Nombre de la p\u00e1gina +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.desc=Es la p\u00e1gina de Confluence publicada que contiene el archivo adjunto. Si no se especifica, se asume la p\u00e1gina actual. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.label=Nombre de archivo +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.desc=Nombre del archivo adjunto para ver en esta p\u00e1gina. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.label=Ancho +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.desc=Especificado en p\u00edxeles (por defecto o ''px'') o como un ''%'' del ancho de la p\u00e1gina. Ejemplos: 200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=Altura +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=Especificado en p\u00edxeles (por defecto o ''px'') o como un ''%'' de la altura de la p\u00e1gina. Ejemplos: 200, 200px, 10% diff --git a/src/main/resources/lang-resource_fr.properties b/src/main/resources/lang-resource_fr.properties index e9aaf60e..460337fb 100644 --- a/src/main/resources/lang-resource_fr.properties +++ b/src/main/resources/lang-resource_fr.properties @@ -54,8 +54,36 @@ onlyoffice.editor.dialog.create.form.button.create-blank=Cr\u00e9er \u00e0 parti onlyoffice.editor.dialog.create.form.message.error=Le fichier s\u00e9lectionn\u00e9 n'est pas au format DOCX onlyoffice.editor.message.demo=Vous utilisez la version d\u00e9mo de ONLYOFFICE Document Server, propos\u00e9e \u00e0 des fins de tests. Veuillez ne pas stocker vos donn\u00e9es confidentielles. onlyoffice.editor.message.docs-api-undefined=ONLYOFFICE ne peut \u00eatre atteint. Veuillez contacter l'administration. +onlyoffice.editor.message.docs-api-unsupported=Version de DocumentServer non prise en charge. onlyoffice.editor.message.forms.error.version=Veuillez mettre \u00e0 jour ONLYOFFICE Docs vers la version 7.0 pour travailler sur les formulaires \u00e0 remplir en ligne. +onlyoffice.editor.message.error.unsupported=Malheureusement, ce format de fichier n'est pas pris en charge onlyoffice.convert.link=Convertir en utilisant ONLYOFFICE -onlyoffice.convert.label=Conversion de {0} en {1}.. +onlyoffice.convert.label=Conversion de {0} en {1}... onlyoffice.convert.message.error=Erreur\: onlyoffice.form.create.link=Cr\u00e9er un formulaire avec ONLYOFFICE +onlyoffice.connector.download-as.link=T\u00e9l\u00e9charger comme +onlyoffice.connector.dialog.conversion.header.title=T\u00e9l\u00e9charger comme avec ONLYOFFICE +onlyoffice.connector.dialog.conversion.field.current-type=Type actuel +onlyoffice.connector.dialog.conversion.field.target-type=Type de cible +onlyoffice.connector.dialog.conversion.message.error.service-prefix=Le service de conversion ONLYOFFICE a renvoy\u00e9 une erreur ($). +onlyoffice.connector.dialog.conversion.message.error.unknown=Erreur inconnue +onlyoffice.connector.dialog.conversion.message.error.timeout=Erreur de d\u00e9lai d'attente +onlyoffice.connector.dialog.conversion.message.error.conversion=Erreur de conversion +onlyoffice.connector.dialog.conversion.message.error.download=Erreur lors du t\u00e9l\u00e9chargement du fichier \u00e0 convertir +onlyoffice.connector.dialog.conversion.message.error.password=Mot de passe incorrect +onlyoffice.connector.dialog.conversion.message.error.database=Erreur lors de l'acc\u00e8s \u00e0 la base de donn\u00e9es des r\u00e9sultats de la conversion +onlyoffice.connector.dialog.conversion.message.error.input=Erreur de saisie +onlyoffice.connector.dialog.conversion.message.error.token=Jeton invalide +onlyoffice.connector.dialog.conversion.message.error.not-reached=Le service de conversion ONLYOFFICE n'est pas accessible. Veuillez contacter l'administration. +onlyoffice.connector.dialog.conversion.message.error.permission=L'utilisateur n'a pas le droit d'effectuer cette op\u00e9ration. +onlyoffice.connector.error.Unknown=Une erreur inconnue s'est produite pendant l'op\u00E9ration. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.label=Aper\u00e7u d'ONLYOFFICE +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc=Ins\u00e9rer un aper\u00e7u d'ONLYOFFICE dans la page. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.label=Nom de la page +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.desc=Page publi\u00e9e de Confluence contenant le fichier joint. Si elle n'est pas sp\u00e9cifi\u00e9e, la page actuelle est prise en compte. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.label=Nom de fichier +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.desc=Nom du fichier joint \u00e0 afficher sur cette page. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.label=Largeur +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.desc=Sp\u00e9cifi\u00e9 soit en pixels (par d\u00efaut ou ''px''), soit en ''%'' de la largeur de la page. Exemples : 200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=Hauteur +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=Sp\u00ecifi\u00e9 soit en pixels (par d\u00efaut ou ''px''), soit en ''%'' de la hauteur de la page. Exemples : 200, 200px, 10%200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=Altezza +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=Specificato in pixel (predefinito o ''px'') o come ''%'' dell'altezza della pagina. Esempi: 200, 200px, 10% diff --git a/src/main/resources/lang-resource_ru.properties b/src/main/resources/lang-resource_ru.properties index f4cd2af0..f2bd0232 100644 --- a/src/main/resources/lang-resource_ru.properties +++ b/src/main/resources/lang-resource_ru.properties @@ -56,7 +56,34 @@ onlyoffice.editor.message.demo=\u0412\u044b\u0020\u0438\u0441\u043f\u043e\u043b\ onlyoffice.editor.message.docs-api-undefined=\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 ONLYOFFICE \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c onlyoffice.editor.message.docs-api-unsupported=\u041d\u0435\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0421\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432. onlyoffice.editor.message.forms.error.version=\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u0435\u0020\u0441\u0435\u0440\u0432\u0435\u0440 ONLYOFFICE Docs \u0434\u043e\u0020\u0432\u0435\u0440\u0441\u0438\u0438 7.0 \u0434\u043b\u044f\u0020\u0440\u0430\u0431\u043e\u0442\u044b\u0020\u0441\u0020\u0444\u043e\u0440\u043c\u0430\u043c\u0438\u0020\u043e\u043d\u043b\u0430\u0439\u043d. +onlyoffice.editor.message.error.unsupported=\u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435, \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f onlyoffice.convert.link=\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432 ONLYOFFICE -onlyoffice.convert.label=\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044F {0} \u0432 {1}.. +onlyoffice.convert.label=\u041A\u043E\u043D\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044F {0} \u0432 {1}... onlyoffice.convert.message.error=\u041E\u0448\u0438\u0431\u043A\u0430\: onlyoffice.form.create.link=\u0421\u043e\u0437\u0434\u0430\u0442\u044c\u0020\u0444\u043e\u0440\u043c\u0443\u002c\u0020\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f ONLYOFFICE +onlyoffice.connector.download-as.link=\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043a\u0430\u043a +onlyoffice.connector.dialog.conversion.header.title=\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043a\u0430\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ONLYOFFICE +onlyoffice.connector.dialog.conversion.field.current-type=\u0422\u0435\u043a\u0443\u0449\u0438\u0439\u0020\u0442\u0438\u043f +onlyoffice.connector.dialog.conversion.field.target-type=\u0426\u0435\u043b\u0435\u0432\u043e\u0439\u0020\u0442\u0438\u043f +onlyoffice.connector.dialog.conversion.message.error.service-prefix=\u0421\u0435\u0440\u0432\u0438\u0441\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438\u0020\u004f\u004e\u004c\u0059\u004f\u0046\u0046\u0049\u0043\u0045\u0020\u0432\u0435\u0440\u043d\u0443\u043b\u0020\u043e\u0448\u0438\u0431\u043a\u0443 ($). +onlyoffice.connector.dialog.conversion.message.error.unknown=\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f\u0020\u043e\u0448\u0438\u0431\u043a\u0430 +onlyoffice.connector.dialog.conversion.message.error.timeout=\u041e\u0448\u0438\u0431\u043a\u0430\u0020\u0432\u0440\u0435\u043c\u0435\u043d\u0438\u0020\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 +onlyoffice.connector.dialog.conversion.message.error.conversion=\u041e\u0448\u0438\u0431\u043a\u0430\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 +onlyoffice.connector.dialog.conversion.message.error.download=\u041e\u0448\u0438\u0431\u043a\u0430\u0020\u043f\u0440\u0438\u0020\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435\u0020\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0020\u0434\u043b\u044f\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438. +onlyoffice.connector.dialog.conversion.message.error.password=\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439\u0020\u043f\u0430\u0440\u043e\u043b\u044c +onlyoffice.connector.dialog.conversion.message.error.database=\u041e\u0448\u0438\u0431\u043a\u0430\u0020\u043f\u0440\u0438\u0020\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u0020\u043a\u0020\u0431\u0430\u0437\u0435\u0020\u0434\u0430\u043d\u043d\u044b\u0445\u0020\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 +onlyoffice.connector.dialog.conversion.message.error.input=\u041e\u0448\u0438\u0431\u043a\u0430\u0020\u0432\u0432\u043e\u0434\u0430 +onlyoffice.connector.dialog.conversion.message.error.token=\u041d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439\u0020\u0442\u043e\u043a\u0435\u043d +onlyoffice.connector.dialog.conversion.message.error.not-reached=\u0421\u0435\u0440\u0432\u0438\u0441\u0020\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 ONLYOFFICE \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430\u002c\u0020\u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c\u0020\u0441\u0020\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c\u002e. +onlyoffice.connector.dialog.conversion.message.error.permission=\u0020\u043d\u0435\u0442\u0020\u043f\u0440\u0430\u0432\u0020\u043d\u0430\u0020\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u0020\u044d\u0442\u043e\u0439\u0020\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. +onlyoffice.connector.error.Unknown=\u0412\u0020\u0445\u043e\u0434\u0435\u0020\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438\u0020\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430\u0020\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f\u0020\u043e\u0448\u0438\u0431\u043a\u0430. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.label=\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0432 ONLYOFFICE +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.desc=\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0432 ONLYOFFICE \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.label=\u0418\u043c\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.page.desc=\u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 Confluence \u0441 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c. \u0415\u0441\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430, \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.label=\u0418\u043c\u044f \u0444\u0430\u0439\u043b\u0430 +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.name.desc=\u0418\u043c\u044f \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043d\u0430 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.label=\u0428\u0438\u0440\u0438\u043d\u0430 +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.width.desc=\u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u043b\u0438 ''px'') \u0438\u043b\u0438 \u043a\u0430\u043a ''%'' \u043e\u0442 \u0448\u0438\u0440\u0438\u043d\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u041f\u0440\u0438\u043c\u0435\u0440\u044b: 200, 200px, 10% +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.label=\u0412\u044b\u0441\u043e\u0442\u0430 +onlyoffice.onlyoffice-confluence-plugin.onlyoffice-preview.param.height.desc=\u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u043b\u0438 ''px'') \u0438\u043b\u0438 \u043a\u0430\u043a ''%'' \u043e\u0442 \u0432\u044b\u0441\u043e\u0442\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u041f\u0440\u0438\u043c\u0435\u0440\u044b: 200, 200px, 10% diff --git a/src/main/resources/onlyoffice-config.properties b/src/main/resources/onlyoffice-config.properties index d6f0f33f..c147f0df 100644 --- a/src/main/resources/onlyoffice-config.properties +++ b/src/main/resources/onlyoffice-config.properties @@ -1,19 +1,8 @@ filesize-max=104857600 +convertation-filesize-max=26214400 timeout=60 files.docservice.secret=Vskoproizvolny Salt par Chivreski files.docservice.url.api=web-apps/apps/api/documents/api.js files.docservice.url.convert=ConvertService.ashx - -docservice.type.word=doc|docx|docm|dot|dotx|dotm|odt|fodt|ott|rtf|txt|html|htm|mht|pdf|djvu|fb2|epub|xps|docxf|oform -docservice.type.cell=xls|xlsx|xlsm|xlt|xltx|xltm|ods|fods|ots|csv -docservice.type.slide=pps|ppsx|ppsm|ppt|pptx|pptm|pot|potx|potm|odp|fodp|otp - -docservice.type.edit=docx|xlsx|pptx|docxf -docservice.type.edit.customizable=csv|odp|ods|odt|rtf|txt - -docservice.type.fill-form=oform - -docservice.type.convert=doc|docm|dot|dotx|epub|htm|html|odp|ods|odt|otp|ots|ott|pot|potm|potx|pps|ppsm|ppsx|ppt|\ - pptm|rtf|xls|xlsm|xlt|xltm|xltx|docx|docxf diff --git a/src/main/resources/templates/download-as.vm b/src/main/resources/templates/download-as.vm new file mode 100644 index 00000000..969a4d0a --- /dev/null +++ b/src/main/resources/templates/download-as.vm @@ -0,0 +1,47 @@ + diff --git a/src/main/resources/templates/editor.vm b/src/main/resources/templates/editor.vm index 51695923..22c90daa 100644 --- a/src/main/resources/templates/editor.vm +++ b/src/main/resources/templates/editor.vm @@ -53,7 +53,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl
- +
@@ -63,17 +63,17 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl var defaultPanelComponent = new Array(); var onAppReady = function () { - var errorMessage = "${errorMessage}"; + var errorMessage = "$!{errorMessage}"; if (errorMessage) { docEditor.showMessage(errorMessage); } - if (${demo}) { + if (Boolean($!{demo})) { docEditor.showMessage("$i18n.getText('onlyoffice.editor.message.demo')"); } }; var onRequestHistory = function () { - var historyInfoUri = "${historyInfoUriAsHtml}"; + var historyInfoUri = "$!{historyInfoUriAsHtml}"; var xhr = new XMLHttpRequest(); xhr.open("GET", historyInfoUri, false); xhr.send(); @@ -86,7 +86,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl var onRequestHistoryData = function (event) { var version = event.data; - var historyDataUri = "${historyDataUriAsHtml}"; + var historyDataUri = "$!{historyDataUriAsHtml}"; var xhr = new XMLHttpRequest(); xhr.open("GET", historyDataUri + "&version=" + version, false); xhr.send(); @@ -144,7 +144,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl }); var xhr = new XMLHttpRequest(); - xhr.open("POST", "${attachmentDataAsHtml}", false); + xhr.open("POST", "$!{attachmentDataAsHtml}", false); xhr.send(JSON.stringify({ command: command, attachments: attachments @@ -172,15 +172,15 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl }; var onRequestInsertImage = function(event) { - insertDialog(docEditor.insertImage, true, ${insertImageTypesAsHtml}, event.data.c); + insertDialog(docEditor.insertImage, true, $insertImageTypesAsHtml, event.data.c); }; var onRequestCompareFile = function() { - insertDialog(docEditor.setRevisedFile, false, ${compareFileTypesAsHtml}); + insertDialog(docEditor.setRevisedFile, false, $compareFileTypesAsHtml); }; var onRequestMailMergeRecipients = function(event) { - insertDialog(docEditor.setMailMergeRecipients, false, ${mailMergeTypesAsHtml}); + insertDialog(docEditor.setMailMergeRecipients, false, $mailMergeTypesAsHtml); }; var onRequestSaveAs = function (event) { @@ -229,7 +229,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl $("#move-button").attr("disabled", "disabled"); var xhr = new XMLHttpRequest(); - xhr.open("POST", "${saveAsUriAsHtml}", true); + xhr.open("POST", "$!{saveAsUriAsHtml}", true); xhr.send(JSON.stringify({ url: url, title: title, @@ -319,6 +319,25 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl docEditor.setActionLink(createActionLink(location.href, actionData)); }; + var onRequestReferenceData = function(event) { + var xhr = new XMLHttpRequest(); + xhr.open("POST", "${referenceDataUriAsHtml}"); + xhr.send(JSON.stringify(event.data)); + + xhr.onreadystatechange = function() { + if (xhr.readyState != 4) return; + if (xhr.status == 200) { + docEditor.setReferenceData(JSON.parse(xhr.responseText)); + } else if (xhr.status == 403) { + docEditor.setReferenceData({error: "$i18n.getText('operation.forbidden.message')"}); + } else if (xhr.status == 404) { + docEditor.setReferenceData({error: "$i18n.getText('title.attachment.not.found')"}); + } else { + docEditor.setReferenceData({error: "$i18n.getText('dialog.error.unknown.title')"}); + } + } + }; + var connectEditor = function () { if (typeof DocsAPI === "undefined") { alert("$i18n.getText('onlyoffice.editor.message.docs-api-undefined')"); @@ -342,6 +361,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl "onRequestCompareFile": onRequestCompareFile, "onRequestMailMergeRecipients": onRequestMailMergeRecipients, "onMakeActionLink": onMakeActionLink, + "onRequestReferenceData": onRequestReferenceData }, }; @@ -350,8 +370,7 @@ $webResourceManager.requireResource("onlyoffice.onlyoffice-confluence-plugin:onl } Object.assign(config, JSON.parse($("#editorConfig").html() || "{}")); - - if ((config.document.fileType === "docxf" || config.document.fileType === "oform") + if (config.document && (config.document.fileType === "docxf" || config.document.fileType === "oform") && docsVersion[0] < 7) { alert("$i18n.getText('onlyoffice.editor.message.forms.error.version')"); return; diff --git a/src/main/resources/templates/preview.vm b/src/main/resources/templates/preview.vm new file mode 100644 index 00000000..77b262ec --- /dev/null +++ b/src/main/resources/templates/preview.vm @@ -0,0 +1,9 @@ +
+ + +
+ + +