diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/LICENSE b/LICENSE index 261eeb9..9e32cde 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,127 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + 木兰宽松许可证, 第2版 - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + 木兰宽松许可证, 第2版 + 2020年1月 http://license.coscl.org.cn/MulanPSL2 - 1. Definitions. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. + 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. + 0. 定义 - "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). + “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 - "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. + 1. 授予版权许可 - "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. 授予专利许可 - 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. + 3. 无商标许可 - 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: + “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and + 4. 分发限制 - (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 + 5. 免责声明与责任限制 - (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. + 6. 语言 + “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 - 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. + 如何将木兰宽松许可证,第2版,应用到您的软件 + + 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: - 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. + 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; - 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. + 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; - 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. + 3, 请将如下声明文本放入每个源文件的头部注释中。 - END OF TERMS AND CONDITIONS + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. - 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. + Mulan Permissive Software License,Version 2 - Copyright [yyyy] [name of copyright owner] + Mulan Permissive Software License,Version 2 (Mulan PSL v2) + January 2020 http://license.coscl.org.cn/MulanPSL2 - 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 + Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + + 0. Definition + + Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + + Contribution means the copyrightable work licensed by a particular Contributor under this License. + + Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + + Legal Entity means the entity making a Contribution and all its Affiliates. + + Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. - http://www.apache.org/licenses/LICENSE-2.0 + 1. Grant of Copyright License - 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. + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + + 2. Grant of Patent License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + + 3. No Trademark License + + No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + + 4. Distribution Restriction + + You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + + 5. Disclaimer of Warranty and Limitation of Liability + + THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 6. Language + + THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + + END OF THE TERMS AND CONDITIONS + + How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + + To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + + i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + + ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. diff --git a/README.md b/README.md index 337ee9a..c414865 100644 --- a/README.md +++ b/README.md @@ -1,247 +1,336 @@ -## Overview -This example will help you integrate ONLYOFFICE Docs into your web application written in Java -with Spring Boot. - -Spring Boot has a lot of functionality, but its most significant features are: dependency management, -auto-configuration, and built-in servlet containers. - -**Please note**: It is intended for testing purposes and demonstrating functionality of the editors. Do NOT use this integration example on your own server without proper code modifications! In case you enabled the test example, disable it before going for production. - -## For Windows - -### Step 1. Install ONLYOFFICE Docs - -Download and install ONLYOFFICE Docs (packaged as Document Server). - -See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx). - -### Step 2. Download the Java code for the editors integration - -Download the [Java-Spring example](https://api.onlyoffice.com/editors/demopreview) from our site. - -To connect the editors to your website, specify the path to the editors installation, server port and the path to the storage folder in the *\src\main\resources\application.properties* file: - -``` - files.storage= - server.port=port - files.docservice.url.site=https://documentserver/ -``` - -where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path. For example, *D:\\\\folder*. Please note that on Windows OS the double backslash must be used as a separator. - -If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *\src\main\resources\editor.html* file. - -### Step 3. Install the prerequisites -To run the Java example code, install the Java version 11 appropriate for your OS and framework **Apache Maven**: - -* Java (download from [the Oracle official website](https://www.oracle.com/ru/java/technologies/javase-jdk11-downloads.html)); -* Apache Maven (download from [the official website](https://maven.apache.org/download.cgi)). - -### Step 4. Set environment variables - -1. After you have installed Java on Windows, set the **JAVA_HOME** environment variable to point to the Java installation directory. - - Find out where Java is installed. If you didn't change the path during installation, it will be something like this: - - ``` - C:\Program Files\Java\jdk11 - ``` - - In **Windows 7** right click **My Computer** and select **Properties**, then click **Advanced**. - - In **Windows 8** go to **Control Panel** -> **System** -> **Advanced System Settings**. - - Click the **Environment Variables** button. - - Under **System Variables**, click **New**. - - In the **Variable Name** field, enter **JAVA_HOME** if you installed the **JDK** (Java Development Kit) or **JRE_HOME** if you installed the **JRE** (Java Runtime Environment). - - In the **Variable Value** field, enter your **JDK** or **JRE** installation path, for example C:\Program Files\Java\jdk11. - - Check if the variable created successfully by **echo** command in the **Command Prompt**: - - ``` - echo %JAVA_HOME% - ``` - -2. Set the **MAVEN_HOME** environment variable: - - Unzip the downloaded archive with the maven to any directory, it will be something like this: - - ``` - C:\apache-maven-3.8.1 - ``` - In **Windows 7** right click **My Computer** and select **Properties**, then click **Advanced**. - - In **Windows 8** go to **Control Panel** -> **System** -> **Advanced System Settings**. - - Click the **Environment Variables** button. - - Under **System Variables**, click **New**. - - In the **Variable Name** field, enter **MAVEN_HOME**. - - In the **Variable Value** field, enter your **JDK** or **JRE** installation path, for example C:\apache-maven-3.8.1. - - Add C:\apache-maven-3.8.1\bin to the PATH system variable: - In system variables, find PATH, clicks on the Edit... button. In “Edit environment variable” dialog, clicks on the New button and add this C:\apache-maven-3.8.1\bin - - Check if the variable created successfully by **echo** command in the **Command Prompt**: - - ``` - echo %MAVEN_HOME% - ``` - - -### Step 5. Start application with Maven - -1. Open the console and go the java-spring folder using the **cd** command, for example: - ``` - cd C:\Program Files\document-server-integration\web\documentserver-example\java-spring - ``` -2. In the open console enter the following commands: - ``` - mvn clean - mvn package - mvn spring-boot:run - ``` -3. Open your browser using **server.address** and **server.port**: - - ``` - http://server.address:server.port/ - ``` - -### Step 6. Check accessibility - - In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. - -Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files. - -## For Linux -### Step 1. Install ONLYOFFICE Docs - -Download and install ONLYOFFICE Docs (packaged as Document Server). - -See the detailed guide to learn how to install Document Server [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx). - -### Step 2. Install the prerequisites and run the website with the editors - -1. Install **Java**: - - ``` - sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get install oracle-java11-installer - ``` - -2. Download the archive with the Java-Spring example and unpack the archive or clone git repository: - - a) archive with Java-Spring: - - ``` - wget https://api.onlyoffice.com/app_data/editor/Java%20Spring%20Example.zip - ``` - - ``` - unzip Java\ Spring\ Example.zip - ``` - b) git repository: - ``` - git clone https://github.com/ONLYOFFICE/document-server-integration.git - ``` - - -3. Change the current directory for the project directory: - - a) from archive - - ``` - cd Java\ Spring\ Example/ - ``` - b) from git repository - ``` - cd document-server-integration/web/documentserver-example/java-spring - ``` -4. Edit the *application.properties* configuration file. Specify the name of your local server with the ONLYOFFICE Document Server installed. - - ``` - nano src/main/resources/application.properties - ``` - - Edit the following lines: - - ``` - files.storage= - server.port=port - files.docservice.url.site=https://documentserver/ - ``` - - where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path. - - -5. Install **Maven**: - - ``` - sudo apt-get install maven - ``` - -6. Build: - - ``` - mvn package - ``` - - 7. Start Java-Spring example: - ``` - ./mvnw spring-boot:run - ``` - 8. Open your browser using **server.address** and **server.port**: - - ``` - http://server.address:server.port/ - ``` +# Spring-Boot-onlyOffice(集成onlyOffice服务) + +springboot集成onlyOffice的实现。在参考网络上的资料结合自身实际情况总结,让集成oo方便快捷。 封装了oo服务的API和统一了配置。 +- 在线编辑,查看,转换 + + +* onlyOffice.yml配置文件 +* 如果解决了你地方问题,请给个 **star** +----------------------------------- +# 对外使用的java类 —— OnlyServiceAPI +## 核心方法 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法名称参数参数说明返回值
openDocument() Map<String,Object> map 文件数据信息
+ {
+ 必填 fileId
+ 必填 fileName
+ 必填 fileType
+ 必填 fileSize
+ 可用携带其它值
+ } +
+
+{
+"editorConfig": {
+    "mode": "edit",
+    "customization": {
+        "feedback": {
+            "visible": false
+        },
+        "help": false,
+        "goback": {
+            "blank": false
+        },
+        "macros": false,
+        "autosave": false,
+        "comments": false,
+        "review": {},
+        "hideRightMenu": true,
+        "anonymous": {
+            "request": false
+        },
+        "forcesave": true,
+        "logo": {},
+        "hideNotes": true
+    },
+    "plugins": {
+        "pluginsData": [],
+        "autostart": []
+    },
+    "callbackUrl": "http://172.31.240.1:9090/onlyOffice/save",
+    "lang": "zh-CN",
+    "user": {
+        "name": "TongHuic7bba5",
+        "id": "c7bba5"
+    }
+  },
+"docServiceApiUrl": "http://172.31.240.1:8886/web-apps/apps/api/documents/api.js",
+"documentType": "word",
+"document": {
+    "permissions": {
+        "edit": true,
+        "chat": false,
+        "review": false
+    },
+    "title": "fdfs.docx",
+    "fileType": "docx",
+    "key": "63f560ec03a94654b10cd4fdeebec05a",
+    "url": "http://172.31.240.1:9090/download/09cee8767dd3476280fa865bacfaf213",
+    "info": {
+        "sharingSettings": [{
+            "isLink": true,
+            "permissions": ["Full Access"],
+            "user": "TongHuic7bba5"
+        }],
+        "created": "2023-08-05 21:38:25"
+    }
+},
+"type": "desktop",
+"token": ""
+}
+
String mode打开方式
edit
view
boolean collaborativeEditing是否协同编辑
handlerStatus()JSONObject jsonObjectonlyOffice 回调传来的值。
https://api.onlyoffice.com/editors/callback
save():触发保存回调。String key是openDocument()返回值中的keyString : 提示信息
String userId用户Id
converted()String filetype文件类型转换后的文件下载地址
String fileId文件Id
String outputtype转化类型
String title转换后的文件名称
String password文档密码
+ +**注意:** + * 外部触发保存操作,save()方法。 + * `autosave`/`forcesave` 参数为默认值时有效 + * 修改文件后,没有执行回调方法。在点击保存后执行回调 + +![](jpg/f.jpg) + + +快速使用 +----------------------------------- + +- 必须的依赖 + +``` pom + + org.springframework.boot + spring-boot-starter-data-redis + + + org.projectlombok + lombok + true + + + com.alibaba + fastjson + 2.0.25 + + + cn.hutool + hutool-all + 5.8.16 + + + com.inversoft + prime-jwt + 1.3.1 + + + org.apache.commons + commons-pool2 + +``` + +- 定义关键接口(oo服务回调使用) `重要` + 1.保存接口 + ``` + 参考:demo/controller/IndexController.saveFile() + 对应配置文件参数:oo.call-back-url + 回调状态 + 0 - 找不到具有密钥标识符的文档 + 1 - 正在编辑文档(打开文件回调) + 2 - 文档已准备好保存 + 3 - 发生文档保存错误 + 4 - 不作任何更改就关闭文档(关闭回调) + 6 - 正在编辑文档,但保存当前文档状态(保存回调) + 7 - 强制保存文档时发生错误 + ``` -### Step 3. Check accessibility + 2.下载文件地址 + ``` + 参考:demo/controller/IndexController.download() + 对应配置文件参数:oo.download-file + 对应openDocument()方法返回值中的 document.url + 打开文件后oo服务要下载对应的文件 + ``` +- 实现SaveFileProcessor类 + ``` + 参考:demo.service.DemoService + ``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法名称 方法说明 参数 参数说明 返回值
saveBeforeInitialization()保存前置方法Map<String, Object> map在openDocument()方法中传入的文件数据信息
byte[] bytes文件二进制数据
String fileExtension文件后缀
save()保存方法,实现自己的保存逻辑Map<String, Object> map在openDocument()方法中传入的文件数据信息Map<String, Object> 更新内存中的信息
byte[] bytes文件二进制数据
byte[] changes当前文件和保存之前文件的区别。changes.zip
String key是openDocument()返回值中的key
saveAfterInitialization()保存后置方法Map<String, Object> map在openDocument()方法中传入的文件数据信息
byte[] bytes文件二进制数据
String fileExtension文件后缀
-In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. -Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files. +## 更新记录 + +- [x] 修复关闭文件后快速再次打开该文件后,保存时报错的bug 2023/11/10 +- [x] 修复内存文件信息在保存后没有修改的bug 2023/10/23 +- [x] 实现和编辑器的数据通信 2023/9/9 (更新链接) + https://blog.xenosp.cn/posts/87468caf/ +- [x] 修复文件转pdf时只有第一页的bug 2023/8/13 + + + + + + + +----------------------------------- + + +# 页面集成 +### html +``` +参考 onlyOffice.html +style.js 中的openDocument() +``` +### vue +``` +参考 onlyOffice.vue +``` +----------------------------------- + +![](jpg/QQ截图20230805221213.jpg) +### 编辑 + +![](jpg/edit.jpg) +![](jpg/editxlsx.jpg) +![](jpg/editppt.jpg) +### 查看 + +![](jpg/view.jpg) +![](jpg/viewxls.jpg) +![](jpg/viewppt.jpg) +### 文件转换 +![](jpg/docx-pdf.jpg) +![](jpg/xlsx2pdf.jpg) + -## For Docker -1. Edit the *application.properties* configuration file. Specify the name of your local server with the ONLYOFFICE Document Server installed ([installation instructions](https://helpcenter.onlyoffice.com/installation/docs-developer-install-docker.aspx)). - ``` - nano src/main/resources/application.properties - ``` - -2. Edit the following lines: - ``` - files.storage= - server.port=port - files.docservice.url.site=https://documentserver/ - ``` - where the **documentserver** is the name of the server with the ONLYOFFICE Docs installed, **port** is any available port and **files.storage** is the path where files will be created and stored (in the project folder by default). You can set an absolute path. -3. Run the next command in the java example directory: - ``` - docker-compose up - ``` -4. Open your browser using **server.address** and **server.port**: - ``` - http://server.address:server.port/ - ``` -## Important security info -Please keep in mind the following security aspects when you are using test examples: -* There is no protection of the storage from unauthorized access since there is no need for authorization. -* There are no checks against parameter substitution in links, since the parameters are generated by the code according to the pre-arranged scripts. -* There are no data checks in requests of saving the file after editing, since each test example is intended for requests only from ONLYOFFICE Document Server. -* There are no prohibitions on using test examples from other sites, since they are intended to interact with ONLYOFFICE Document Server from another domain. \ No newline at end of file diff --git a/file/8c969104e32f4efc9d83946ad5108ce2 b/file/8c969104e32f4efc9d83946ad5108ce2 new file mode 100644 index 0000000..e69de29 diff --git a/file/a0f59131619d430fb72a146ca2477ff6.docx b/file/a0f59131619d430fb72a146ca2477ff6.docx new file mode 100644 index 0000000..4efa3ba Binary files /dev/null and b/file/a0f59131619d430fb72a146ca2477ff6.docx differ diff --git a/jpg/QQ截图20230805221213.jpg b/jpg/QQ截图20230805221213.jpg new file mode 100644 index 0000000..ab2ec13 Binary files /dev/null and b/jpg/QQ截图20230805221213.jpg differ diff --git a/jpg/docx-pdf.jpg b/jpg/docx-pdf.jpg new file mode 100644 index 0000000..3927db4 Binary files /dev/null and b/jpg/docx-pdf.jpg differ diff --git a/jpg/edit.jpg b/jpg/edit.jpg new file mode 100644 index 0000000..b969a8b Binary files /dev/null and b/jpg/edit.jpg differ diff --git a/jpg/editppt.jpg b/jpg/editppt.jpg new file mode 100644 index 0000000..79df123 Binary files /dev/null and b/jpg/editppt.jpg differ diff --git a/jpg/editxlsx.jpg b/jpg/editxlsx.jpg new file mode 100644 index 0000000..ea3fa88 Binary files /dev/null and b/jpg/editxlsx.jpg differ diff --git a/jpg/f.jpg b/jpg/f.jpg new file mode 100644 index 0000000..cefac1c Binary files /dev/null and b/jpg/f.jpg differ diff --git a/jpg/view.jpg b/jpg/view.jpg new file mode 100644 index 0000000..237dbb5 Binary files /dev/null and b/jpg/view.jpg differ diff --git a/jpg/viewppt.jpg b/jpg/viewppt.jpg new file mode 100644 index 0000000..4f44484 Binary files /dev/null and b/jpg/viewppt.jpg differ diff --git a/jpg/viewxls.jpg b/jpg/viewxls.jpg new file mode 100644 index 0000000..fd9e82f Binary files /dev/null and b/jpg/viewxls.jpg differ diff --git a/jpg/xlsx2pdf.jpg b/jpg/xlsx2pdf.jpg new file mode 100644 index 0000000..5007691 Binary files /dev/null and b/jpg/xlsx2pdf.jpg differ diff --git a/plugins/externallistener/README.md b/plugins/externallistener/README.md new file mode 100644 index 0000000..194ca7d --- /dev/null +++ b/plugins/externallistener/README.md @@ -0,0 +1,3 @@ +## Overview + +(Linux服务器安装好)把当前文件夹放到路径: /var/www/onlyoffice/documentserver/sdkjs-plugins \ No newline at end of file diff --git a/plugins/externallistener/config.json b/plugins/externallistener/config.json new file mode 100644 index 0000000..93d38c1 --- /dev/null +++ b/plugins/externallistener/config.json @@ -0,0 +1,25 @@ +{ + "name" : "Listener", + "guid" : "asc.{A8705DEE-7544-4C33-B3D5-168406D92F72}", + "baseUrl" : "", + "variations" : [ + { + "description" : "Listener", + "url" : "index.html", + "icons" : ["resources/img/icon.png", "resources/img/icon@2x.png"], + "isViewer" : false, + "EditorsSupport" : ["word", "cell", "slide"], + "isVisual" : false, + "isModal" : true, + "isInsideMode" : false, + "isSystem" : true, + "initDataType" : "none", + "initData" : "", + "isUpdateOleOnResize" : true, + "buttons" : [], + "events" : [ + "onExternalPluginMessage" + ] + } + ] +} \ No newline at end of file diff --git a/plugins/externallistener/index.html b/plugins/externallistener/index.html new file mode 100644 index 0000000..3d73063 --- /dev/null +++ b/plugins/externallistener/index.html @@ -0,0 +1,28 @@ + + + + + + Listener + + + + + + + + \ No newline at end of file diff --git a/plugins/externallistener/resources/img/icon.png b/plugins/externallistener/resources/img/icon.png new file mode 100644 index 0000000..afd662c Binary files /dev/null and b/plugins/externallistener/resources/img/icon.png differ diff --git a/plugins/externallistener/resources/img/icon@2x.png b/plugins/externallistener/resources/img/icon@2x.png new file mode 100644 index 0000000..75a16d8 Binary files /dev/null and b/plugins/externallistener/resources/img/icon@2x.png differ diff --git a/plugins/externallistener/scripts/code.js b/plugins/externallistener/scripts/code.js new file mode 100644 index 0000000..4472bc6 --- /dev/null +++ b/plugins/externallistener/scripts/code.js @@ -0,0 +1,103 @@ +/** + * + * (c) Copyright Ascensio System SIA 2020 + * + * 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(window, undefined){ + + window.Asc.plugin.init = function() { + console.log("插件初始化") + + // none + window.parent.Common.Gateway.on('internalcommand', function(data){ + console.log(data); // 接受到123参数console.log(data.data); // 接受到321参数 + var data_ = data.data + switch (data.command){ + case "insertText": + let text = "${"+data_.text+"}" + window.Asc.plugin.executeMethod ("PasteText", [text]); + if(window.Asc.plugin.info.editorType == 'cell'){ + CorrectText('insertText') + } + break; + case 'getText': + CorrectText('getText') + break + } + }); + + var _info = window.Asc.plugin.info; + var userName =_info.userName + var userId = _info.userId + + function CorrectText (command) { + let data = { + command:command, + text:"" + } + switch (window.Asc.plugin.info.editorType) { + case 'word': + case 'slide': { + window.Asc.plugin.executeMethod ("GetSelectedText", [{"Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9)}], function (e) { + let text = e.trim() + data.text = text + window.parent.parent.postMessage(JSON.stringify(data),'*'); + }); + break; + } + case 'cell': { + Asc.scope.command = command; + window.Asc.plugin.callCommand (function () { + var oWorksheet = Api.GetActiveSheet(); + var oActiveCell = oWorksheet.GetActiveCell(); + let str = oActiveCell.Text + if(str.indexOf("${") != -1){ + str = str.substring(2,str.length-1) + } + let data = { + command:Asc.scope.command, + sheetName:oWorksheet.Name, + text:str, + x:oActiveCell.Row, + y:oActiveCell.Col + } + + localStorage.setItem('dataInfo', JSON.stringify(data)) + }, false,false,function(){ + window.parent.parent.postMessage(localStorage.getItem('dataInfo'),'*'); + localStorage.removeItem('dataInfo') + }); + /* window.Asc.plugin.executeMethod ("GetSelectedText", [{"Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9)}], function (e) { + let text = e.trim() + console.log(text) + data.text = text + if (text == '') { + text = text.replace (/\t/g, '\n'); + window.parent.parent.postMessage(JSON.stringify(data),'*'); + } + else { + + } + });*/ + break; + } + } + } + }; + + window.Asc.plugin.button = function(id) { + }; + +})(window, undefined); diff --git a/plugins/externallistener/translations/langs.json b/plugins/externallistener/translations/langs.json new file mode 100644 index 0000000..82daa55 --- /dev/null +++ b/plugins/externallistener/translations/langs.json @@ -0,0 +1,3 @@ +[ + "zh-CN" +] \ No newline at end of file diff --git a/plugins/externallistener/translations/zh-CN.json b/plugins/externallistener/translations/zh-CN.json new file mode 100644 index 0000000..0e0dcd2 --- /dev/null +++ b/plugins/externallistener/translations/zh-CN.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index ba4ac4d..7d383c5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,112 +1,147 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.5.1 - - - com.onlyoffice - integration - 1.0 - Java Spring Integration Example - ONLYOFFICE Java Spring Integration - - 11 - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-devtools - true - - - org.springframework.boot - spring-boot-starter-thymeleaf - 2.5.1 - - - org.springframework.boot - spring-boot-starter-data-jpa - - - com.h2database - h2 - runtime - - - com.googlecode.json-simple - json-simple - 1.1 - - - com.google.code.gson - gson - 2.8.9 - - - com.inversoft - prime-jwt - 1.3.1 - - - org.projectlombok - lombok - 1.18.20 - provided - - - com.fasterxml.jackson.core - jackson-core - 2.13.4 - - - com.fasterxml.jackson.core - jackson-databind - 2.13.4.2 - - - org.modelmapper - modelmapper - 2.4.2 - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.2.0 - - - validate - validate - - checkstyle.xml - true - true - true - warning - true - true - - - - check - - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.6 + + + com.oo + Spring-Boot-onlyOffice + 0.0.1-SNAPSHOT + Spring-Boot-onlyOffice + Demo project for Spring Boot + + 1.8 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.baomidou + mybatis-plus-boot-starter + 3.5.1 + + + com.baomidou + mybatis-plus-generator + 3.5.1 + + + com.alibaba + druid-spring-boot-starter + 1.1.22 + + + mysql + mysql-connector-java + 8.0.17 + + + com.alibaba + fastjson + 2.0.25 + + + cn.hutool + hutool-all + 5.8.16 + + + com.inversoft + prime-jwt + 1.3.1 + + + org.apache.commons + commons-pool2 + + + org.springframework.boot + spring-boot-starter-data-redis + + + commons-fileupload + commons-fileupload + 1.4 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + diff --git a/src/main/java/com/onlyoffice/integration/ExampleData.java b/src/main/java/com/onlyoffice/integration/ExampleData.java deleted file mode 100644 index 6fe3c3a..0000000 --- a/src/main/java/com/onlyoffice/integration/ExampleData.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration; - -import com.onlyoffice.integration.documentserver.serializers.FilterState; -import com.onlyoffice.integration.services.UserServices; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import java.util.ArrayList; -import java.util.List; - -@Component -public class ExampleData { - @Autowired - private UserServices userService; - @PostConstruct - public void init() { - // the description for user 0 - List descriptionUserZero = List.of( - "The name is requested when the editor is opened", - "Doesn’t belong to any group", - "Can review all the changes", - "Can perform all actions with comments", - "The file favorite state is undefined", - "Can't mention others in comments", - "Can't create new files from the editor", - "Can’t see anyone’s information", - "Can't rename files from the editor", - "Can't view chat", - "Can't protect file", - "View file without collaboration" - ); - - // the description for user 1 - List descriptionUserFirst = List.of( - "File author by default", - "He doesn’t belong to any of the groups", - "He can review all the changes", - "He can do everything with the comments", - "The file favorite state is undefined", - "Can create a file from a template with data from the editor", - "Can see the information about all users", - "Can view chat" - ); - - // the description for user 2 - List descriptionUserSecond = List.of( - "He belongs to Group2", - "He can review only his own changes or the changes made by the users who don’t belong" - + " to any of the groups", - "He can view every comment, edit his comments and the comments left by the users " - + "who don't belong to any of the groups and remove only his comments", - "This file is favorite", - "Can create a file from an editor", - "Can see the information about users from Group2 and users who don’t belong to any group", - "Can view chat" - ); - - // the description for user 3 - List descriptionUserThird = List.of( - "He belongs to Group3", - "He can review only the changes made by the users from Group2", - "He can view the comments left by the users from Group2 and Group3 and edit the comments left by " - + "the users from Group2", - "This file isn’t favorite", - "He can’t copy data from the file into the clipboard", - "He can’t download the file", - "He can’t print the file", - "Can create a file from an editor", - "Can see the information about Group2 users", - "Can view chat" - ); - - // create user 1 with the specified parameters - userService.createUser("John Smith", "smith@example.com", descriptionUserFirst, - "", List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), - List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), - List.of(FilterState.NULL.toString()), null, true, true); - - // create user 2 with the specified parameters - userService.createUser("Mark Pottato", "pottato@example.com", descriptionUserSecond, - "group-2", List.of("", "group-2"), List.of(FilterState.NULL.toString()), - List.of("group-2", ""), List.of("group-2"), List.of("group-2", ""), true, true, - true); - - // create user 3 with the specified parameters - userService.createUser("Hamish Mitchell", "mitchell@example.com", descriptionUserThird, - "group-3", List.of("group-2"), List.of("group-2", "group-3"), List.of("group-2"), - new ArrayList<>(), List.of("group-2"), false, true, true); - - // create user 0 with the specified parameters - userService.createUser("Anonymous", null, descriptionUserZero, "", - List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), - List.of(FilterState.NULL.toString()), List.of(FilterState.NULL.toString()), - new ArrayList<>(), null, false, false); - } -} diff --git a/src/main/java/com/onlyoffice/integration/IntegrationApplication.java b/src/main/java/com/onlyoffice/integration/IntegrationApplication.java deleted file mode 100644 index 4a1a0cc..0000000 --- a/src/main/java/com/onlyoffice/integration/IntegrationApplication.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class IntegrationApplication { - - // run the SpringApplication from the IntagrationApplication with the specified parameters - public static void main(final String[] args) { - SpringApplication.run(IntegrationApplication.class, args); - } - -} diff --git a/src/main/java/com/onlyoffice/integration/IntegrationConfiguration.java b/src/main/java/com/onlyoffice/integration/IntegrationConfiguration.java deleted file mode 100644 index d9d7520..0000000 --- a/src/main/java/com/onlyoffice/integration/IntegrationConfiguration.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import org.json.simple.parser.JSONParser; -import org.modelmapper.ModelMapper; -import org.modelmapper.convention.MatchingStrategies; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.annotation.PostConstruct; - -import com.onlyoffice.integration.documentserver.util.SSLUtils; - -@Configuration -public class IntegrationConfiguration { - - @Value("${files.storage}") - private String storageAddress; - - @Value("${files.docservice.verify-peer-off}") - private String verifyPerrOff; - - @Autowired - private FileStoragePathBuilder storagePathBuilder; - - @Autowired - private SSLUtils ssl; - - @Bean - public ModelMapper mapper() { // create the model mapper - ModelMapper mapper = new ModelMapper(); - mapper.getConfiguration() // get the mapper configuration and set new parameters to it - .setMatchingStrategy(MatchingStrategies.STRICT) // specify the STRICT matching strategy - .setFieldMatchingEnabled(true) // define if the field matching is enabled or not - .setSkipNullEnabled(true) // define if null value will be skipped or not - .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE); /* specify - the PRIVATE field access level */ - return mapper; - } - - @Bean - public JSONParser jsonParser() { // create JSON parser - return new JSONParser(); - } - - @PostConstruct - public void init() { // initialize the storage path builder - storagePathBuilder.configure(storageAddress.isBlank() ? null : storageAddress); - if (!verifyPerrOff.isEmpty()) { - try { - if (verifyPerrOff.equals("true")) { - ssl.turnOffSslChecking(); //the certificate will be ignored - } else { - ssl.turnOnSslChecking(); //the certificate will be verified - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - @Bean - public ObjectMapper objectMapper() { // create the object mapper - return new ObjectMapper(); - } -} diff --git a/src/main/java/com/onlyoffice/integration/controllers/EditorController.java b/src/main/java/com/onlyoffice/integration/controllers/EditorController.java deleted file mode 100644 index f9c24ad..0000000 --- a/src/main/java/com/onlyoffice/integration/controllers/EditorController.java +++ /dev/null @@ -1,239 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.controllers; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.onlyoffice.integration.documentserver.managers.history.HistoryManager; -import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; -import com.onlyoffice.integration.documentserver.models.enums.Action; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.entities.User; -import com.onlyoffice.integration.dto.Mentions; -import com.onlyoffice.integration.documentserver.models.enums.Type; -import com.onlyoffice.integration.documentserver.models.filemodel.FileModel; -import com.onlyoffice.integration.services.UserServices; -import com.onlyoffice.integration.services.configurers.FileConfigurer; -import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper; -import lombok.SneakyThrows; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; - -import static com.onlyoffice.integration.documentserver.util.Constants.ANONYMOUS_USER_ID; - -@CrossOrigin("*") -@Controller -public class EditorController { - - @Value("${files.docservice.url.site}") - private String docserviceSite; - - @Value("${files.docservice.url.api}") - private String docserviceApiUrl; - - @Value("${files.docservice.languages}") - private String langs; - - @Autowired - private FileStoragePathBuilder storagePathBuilder; - - @Autowired - private JwtManager jwtManager; - - @Autowired - private UserServices userService; - - @Autowired - private HistoryManager historyManager; - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private FileConfigurer fileConfigurer; - - @GetMapping(path = "${url.editor}") - // process request to open the editor page - public String index(@RequestParam("fileName") final String fileName, - @RequestParam(value = "action", required = false) final String actionParam, - @RequestParam(value = "type", required = false) final String typeParam, - @RequestParam(value = "actionLink", required = false) final String actionLink, - @RequestParam(value = "directUrl", required = false, - defaultValue = "false") final Boolean directUrl, - @CookieValue(value = "uid") final String uid, - @CookieValue(value = "ulang") final String lang, - final Model model) throws JsonProcessingException { - Action action = Action.edit; - Type type = Type.desktop; - Locale locale = new Locale("en"); - - if (actionParam != null) { - action = Action.valueOf(actionParam); - } - if (typeParam != null) { - type = Type.valueOf(typeParam); - } - - List langsAndKeys = Arrays.asList(langs.split("\\|")); - for (String langAndKey : langsAndKeys) { - String[] couple = langAndKey.split(":"); - if (couple[0].equals(lang)) { - String[] langAndCountry = couple[0].split("-"); - locale = new Locale(langAndCountry[0], langAndCountry.length > 1 ? langAndCountry[1] : ""); - } - } - - Optional optionalUser = userService.findUserById(Integer.parseInt(uid)); - - // if the user is not present, return the ONLYOFFICE start page - if (!optionalUser.isPresent()) { - return "index.html"; - } - - User user = optionalUser.get(); - - // get file model with the default file parameters - FileModel fileModel = fileConfigurer.getFileModel( - DefaultFileWrapper - .builder() - .fileName(fileName) - .type(type) - .lang(locale.toLanguageTag()) - .action(action) - .user(user) - .actionData(actionLink) - .isEnableDirectUrl(directUrl) - .build() - ); - - // add attributes to the specified model - // add file model with the default parameters to the original model - model.addAttribute("model", fileModel); - - // get file history and add it to the model - model.addAttribute("fileHistory", historyManager.getHistory(fileModel.getDocument())); - - // create the document service api URL and add it to the model - model.addAttribute("docserviceApiUrl", docserviceSite + docserviceApiUrl); - - // get an image and add it to the model - model.addAttribute("dataInsertImage", getInsertImage(directUrl)); - - // get a document for comparison and add it to the model - model.addAttribute("dataCompareFile", getCompareFile(directUrl)); - - // get recipients data for mail merging and add it to the model - model.addAttribute("dataMailMergeRecipients", getMailMerge(directUrl)); - - // get user data for mentions and add it to the model - model.addAttribute("usersForMentions", getUserMentions(uid)); - return "editor.html"; - } - - private List getUserMentions(final String uid) { // get user data for mentions - List usersForMentions = new ArrayList<>(); - if (uid != null && !uid.equals("4")) { - List list = userService.findAll(); - for (User u : list) { - if (u.getId() != Integer.parseInt(uid) && u.getId() != ANONYMOUS_USER_ID) { - - // user data includes user names and emails - usersForMentions.add(new Mentions(u.getName(), u.getEmail())); - } - } - } - - return usersForMentions; - } - - @SneakyThrows - private String getInsertImage(final Boolean directUrl) { // get an image that will be inserted into the document - Map dataInsertImage = new HashMap<>(); - dataInsertImage.put("fileType", "png"); - dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.png"); - if (directUrl) { - dataInsertImage.put("directUrl", storagePathBuilder - .getServerUrl(false) + "/css/img/logo.png"); - } - - // check if the document token is enabled - if (jwtManager.tokenEnabled()) { - - // create token from the dataInsertImage object - dataInsertImage.put("token", jwtManager.createToken(dataInsertImage)); - } - - return objectMapper.writeValueAsString(dataInsertImage) - .substring(1, objectMapper.writeValueAsString(dataInsertImage).length() - 1); - } - - // get a document that will be compared with the current document - @SneakyThrows - private String getCompareFile(final Boolean directUrl) { - Map dataCompareFile = new HashMap<>(); - dataCompareFile.put("fileType", "docx"); - dataCompareFile.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx"); - if (directUrl) { - dataCompareFile.put("directUrl", storagePathBuilder - .getServerUrl(false) + "/assets?name=sample.docx"); - } - - // check if the document token is enabled - if (jwtManager.tokenEnabled()) { - - // create token from the dataCompareFile object - dataCompareFile.put("token", jwtManager.createToken(dataCompareFile)); - } - - return objectMapper.writeValueAsString(dataCompareFile); - } - - @SneakyThrows - private String getMailMerge(final Boolean directUrl) { - Map dataMailMergeRecipients = new HashMap<>(); // get recipients data for mail merging - dataMailMergeRecipients.put("fileType", "csv"); - dataMailMergeRecipients.put("url", storagePathBuilder.getServerUrl(true) + "/csv"); - if (directUrl) { - dataMailMergeRecipients.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv"); - } - - // check if the document token is enabled - if (jwtManager.tokenEnabled()) { - - // create token from the dataMailMergeRecipients object - dataMailMergeRecipients.put("token", jwtManager.createToken(dataMailMergeRecipients)); - } - - return objectMapper.writeValueAsString(dataMailMergeRecipients); - } -} diff --git a/src/main/java/com/onlyoffice/integration/controllers/FileController.java b/src/main/java/com/onlyoffice/integration/controllers/FileController.java deleted file mode 100644 index c5259ea..0000000 --- a/src/main/java/com/onlyoffice/integration/controllers/FileController.java +++ /dev/null @@ -1,624 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.controllers; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.onlyoffice.integration.documentserver.callbacks.CallbackHandler; -import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; -import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.dto.Converter; -import com.onlyoffice.integration.dto.ConvertedData; -import com.onlyoffice.integration.dto.Track; -import com.onlyoffice.integration.entities.User; -import com.onlyoffice.integration.documentserver.models.enums.DocumentType; -import com.onlyoffice.integration.services.UserServices; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import com.onlyoffice.integration.documentserver.util.service.ServiceConverter; -import com.onlyoffice.integration.documentserver.managers.document.DocumentManager; -import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - -@CrossOrigin("*") -@Controller -public class FileController { - - @Value("${files.docservice.header}") - private String documentJwtHeader; - - @Value("${filesize-max}") - private String filesizeMax; - - @Value("${files.docservice.url.site}") - private String docserviceUrlSite; - - @Value("${files.docservice.url.command}") - private String docserviceUrlCommand; - - @Autowired - private FileUtility fileUtility; - @Autowired - private DocumentManager documentManager; - @Autowired - private JwtManager jwtManager; - @Autowired - private FileStorageMutator storageMutator; - @Autowired - private FileStoragePathBuilder storagePathBuilder; - @Autowired - private UserServices userService; - @Autowired - private CallbackHandler callbackHandler; - @Autowired - private ObjectMapper objectMapper; - @Autowired - private ServiceConverter serviceConverter; - @Autowired - private CallbackManager callbackManager; - - // create user metadata - private String createUserMetadata(final String uid, final String fullFileName) { - Optional optionalUser = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID - String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase(); // get document type - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - storageMutator.createMeta(fullFileName, // create meta information with the user ID and name specified - String.valueOf(user.getId()), user.getName()); - } - return "{ \"filename\": \"" + fullFileName + "\", \"documentType\": \"" + documentType + "\" }"; - } - - // download data from the specified file - private ResponseEntity downloadFile(final String fileName) { - Resource resource = storageMutator.loadFileAsResource(fileName); // load the specified file as a resource - String contentType = "application/octet-stream"; - - // create a response with the content type, header and body with the file data - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(contentType)) - .header(HttpHeaders.CONTENT_DISPOSITION, - "attachment; filename=\"" + resource.getFilename() + "\"") - .body(resource); - } - - // download data from the specified history file - private ResponseEntity downloadFileHistory(final String fileName, - final String version, - final String file) { - - // load the specified file as a resource - Resource resource = storageMutator.loadFileAsResourceHistory(fileName, version, file); - String contentType = "application/octet-stream"; - - // create a response with the content type, header and body with the file data - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(contentType)) - .header(HttpHeaders.CONTENT_DISPOSITION, - "attachment; filename=\"" + resource.getFilename() + "\"") - .body(resource); - } - - @PostMapping("/upload") - @ResponseBody - public String upload(@RequestParam("file") final MultipartFile file, // upload a file - @CookieValue("uid") final String uid) { - try { - String fullFileName = file.getOriginalFilename(); // get file name - String fileExtension = fileUtility.getFileExtension(fullFileName); // get file extension - long fileSize = file.getSize(); // get file size - byte[] bytes = file.getBytes(); // get file in bytes - - // check if the file size exceeds the maximum file size or is less than 0 - if (fileUtility.getMaxFileSize() < fileSize || fileSize <= 0) { - return "{ \"error\": \"File size is incorrect\"}"; // if so, write an error message to the response - } - - // check if file extension is supported by the editor - if (!fileUtility.getFileExts().contains(fileExtension)) { - - // if not, write an error message to the response - return "{ \"error\": \"File type is not supported\"}"; - } - - String fileNamePath = storageMutator.updateFile(fullFileName, bytes); // update a file - if (fileNamePath.isBlank()) { - throw new IOException("Could not update a file"); // if the file cannot be updated, an error occurs - } - - fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath) + fileExtension; // get full file name - - return createUserMetadata(uid, fullFileName); // create user metadata and return it - } catch (Exception e) { - e.printStackTrace(); - } - - // if the operation of file uploading is unsuccessful, an error occurs - return "{ \"error\": \"Something went wrong when uploading the file.\"}"; - } - - @PostMapping(path = "${url.converter}") - @ResponseBody - public String convert(@RequestBody final Converter body, // convert a file - @CookieValue("uid") final String uid, @CookieValue("ulang") final String lang) { - // get file name - String fileName = body.getFileName(); - - // get URL for downloading a file with the specified name - String fileUri = documentManager.getDownloadUrl(fileName, true); - - // get file password if it exists - String filePass = body.getFilePass() != null ? body.getFilePass() : null; - - // get file extension - String fileExt = fileUtility.getFileExtension(fileName); - - // get document type (word, cell or slide) - DocumentType type = fileUtility.getDocumentType(fileName); - - // convert to .ooxml - String internalFileExt = "ooxml"; - - try { - // check if the file with such an extension can be converted - if (fileUtility.getConvertExts().contains(fileExt)) { - String key = serviceConverter.generateRevisionId(fileUri); // generate document key - ConvertedData response = serviceConverter // get the URL to the converted file - .getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang); - - String newFileUri = response.getUri(); - String newFileType = "." + response.getFileType(); - - if (newFileUri.isEmpty()) { - return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}"; - } - - /* get a file name of an internal file extension with an index if the file - with such a name already exists */ - String nameWithInternalExt = fileUtility.getFileNameWithoutExtension(fileName) + newFileType; - String correctedName = documentManager.getCorrectName(nameWithInternalExt); - - URL url = new URL(newFileUri); - java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); - InputStream stream = connection.getInputStream(); // get input stream of the converted file - - if (stream == null) { - connection.disconnect(); - throw new RuntimeException("Input stream is null"); - } - - // remove source file - storageMutator.deleteFile(fileName); - - // create the converted file with input stream - storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream); - fileName = correctedName; - } - - // create meta information about the converted file with the user ID and name specified - return createUserMetadata(uid, fileName); - } catch (Exception e) { - e.printStackTrace(); - } - // if the operation of file converting is unsuccessful, an error occurs - return "{ \"error\": \"" + "The file can't be converted.\"}"; - } - - @PostMapping("/delete") - @ResponseBody - public String delete(@RequestBody final Converter body) { // delete a file - try { - String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name - - // delete a file from the storage and return the status of this operation (true or false) - boolean fileSuccess = storageMutator.deleteFile(fullFileName); - - // delete file history and return the status of this operation (true or false) - boolean historySuccess = storageMutator.deleteFileHistory(fullFileName); - - return "{ \"success\": \"" + (fileSuccess && historySuccess) + "\"}"; - } catch (Exception e) { - // if the operation of file deleting is unsuccessful, an error occurs - return "{ \"error\": \"" + e.getMessage() + "\"}"; - } - } - - @GetMapping("/downloadhistory") - public ResponseEntity downloadHistory(final HttpServletRequest request, // download a file - @RequestParam("fileName") final String fileName, - @RequestParam("ver") final String version, - @RequestParam("file") final String file) { // history file - try { - // check if a token is enabled or not - if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) { - String header = request.getHeader(documentJwtHeader == null // get the document JWT header - || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); - if (header != null && !header.isEmpty()) { - String token = header - .replace("Bearer ", ""); // token is the header without the Bearer prefix - jwtManager.readToken(token); // read the token - } else { - return null; - } - } - return downloadFileHistory(fileName, version, file); // download data from the specified file - } catch (Exception e) { - return null; - } - } - - @GetMapping(path = "${url.download}") - public ResponseEntity download(final HttpServletRequest request, // download a file - @RequestParam("fileName") final String fileName, - @RequestParam(value = "userAddress", required = false) - final String userAddress) { - try { - // check if a token is enabled or not - if (jwtManager.tokenEnabled() && userAddress != null && jwtManager.tokenUseForRequest()) { - String header = request.getHeader(documentJwtHeader == null // get the document JWT header - || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); - if (header != null && !header.isEmpty()) { - String token = header - .replace("Bearer ", ""); // token is the header without the Bearer prefix - jwtManager.readToken(token); // read the token - } else { - return null; - } - } - return downloadFile(fileName); // download data from the specified file - } catch (Exception e) { - return null; - } - } - - @GetMapping("/create") - public String create(@RequestParam("fileExt") - final String fileExt, // create a sample file of the specified extension - @RequestParam(value = "sample", required = false) final Optional isSample, - @CookieValue(value = "uid", required = false) final String uid, - final Model model) { - // specify if the sample data exists or not - Boolean sampleData = (isSample.isPresent() && !isSample.isEmpty()) && isSample.get(); - if (fileExt != null) { - try { - Optional user = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID - if (!user.isPresent()) { - // if the user with the specified ID doesn't exist, an error occurs - throw new RuntimeException("Could not fine any user with id = " + uid); - } - String fileName = documentManager.createDemo(fileExt, - sampleData, - uid, - user.get().getName()); // create a demo document with the sample data - if (fileName.isBlank() || fileName == null) { - throw new RuntimeException("You must have forgotten to add asset files"); - } - return "redirect:editor?fileName=" + URLEncoder - .encode(fileName, StandardCharsets.UTF_8); // redirect the request - } catch (Exception ex) { - model.addAttribute("error", ex.getMessage()); - return "error.html"; - } - } - return "redirect:/"; - } - - @GetMapping("/assets") - public ResponseEntity assets(@RequestParam("name") - final String name) { // get sample files from the assests - String fileName = Path.of("assets", "document-templates", "sample", fileUtility.getFileName(name)).toString(); - return downloadFile(fileName); - } - - @GetMapping("/csv") - public ResponseEntity csv() { // download a csv file - String fileName = Path.of("assets", "document-templates", "sample", "csv.csv").toString(); - return downloadFile(fileName); - } - - @GetMapping("/files") - @ResponseBody - public ArrayList> files(@RequestParam(value = "fileId", required = false) - final String fileId) { // get files information - return fileId == null ? documentManager.getFilesInfo() : documentManager.getFilesInfo(fileId); - } - - @PostMapping(path = "${url.track}") - @ResponseBody - public String track(final HttpServletRequest request, // track file changes - @RequestParam("fileName") final String fileName, - @RequestParam("userAddress") final String userAddress, - @RequestBody final Track body) { - Track track; - try { - String bodyString = objectMapper - .writeValueAsString(body); // write the request body to the object mapper as a string - String header = request.getHeader(documentJwtHeader == null // get the request header - || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); - - if (bodyString.isEmpty()) { // if the request body is empty, an error occurs - throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}"); - } - - JSONObject bodyCheck = jwtManager.parseBody(bodyString, header); // parse the request body - track = objectMapper.readValue(bodyCheck.toJSONString(), Track.class); // read the request body - } catch (Exception e) { - e.printStackTrace(); - return e.getMessage(); - } - - int error = callbackHandler.handle(track, fileName); - - return "{\"error\":" + error + "}"; - } - - @PostMapping("/saveas") - @ResponseBody - public String saveAs(@RequestBody final JSONObject body, @CookieValue("uid") final String uid) { - String title = (String) body.get("title"); - String saveAsFileUrl = (String) body.get("url"); - - try { - String fileName = documentManager.getCorrectName(title); - String curExt = fileUtility.getFileExtension(fileName); - - if (!fileUtility.getFileExts().contains(curExt)) { - return "{\"error\":\"File type is not supported\"}"; - } - - URL url = new URL(saveAsFileUrl); - java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); - InputStream stream = connection.getInputStream(); - - if (Integer.parseInt(filesizeMax) < stream.available() || stream.available() <= 0) { - return "{\"error\":\"File size is incorrect\"}"; - } - storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream); - createUserMetadata(uid, fileName); - - return "{\"file\": \"" + fileName + "\"}"; - } catch (IOException e) { - e.printStackTrace(); - return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}"; - } - } - - @PostMapping("/rename") - @ResponseBody - public String rename(@RequestBody final JSONObject body) { - String newfilename = (String) body.get("newfilename"); - String dockey = (String) body.get("dockey"); - String origExt = "." + (String) body.get("ext"); - String curExt = newfilename; - - if (newfilename.indexOf(".") != -1) { - curExt = (String) fileUtility.getFileExtension(newfilename); - } - - if (origExt.compareTo(curExt) != 0) { - newfilename += origExt; - } - - HashMap meta = new HashMap<>(); - meta.put("title", newfilename); - - try { - callbackManager.commandRequest("meta", dockey, meta); - return "result ok"; - } catch (Exception e) { - e.printStackTrace(); - return e.getMessage(); - } - } - - @PostMapping("/reference") - @ResponseBody - public String reference(@RequestBody final JSONObject body) { - try { - JSONParser parser = new JSONParser(); - Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - - String userAddress = ""; - String fileName = ""; - - if (body.containsKey("referenceData")) { - LinkedHashMap referenceDataObj = (LinkedHashMap) body.get("referenceData"); - String instanceId = (String) referenceDataObj.get("instanceId"); - - if (instanceId.equals(storagePathBuilder.getServerUrl(false))) { - JSONObject fileKey = (JSONObject) parser.parse((String) referenceDataObj.get("fileKey")); - userAddress = (String) fileKey.get("userAddress"); - if (userAddress.equals(InetAddress.getLocalHost().getHostAddress())) { - fileName = (String) fileKey.get("fileName"); - } - } - } - - - if (fileName.equals("")) { - try { - String path = (String) body.get("path"); - path = fileUtility.getFileName(path); - File f = new File(storagePathBuilder.getFileLocation(path)); - if (f.exists()) { - fileName = path; - } - } catch (Exception e) { - return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}"; - } - } - - if (fileName.equals("")) { - return "{ \"error\": \"File not found\"}"; - } - - boolean directUrl = (boolean) body.get("directUrl"); - - HashMap fileKey = new HashMap<>(); - fileKey.put("fileName", fileName); - fileKey.put("userAddress", InetAddress.getLocalHost().getHostAddress()); - - HashMap referenceData = new HashMap<>(); - referenceData.put("instanceId", storagePathBuilder.getServerUrl(true)); - referenceData.put("fileKey", gson.toJson(fileKey)); - - HashMap data = new HashMap<>(); - data.put("fileType", fileUtility.getFileExtension(fileName).replace(".", "")); - data.put("url", documentManager.getDownloadUrl(fileName, true)); - data.put("directUrl", directUrl ? documentManager.getDownloadUrl(fileName, false) : null); - data.put("referenceData", referenceData); - data.put("path", fileName); - - if (jwtManager.tokenEnabled()) { - String token = jwtManager.createToken(data); - data.put("token", token); - } - return gson.toJson(data); - } catch (Exception e) { - e.printStackTrace(); - return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}"; - } - } - - @PutMapping("/restore") - @ResponseBody - public String restore(@RequestBody final JSONObject body) { - try { - String sourceBasename = (String) body.get("fileName"); - Integer version = (Integer) body.get("version"); - String userID = (String) body.get("userId"); - - String sourceStringFile = storagePathBuilder.getFileLocation(sourceBasename); - File sourceFile = new File(sourceStringFile); - Path sourcePathFile = sourceFile.toPath(); - String historyDirectory = storagePathBuilder.getHistoryDir(sourcePathFile.toString()); - - Integer bumpedVersion = storagePathBuilder.getFileVersion(historyDirectory, false); - String bumpedVersionStringDirectory = documentManager.versionDir(historyDirectory, bumpedVersion, true); - File bumpedVersionDirectory = new File(bumpedVersionStringDirectory); - if (!bumpedVersionDirectory.exists()) { - bumpedVersionDirectory.mkdir(); - } - - Path bumpedKeyPathFile = Paths.get(bumpedVersionStringDirectory, "key.txt"); - String bumpedKeyStringFile = bumpedKeyPathFile.toString(); - File bumpedKeyFile = new File(bumpedKeyStringFile); - String bumpedKey = serviceConverter.generateRevisionId( - storagePathBuilder.getStorageLocation() - + "/" - + sourceBasename - + "/" - + Long.toString(sourceFile.lastModified()) - ); - FileWriter bumpedKeyFileWriter = new FileWriter(bumpedKeyFile); - bumpedKeyFileWriter.write(bumpedKey); - bumpedKeyFileWriter.close(); - - Integer userInnerID = Integer.parseInt(userID.replace("uid-", "")); - User user = userService.findUserById(userInnerID).get(); - - Path bumpedChangesPathFile = Paths.get(bumpedVersionStringDirectory, "changes.json"); - String bumpedChangesStringFile = bumpedChangesPathFile.toString(); - File bumpedChangesFile = new File(bumpedChangesStringFile); - JSONObject bumpedChangesUser = new JSONObject(); - // Don't add the `uid-` prefix. - // https://github.com/ONLYOFFICE/document-server-integration/issues/437#issuecomment-1663526562 - bumpedChangesUser.put("id", user.getId()); - bumpedChangesUser.put("name", user.getName()); - JSONObject bumpedChangesChangesItem = new JSONObject(); - bumpedChangesChangesItem.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); - bumpedChangesChangesItem.put("user", bumpedChangesUser); - JSONArray bumpedChangesChanges = new JSONArray(); - bumpedChangesChanges.add(bumpedChangesChangesItem); - JSONObject bumpedChanges = new JSONObject(); - bumpedChanges.put("serverVersion", null); - bumpedChanges.put("changes", bumpedChangesChanges); - String bumpedChangesContent = bumpedChanges.toJSONString(); - FileWriter bumpedChangesFileWriter = new FileWriter(bumpedChangesFile); - bumpedChangesFileWriter.write(bumpedChangesContent); - bumpedChangesFileWriter.close(); - - String sourceExtension = fileUtility.getFileExtension(sourceBasename); - String previousBasename = "prev" + sourceExtension; - - Path bumpedFile = Paths.get(bumpedVersionStringDirectory, previousBasename); - Files.move(sourcePathFile, bumpedFile); - - String recoveryVersionStringDirectory = documentManager.versionDir(historyDirectory, version, true); - Path recoveryPathFile = Paths.get(recoveryVersionStringDirectory, previousBasename); - String recoveryStringFile = recoveryPathFile.toString(); - FileInputStream recoveryStream = new FileInputStream(recoveryStringFile); - storageMutator.createFile(sourcePathFile, recoveryStream); - recoveryStream.close(); - - JSONObject responseBody = new JSONObject(); - responseBody.put("error", null); - responseBody.put("success", true); - return responseBody.toJSONString(); - } catch (Exception error) { - error.printStackTrace(); - JSONObject responseBody = new JSONObject(); - responseBody.put("error", error.getMessage()); - responseBody.put("success", false); - return responseBody.toJSONString(); - } - } -} diff --git a/src/main/java/com/onlyoffice/integration/controllers/IndexController.java b/src/main/java/com/onlyoffice/integration/controllers/IndexController.java deleted file mode 100644 index 1088ead..0000000 --- a/src/main/java/com/onlyoffice/integration/controllers/IndexController.java +++ /dev/null @@ -1,147 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.controllers; - -import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.documentserver.util.Misc; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import com.onlyoffice.integration.entities.User; -import com.onlyoffice.integration.services.UserServices; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@CrossOrigin("*") -@Controller -public class IndexController { - - @Autowired - private FileStorageMutator storageMutator; - - @Autowired - private FileStoragePathBuilder storagePathBuilder; - - @Autowired - private FileUtility fileUtility; - - @Autowired - private Misc mistUtility; - - @Autowired - private UserServices userService; - - @Value("${files.docservice.url.site}") - private String docserviceSite; - - @Value("${files.docservice.url.preloader}") - private String docservicePreloader; - - @Value("${url.converter}") - private String urlConverter; - - @Value("${url.editor}") - private String urlEditor; - - @Value("${files.docservice.languages}") - private String langs; - - @GetMapping("${url.index}") - public String index(@RequestParam(value = "directUrl", required = false) final Boolean directUrl, - final Model model) { - java.io.File[] files = storageMutator.getStoredFiles(); // get all the stored files from the storage - List docTypes = new ArrayList<>(); - List filesEditable = new ArrayList<>(); - List versions = new ArrayList<>(); - List isFillFormDoc = new ArrayList<>(); - List langsAndKeys = Arrays.asList(langs.split("\\|")); - - Map languages = new LinkedHashMap<>(); - - langsAndKeys.forEach((str) -> { - String[] couple = str.split(":"); - languages.put(couple[0], couple[1]); - }); - - List users = userService.findAll(); // get a list of all the users - - String tooltip = users.stream() // get the tooltip with the user descriptions - .map(user -> mistUtility.convertUserDescriptions(user.getName(), - user.getDescriptions())) // convert user descriptions to the specified format - .collect(Collectors.joining()); - - for (java.io.File file:files) { // run through all the files - String fileName = file.getName(); // get file name - docTypes.add(fileUtility - .getDocumentType(fileName) - .toString() - .toLowerCase()); // add a document type of each file to the list - filesEditable.add(fileUtility.getEditedExts() - .contains(fileUtility.getFileExtension(fileName))); // specify if a file is editable or not - versions.add(" [" + storagePathBuilder. - getFileVersion(fileName, true) + "]"); // add a file version to the list - isFillFormDoc.add(fileUtility.getFillExts().contains(fileUtility.getFileExtension(fileName))); - } - - // add all the parameters to the model - model.addAttribute("isFillFormDoc", isFillFormDoc); - model.addAttribute("versions", versions); - model.addAttribute("files", files); - model.addAttribute("docTypes", docTypes); - model.addAttribute("filesEditable", filesEditable); - model.addAttribute("datadocs", docserviceSite + docservicePreloader); - model.addAttribute("tooltip", tooltip); - model.addAttribute("users", users); - model.addAttribute("languages", languages); - model.addAttribute("directUrl", directUrl); - - return "index.html"; - } - - @PostMapping("/config") - @ResponseBody - public HashMap configParameters() { // get configuration parameters - HashMap configuration = new HashMap<>(); - - configuration.put("FillExtList", String.join(",", fileUtility - .getFillExts())); // put a list of the extensions that can be filled to config - configuration.put("ConverExtList", String.join(",", fileUtility - .getConvertExts())); // put a list of the extensions that can be converted to config - configuration.put("EditedExtList", String.join(",", fileUtility - .getEditedExts())); // put a list of the extensions that can be edited to config - configuration.put("UrlConverter", urlConverter); - configuration.put("UrlEditor", urlEditor); - - return configuration; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java deleted file mode 100644 index 5e5743a..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks; - -import com.onlyoffice.integration.dto.Track; -import org.springframework.beans.factory.annotation.Autowired; - -// specify the callback handler functions -public interface Callback { - int handle(Track body, String fileName); // handle the callback - int getStatus(); // get document status - @Autowired - default void selfRegistration(CallbackHandler callbackHandler) { // register a callback handler - callbackHandler.register(getStatus(), this); - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java deleted file mode 100644 index 3f643ce..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks; - -import com.onlyoffice.integration.dto.Track; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -@Service -public class CallbackHandler { - - private Logger logger = LoggerFactory.getLogger(CallbackHandler.class); - - private Map callbackHandlers = new HashMap<>(); - - public void register(final int code, final Callback callback) { // register a callback handler - callbackHandlers.put(code, callback); - } - - public int handle(final Track body, final String fileName) { // handle a callback - Callback callback = callbackHandlers.get(body.getStatus()); - if (callback == null) { - logger.warn("Callback status " + body.getStatus() + " is not supported yet"); - return 0; - } - - int result = callback.handle(body, fileName); - return result; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java deleted file mode 100644 index dfc27bb..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks; - -// document status -public enum Status { - EDITING(1), // 1 - document is being edited - SAVE(2), // 2 - document is ready for saving - CORRUPTED(3), // 3 - document saving error has occurred - MUST_FORCE_SAVE(6), // 6 - document is being edited, but the current document state is saved - CORRUPTED_FORCE_SAVE(7); // 7 - error has occurred while force saving the document - private int code; - Status(final int codeParam) { - this.code = codeParam; - } - public int getCode() { // get document status - return this.code; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java deleted file mode 100644 index 4f482c7..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks.implementations; - -import com.onlyoffice.integration.documentserver.callbacks.Callback; -import com.onlyoffice.integration.documentserver.callbacks.Status; -import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager; -import com.onlyoffice.integration.dto.Action; -import com.onlyoffice.integration.dto.Track; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class EditCallback implements Callback { - @Autowired - private CallbackManager callbackManager; - @Override - public int handle(final Track body, - final String fileName) { // handle the callback when the document is being edited - int result = 0; - Action action = body.getActions().get(0); // get the user ID who is editing the document - if (action.getType().equals(com.onlyoffice.integration.documentserver.models.enums - .Action.edit)) { // if this value is not equal to the user ID - String user = action.getUserid(); // get user ID - if (!body.getUsers().contains(user)) { // if this user is not specified in the body - String key = body.getKey(); // get document key - try { - // create a command request to forcibly save the document being edited without closing it - callbackManager.commandRequest("forcesave", key, null); - } catch (Exception e) { - e.printStackTrace(); - result = 1; - } - } - } - return result; - } - - @Override - public int getStatus() { // get document status - return Status.EDITING.getCode(); // return status 1 - document is being edited - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java deleted file mode 100644 index 0aa9c8e..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks.implementations; - -import com.onlyoffice.integration.documentserver.callbacks.Callback; -import com.onlyoffice.integration.documentserver.callbacks.Status; -import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager; -import com.onlyoffice.integration.dto.Track; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class ForcesaveCallback implements Callback { - @Autowired - private CallbackManager callbackManager; - @Override - public int handle(final Track body, - final String fileName) { // handle the callback when the force saving request is performed - int result = 0; - try { - callbackManager.processForceSave(body, fileName); // file force saving process - } catch (Exception ex) { - ex.printStackTrace(); - result = 1; - } - return result; - } - - @Override - public int getStatus() { // get document status - // return status 6 - document is being edited, but the current document state is saved - return Status.MUST_FORCE_SAVE.getCode(); - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java b/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java deleted file mode 100644 index d679761..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.callbacks.implementations; - -import com.onlyoffice.integration.documentserver.callbacks.Callback; -import com.onlyoffice.integration.documentserver.callbacks.Status; -import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager; -import com.onlyoffice.integration.dto.Track; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class SaveCallback implements Callback { - @Autowired - private CallbackManager callbackManager; - @Override - public int handle(final Track body, - final String fileName) { // handle the callback when the saving request is performed - int result = 0; - try { - callbackManager.processSave(body, fileName); // file saving process - } catch (Exception ex) { - ex.printStackTrace(); - result = 1; - } - - return result; - } - - @Override - public int getStatus() { // get document status - return Status.SAVE.getCode(); // return status 2 - document is ready for saving - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/CallbackManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/CallbackManager.java deleted file mode 100644 index e0d3c5d..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/CallbackManager.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.callback; - -import com.onlyoffice.integration.dto.Track; -import java.util.HashMap; - -public interface CallbackManager { // specify the callback manager functions - void processSave(Track body, String fileName); // file saving process - void commandRequest(String method, String key, HashMap meta); // create a command request - void processForceSave(Track body, String fileName); // file force saving process -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/DefaultCallbackManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/DefaultCallbackManager.java deleted file mode 100644 index d1edc0b..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/DefaultCallbackManager.java +++ /dev/null @@ -1,333 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.callback; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.onlyoffice.integration.documentserver.managers.document.DocumentManager; -import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; -import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import com.onlyoffice.integration.dto.Action; -import com.onlyoffice.integration.documentserver.util.service.ServiceConverter; -import com.onlyoffice.integration.dto.Track; -import lombok.SneakyThrows; -import org.json.simple.JSONObject; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Primary; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.onlyoffice.integration.documentserver.util.Constants.FILE_SAVE_TIMEOUT; - -// todo: Refactoring -@Component -@Primary -public class DefaultCallbackManager implements CallbackManager { - - @Value("${files.docservice.url.site}") - private String docserviceUrlSite; - @Value("${files.docservice.url.command}") - private String docserviceUrlCommand; - @Value("${files.docservice.header}") - private String documentJwtHeader; - - @Autowired - private DocumentManager documentManager; - @Autowired - private JwtManager jwtManager; - @Autowired - private FileUtility fileUtility; - @Autowired - private FileStorageMutator storageMutator; - @Autowired - private FileStoragePathBuilder storagePathBuilder; - @Autowired - private ObjectMapper objectMapper; - @Autowired - private ServiceConverter serviceConverter; - - // download file from url - @SneakyThrows - private byte[] getDownloadFile(final String url) { - if (url == null || url.isEmpty()) { - throw new RuntimeException("Url argument is not specified"); // URL isn't specified - } - - URL uri = new URL(url); - java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection(); - connection.setConnectTimeout(FILE_SAVE_TIMEOUT); - InputStream stream = connection.getInputStream(); // get input stream of the file information from the URL - - int statusCode = connection.getResponseCode(); - if (statusCode != HttpStatus.OK.value()) { // checking status code - connection.disconnect(); - throw new RuntimeException("Document editing service returned status: " + statusCode); - } - - if (stream == null) { - connection.disconnect(); - throw new RuntimeException("Input stream is null"); - } - - return stream.readAllBytes(); - } - - // file saving - @SneakyThrows - private void saveFile(final byte[] byteArray, final Path path) { - if (path == null) { - throw new RuntimeException("Path argument is not specified"); // file isn't specified - } - // update a file or create a new one - storageMutator.createOrUpdateFile(path, new ByteArrayInputStream(byteArray)); - } - - @Override - @SneakyThrows - public void processSave(final Track body, final String fileName) { // file saving process - String downloadUri = body.getUrl(); - String changesUri = body.getChangesurl(); - String key = body.getKey(); - String newFileName = fileName; - - String curExt = fileUtility.getFileExtension(fileName); // get current file extension - String downloadExt = "." + body.getFiletype(); // get an extension of the downloaded file - - // todo: Refactoring - // convert downloaded file to the file with the current extension if these extensions aren't equal - if (!curExt.equals(downloadExt)) { - try { - String newFileUri = serviceConverter - .getConvertedData(downloadUri, downloadExt, curExt, - serviceConverter.generateRevisionId(downloadUri), null, false, - null).getUri(); // convert a file and get URL to a new file - if (newFileUri.isEmpty()) { - newFileName = documentManager - .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) - + downloadExt); // get the correct file name if it already exists - } else { - downloadUri = newFileUri; - } - } catch (Exception e) { - newFileName = documentManager - .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); - } - } - - byte[] byteArrayFile = getDownloadFile(downloadUri); // download document file - - String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file - Path lastVersion = Paths.get(storagePathBuilder - .getFileLocation(fileName)); // get the path to the last file version - - if (lastVersion.toFile().exists()) { // if the last file version exists - Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath)); // get the history directory - storageMutator.createDirectory(histDir); // and create it - - String versionDir = documentManager - .versionDir(histDir.toAbsolutePath().toString(), // get the file version directory - storagePathBuilder - .getFileVersion(histDir.toAbsolutePath().toString(), false), true); - - Path ver = Paths.get(versionDir); - Path toSave = Paths.get(storagePath); - - storageMutator.createDirectory(ver); // create the file version directory - - lastVersion.toFile().renameTo(new File(versionDir + File.separator + "prev" + curExt)); - - saveFile(byteArrayFile, toSave); // save document file - - byte[] byteArrayChanges = getDownloadFile(changesUri); // download file changes - saveFile(byteArrayChanges, Path - .of(versionDir + File.separator + "diff.zip")); // save file changes to the diff.zip archive - - JSONObject jsonChanges = new JSONObject(); // create a json object for document changes - jsonChanges.put("changes", body.getHistory().getChanges()); // put the changes to the json object - jsonChanges.put("serverVersion", body.getHistory() - .getServerVersion()); // put the server version to the json object - String history = objectMapper.writeValueAsString(jsonChanges); - - if (history == null && body.getHistory() != null) { - history = objectMapper.writeValueAsString(body.getHistory()); - } - - if (history != null && !history.isEmpty()) { - // write the history changes to the changes.json file - storageMutator.writeToFile(versionDir + File.separator + "changes.json", history); - } - - // write the key value to the key.txt file - storageMutator.writeToFile(versionDir + File.separator + "key.txt", key); - - // get the path to the forcesaved file version and remove it - storageMutator.deleteFile(storagePathBuilder.getForcesavePath(newFileName, false)); - } - } - - // todo: Replace (String method) with (Enum method) - @SneakyThrows - public void commandRequest(final String method, - final String key, - final HashMap meta) { // create a command request - String documentCommandUrl = docserviceUrlSite + docserviceUrlCommand; - - URL url = new URL(documentCommandUrl); - java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); - - HashMap params = new HashMap(); - params.put("c", method); - params.put("key", key); - - if (meta != null) { - params.put("meta", meta); - } - - String headerToken; - // check if a secret key to generate token exists or not - if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) { - Map payloadMap = new HashMap<>(); - payloadMap.put("payload", params); - headerToken = jwtManager.createToken(payloadMap); // encode a payload object into a header token - - // add a header Authorization with a header token and Authorization prefix in it - connection.setRequestProperty(documentJwtHeader.equals("") - ? "Authorization" : documentJwtHeader, "Bearer " + headerToken); - - String token = jwtManager.createToken(params); // encode a payload object into a body token - params.put("token", token); - } - - String bodyString = objectMapper.writeValueAsString(params); - - byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8); - - connection.setRequestMethod("POST"); // set the request method - connection - .setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // set the Content-Type header - connection.setDoOutput(true); // set the doOutput field to true - connection.connect(); - - try (OutputStream os = connection.getOutputStream()) { - os.write(bodyByte); // write bytes to the output stream - } - - InputStream stream = connection.getInputStream(); // get input stream - - if (stream == null) { - throw new RuntimeException("Could not get an answer"); - } - - String jsonString = serviceConverter.convertStreamToString(stream); // convert stream to json string - connection.disconnect(); - - JSONObject response = serviceConverter.convertStringToJSON(jsonString); // convert json string to json object - // todo: Add errors ENUM - String responseCode = response.get("error").toString(); - switch (responseCode) { - case "0": - case "4": - break; - default: - throw new RuntimeException(response.toJSONString()); - } - } - - @SneakyThrows - public void processForceSave(final Track body, final String fileNameParam) { // file force saving process - - String downloadUri = body.getUrl(); - String fileName = fileNameParam; - - String curExt = fileUtility.getFileExtension(fileName); // get current file extension - String downloadExt = "." + body.getFiletype(); // get an extension of the downloaded file - - Boolean newFileName = false; - - // convert downloaded file to the file with the current extension if these extensions aren't equal - // todo: Extract function - if (!curExt.equals(downloadExt)) { - try { - // convert file and get URL to a new file - String newFileUri = serviceConverter - .getConvertedData(downloadUri, downloadExt, curExt, serviceConverter - .generateRevisionId(downloadUri), null, false, null).getUri(); - if (newFileUri.isEmpty()) { - newFileName = true; - } else { - downloadUri = newFileUri; - } - } catch (Exception e) { - newFileName = true; - } - } - - byte[] byteArrayFile = getDownloadFile(downloadUri); // download document file - String forcesavePath = ""; - - // todo: Use ENUMS - // todo: Pointless toString conversion - boolean isSubmitForm = body.getForcesavetype().toString().equals("3"); - - // todo: Extract function - if (isSubmitForm) { // if the form is submitted - if (newFileName) { - // get the correct file name if it already exists - fileName = documentManager - .getCorrectName(fileUtility - .getFileNameWithoutExtension(fileName) + "-form" + downloadExt); - } else { - fileName = documentManager - .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form" + curExt); - } - forcesavePath = storagePathBuilder.getFileLocation(fileName); // create forcesave path if it doesn't exist - List actions = body.getActions(); - Action action = actions.get(0); - String user = action.getUserid(); // get the user ID - // create meta data for the forcesaved file - storageMutator.createMeta(fileName, user, "Filling Form"); - } else { - if (newFileName) { - fileName = documentManager - .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); - } - - forcesavePath = storagePathBuilder.getForcesavePath(fileName, false); - if (forcesavePath.isEmpty()) { - forcesavePath = storagePathBuilder.getForcesavePath(fileName, true); - } - } - - saveFile(byteArrayFile, Path.of(forcesavePath)); - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java deleted file mode 100644 index 1baecb4..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java +++ /dev/null @@ -1,246 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.document; - -import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import com.onlyoffice.integration.documentserver.util.service.ServiceConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.net.InetAddress; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; - -import static com.onlyoffice.integration.documentserver.util.Constants.KILOBYTE_SIZE; - -@Component -@Primary -public class DefaultDocumentManager implements DocumentManager { - - @Value("${files.storage.folder}") - private String storageFolder; - @Value("${files.storage}") - private String filesStorage; - @Value("${url.track}") - private String trackUrl; - @Value("${url.download}") - private String downloadUrl; - - @Autowired - private FileStorageMutator storageMutator; - @Autowired - private FileStoragePathBuilder storagePathBuilder; - @Autowired - private FileUtility fileUtility; - @Autowired - private ServiceConverter serviceConverter; - - // get URL to the created file - public String getCreateUrl(final String fileName, final Boolean sample) { - String fileExt = fileUtility.getFileExtension(fileName).replace(".", ""); - String url = storagePathBuilder.getServerUrl(true) - + "/create?fileExt=" + fileExt + "&sample=" + sample; - return url; - } - - // get a file name with an index if the file with such a name already exists - public String getCorrectName(final String fileName) { - String baseName = fileUtility.getFileNameWithoutExtension(fileName); // get file name without extension - String ext = fileUtility.getFileExtension(fileName); // get file extension - String name = baseName + ext; // create a full file name - - Path path = Paths.get(storagePathBuilder.getFileLocation(name)); - - // run through all the files with such a name in the storage directory - for (int i = 1; Files.exists(path); i++) { - name = baseName + " (" + i + ")" + ext; // and add an index to the base name - path = Paths.get(storagePathBuilder.getFileLocation(name)); - } - - return name; - } - - // get file URL - public String getFileUri(final String fileName, final Boolean forDocumentServer) { - try { - String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL - String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory - String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName - : fileName.substring(fileName.indexOf(InetAddress.getLocalHost() - .getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1); - if (!filesStorage.isEmpty() && filePathDownload.contains(filesStorage)) { - filePathDownload = filePathDownload.substring(filesStorage.length() + 1); - } - - String filePath = serverPath + "/download?fileName=" + URLEncoder - .encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString()) + "&userAddress" - + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()); - return filePath; - } catch (UnsupportedEncodingException | UnknownHostException e) { - return ""; - } - } - - // get file URL - public String getHistoryFileUrl(final String fileName, final Integer version, final String file, - final Boolean forDocumentServer) { - try { - String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL - String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory - String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName - : fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress()) - + InetAddress.getLocalHost().getHostAddress().length() + 1); - String userAddress = forDocumentServer ? "&userAddress" + URLEncoder - .encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : ""; - String filePath = serverPath + "/downloadhistory?fileName=" + URLEncoder - .encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString()) - + "&ver=" + version + "&file=" + file - + userAddress; - return filePath; - } catch (UnsupportedEncodingException | UnknownHostException e) { - return ""; - } - } - - // get the callback URL - public String getCallback(final String fileName) { - String serverPath = storagePathBuilder.getServerUrl(true); - String storageAddress = storagePathBuilder.getStorageLocation(); - try { - String query = trackUrl + "?fileName=" - + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) - + "&userAddress=" + URLEncoder - .encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()); - return serverPath + query; - } catch (UnsupportedEncodingException e) { - return ""; - } - } - - // get URL to download a file - public String getDownloadUrl(final String fileName, final Boolean isServer) { - String serverPath = storagePathBuilder.getServerUrl(isServer); - String storageAddress = storagePathBuilder.getStorageLocation(); - try { - String userAddress = isServer ? "&userAddress=" + URLEncoder - .encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : ""; - String query = downloadUrl + "?fileName=" - + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) - + userAddress; - - return serverPath + query; - } catch (UnsupportedEncodingException e) { - return ""; - } - } - - // get file information - public ArrayList> getFilesInfo() { - ArrayList> files = new ArrayList<>(); - - // run through all the stored files - for (File file : storageMutator.getStoredFiles()) { - Map map = new LinkedHashMap<>(); // write all the parameters to the map - map.put("version", storagePathBuilder.getFileVersion(file.getName(), false)); - map.put("id", serviceConverter - .generateRevisionId(storagePathBuilder.getStorageLocation() - + "/" + file.getName() + "/" - + Paths.get(storagePathBuilder.getFileLocation(file.getName())) - .toFile() - .lastModified())); - map.put("contentLength", new BigDecimal(String.valueOf((file.length() / Double.valueOf(KILOBYTE_SIZE)))) - .setScale(2, RoundingMode.HALF_UP) + " KB"); - map.put("pureContentLength", file.length()); - map.put("title", file.getName()); - map.put("updated", String.valueOf(new Date(file.lastModified()))); - files.add(map); - } - - return files; - } - - // get file information by its ID - public ArrayList> getFilesInfo(final String fileId) { - ArrayList> file = new ArrayList<>(); - - for (Map map : getFilesInfo()) { - if (map.get("id").equals(fileId)) { - file.add(map); - break; - } - } - - return file; - } - - // get the path to the file version by the history path and file version - public String versionDir(final String path, final Integer version, final boolean historyPath) { - if (!historyPath) { - return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version; - } - return path + File.separator + version; - } - - // create demo document - public String createDemo(final String fileExt, final Boolean sample, final String uid, final String uname) { - String demoName = (sample ? "sample." : "new.") - + fileExt; // create sample or new template file with the necessary extension - String demoPath = - "assets" - + File.separator - + "document-templates" - + File.separator - + (sample ? "sample" : "new") - + File.separator - + demoName; - - // get a file name with an index if the file with such a name already exists - String fileName = getCorrectName(demoName); - - InputStream stream = Thread.currentThread() - .getContextClassLoader() - .getResourceAsStream(demoPath); // get the input file stream - - if (stream == null) { - return null; - } - - storageMutator.createFile(Path.of(storagePathBuilder - .getFileLocation(fileName)), stream); // create a file in the specified directory - storageMutator.createMeta(fileName, uid, uname); // create meta information of the demo file - - return fileName; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java deleted file mode 100644 index 6b8eb25..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.document; - -import java.util.ArrayList; -import java.util.Map; - -// specify the document manager functions -public interface DocumentManager { - - // get a file name with an index if the file with such a name already exists - String getCorrectName(String fileName); - String getFileUri(String fileName, Boolean forDocumentServer); // get file URL - String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer); // get file URL - String getCallback(String fileName); // get the callback URL - String getDownloadUrl(String fileName, Boolean forDocumentServer); // get URL to download a file - ArrayList> getFilesInfo(); // get file information - ArrayList> getFilesInfo(String fileId); // get file information by its ID - - // get the path to the file version by the history path and file version - String versionDir(String path, Integer version, boolean historyPath); - - // create demo document - String createDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception; - String getCreateUrl(String fileName, Boolean sample); // get URL to the created file -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/history/DefaultHistoryManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/history/DefaultHistoryManager.java deleted file mode 100644 index 2511246..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/history/DefaultHistoryManager.java +++ /dev/null @@ -1,183 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.history; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.onlyoffice.integration.documentserver.managers.document.DocumentManager; -import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; -import com.onlyoffice.integration.documentserver.models.filemodel.Document; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import lombok.SneakyThrows; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; - -// todo: Rebuild completely -@Component -public class DefaultHistoryManager implements HistoryManager { - - @Autowired - private FileStoragePathBuilder storagePathBuilder; - - @Autowired - private DocumentManager documentManager; - - @Autowired - private JwtManager jwtManager; - - @Autowired - private FileUtility fileUtility; - - @Autowired - private JSONParser parser; - - @Autowired - private ObjectMapper objectMapper; - - // todo: Refactoring - @SneakyThrows - public String[] getHistory(final Document document) { // get document history - - // get history directory - String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle())); - Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version - - if (curVer > 0) { // check if the current file version is greater than 0 - List hist = new ArrayList<>(); - Map histData = new HashMap<>(); - - for (Integer i = 1; i <= curVer; i++) { // run through all the file versions - Map obj = new HashMap(); - Map dataObj = new HashMap(); - String verDir = documentManager - .versionDir(histDir, i, true); // get the path to the given file version - - String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir - + File.separator + "key.txt")); // get document key - obj.put("key", key); - obj.put("version", i); - - if (i == 1) { // check if the version number is equal to 1 - String createdInfo = readFileToEnd(new File(histDir - + File.separator + "createdInfo.json")); // get file with meta data - JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object - - // write meta information to the object (user information and creation date) - obj.put("created", json.get("created")); - Map user = new HashMap(); - user.put("id", json.get("id")); - user.put("name", json.get("name")); - obj.put("user", user); - } - - dataObj.put("fileType", fileUtility - .getFileExtension(document.getTitle()).replace(".", "")); - dataObj.put("key", key); - dataObj.put("url", i == curVer ? document.getUrl() - : documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility - .getFileExtension(document.getTitle()), true)); - if (!document.getDirectUrl().equals("")) { - dataObj.put("directUrl", i == curVer ? document.getDirectUrl() - : documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility - .getFileExtension(document.getTitle()), false)); - } - dataObj.put("version", i); - - if (i > 1) { //check if the version number is greater than 1 - // if so, get the path to the changes.json file - JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(documentManager - .versionDir(histDir, i - 1, true) + File.separator + "changes.json"))); - JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0); - - // write information about changes to the object - obj.put("changes", changes.get("changes")); - obj.put("serverVersion", changes.get("serverVersion")); - obj.put("created", change.get("created")); - obj.put("user", change.get("user")); - - // get the history data from the previous file version - Map prev = (Map) histData.get(Integer.toString(i - 2)); - Map prevInfo = new HashMap(); - prevInfo.put("fileType", prev.get("fileType")); - prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version - prevInfo.put("url", prev.get("url")); - if (!document.getDirectUrl().equals("")) { - prevInfo.put("directUrl", prev.get("directUrl")); - } - - // write information about previous file version to the data object - dataObj.put("previous", prevInfo); - // write the path to the diff.zip archive with differences in this file version - Integer verdiff = i - 1; - dataObj.put("changesUrl", documentManager - .getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true)); - } - - if (jwtManager.tokenEnabled()) { - dataObj.put("token", jwtManager.createToken(dataObj)); - } - - hist.add(obj); - histData.put(Integer.toString(i - 1), dataObj); - } - - // write history information about the current file version to the history object - Map histObj = new HashMap(); - histObj.put("currentVersion", curVer); - histObj.put("history", hist); - - try { - return new String[]{objectMapper.writeValueAsString(histObj), - objectMapper.writeValueAsString(histData)}; - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } - return new String[]{"", ""}; - } - - // read a file - private String readFileToEnd(final File file) { - String output = ""; - try { - try (FileInputStream is = new FileInputStream(file)) { - Scanner scanner = new Scanner(is); // read data from the source - scanner.useDelimiter("\\A"); - while (scanner.hasNext()) { - output += scanner.next(); - } - scanner.close(); - } - } catch (Exception e) { - } - return output; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/history/HistoryManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/history/HistoryManager.java deleted file mode 100644 index 2be05ff..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/history/HistoryManager.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.history; - -import com.onlyoffice.integration.documentserver.models.filemodel.Document; - -// specify the history manager functions -public interface HistoryManager { - String[] getHistory(Document document); // get document history -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java deleted file mode 100644 index a7161d7..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.jwt; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.primeframework.jwt.Signer; -import org.primeframework.jwt.Verifier; -import org.primeframework.jwt.domain.JWT; -import org.primeframework.jwt.hmac.HMACSigner; -import org.primeframework.jwt.hmac.HMACVerifier; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.util.LinkedHashMap; -import java.util.Map; - -@Component -public class DefaultJwtManager implements JwtManager { - @Value("${files.docservice.secret}") - private String tokenSecret; - @Value("${files.docservice.token-use-for-request}") - private String tokenUseForRequest; - @Autowired - private ObjectMapper objectMapper; - @Autowired - private JSONParser parser; - - // create document token - @Override - public String createToken(final Map payloadClaims) { - try { - // build a HMAC signer using a SHA-256 hash - Signer signer = HMACSigner.newSHA256Signer(tokenSecret); - JWT jwt = new JWT(); - for (String key : payloadClaims.keySet()) { // run through all the keys from the payload - jwt.addClaim(key, payloadClaims.get(key)); // and write each claim to the jwt - } - return JWT.getEncoder().encode(jwt, signer); // sign and encode the JWT to a JSON string representation - } catch (Exception e) { - return ""; - } - } - - // check if the token is enabled - @Override - public boolean tokenEnabled() { - return tokenSecret != null && !tokenSecret.isEmpty(); - } - - @Override - public boolean tokenUseForRequest() { - return Boolean.parseBoolean(tokenUseForRequest) && !tokenUseForRequest.isEmpty(); - } - - // read document token - @Override - public JWT readToken(final String token) { - try { - // build a HMAC verifier using the token secret - Verifier verifier = HMACVerifier.newVerifier(tokenSecret); - - // verify and decode the encoded string JWT to a rich object - return JWT.getDecoder().decode(token, verifier); - } catch (Exception exception) { - return null; - } - } - - // parse the body - @Override - public JSONObject parseBody(final String payload, final String header) { - JSONObject body; - try { - Object obj = parser.parse(payload); // get body parameters by parsing the payload - body = (JSONObject) obj; - } catch (Exception ex) { - throw new RuntimeException("{\"error\":1,\"message\":\"JSON Parsing error\"}"); - } - if (tokenEnabled() && tokenUseForRequest()) { // check if the token is enabled - String token = (String) body.get("token"); // get token from the body - if (token == null) { // if token is empty - if (header != null && header.trim()!="") { // and the header is defined - - // get token from the header (it is placed after the Bearer prefix if it exists) - token = header.startsWith("Bearer ") ? header.substring("Bearer ".length()) : header; - } - } - if (token == null || token.trim()=="") { - throw new RuntimeException("{\"error\":1,\"message\":\"JWT expected\"}"); - } - - JWT jwt = readToken(token); // read token - if (jwt == null) { - throw new RuntimeException("{\"error\":1,\"message\":\"JWT validation failed\"}"); - } - if (jwt.getObject("payload") != null) { // get payload from the token and check if it is not empty - try { - @SuppressWarnings("unchecked") LinkedHashMap jwtPayload = - (LinkedHashMap) jwt.getObject("payload"); - - jwt.claims = jwtPayload; - } catch (Exception ex) { - throw new RuntimeException("{\"error\":1,\"message\":\"Wrong payload\"}"); - } - } - try { - Object obj = parser.parse(objectMapper.writeValueAsString(jwt.claims)); - body = (JSONObject) obj; - } catch (Exception ex) { - throw new RuntimeException("{\"error\":1,\"message\":\"Parsing error\"}"); - } - } - - return body; - } -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java deleted file mode 100644 index 78b100d..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.jwt; - -import org.json.simple.JSONObject; -import org.primeframework.jwt.domain.JWT; - -import java.util.Map; - -// specify the jwt manager functions -public interface JwtManager { - boolean tokenEnabled(); // check if the token is enabled - boolean tokenUseForRequest(); // check if the token is enabled - String createToken(Map payloadClaims); // create document token - JWT readToken(String token); // read document token - JSONObject parseBody(String payload, String header); // parse the body -} diff --git a/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java b/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java deleted file mode 100644 index aaff9cb..0000000 --- a/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * - * (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 com.onlyoffice.integration.documentserver.managers.template; - -import com.onlyoffice.integration.documentserver.models.enums.DocumentType; -import com.onlyoffice.integration.documentserver.models.filemodel.Template; -import com.onlyoffice.integration.documentserver.managers.document.DocumentManager; -import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; -import com.onlyoffice.integration.documentserver.util.file.FileUtility; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Component -@Qualifier("sample") -public class SampleTemplateManager implements TemplateManager { - @Autowired - private DocumentManager documentManager; - - @Autowired - private FileStoragePathBuilder storagePathBuilder; - - @Autowired - private FileUtility fileUtility; - - // create a template document with the specified name - public List