最新onlyoffice后端

This commit is contained in:
wangqiong
2024-03-14 09:05:00 +08:00
parent ff6f67a160
commit 7c9681b236
423 changed files with 23054 additions and 17889 deletions
+33
View File
@@ -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/
+95 -169
View File
@@ -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版,应用到您的软件
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.
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
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.
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
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.
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
END OF TERMS AND CONDITIONS
3, 请将如下声明文本放入每个源文件的头部注释中。
APPENDIX: How to apply the Apache License to your work.
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.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Mulan Permissive Software License,Version 2
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
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
http://www.apache.org/licenses/LICENSE-2.0
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
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.
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.
1. Grant of Copyright 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.
+292 -203
View File
@@ -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-onlyOffice(集成onlyOffice服务)
Spring Boot has a lot of functionality, but its most significant features are: dependency management,
auto-configuration, and built-in servlet containers.
springboot集成onlyOffice的实现。在参考网络上的资料结合自身实际情况总结,让集成oo方便快捷。 封装了oo服务的API和统一了配置。
- 在线编辑,查看,转换
**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
* onlyOffice.yml配置文件
* 如果解决了你地方问题,请给个 **star**
-----------------------------------
# 对外使用的java类 —— OnlyServiceAPI
## 核心方法
### Step 1. Install ONLYOFFICE Docs
<table>
<thead>
<tr>
<th>方法名称</th>
<th>参数</th>
<th>参数说明</th>
<th>返回值</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="3">openDocument()</td>
<td> Map&lt;String,Object&gt; map</td>
<td> 文件数据信息<br>
{<br>
必填 fileId<br>
必填 fileName<br>
必填 fileType<br>
必填 fileSize<br>
可用携带其它值<br>
}
</td>
<td rowspan="3">
<pre>
{
"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": ""
}</pre>
</td>
</tr>
<tr>
<td>String mode</td>
<td>打开方式 <br>edit<br>view</td>
</tr>
<tr>
<td>boolean collaborativeEditing</td>
<td>是否协同编辑</td>
</tr>
<tr>
<td>handlerStatus()</td>
<td>JSONObject jsonObject</td>
<td>onlyOffice 回调传来的值。<br>https://api.onlyoffice.com/editors/callback</td>
<td></td>
</tr>
<tr>
<td rowspan="2">save():触发保存回调。</td>
<td>String key</td>
<td>是openDocument()返回值中的key</td>
<td rowspan="2">String : 提示信息</td>
</tr>
<tr>
<td>String userId</td>
<td>用户Id</td>
</tr>
<tr>
<td rowspan="5">converted()</td>
<td>String filetype</td>
<td>文件类型</td>
<td rowspan="5">转换后的文件下载地址</td>
</tr>
<tr>
<td>String fileId</td>
<td>文件Id</td>
</tr>
<tr>
<td>String outputtype</td>
<td>转化类型</td>
</tr>
<tr>
<td>String title</td>
<td>转换后的文件名称</td>
</tr>
<tr>
<td>String password</td>
<td>文档密码</td>
</tr>
</tbody>
</table>
Download and install ONLYOFFICE Docs (packaged as Document Server).
**注意:**
* 外部触发保存操作,save()方法。
* `autosave`/`forcesave` 参数为默认值时有效
* 修改文件后,没有执行回调方法。在点击保存后执行回调
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
![](jpg/f.jpg)
### 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/
``` pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<dependency>
<groupId>com.inversoft</groupId>
<artifactId>prime-jwt</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
```
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:
- 定义关键接口(oo服务回调使用) `重要`
1.保存接口
```
C:\Program Files\Java\jdk11
参考:demo/controller/IndexController.saveFile()
对应配置文件参数:oo.call-back-url
回调状态
0 - 找不到具有密钥标识符的文档
1 - 正在编辑文档(打开文件回调)
2 - 文档已准备好保存
3 - 发生文档保存错误
4 - 不作任何更改就关闭文档(关闭回调)
6 - 正在编辑文档,但保存当前文档状态(保存回调)
7 - 强制保存文档时发生错误
```
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**:
2.下载文件地址
```
echo %JAVA_HOME%
参考:demo/controller/IndexController.download()
对应配置文件参数:oo.download-file
对应openDocument()方法返回值中的 document.url
打开文件后oo服务要下载对应的文件
```
2. Set the **MAVEN_HOME** environment variable:
Unzip the downloaded archive with the maven to any directory, it will be something like this:
- 实现SaveFileProcessor类
```
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%
参考:demo.service.DemoService
```
<table>
<thead>
<tr>
<th> 方法名称 </th>
<th> 方法说明 </th>
<th> 参数 </th>
<th> 参数说明 </th>
<th> 返回值 </th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="3">saveBeforeInitialization()</td>
<td rowspan="3">保存前置方法</td>
<td>Map&lt;String, Object&gt; map</td>
<td>在openDocument()方法中传入的文件数据信息</td>
<td rowspan="3"></td>
</tr>
<tr>
<td>byte[] bytes</td>
<td>文件二进制数据</td>
</tr>
<tr>
<td>String fileExtension</td>
<td>文件后缀</td>
</tr>
<tr>
<td rowspan="4">save()</td>
<td rowspan="4">保存方法,实现自己的保存逻辑</td>
<td>Map&lt;String, Object&gt; map</td>
<td>在openDocument()方法中传入的文件数据信息</td>
<td rowspan="4">Map&lt;String, Object&gt; 更新内存中的信息</td>
</tr>
<tr>
<td>byte[] bytes</td>
<td>文件二进制数据</td>
</tr>
<tr>
<td>byte[] changes</td>
<td>当前文件和保存之前文件的区别。changes.zip</td>
</tr>
<tr>
<td>String key</td>
<td>是openDocument()返回值中的key</td>
</tr>
<tr>
<td rowspan="3">saveAfterInitialization()</td>
<td rowspan="3">保存后置方法</td>
<td>Map&lt;String, Object&gt; map</td>
<td>在openDocument()方法中传入的文件数据信息</td>
<td rowspan="3"></td>
</tr>
<tr>
<td>byte[] bytes</td>
<td>文件二进制数据</td>
</tr>
<tr>
<td>String fileExtension</td>
<td>文件后缀</td>
</tr>
</tbody>
</table>
### 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
```
- [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
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/
```
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
-----------------------------------
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 Docker
# 页面集成
### 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)
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.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

+3
View File
@@ -0,0 +1,3 @@
## Overview
(Linux服务器安装好)把当前文件夹放到路径: /var/www/onlyoffice/documentserver/sdkjs-plugins
+25
View File
@@ -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"
]
}
]
}
+28
View File
@@ -0,0 +1,28 @@
<!--
(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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Listener</title>
<script type="text/javascript" src="../v1/plugins.js"></script>
<script type="text/javascript" src="../v1/plugins-ui.js"></script>
<link rel="stylesheet" href="../v1/plugins.css">
<script type="text/javascript" src="scripts/code.js"></script>
</head>
<body>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+103
View File
@@ -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);
@@ -0,0 +1,3 @@
[
"zh-CN"
]
@@ -0,0 +1,3 @@
{
}
+92 -57
View File
@@ -5,50 +5,71 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.onlyoffice</groupId>
<artifactId>integration</artifactId>
<version>1.0</version>
<name>Java Spring Integration Example</name>
<description>ONLYOFFICE Java Spring Integration</description>
<groupId>com.oo</groupId>
<artifactId>Spring-Boot-onlyOffice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring-Boot-onlyOffice</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.5.1</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<dependency>
<groupId>com.inversoft</groupId>
@@ -56,57 +77,71 @@
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.4</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.2</version>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<logViolationsToConsole>true</logViolationsToConsole>
<violationSeverity>warning</violationSeverity>
<consoleOutput>true</consoleOutput>
<includeTestSourceDirectory>true
</includeTestSourceDirectory>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
@@ -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<String> 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<String> 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<String> 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<String> 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);
}
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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<DefaultFileWrapper> 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<String> 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<User> 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<Mentions> getUserMentions(final String uid) { // get user data for mentions
List<Mentions> usersForMentions = new ArrayList<>();
if (uid != null && !uid.equals("4")) {
List<User> 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<String, Object> 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<String, Object> 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<String, Object> 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);
}
}
@@ -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<User> 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<Resource> 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<Resource> 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<Resource> 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<Resource> 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<Boolean> 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> 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<Resource> 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<Resource> csv() { // download a csv file
String fileName = Path.of("assets", "document-templates", "sample", "csv.csv").toString();
return downloadFile(fileName);
}
@GetMapping("/files")
@ResponseBody
public ArrayList<Map<String, Object>> 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<String, String> meta = new HashMap<>();
meta.put("title", newfilename);
try {
callbackManager.commandRequest("meta", dockey, meta);
return "result ok";
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
@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<String, Object> fileKey = new HashMap<>();
fileKey.put("fileName", fileName);
fileKey.put("userAddress", InetAddress.getLocalHost().getHostAddress());
HashMap<String, Object> referenceData = new HashMap<>();
referenceData.put("instanceId", storagePathBuilder.getServerUrl(true));
referenceData.put("fileKey", gson.toJson(fileKey));
HashMap<String, Object> 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();
}
}
}
@@ -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<String> docTypes = new ArrayList<>();
List<Boolean> filesEditable = new ArrayList<>();
List<String> versions = new ArrayList<>();
List<Boolean> isFillFormDoc = new ArrayList<>();
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
Map<String, String> languages = new LinkedHashMap<>();
langsAndKeys.forEach((str) -> {
String[] couple = str.split(":");
languages.put(couple[0], couple[1]);
});
List<User> users = userService.findAll(); // get a list of all the users
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<String, String> configParameters() { // get configuration parameters
HashMap<String, String> configuration = new HashMap<>();
configuration.put("FillExtList", String.join(",", fileUtility
.getFillExts())); // put a list of the extensions that can be filled to config
configuration.put("ConverExtList", String.join(",", fileUtility
.getConvertExts())); // put a list of the extensions that can be converted to config
configuration.put("EditedExtList", String.join(",", fileUtility
.getEditedExts())); // put a list of the extensions that can be edited to config
configuration.put("UrlConverter", urlConverter);
configuration.put("UrlEditor", urlEditor);
return configuration;
}
}
@@ -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);
}
}
@@ -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<Integer, Callback> callbackHandlers = new HashMap<>();
public void register(final int code, final Callback callback) { // register a callback handler
callbackHandlers.put(code, callback);
}
public int handle(final Track body, final String fileName) { // handle a callback
Callback callback = callbackHandlers.get(body.getStatus());
if (callback == null) {
logger.warn("Callback status " + body.getStatus() + " is not supported yet");
return 0;
}
int result = callback.handle(body, fileName);
return result;
}
}
@@ -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;
}
}
@@ -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
}
}
@@ -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();
}
}
@@ -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
}
}
@@ -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
}
@@ -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<String, Object> params = new HashMap<String, Object>();
params.put("c", method);
params.put("key", key);
if (meta != null) {
params.put("meta", meta);
}
String headerToken;
// check if a secret key to generate token exists or not
if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
Map<String, Object> payloadMap = new HashMap<>();
payloadMap.put("payload", params);
headerToken = jwtManager.createToken(payloadMap); // encode a payload object into a header token
// add a header Authorization with a header token and Authorization prefix in it
connection.setRequestProperty(documentJwtHeader.equals("")
? "Authorization" : documentJwtHeader, "Bearer " + headerToken);
String token = jwtManager.createToken(params); // encode a payload object into a body token
params.put("token", token);
}
String bodyString = objectMapper.writeValueAsString(params);
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
connection.setRequestMethod("POST"); // set the request method
connection
.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // set the Content-Type header
connection.setDoOutput(true); // set the doOutput field to true
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte); // write bytes to the output stream
}
InputStream stream = connection.getInputStream(); // get input stream
if (stream == null) {
throw new RuntimeException("Could not get an answer");
}
String jsonString = serviceConverter.convertStreamToString(stream); // convert stream to json string
connection.disconnect();
JSONObject response = serviceConverter.convertStringToJSON(jsonString); // convert json string to json object
// todo: Add errors ENUM
String responseCode = response.get("error").toString();
switch (responseCode) {
case "0":
case "4":
break;
default:
throw new RuntimeException(response.toJSONString());
}
}
@SneakyThrows
public void processForceSave(final Track body, final String fileNameParam) { // file force saving process
String downloadUri = body.getUrl();
String 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<Action> 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));
}
}
@@ -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<Map<String, Object>> getFilesInfo() {
ArrayList<Map<String, Object>> files = new ArrayList<>();
// run through all the stored files
for (File file : storageMutator.getStoredFiles()) {
Map<String, Object> map = new LinkedHashMap<>(); // write all the parameters to the map
map.put("version", storagePathBuilder.getFileVersion(file.getName(), false));
map.put("id", serviceConverter
.generateRevisionId(storagePathBuilder.getStorageLocation()
+ "/" + file.getName() + "/"
+ Paths.get(storagePathBuilder.getFileLocation(file.getName()))
.toFile()
.lastModified()));
map.put("contentLength", new BigDecimal(String.valueOf((file.length() / Double.valueOf(KILOBYTE_SIZE))))
.setScale(2, RoundingMode.HALF_UP) + " KB");
map.put("pureContentLength", file.length());
map.put("title", file.getName());
map.put("updated", String.valueOf(new Date(file.lastModified())));
files.add(map);
}
return files;
}
// get file information by its ID
public ArrayList<Map<String, Object>> getFilesInfo(final String fileId) {
ArrayList<Map<String, Object>> file = new ArrayList<>();
for (Map<String, Object> map : getFilesInfo()) {
if (map.get("id").equals(fileId)) {
file.add(map);
break;
}
}
return file;
}
// get the path to the file version by the history path and file version
public String versionDir(final String path, final Integer version, final boolean historyPath) {
if (!historyPath) {
return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version;
}
return path + File.separator + version;
}
// create demo document
public String createDemo(final String fileExt, final Boolean sample, final String uid, final String uname) {
String demoName = (sample ? "sample." : "new.")
+ fileExt; // create sample or new template file with the necessary extension
String demoPath =
"assets"
+ File.separator
+ "document-templates"
+ File.separator
+ (sample ? "sample" : "new")
+ File.separator
+ demoName;
// get a file name with an index if the file with such a name already exists
String fileName = getCorrectName(demoName);
InputStream stream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(demoPath); // get the input file stream
if (stream == null) {
return null;
}
storageMutator.createFile(Path.of(storagePathBuilder
.getFileLocation(fileName)), stream); // create a file in the specified directory
storageMutator.createMeta(fileName, uid, uname); // create meta information of the demo file
return fileName;
}
}
@@ -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<Map<String, Object>> getFilesInfo(); // get file information
ArrayList<Map<String, Object>> getFilesInfo(String fileId); // get file information by its ID
// get the path to the file version by the history path and file version
String versionDir(String path, Integer version, boolean historyPath);
// create demo document
String createDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception;
String getCreateUrl(String fileName, Boolean sample); // get URL to the created file
}
@@ -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<Object> hist = new ArrayList<>();
Map<String, Object> histData = new HashMap<>();
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
Map<String, Object> obj = new HashMap<String, Object>();
Map<String, Object> dataObj = new HashMap<String, Object>();
String verDir = documentManager
.versionDir(histDir, i, true); // get the path to the given file version
String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir
+ File.separator + "key.txt")); // get document key
obj.put("key", key);
obj.put("version", i);
if (i == 1) { // check if the version number is equal to 1
String createdInfo = readFileToEnd(new File(histDir
+ File.separator + "createdInfo.json")); // get file with meta data
JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object
// write meta information to the object (user information and creation date)
obj.put("created", json.get("created"));
Map<String, Object> user = new HashMap<String, Object>();
user.put("id", json.get("id"));
user.put("name", json.get("name"));
obj.put("user", user);
}
dataObj.put("fileType", fileUtility
.getFileExtension(document.getTitle()).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<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));
Map<String, Object> prevInfo = new HashMap<String, Object>();
prevInfo.put("fileType", prev.get("fileType"));
prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version
prevInfo.put("url", prev.get("url"));
if (!document.getDirectUrl().equals("")) {
prevInfo.put("directUrl", prev.get("directUrl"));
}
// write information about previous file version to the data object
dataObj.put("previous", prevInfo);
// write the path to the diff.zip archive with differences in this file version
Integer verdiff = i - 1;
dataObj.put("changesUrl", documentManager
.getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true));
}
if (jwtManager.tokenEnabled()) {
dataObj.put("token", jwtManager.createToken(dataObj));
}
hist.add(obj);
histData.put(Integer.toString(i - 1), dataObj);
}
// write history information about the current file version to the history object
Map<String, Object> histObj = new HashMap<String, Object>();
histObj.put("currentVersion", curVer);
histObj.put("history", hist);
try {
return new String[]{objectMapper.writeValueAsString(histObj),
objectMapper.writeValueAsString(histData)};
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return new String[]{"", ""};
}
// 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;
}
}
@@ -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
}
@@ -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<String, Object> payloadClaims) {
try {
// build a HMAC signer using a SHA-256 hash
Signer signer = HMACSigner.newSHA256Signer(tokenSecret);
JWT jwt = new JWT();
for (String key : payloadClaims.keySet()) { // run through all the keys from the payload
jwt.addClaim(key, payloadClaims.get(key)); // and write each claim to the jwt
}
return JWT.getEncoder().encode(jwt, signer); // sign and encode the JWT to a JSON string representation
} catch (Exception e) {
return "";
}
}
// check if the token is enabled
@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<String, Object> jwtPayload =
(LinkedHashMap<String, Object>) jwt.getObject("payload");
jwt.claims = jwtPayload;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"Wrong payload\"}");
}
}
try {
Object obj = parser.parse(objectMapper.writeValueAsString(jwt.claims));
body = (JSONObject) obj;
} catch (Exception ex) {
throw new RuntimeException("{\"error\":1,\"message\":\"Parsing error\"}");
}
}
return body;
}
}
@@ -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<String, Object> payloadClaims); // create document token
JWT readToken(String token); // read document token
JSONObject parseBody(String payload, String header); // parse the body
}
@@ -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<Template> createTemplates(final String fileName) {
List<Template> templates = List.of(
new Template("", "Blank", documentManager
.getCreateUrl(fileName, false)), // create a blank template
new Template(getTemplateImageUrl(fileName), "With sample content", documentManager
.getCreateUrl(fileName,
true)) // create a template with sample content using the template image
);
return templates;
}
// get the template image URL for the specified file
public String getTemplateImageUrl(final String fileName) {
DocumentType fileType = fileUtility.getDocumentType(fileName); // get the file type
String path = storagePathBuilder.getServerUrl(true); // get server URL
if (fileType.equals(DocumentType.word)) { // get URL to the template image for the word document type
return path + "/css/img/file_docx.svg";
} else if (fileType.equals(DocumentType.slide)) { // get URL to the template image for the slide document type
return path + "/css/img/file_pptx.svg";
} else if (fileType.equals(DocumentType.cell)) { // get URL to the template image for the cell document type
return path + "/css/img/file_xlsx.svg";
}
return path + "/css/img/file_docx.svg"; // get URL to the template image for the default document type (word)
}
}
@@ -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.template;
import com.onlyoffice.integration.documentserver.models.filemodel.Template;
import java.util.List;
// specify the template manager functions
public interface TemplateManager {
List<Template> createTemplates(String fileName); // create a template document with the specified name
String getTemplateImageUrl(String fileName); // get the template image URL for the specified file
}
@@ -1,24 +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.models;
import java.io.Serializable;
public abstract class AbstractModel implements Serializable {
}
@@ -1,53 +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.models.configurations;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
/* The parameters which allow to customize the editor interface so that it looked like your
other products (if there are any) and change the presence or absence of the additional buttons,
links, change logos and editor owner details. */
public class Customization {
@Autowired
private Logo logo; // the image file at the top left corner of the Editor header
@Autowired
private Goback goback; // the settings for the Open file location menu button and upper right corner button
private Boolean autosave = true; // if the Autosave menu option is enabled or disabled
private Boolean comments = true; // if the Comments menu button is displayed or hidden
private Boolean compactHeader = false; /* if the additional action buttons are displayed
in the upper part of the editor window header next to the logo (false) or in the toolbar (true) */
private Boolean compactToolbar = false; // if the top toolbar type displayed is full (false) or compact (true)
private Boolean compatibleFeatures = false; // the use of functionality only compatible with the OOXML format
private Boolean forcesave = false; /* add the request for the forced file saving to the callback handler
when saving the document within the document editing service */
private Boolean help = true; // if the Help menu button is displayed or hidden
private Boolean hideRightMenu = false; // if the right menu is displayed or hidden on first loading
private Boolean hideRulers = false; // if the editor rulers are displayed or hidden
private Boolean submitForm = false; // if the Submit form button is displayed or hidden
private Boolean about = true;
private Boolean feedback = true;
}
@@ -1,40 +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.models.configurations;
import com.onlyoffice.integration.documentserver.models.enums.ToolbarDocked;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
/* The parameters which allow to change the settings
which define the behavior of the buttons in the embedded mode */
public class Embedded {
private String embedUrl; /* the absolute URL to the document serving as a source file for the document embedded
into the web page */
private String saveUrl; /* the absolute URL that will allow the document to be saved
onto the user personal computer */
private String shareUrl; // the absolute URL that will allow other users to share this document
private ToolbarDocked toolbarDocked; // the place for the embedded viewer toolbar, can be either top or bottom
}
@@ -1,48 +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.models.configurations;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
public class Goback { // the settings for the Open file location menu button and upper right corner button
@Autowired
private FileStoragePathBuilder storagePathBuilder;
@Value("${url.index}")
private String indexMapping;
@Getter
private String url; /* the absolute URL to the website address which will be opened
when clicking the Open file location menu button */
@PostConstruct
private void init() {
this.url = storagePathBuilder.getServerUrl(false) + indexMapping;
}
}
@@ -1,45 +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.models.configurations;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@Component
@Scope("prototype")
@Getter
@Setter
/* The additional parameters for the document (document owner, folder where the document is stored,
uploading date, sharing settings) */
public class Info {
private String owner = "Me"; // the name of the document owner/creator
private Boolean favorite = null; // the highlighting state of the Favorite icon
private String uploaded = getDate(); // the document uploading date
private String getDate() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);
return simpleDateFormat.format(new Date());
}
}
@@ -1,38 +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.models.configurations;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
public class Logo { // the image file at the top left corner of the Editor header
@Value("${logo.image}")
private String image; // the path to the image file used to show in common work mode
@Value("${logo.imageEmbedded}")
private String imageEmbedded; // the path to the image file used to show in the embedded mode
@Value("${logo.url}")
private String url; // the absolute URL which will be used when someone clicks the logo image
}
@@ -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.models.enums;
public enum Action {
edit,
review,
view,
embedded,
filter,
comment,
chat,
fillForms,
blockcontent,
protect
}
@@ -1,48 +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.models.enums;
public enum ConvertErrorType {
EMPTY_ERROR(0, ""),
CONVERTATION_UNKNOWN(-1, "Error convertation unknown"),
CONVERTATION_TIMEOUT(-2, "Error convertation timeout"),
CONVERTATION_ERROR(-3, "Error convertation error"),
DOWNLOAD_ERROR(-4, "Error download error"),
UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
DATABASE_ERROR(-6, "Error database"),
DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
private final int code;
private final String label;
ConvertErrorType(final int codeParam, final String labelParam) {
this.code = codeParam;
this.label = labelParam;
}
public static String labelOfCode(final int code) {
for (ConvertErrorType convertErrorType : values()) {
if (convertErrorType.code == code) {
return convertErrorType.label;
}
}
return "ErrorCode = " + code;
}
}
@@ -1,25 +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.models.enums;
public enum DocumentType {
word,
cell,
slide
}
@@ -1,24 +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.models.enums;
public enum Mode {
edit,
view
}
@@ -1,24 +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.models.enums;
public enum ToolbarDocked {
top,
bottom
}
@@ -1,25 +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.models.enums;
public enum Type {
desktop,
mobile,
embedded
}
@@ -1,41 +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.models.filemodel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.onlyoffice.integration.documentserver.serializers.SerializerFilter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentGroup {
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> view; // define a list of groups whose comments the user can view
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> edit; // define a list of groups whose comments the user can edit
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> remove; // define a list of groups whose comments the user can remove
}
@@ -1,49 +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.models.filemodel;
import com.onlyoffice.integration.documentserver.models.configurations.Info;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.HashMap;
@Component
@Scope("prototype")
@Getter
@Setter
public class Document { // the parameters pertaining to the document (title, url, file type, etc.)
@Autowired
private Info info; /* additional parameters for the document (document owner, folder where the document is stored,
uploading date, sharing settings) */
@Autowired
private Permission permissions; // the permission for the document to be edited and downloaded or not
private String fileType; // the file type for the source viewed or edited document
private String key; // the unique document identifier used by the service to recognize the document
private String urlUser; /* the absolute URL that will allow the document to be saved
onto the user personal computer */
private String title; /* the desired file name for the viewed or edited document which will also be used
as file name when the document is downloaded */
private String url; // the absolute URL where the source viewed or edited document is stored
private String directUrl;
private HashMap<String, Object> referenceData;
}
@@ -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.models.filemodel;
import com.onlyoffice.integration.documentserver.models.configurations.Customization;
import com.onlyoffice.integration.documentserver.models.configurations.Embedded;
import com.onlyoffice.integration.documentserver.models.enums.Mode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
@Component
@Scope("prototype")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EditorConfig { /* the parameters pertaining to the editor interface: opening mode (viewer or editor),
interface language, additional buttons, etc. */
private HashMap<String, Object> actionLink = null; /* the data which contains the information about the
action in the document that will be scrolled to */
private String callbackUrl; // the absolute URL to the document storage service
private HashMap<String, Object> coEditing = null;
private String createUrl; // the absolute URL of the document where it will be created and available after creation
@Autowired
private Customization customization; /* the parameters which allow to customize the editor interface
so that it looked like your other products (if there are any) and change the presence or absence
of the additional buttons, links, change logos and editor owner details */
@Autowired
private Embedded embedded; /* the parameters which allow to change the settings which define
the behavior of the buttons in the embedded mode */
private String lang; // the editor interface language
private Mode mode; // the editor opening mode
@Autowired
private User user; // the user currently viewing or editing the document
private List<Template> templates; /* the presence or absence
of the templates in the <b>Create New...</b> menu option */
}
@@ -1,44 +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.models.filemodel;
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
import com.onlyoffice.integration.documentserver.models.enums.Type;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
/* the file base parameters which include the platform type used,
document display size (width and height) and type of the document opened */
public class FileModel {
@Autowired
private Document document; // the parameters pertaining to the document (title, url, file type, etc.)
private DocumentType documentType; // the document type to be opened
@Autowired
private EditorConfig editorConfig; /* the parameters pertaining to the
editor interface: opening mode (viewer or editor), interface language, additional buttons, etc. */
private String token; // the encrypted signature added to the Document Server config
private Type type; // the platform type used to access the document
}
@@ -1,55 +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.models.filemodel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.onlyoffice.integration.documentserver.models.AbstractModel;
import com.onlyoffice.integration.documentserver.serializers.SerializerFilter;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Scope("prototype")
@Getter
@Setter
public class Permission extends AbstractModel { // the permission for the document to be edited and downloaded or not
private Boolean comment = true; // if the document can be commented or not
private Boolean copy = true; // if the content can be copied to the clipboard or not
private Boolean download = true; // if the document can be downloaded or only viewed or edited online
private Boolean edit = true; // if the document can be edited or only viewed
private Boolean print = true; // if the document can be printed or not
private Boolean fillForms = true; // if the forms can be filled
private Boolean modifyFilter = true; /* if the filter can applied globally (true) affecting all the
other users, or locally (false) */
private Boolean modifyContentControl = true; // if the content control settings can be changed
private Boolean review = true; // if the document can be reviewed or not
private Boolean chat = true; // if a chat can be used
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> reviewGroups; // the groups whose changes the user can accept/reject
@Autowired
private CommentGroup commentGroups; // the groups whose comments the user can edit, remove and/or view
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
private List<String> userInfoGroups;
private Boolean protect = true;
}
@@ -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.models.filemodel;
import java.util.HashMap;
import java.util.Map;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import org.springframework.beans.factory.annotation.Autowired;
public class ReferenceData {
@Autowired
private FileStoragePathBuilder storagePathBuilder;
private final String instanceId;
private final Map<String, String> fileKey;
public ReferenceData(final String fileName, final String curUserHostAddress, final User user) {
instanceId = storagePathBuilder.getServerUrl(true);
Map<String, String> fileKeyList = new HashMap<>();
if (!user.getId().equals("uid-0")) {
fileKeyList.put("fileName", fileName);
fileKeyList.put("userAddress", curUserHostAddress);
} else {
fileKeyList = null;
}
fileKey = fileKeyList;
}
}
@@ -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.models.filemodel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class Template { // the document template parameters
private String image; // the absolute URL to the image for template
private String title; // the template title that will be displayed in the <b>Create New...</b> menu option
private String url; // the absolute URL to the document where it will be created and available after creation
}
@@ -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.models.filemodel;
import com.onlyoffice.integration.documentserver.models.AbstractModel;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
@Getter
@Setter
public class User extends AbstractModel {
private String id;
private String name;
private String group;
// the user configuration parameters
public void configure(final int idParam, final String nameParam, final String groupParam) {
this.id = "uid-" + idParam; // the user id
this.name = nameParam; // the user name
this.group = groupParam; // the group the user belongs to
}
}
@@ -1,23 +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.serializers;
public enum FilterState {
NULL
}
@@ -1,38 +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.serializers;
import java.util.List;
public class SerializerFilter {
@Override
public boolean equals(final Object obj) {
if (obj instanceof List) {
if (((List<?>) obj).size() == 1 && ((List<?>) obj).get(0) == FilterState.NULL.toString()) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return super.hashCode();
}
}
@@ -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.storage;
import org.springframework.core.io.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Path;
// specify the file storage mutator functions
public interface FileStorageMutator {
void createDirectory(Path path); // create a new directory if it does not exist
boolean createFile(Path path, InputStream stream); // create a new file if it does not exist
boolean deleteFile(String fileName); // delete a file
boolean deleteFileHistory(String fileName); // delete file history
String updateFile(String fileName, byte[] bytes); // update a file
boolean writeToFile(String pathName, String payload); // write the payload to the file
boolean moveFile(Path source, Path destination); // move a file to the specified destination
Resource loadFileAsResource(String fileName); // load file as a resource
Resource loadFileAsResourceHistory(String fileName, String version, String file); // load file as a resource
File[] getStoredFiles(); // get a collection of all the stored files
void createMeta(String fileName, String uid, String uname); // create the file meta information
boolean createOrUpdateFile(Path path, ByteArrayInputStream stream); // create or update a file
}
@@ -1,31 +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.storage;
// specify the file storage path builder functions
public interface FileStoragePathBuilder {
void configure(String address); // create a new storage folder
String getStorageLocation(); // get the storage directory
String getFileLocation(String fileName); // get the directory of the specified file
String getServerUrl(Boolean forDocumentServer); // get the server URL
String getHistoryDir(String fileName); // get the history directory
int getFileVersion(String historyPath, Boolean ifIndexPage); // get the file version
String getForcesavePath(String fileName, Boolean create); /* get the path where all the
forcely saved file versions are saved or create it */
}
@@ -1,392 +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.storage;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import lombok.Getter;
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.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Component;
import org.springframework.util.FileSystemUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.onlyoffice.integration.documentserver.util.Constants.KILOBYTE_SIZE;
// todo: Refactoring
@Component
@Primary
public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuilder {
@Getter
private String storageAddress;
@Value("${files.storage.folder}")
private String storageFolder;
@Value("${files.docservice.url.example}")
private String docserviceUrlExample;
@Value("${files.docservice.history.postfix}")
private String historyPostfix;
@Autowired
private FileUtility fileUtility;
@Autowired
private HttpServletRequest request;
/*
This Storage configuration method should be called whenever a new storage folder is required
*/
public void configure(final String address) {
this.storageAddress = address;
if (this.storageAddress == null) {
try {
this.storageAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
this.storageAddress = "unknown_storage";
}
}
this.storageAddress.replaceAll("[^0-9a-zA-Z.=]", "_");
createDirectory(Paths.get(getStorageLocation()));
}
// get the storage directory
public String getStorageLocation() {
String serverPath = System.getProperty("user.dir"); // get the path to the server
String directory; // create the storage directory
if (Paths.get(this.storageAddress).isAbsolute()) {
directory = this.storageAddress + File.separator;
} else {
directory = serverPath
+ File.separator + storageFolder
+ File.separator + this.storageAddress
+ File.separator;
}
if (!Files.exists(Paths.get(directory))) {
createDirectory(Paths.get(directory));
}
return directory;
}
// get the directory of the specified file
public String getFileLocation(final String fileName) {
if (fileName.contains(File.separator)) {
return getStorageLocation() + fileName;
}
return getStorageLocation() + fileUtility.getFileName(fileName);
}
// create a new directory if it does not exist
public void createDirectory(final Path path) {
if (Files.exists(path)) {
return;
}
try {
Files.createDirectories(path);
} catch (IOException e) {
e.printStackTrace();
}
}
// create a new file if it does not exist
public boolean createFile(final Path path, final InputStream stream) {
if (Files.exists(path)) {
return true;
}
try {
File file = Files.createFile(path).toFile(); // create a new file in the specified path
try (FileOutputStream out = new FileOutputStream(file)) {
int read;
final byte[] bytes = new byte[KILOBYTE_SIZE];
while ((read = stream.read(bytes)) != -1) {
out.write(bytes, 0, read); // write bytes to the output stream
}
out.flush(); // force write data to the output stream that can be cached in the current thread
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
// delete a file
public boolean deleteFile(final String fileNameParam) {
String fileName = URLDecoder
.decode(fileNameParam, StandardCharsets.UTF_8); // decode a x-www-form-urlencoded string
if (fileName.isBlank()) {
return false;
}
String filenameWithoutExt = fileUtility
.getFileNameWithoutExtension(fileName); // get file name without extension
Path filePath = fileName.contains(File.separator)
? Paths.get(fileName) : Paths.get(getFileLocation(fileName)); // get the path to the file
Path filePathWithoutExt = fileName.contains(File.separator)
? Paths.get(filenameWithoutExt) : Paths
.get(getStorageLocation() + filenameWithoutExt); // get the path to the file without extension
// delete the specified file; for directories, recursively delete any nested directories or files as well
boolean fileDeleted = FileSystemUtils.deleteRecursively(filePath.toFile());
/* delete the specified file without extension; for directories,
recursively delete any nested directories or files as well */
boolean fileWithoutExtDeleted = FileSystemUtils.deleteRecursively(filePathWithoutExt.toFile());
return fileDeleted && fileWithoutExtDeleted;
}
// delete file history
public boolean deleteFileHistory(final String fileNameParam) {
String fileName = URLDecoder
.decode(fileNameParam, StandardCharsets.UTF_8); // decode a x-www-form-urlencoded string
if (fileName.isBlank()) {
return false;
}
Path fileHistoryPath = Paths
.get(getStorageLocation() + getHistoryDir(fileName)); // get the path to the history file
Path fileHistoryPathWithoutExt = Paths.get(getStorageLocation() + getHistoryDir(fileUtility
.getFileNameWithoutExtension(fileName))); // get the path to the history file without extension
/* delete the specified history file; for directories,
recursively delete any nested directories or files as well */
boolean historyDeleted = FileSystemUtils.deleteRecursively(fileHistoryPath.toFile());
/* delete the specified history file without extension; for directories,
recursively delete any nested directories or files as well */
boolean historyWithoutExtDeleted = FileSystemUtils.deleteRecursively(fileHistoryPathWithoutExt.toFile());
return historyDeleted || historyWithoutExtDeleted;
}
// update a file
public String updateFile(final String fileName, final byte[] bytes) {
Path path = fileUtility
.generateFilepath(getStorageLocation(), fileName); // generate the path to the specified file
try {
Files.write(path, bytes); // write new information in the bytes format to the file
return path.getFileName().toString();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
// move a file to the specified destination
public boolean moveFile(final Path source, final Path destination) {
try {
Files.move(source, destination,
new StandardCopyOption[]{StandardCopyOption.REPLACE_EXISTING});
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
// write the payload to the file
public boolean writeToFile(final String pathName, final String payload) {
try (FileWriter fw = new FileWriter(pathName)) {
fw.write(payload);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
// get the path where all the forcely saved file versions are saved or create it
public String getForcesavePath(final String fileName, final Boolean create) {
String directory = getStorageLocation();
Path path = Paths.get(directory); // get the storage directory
if (!Files.exists(path)) {
return "";
}
directory = getFileLocation(fileName) + historyPostfix + File.separator;
path = Paths.get(directory); // get the history file directory
if (!create && !Files.exists(path)) {
return "";
}
createDirectory(path); // create a new directory where all the forcely saved file versions will be saved
directory = directory + fileName;
path = Paths.get(directory);
if (!create && !Files.exists(path)) {
return "";
}
return directory;
}
// load file as a resource
public Resource loadFileAsResource(final String fileName) {
String fileLocation = getForcesavePath(fileName,
false); // get the path where all the forcely saved file versions are saved
if (fileLocation.isBlank()) { // if file location is empty
fileLocation = getFileLocation(fileName); // get it by the file name
}
try {
Path filePath = Paths.get(fileLocation); // get the path to the file location
Resource resource = new UrlResource(filePath.toUri()); // convert the file path to URL
if (resource.exists()) {
return resource;
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
public Resource loadFileAsResourceHistory(final String fileName, final String version, final String file) {
String fileLocation = getStorageLocation() + fileName + "-hist" + File.separator + version
+ File.separator + file; // get it by the file name
try {
Path filePath = Paths.get(fileLocation); // get the path to the file location
Resource resource = new UrlResource(filePath.toUri()); // convert the file path to URL
if (resource.exists()) {
return resource;
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
// get a collection of all the stored files
public File[] getStoredFiles() {
File file = new File(getStorageLocation());
return file.listFiles(pathname -> pathname.isFile());
}
@SneakyThrows
public void createMeta(final String fileName,
final String uid,
final String uname) { // create the file meta information
String histDir = getHistoryDir(getFileLocation(fileName)); // get the history directory
Path path = Paths.get(histDir); // get the path to the history directory
createDirectory(path); // create the history directory
// create the json object with the file metadata
JSONObject json = new JSONObject();
json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date())); // put the file creation date to the json object
json.put("id", uid); // put the user ID to the json object
json.put("name", uname); // put the user name to the json object
File meta = new File(histDir + File.separator
+ "createdInfo.json"); // create the createdInfo.json file with the file meta information
try (FileWriter writer = new FileWriter(meta)) {
json.writeJSONString(writer);
} catch (IOException ex) {
ex.printStackTrace();
}
}
// create or update a file
public boolean createOrUpdateFile(final Path path, final ByteArrayInputStream stream) {
if (!Files.exists(path)) { // if the specified file does not exist
return createFile(path, stream); // create it in the specified directory
} else {
try {
Files.write(path, stream
.readAllBytes()); // otherwise, write new information in the bytes format to the file
return true;
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
// get the server URL
public String getServerUrl(final Boolean forDocumentServer) {
if (forDocumentServer && !docserviceUrlExample.equals("")) {
return docserviceUrlExample;
} else {
return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ request.getContextPath();
}
}
// get the history directory
public String getHistoryDir(final String path) {
return path + historyPostfix;
}
// get the file version
public int getFileVersion(final String historyPath, final Boolean ifIndexPage) {
Path path;
if (ifIndexPage) { // if the start page is opened
path = Paths.get(getStorageLocation()
+ getHistoryDir(historyPath)); // get the storage directory and add the history directory to it
} else {
path = Paths.get(historyPath); // otherwise, get the path to the history directory
if (!Files.exists(path)) {
return 1; // if the history directory does not exist, then the file version is 1
}
}
// run through all the files in the history directory
try (Stream<Path> stream = Files.walk(path, 1)) {
return stream
.filter(file -> Files.isDirectory(file)) // take only directories from the history folder
.map(Path::getFileName) // get file names
.map(Path::toString) // and convert them into strings
.collect(Collectors.toSet()).size(); /* convert stream into set
and get its size which specifies the file version */
} catch (IOException e) {
e.printStackTrace();
return 0;
}
}
}
@@ -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.util;
public final class Constants {
public static final Integer MAX_FILE_SIZE = 5 * 1024 * 1024;
public static final Integer CONVERT_TIMEOUT_MS = 120000;
public static final String CONVERTATION_ERROR_MESSAGE_TEMPLATE = "Error occurred in the ConvertService: ";
public static final Long FULL_LOADING_IN_PERCENT = 100L;
public static final Integer FILE_SAVE_TIMEOUT = 5000;
public static final Integer MAX_KEY_LENGTH = 20;
public static final Integer ANONYMOUS_USER_ID = 4;
public static final Integer KILOBYTE_SIZE = 1024;
private Constants() { }
}
@@ -1,36 +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.util;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class Misc {
// convert user descriptions to the specified format
public String convertUserDescriptions(final String username, final List<String> description) {
String result = "<div class=\"user-descr\"><b>" + username + "</b><br/><ul>" + description.
stream().map(text -> "<li>" + text + "</li>")
.collect(Collectors.joining()) + "</ul></div>";
return result;
}
}
@@ -1,78 +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.util;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.springframework.stereotype.Component;
/**
* Disables and enables certificate and host-name checking in
* HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
* Has no effect on implementations such as Apache Http Client, Ok Http.
*/
@Component
public final class SSLUtils {
private final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
private final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
public boolean verify(final String hostname, final SSLSession sslSession) {
return true;
}
};
private final TrustManager[] unquestioningTrustManager = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(final X509Certificate[] certs, final String authType) {
}
public void checkServerTrusted(final X509Certificate[] certs, final String authType) {
}
} };
public void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, unquestioningTrustManager, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
}
@@ -1,203 +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.util.file;
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.onlyoffice.integration.documentserver.util.Constants.MAX_FILE_SIZE;
@Component
@Qualifier("default")
public class DefaultFileUtility implements FileUtility {
@Value("${filesize-max}")
private String filesizeMax;
@Value("${files.docservice.viewed-docs}")
private String docserviceViewedDocs;
@Value("${files.docservice.edited-docs}")
private String docserviceEditedDocs;
@Value("${files.docservice.convert-docs}")
private String docserviceConvertDocs;
@Value("${files.docservice.fillforms-docs}")
private String docserviceFillDocs;
// document extensions
private List<String> extsDocument = Arrays.asList(
".doc", ".docx", ".docm",
".dot", ".dotx", ".dotm",
".odt", ".fodt", ".ott", ".rtf", ".txt",
".html", ".htm", ".mht", ".xml",
".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oform");
// spreadsheet extensions
private List<String> extsSpreadsheet = Arrays.asList(
".xls", ".xlsx", ".xlsm", ".xlsb",
".xlt", ".xltx", ".xltm",
".ods", ".fods", ".ots", ".csv");
// presentation extensions
private List<String> extsPresentation = Arrays.asList(
".pps", ".ppsx", ".ppsm",
".ppt", ".pptx", ".pptm",
".pot", ".potx", ".potm",
".odp", ".fodp", ".otp");
// get the document type
public DocumentType getDocumentType(final String fileName) {
String ext = getFileExtension(fileName).toLowerCase(); // get file extension from its name
// word type for document extensions
if (extsDocument.contains(ext)) {
return DocumentType.word;
}
// cell type for spreadsheet extensions
if (extsSpreadsheet.contains(ext)) {
return DocumentType.cell;
}
// slide type for presentation extensions
if (extsPresentation.contains(ext)) {
return DocumentType.slide;
}
// default file type is word
return DocumentType.word;
}
// get file name from its URL
public String getFileName(final String url) {
if (url == null) {
return "";
}
// get file name from the last part of URL
String fileName = url.substring(url.lastIndexOf('/') + 1);
fileName = fileName.split("\\?")[0];
return fileName;
}
// get file name without extension
public String getFileNameWithoutExtension(final String url) {
String fileName = getFileName(url);
if (fileName == null) {
return null;
}
String fileNameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
return fileNameWithoutExt;
}
// get file extension from URL
public String getFileExtension(final String url) {
String fileName = getFileName(url);
if (fileName == null) {
return null;
}
String fileExt = fileName.substring(fileName.lastIndexOf("."));
return fileExt.toLowerCase();
}
// get an editor internal extension
public String getInternalExtension(final DocumentType type) {
// .docx for word file type
if (type.equals(DocumentType.word)) {
return ".docx";
}
// .xlsx for cell file type
if (type.equals(DocumentType.cell)) {
return ".xlsx";
}
// .pptx for slide file type
if (type.equals(DocumentType.slide)) {
return ".pptx";
}
// the default file type is .docx
return ".docx";
}
public List<String> getFillExts() {
return Arrays.asList(docserviceFillDocs.split("\\|"));
}
// get file extensions that can be viewed
public List<String> getViewedExts() {
return Arrays.asList(docserviceViewedDocs.split("\\|"));
}
// get file extensions that can be edited
public List<String> getEditedExts() {
return Arrays.asList(docserviceEditedDocs.split("\\|"));
}
// get file extensions that can be converted
public List<String> getConvertExts() {
return Arrays.asList(docserviceConvertDocs.split("\\|"));
}
// get all the supported file extensions
public List<String> getFileExts() {
List<String> res = new ArrayList<>();
res.addAll(getViewedExts());
res.addAll(getEditedExts());
res.addAll(getConvertExts());
res.addAll(getFillExts());
return res;
}
// generate the file path from file directory and name
public Path generateFilepath(final String directory, final String fullFileName) {
String fileName = getFileNameWithoutExtension(fullFileName); // get file name without extension
String fileExtension = getFileExtension(fullFileName); // get file extension
Path path = Paths.get(directory + fullFileName); // get the path to the files with the specified name
for (int i = 1; Files.exists(path); i++) { // run through all the files with the specified name
// get a name of each file without extension and add an index to it
fileName = getFileNameWithoutExtension(fullFileName) + "(" + i + ")";
// create a new path for this file with the correct name and extension
path = Paths.get(directory + fileName + fileExtension);
}
path = Paths.get(directory + fileName + fileExtension);
return path;
}
// get maximum file size
public long getMaxFileSize() {
long size = Long.parseLong(filesizeMax);
return size > 0 ? size : MAX_FILE_SIZE;
}
}
@@ -1,41 +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.util.file;
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
import java.nio.file.Path;
import java.util.List;
// specify the file utility functions
public interface FileUtility {
DocumentType getDocumentType(String fileName); // get the document type
String getFileName(String url); // get file name from its URL
String getFileNameWithoutExtension(String url); // get file name without extension
String getFileExtension(String url); // get file extension from URL
String getInternalExtension(DocumentType type); // get an editor internal extension
List<String> getFileExts(); // get all the supported file extensions
List<String> getFillExts(); // get file extensions that can be filled
List<String> getViewedExts(); // get file extensions that can be viewed
List<String> getEditedExts(); // get file extensions that can be edited
List<String> getConvertExts(); // get file extensions that can be converted
Path generateFilepath(String directory, String fullFileName); /* generate the file path
from file directory and name */
long getMaxFileSize(); // get maximum file size
}
@@ -1,267 +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.util.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
import com.onlyoffice.integration.documentserver.models.enums.ConvertErrorType;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.dto.Convert;
import com.onlyoffice.integration.dto.ConvertedData;
import lombok.SneakyThrows;
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.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static com.onlyoffice.integration.documentserver.util.Constants.CONVERTATION_ERROR_MESSAGE_TEMPLATE;
import static com.onlyoffice.integration.documentserver.util.Constants.CONVERT_TIMEOUT_MS;
import static com.onlyoffice.integration.documentserver.util.Constants.FULL_LOADING_IN_PERCENT;
import static com.onlyoffice.integration.documentserver.util.Constants.MAX_KEY_LENGTH;
// todo: Refactoring
@Component
public class DefaultServiceConverter implements ServiceConverter {
@Value("${files.docservice.header}")
private String documentJwtHeader;
@Value("${files.docservice.url.site}")
private String docServiceUrl;
@Value("${files.docservice.url.converter}")
private String docServiceUrlConverter;
@Value("${files.docservice.timeout}")
private String docserviceTimeout;
private int convertTimeout;
@Autowired
private JwtManager jwtManager;
@Autowired
private FileUtility fileUtility;
@Autowired
private JSONParser parser;
@Autowired
private ObjectMapper objectMapper;
@PostConstruct
public void init() {
int timeout = Integer.parseInt(docserviceTimeout); // parse the dcoument service timeout value
convertTimeout = timeout > 0 ? timeout : CONVERT_TIMEOUT_MS;
}
@SneakyThrows
private String postToServer(final Convert body, final String headerToken) { // send the POST request to the server
String bodyString = objectMapper
.writeValueAsString(body); // write the body request to the object mapper in the string format
URL url = null;
java.net.HttpURLConnection connection = null;
InputStream response = null;
String jsonString = null;
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8); // convert body string into bytes
try {
// set the request parameters
url = new URL(docServiceUrl + docServiceUrlConverter);
connection = (java.net.HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setFixedLengthStreamingMode(bodyByte.length);
connection.setRequestProperty("Accept", "application/json");
connection.setConnectTimeout(convertTimeout);
// check if the token is enabled
if (jwtManager.tokenEnabled()) {
// set the JWT header to the request
connection.setRequestProperty(documentJwtHeader.isBlank()
? "Authorization" : documentJwtHeader, "Bearer " + headerToken);
}
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte); // write bytes to the output stream
os.flush(); // force write data to the output stream that can be cached in the current thread
}
int statusCode = connection.getResponseCode();
if (statusCode != HttpStatus.OK.value()) { // checking status code
connection.disconnect();
throw new RuntimeException("Convertation service returned status: " + statusCode);
}
response = connection.getInputStream(); // get the input stream
jsonString = convertStreamToString(response); // convert the response stream into a string
} finally {
connection.disconnect();
return jsonString;
}
}
// get the URL to the converted file
public ConvertedData getConvertedData(final String documentUri, final String fromExtension,
final String toExtension, final String documentRevisionId,
final String filePass, final Boolean isAsync, final String lang) {
// check if the fromExtension parameter is defined; if not, get it from the document url
String fromExt = fromExtension == null || fromExtension.isEmpty()
? fileUtility.getFileExtension(documentUri) : fromExtension;
// check if the file name parameter is defined; if not, get random uuid for this file
String title = fileUtility.getFileName(documentUri);
title = title == null || title.isEmpty() ? UUID.randomUUID().toString() : title;
String documentRevId = documentRevisionId == null || documentRevisionId.isEmpty()
? documentUri : documentRevisionId;
documentRevId = generateRevisionId(documentRevId); // create document token
// write all the necessary parameters to the body object
Convert body = new Convert();
body.setLang(lang);
body.setUrl(documentUri);
body.setOutputtype(toExtension.replace(".", ""));
body.setFiletype(fromExt.replace(".", ""));
body.setTitle(title);
body.setKey(documentRevId);
body.setFilePass(filePass);
if (isAsync) {
body.setAsync(true);
}
String headerToken = "";
if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("region", lang);
map.put("url", body.getUrl());
map.put("outputtype", body.getOutputtype());
map.put("filetype", body.getFiletype());
map.put("title", body.getTitle());
map.put("key", body.getKey());
map.put("password", body.getFilePass());
if (isAsync) {
map.put("async", body.getAsync());
}
// add token to the body if it is enabled
String token = jwtManager.createToken(map);
body.setToken(token);
Map<String, Object> payloadMap = new HashMap<String, Object>();
payloadMap.put("payload", map); // create payload object
headerToken = jwtManager.createToken(payloadMap); // create header token
}
String jsonString = postToServer(body, headerToken);
return getResponseData(jsonString);
}
// generate document key
public String generateRevisionId(final String expectedKey) {
/* if the expected key length is greater than 20
then he expected key is hashed and a fixed length value is stored in the string format */
String formatKey = expectedKey.length() > MAX_KEY_LENGTH
? Integer.toString(expectedKey.hashCode()) : expectedKey;
String key = formatKey.replace("[^0-9-.a-zA-Z_=]", "_");
return key.substring(0, Math.min(key.length(), MAX_KEY_LENGTH)); // the resulting key length is 20 or less
}
// todo: Replace with a registry (callbacks package for reference)
// create an error message for an error code
private void processConvertServiceResponceError(final int errorCode) {
String errorMessage = CONVERTATION_ERROR_MESSAGE_TEMPLATE + ConvertErrorType.labelOfCode(errorCode);
throw new RuntimeException(errorMessage);
}
// get the response URL
@SneakyThrows
private ConvertedData getResponseData(final String jsonString) {
JSONObject jsonObj = convertStringToJSON(jsonString);
Object error = jsonObj.get("error");
if (error != null) { // if an error occurs
processConvertServiceResponceError(Math.toIntExact((long) error)); // then get an error message
}
// check if the conversion is completed and save the result to a variable
Boolean isEndConvert = (Boolean) jsonObj.get("endConvert");
Long resultPercent = 0L;
String responseUri = null;
String responseFileType = null;
ConvertedData convertedData = new ConvertedData("", "");
if (isEndConvert) { // if the conversion is completed
resultPercent = FULL_LOADING_IN_PERCENT;
responseUri = (String) jsonObj.get("fileUrl"); // get the file URL
responseFileType = (String) jsonObj.get("fileType"); // get the file type
convertedData.setUri(responseUri);
convertedData.setFileType(responseFileType);
} else { // if the conversion isn't completed
resultPercent = (Long) jsonObj.get("percent");
// get the percentage value of the conversion process
resultPercent = resultPercent >= FULL_LOADING_IN_PERCENT ? FULL_LOADING_IN_PERCENT - 1 : resultPercent;
}
return convertedData;
}
// convert stream to string
@SneakyThrows
public String convertStreamToString(final InputStream stream) {
InputStreamReader inputStreamReader = new InputStreamReader(stream); // create an object to get incoming stream
StringBuilder stringBuilder = new StringBuilder(); // create a string builder object
// create an object to read incoming streams
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = bufferedReader.readLine(); // get incoming streams by lines
while (line != null) {
stringBuilder.append(line); // concatenate strings using the string builder
line = bufferedReader.readLine();
}
String result = stringBuilder.toString();
return result;
}
// convert string to json
@SneakyThrows
public JSONObject convertStringToJSON(final String jsonString) {
Object obj = parser.parse(jsonString); // parse json string
JSONObject jsonObj = (JSONObject) obj; // and turn it into a json object
return jsonObj;
}
}
@@ -1,34 +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.util.service;
import com.onlyoffice.integration.dto.ConvertedData;
import org.json.simple.JSONObject;
import java.io.InputStream;
// specify the converter service functions
public interface ServiceConverter {
ConvertedData getConvertedData(String documentUri, String fromExtension, // get the URL to the converted file
String toExtension, String documentRevisionId,
String filePass, Boolean isAsync, String lang);
String generateRevisionId(String expectedKey); // generate document key
String convertStreamToString(InputStream stream); // convert stream to string
JSONObject convertStringToJSON(String jsonString); // convert string to json
}
@@ -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.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Action {
private String userid;
private com.onlyoffice.integration.documentserver.models.enums.Action type;
}
@@ -1,31 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChangesHistory {
private String created;
private ChangesUser user;
}
@@ -1,31 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChangesUser {
private String id;
private String name;
}
@@ -1,40 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Convert {
private String url;
private String outputtype;
private String filetype;
private String title;
private String key;
private String filePass;
private Boolean async;
private String token;
private String lang;
}
@@ -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.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ConvertedData {
private String uri;
private String fileType;
}
@@ -1,36 +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.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class Converter {
@JsonProperty("filename")
private String fileName;
@JsonProperty("filePass")
private String filePass;
@JsonProperty("lang")
private String lang;
}
@@ -1,40 +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.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.onlyoffice.integration.documentserver.models.filemodel.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class History {
@JsonProperty("serverVersion")
private String serverVersion;
private String key;
private Integer version;
private String created;
private User user;
private List<ChangesHistory> changes;
}
@@ -1,31 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class Mentions {
private String name;
private String email;
}
@@ -1,46 +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.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Track {
private String filetype;
private String url;
private String key;
private String changesurl;
private History history;
private String token;
private Integer forcesavetype;
private Integer status;
private List<String> users;
private List<Action> actions;
private String userdata;
private String lastsave;
private Boolean notmodified;
}
@@ -1,41 +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.entities;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
@MappedSuperclass
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public abstract class AbstractEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
@@ -1,39 +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.entities;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.List;
@Entity
@Table(name = "`group`")
@Getter
@Setter
public class Group extends AbstractEntity {
@Column(unique = true)
private String name;
@OneToMany(mappedBy = "group")
private List<User> users;
}
@@ -1,56 +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.entities;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import java.util.List;
@Entity
@Table(name = "`permission`")
@Getter
@Setter
public class Permission extends AbstractEntity {
private Boolean comment = true;
private Boolean copy = true;
private Boolean download = true;
private Boolean edit = true;
private Boolean print = true;
private Boolean fillForms = true;
private Boolean modifyFilter = true;
private Boolean modifyContentControl = true;
private Boolean review = true;
private Boolean chat = true;
private Boolean templates = true;
@ManyToMany
private List<Group> reviewGroups;
@ManyToMany
private List<Group> commentsViewGroups;
@ManyToMany
private List<Group> commentsEditGroups;
@ManyToMany
private List<Group> commentsRemoveGroups;
@ManyToMany
private List<Group> userInfoGroups;
private Boolean protect = true;
}
@@ -1,48 +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.entities;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import java.util.List;
@Entity
@Table(name = "`user`")
@Getter
@Setter
public class User extends AbstractEntity {
private String name;
private String email;
private Boolean favorite;
@ManyToOne
private Group group;
@OneToOne
private Permission permissions;
// @Column(columnDefinition = "CLOB")
@ElementCollection
@CollectionTable(name = "user_descriptions")
private List<String> descriptions;
}
@@ -1,58 +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.mappers;
import com.onlyoffice.integration.entities.AbstractEntity;
import com.onlyoffice.integration.documentserver.models.AbstractModel;
import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Objects;
public abstract class AbstractMapper<E extends AbstractEntity, M extends AbstractModel> implements Mapper<E, M> {
@Autowired
private ModelMapper mapper;
private Class<M> modelClass;
AbstractMapper(final Class<M> modelClassParam) {
this.modelClass = modelClassParam;
}
@Override
public M toModel(final E entity) { // convert the entity to the model
return Objects.isNull(entity) // check if an entity is not empty
? null
: mapper.map(entity, modelClass); // and add it to the model mapper
}
Converter<E, M> modelConverter() { // specify the model converter
return context -> {
E source = context.getSource(); // get the source entity
M destination = context.getDestination(); // get the destination model
handleSpecificFields(source, destination); // map the entity to the model
return context.getDestination();
};
}
void handleSpecificFields(final E source, final M destination) {
}
}
@@ -1,27 +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.mappers;
import com.onlyoffice.integration.entities.AbstractEntity;
import com.onlyoffice.integration.documentserver.models.AbstractModel;
// specify the model mapper functions
public interface Mapper<E extends AbstractEntity, M extends AbstractModel> {
M toModel(E entity); // convert the entity to the model
}
@@ -1,69 +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.mappers;
import com.onlyoffice.integration.entities.Permission;
import com.onlyoffice.integration.documentserver.models.filemodel.CommentGroup;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.stream.Collectors;
@Component
@Primary
public class PermissionsMapper extends AbstractMapper<Permission,
com.onlyoffice.integration.documentserver.models.filemodel.Permission> {
@Autowired
private ModelMapper mapper;
public PermissionsMapper() {
super(com.onlyoffice.integration.documentserver.models.filemodel.Permission.class);
}
@PostConstruct
public void configure() { // configure the permission mapper
mapper.createTypeMap(Permission.class, com.onlyoffice.integration.documentserver.models.filemodel
.Permission.class) // create the type map
.setPostConverter(modelConverter()); // and apply the post converter to it
}
@Override
void handleSpecificFields(final Permission source,
final com.onlyoffice.integration.documentserver.models.filemodel
.Permission destination) { // handle specific permission fields
destination.setReviewGroups(source.getReviewGroups().stream()
.map(g -> g.getName())
.collect(Collectors.toList())); // set the reviewGroups parameter
// set the commentGroups parameter
destination.setCommentGroups(
new CommentGroup(
source.getCommentsViewGroups().stream().map(g -> g.getName()).collect(Collectors.toList()),
source.getCommentsEditGroups().stream().map(g -> g.getName()).collect(Collectors.toList()),
source.getCommentsRemoveGroups().stream().map(g -> g.getName()).collect(Collectors.toList())
)
);
destination.setUserInfoGroups(source.getUserInfoGroups().stream()
.map(g -> g.getName())
.collect(Collectors.toList()));
}
}
@@ -1,53 +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.mappers;
import com.onlyoffice.integration.entities.User;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Primary
public class UsersMapper extends AbstractMapper<User, com.onlyoffice.integration.documentserver.models.filemodel.User> {
@Autowired
private ModelMapper mapper;
public UsersMapper() {
super(com.onlyoffice.integration.documentserver.models.filemodel.User.class);
}
@PostConstruct
public void configure() { // configure the users mapper
mapper.createTypeMap(User.class, com.onlyoffice.integration.documentserver.models.filemodel
.User.class) // create the type map
.setPostConverter(modelConverter()); // and apply the post converter to it
}
@Override
public void handleSpecificFields(final User source,
final com.onlyoffice.integration.documentserver.models.filemodel
.User destination) { // handle specific users fields
destination.setGroup(source.getGroup() != null
? source.getGroup().getName() : null); // set the Group parameter
}
}
@@ -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.repositories;
import com.onlyoffice.integration.entities.Group;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface GroupRepository extends JpaRepository<Group, Integer> {
Optional<Group> findGroupByName(String name);
}
@@ -1,25 +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.repositories;
import com.onlyoffice.integration.entities.Permission;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PermissionRepository extends JpaRepository<Permission, Integer> {
}
@@ -1,25 +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.repositories;
import com.onlyoffice.integration.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
}
@@ -1,63 +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.services;
import com.onlyoffice.integration.entities.Group;
import com.onlyoffice.integration.repositories.GroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class GroupServices {
@Autowired
private GroupRepository groupRepository;
// create a new group with the specified name
public Group createGroup(final String name) {
if (name == null) {
return null; // check if a name is specified
}
Optional<Group> group = groupRepository
.findGroupByName(name); // check if group with such a name already exists
if (group.isPresent()) {
return group.get(); // if it exists, return it
}
Group newGroup = new Group();
newGroup.setName(name); // otherwise, create a new group with the specified name
groupRepository.save(newGroup); // save a new group
return newGroup;
}
// create a list of groups from the reviewGroups permission parameter
public List<Group> createGroups(final List<String> reviewGroups) {
if (reviewGroups == null) {
return null; // check if the reviewGroups permission exists
}
// convert this parameter to a list of groups whose changes the user can accept/reject
return reviewGroups.stream()
.map(group -> createGroup(group))
.collect(Collectors.toList());
}
}
@@ -1,65 +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.services;
import com.onlyoffice.integration.entities.Group;
import com.onlyoffice.integration.entities.Permission;
import com.onlyoffice.integration.repositories.PermissionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PermissionServices {
@Autowired
private PermissionRepository permissionRepository;
// create permissions with the specified parameters
public Permission createPermission(final List<Group> reviewGroups,
final List<Group> commentViewGroups,
final List<Group> commentEditGroups,
final List<Group> commentRemoveGroups,
final List<Group> userInfoGroups,
final Boolean chat,
final Boolean protect) {
Permission permission = new Permission();
permission.setReviewGroups(reviewGroups); // define the groups whose changes the user can accept/reject
permission.setCommentsViewGroups(commentViewGroups); // defines the groups whose comments the user can view
permission.setCommentsEditGroups(commentEditGroups); // defines the groups whose comments the user can edit
permission.setCommentsRemoveGroups(commentRemoveGroups); /* defines the groups
whose comments the user can remove */
permission.setUserInfoGroups(userInfoGroups);
permission.setChat(chat);
permission.setProtect(protect);
permissionRepository.save(permission); // save new permissions
return permission;
}
// update permissions
public Permission updatePermission(final Permission newPermission) {
permissionRepository.save(newPermission); // save new permissions
return newPermission;
}
}

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