Merge pull request 'release/v1.10.0 from release/v1.10.0 into master
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/9
2
.github/workflows/lint-ruby.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
bundle update
|
||||
bundle install
|
||||
|
||||
- name: Rubocop
|
||||
run: |
|
||||
|
||||
4
.gitmodules
vendored
@ -48,10 +48,6 @@
|
||||
path = web/documentserver-example/java/src/main/resources/assets/document-formats
|
||||
url = https://github.com/ONLYOFFICE/document-formats
|
||||
branch = master
|
||||
[submodule "web/documentserver-example/java-spring/src/main/resources/assets/document-formats"]
|
||||
path = web/documentserver-example/java-spring/src/main/resources/assets/document-formats
|
||||
url = https://github.com/ONLYOFFICE/document-formats
|
||||
branch = master
|
||||
[submodule "web/documentserver-example/csharp/assets/document-templates"]
|
||||
path = web/documentserver-example/csharp/assets/document-templates
|
||||
url = https://github.com/ONLYOFFICE/document-templates
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
Document Server integration example uses code from the following 3rd party projects.
|
||||
|
||||
|
||||
web/documentserver-example/csharp
|
||||
|
||||
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
|
||||
@ -132,6 +131,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
|
||||
License: Apache 2.0
|
||||
License File: jackson-databind.license
|
||||
|
||||
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: jackson-dataformat-properties.license
|
||||
|
||||
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
|
||||
License: MIT, GPL
|
||||
License File: jQuery.BlockUI.license
|
||||
@ -156,6 +159,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
|
||||
License: MIT
|
||||
License File: jQuery.UI.license
|
||||
|
||||
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
|
||||
License Public Domain
|
||||
License File: json.license
|
||||
|
||||
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: JSON.simple.license
|
||||
@ -168,14 +175,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
|
||||
License: Apache 2.0
|
||||
License File modelmapper.license
|
||||
|
||||
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: prime-jwt.license
|
||||
|
||||
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
@ -271,6 +278,9 @@ urllib - Request HTTP URLs in a complex world — basic and digest authen
|
||||
License: MIT
|
||||
License File: urllib.license
|
||||
|
||||
utf7 - Encodes and decodes JavaScript (Unicode/UCS-2) strings to UTF-7 ASCII strings. (https://github.com/kkaefer/utf7/blob/master/LICENSE)
|
||||
License: MIT
|
||||
License File: utf7.license
|
||||
|
||||
|
||||
web/documentserver-example/php
|
||||
|
||||
13
CHANGELOG.md
@ -1,5 +1,18 @@
|
||||
# Change Log
|
||||
|
||||
## 1.10.0
|
||||
- nodejs: converting function on index page
|
||||
- java-spring: using java docs-integration-sdk
|
||||
- tabs menu
|
||||
- creating and editing pdf instead docxf
|
||||
- filling by default
|
||||
- forgotten files
|
||||
- delete all files
|
||||
- save as for pdf
|
||||
- handling conversion -9 error
|
||||
- change inserted image
|
||||
- different goback for users
|
||||
|
||||
## 1.9.0
|
||||
- nodejs: filling by default
|
||||
- nodejs: docxf, oform as pdf documentType
|
||||
|
||||
10
Readme.md
@ -1,11 +1,11 @@
|
||||
## Integration examples
|
||||
|
||||
Test examples are simple document management systems that can be built into your application for testing.
|
||||
These test examples are simple document management systems that can be built into your application for testing.
|
||||
Do NOT use these integration examples on your own server without proper code modifications!
|
||||
In case you enabled any of the test examples, disable it before going for production.
|
||||
|
||||
These examples show the way to integrate [ONLYOFFICE Docs][2] into your own website or application using one of the programming languages.
|
||||
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Node.js, PHP and Ruby.
|
||||
The package contains examples written in .Net (C# MVC), .Net (C#), Java, Java Spring, Node.js, PHP, Python and Ruby.
|
||||
|
||||
You should change `http://documentserver` to your server address in these files:
|
||||
* [.Net (C# MVC)](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/csharp-mvc) - `web/documentserver-example/csharp-mvc/web.appsettings.config`
|
||||
@ -13,9 +13,9 @@ You should change `http://documentserver` to your server address in these files:
|
||||
* [Java](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java) - `web/documentserver-example/java/src/main/resources/settings.properties`
|
||||
* [Java Spring](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/java-spring) - `web/documentserver-example/java-spring/src/main/resources/application.properties`
|
||||
* [Node.js](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/nodejs) - `web/documentserver-example/nodejs/config/default.json`
|
||||
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/config.json`
|
||||
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/config.py`
|
||||
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/config/application.rb`
|
||||
* [PHP](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/php) - `web/documentserver-example/php/src/configuration/ConfigurationManager.php`
|
||||
* [Python](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/python) - `web/documentserver-example/python/src/configuration/configuration.py`
|
||||
* [Ruby](https://github.com/ONLYOFFICE/document-server-integration/tree/master/web/documentserver-example/ruby) - `web/documentserver-example/ruby/app/configuration/configuration.rb`
|
||||
|
||||
More information on how to use these examples can be found here: [http://api.onlyoffice.com/editors/demopreview](http://api.onlyoffice.com/editors/demopreview "http://api.onlyoffice.com/editors/demopreview")
|
||||
|
||||
|
||||
@ -38,9 +38,15 @@ namespace OnlineEditorsExampleMVC
|
||||
|
||||
// create the main script bundle
|
||||
bundles.Add(new ScriptBundle("~/bundles/scripts").Include(
|
||||
"~/Scripts/formats.js",
|
||||
"~/Scripts/jscript.js"
|
||||
));
|
||||
|
||||
// create the forgotten page script bundle
|
||||
bundles.Add(new ScriptBundle("~/bundles/forgotten").Include(
|
||||
"~/Scripts/forgotten.js"
|
||||
));
|
||||
|
||||
// create a style bundle
|
||||
bundles.Add(new StyleBundle("~/Content/css").Include(
|
||||
"~/Content/stylesheet.css",
|
||||
@ -52,6 +58,11 @@ namespace OnlineEditorsExampleMVC
|
||||
bundles.Add(new StyleBundle("~/Content/editor").Include(
|
||||
"~/Content/editor.css"
|
||||
));
|
||||
|
||||
// create the forgotten page style bundle
|
||||
bundles.Add(new StyleBundle("~/Content/forgotten").Include(
|
||||
"~/Content/forgotten.css"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
161
web/documentserver-example/csharp-mvc/Content/forgotten.css
Normal file
@ -0,0 +1,161 @@
|
||||
.center {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 832px;
|
||||
margin: 0 32px;
|
||||
padding: 48px 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #E2E2E2;
|
||||
}
|
||||
|
||||
.tableRow td:first-child {
|
||||
width: 70%;
|
||||
flex-grow: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.tableHeader td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 10%;
|
||||
text-align: center;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.tableHeader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stored-edit {
|
||||
display: block;
|
||||
padding-top: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
menu.links {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scroll-table-body table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 12px;
|
||||
line-height: normal;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.stored-list {
|
||||
height: calc(100% - 58px);
|
||||
}
|
||||
|
||||
header {
|
||||
min-width:auto;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 1152px;
|
||||
}
|
||||
|
||||
@media (max-width: 1279px) and (min-width: 1024px) {
|
||||
.left-panel {
|
||||
width: 208px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 688px;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: 928px;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) and (min-width: 593px) {
|
||||
.center {
|
||||
max-width: 768px;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
|
||||
.table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 208px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: 768px;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 592px) and (min-width: 320px) {
|
||||
.center, .table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 28px 16px;
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 3c0-1.65685 1.34315-3 3-3h20l7 7v30c0 1.6569-1.3431 3-3 3H3c-1.65685 0-3-1.3431-3-3V3z" fill="#27ABA3"/><path d="M23 0l7 7h-4c-1.6569 0-3-1.34315-3-3V0z" fill="#008078"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 14H6v7h18v-7zm-.8182 5.9978H6.81818V15H23.1818v4.9978zM24 23H6v7h18v-7zm-.8182 5.9978H6.81818V24H23.1818v4.9978z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 463 B |
@ -0,0 +1,5 @@
|
||||
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 3C0 1.34315 1.34315 0 3 0H23L30 7V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#9E1919"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0062 15V16.0065H24V15H17.0062ZM17.0062 19V20.0163H24V19H17.0062ZM24 23H17.0062V24.0261H24V23ZM6 28V27.0293H24V28H6ZM7 16H14V23H7V16ZM6 15H7H14H15V16V23V24H14H7H6V23V16V15Z" fill="white"/>
|
||||
<path d="M23 0L30 7H26C24.3431 7 23 5.65685 23 4V0Z" fill="black" fill-opacity="0.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@ -0,0 +1,3 @@
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 17V11H12V17H17V9H20L10 0L0 9H3V17H8Z" fill="#444444"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 173 B |
@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 1h8l4 4v10H2V1z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5l-4-4H2v14h12V5zm-4-5l5 5v11H1V0h9z" fill="#BFBFBF"/><path fill="#9E1919" d="M3 10h10v4H3z"/><path d="M7 7V2H3v5h4zM8 3V2h2v1H8zM8 5V4h5v1H8zM13 6H8v1h5V6zM13 8H3v1h10V8z" fill="#BFBFBF"/><path opacity=".3" d="M9 1h1v3h4l1 1H9V1z" fill="#333"/></svg>
|
||||
|
After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5332 22.2243L0.632544 17.5921C-0.210848 17.1877 -0.210848 16.5627 0.632544 16.1951L4.07945 14.5775L10.4966 17.5921C11.34 17.9965 12.6967 17.9965 13.5034 17.5921L19.9206 14.5775L23.3675 16.1951C24.2108 16.5995 24.2108 17.2245 23.3675 17.5921L13.4668 22.2243C12.6967 22.592 11.34 22.592 10.5332 22.2243Z" fill="#FF6F3D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 16.4922L0.630617 11.8546C-0.210206 11.4497 -0.210206 10.824 0.630617 10.456L3.99391 8.87329L10.5011 11.9282C11.342 12.3331 12.6946 12.3331 13.4989 11.9282L20.0061 8.87329L23.3694 10.456C24.2102 10.8608 24.2102 11.4865 23.3694 11.8546L13.4989 16.4922C12.658 16.897 11.3054 16.897 10.5011 16.4922Z" fill="#95C038"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 10.8195L0.630617 6.24863C-0.210206 5.84959 -0.210206 5.23289 0.630617 4.87013L10.5011 0.299281C11.342 -0.0997605 12.6946 -0.0997605 13.4989 0.299281L23.3694 4.87013C24.2102 5.26917 24.2102 5.88587 23.3694 6.24863L13.4989 10.8195C12.658 11.1822 11.3054 11.1822 10.5011 10.8195Z" fill="#5DC0E8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="20" height="2" rx="1" fill="white"/>
|
||||
<rect y="6" width="20" height="2" rx="1" fill="white"/>
|
||||
<rect y="12" width="20" height="2" rx="1" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 278 B |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13H7C6.44772 13 6 12.5523 6 12C6 11.4477 6.44772 11 7 11H11V7C11 6.44772 11.4477 6 12 6C12.5523 6 13 6.44772 13 7V11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H13V17Z" fill="#444444"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
@ -79,7 +79,8 @@
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
@ -119,7 +120,8 @@
|
||||
.contentCells-icon{
|
||||
width: 5%;
|
||||
}
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
@ -175,7 +177,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 715px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
@ -263,7 +266,8 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
@ -293,7 +297,8 @@
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
@ -407,7 +412,8 @@
|
||||
padding: 16px 0 6px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@ -502,6 +508,17 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.buttonsMobile.indent {
|
||||
margin-bottom: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.button.file-type:hover,
|
||||
.button.file-type {
|
||||
height: 28px;
|
||||
width: 100px;
|
||||
margin-bottom: 10px !important;
|
||||
font-size: 9px;
|
||||
}
|
||||
.button.gray{
|
||||
margin: 0;
|
||||
}
|
||||
@ -527,7 +544,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 510px) and (min-width: 470px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
@ -553,7 +571,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 470px) and (min-width: 420px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 30%;
|
||||
}
|
||||
.tableRow td:first-child{
|
||||
@ -588,7 +607,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 420px) and (min-width: 320px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
@ -638,7 +658,8 @@
|
||||
}
|
||||
}
|
||||
@media (max-width: 769px) and (min-width: 715px){
|
||||
.tableRow{
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
@ -687,3 +708,216 @@
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 592px) and (min-width: 320px) {
|
||||
body.menu-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
min-width: auto;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header, footer {
|
||||
position: -webkit-sticky; /* Safari */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
background-color: rgba(186, 186, 186, 0.6);
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
align-items: start;
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
height: calc(100% - 124px);
|
||||
z-index:99;
|
||||
}
|
||||
|
||||
.left-panel.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.help-block {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-color: #F5F5F5;
|
||||
width: 248px;
|
||||
padding-left: 16px;
|
||||
padding-top: 33px;
|
||||
padding-bottom: 33px;
|
||||
padding-right: 40px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mobile-close-btn {
|
||||
display: block;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background-color: #E2E2E2;
|
||||
border-radius: 2px;
|
||||
border-color: #E2E2E2;
|
||||
color: #808080;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
padding: 28px 16px;
|
||||
}
|
||||
|
||||
#portal-info {
|
||||
width: 100%;
|
||||
max-width: fit-content;
|
||||
}
|
||||
|
||||
menu.links {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
span.portal-name {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span.portal-descr:first-child {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
span.portal-descr {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.user-descr {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: auto;
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
padding: 12px 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.user-descr ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-descr ul.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.user-descr b {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.user-descr b::before {
|
||||
content: url("images/plus.svg");
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.storedHeader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.storedHeaderClearAll {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
top: 36px;
|
||||
}
|
||||
|
||||
.scroll-table-body tr:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
padding: 16px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableRow td:first-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.header-list {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.firstContentCellViewers {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.firstContentCellViewers ~ td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.downloadContentCellShift:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.responsive-nav {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0;
|
||||
align-items: center;
|
||||
column-gap: 16px;
|
||||
padding: 10px 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: calc(100% - 124px);
|
||||
}
|
||||
|
||||
.user-block-table {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +65,14 @@ header img {
|
||||
margin: 10px 0 22px 32px;
|
||||
}
|
||||
|
||||
.responsive-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-close-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.center {
|
||||
position:relative;
|
||||
margin: 0 auto 0;
|
||||
@ -164,7 +172,7 @@ label .checkbox {
|
||||
}
|
||||
|
||||
.try-editor.form {
|
||||
background-image: url("images/file_docxf.svg");
|
||||
background-image: url("images/file_pdf.svg");
|
||||
}
|
||||
|
||||
.side-option {
|
||||
@ -230,6 +238,33 @@ label .checkbox {
|
||||
color: #FF6F3D;
|
||||
}
|
||||
|
||||
.button.file-type {
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
padding: 8px 8px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button.file-type.disable {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.button.file-type.pale {
|
||||
opacity: 30%;
|
||||
}
|
||||
|
||||
.button.file-type.document {
|
||||
background: #446995;
|
||||
}
|
||||
|
||||
.button.file-type.spreadsheet {
|
||||
background: #40865C;
|
||||
}
|
||||
|
||||
.button.file-type.presentation {
|
||||
background: #AA5252;
|
||||
}
|
||||
|
||||
.upload-panel {
|
||||
float: left;
|
||||
padding: 24px 0;
|
||||
@ -271,6 +306,43 @@ label .checkbox {
|
||||
border-bottom: 1px solid #D0D5DA;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
column-gap: 30px;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
border-bottom: 1px solid #E2E2E2;
|
||||
margin: 0;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.links li {
|
||||
padding: 4px;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.links li.active {
|
||||
border-bottom: 2px solid #FF6F3D;
|
||||
}
|
||||
|
||||
.links li.active a {
|
||||
color: #FF6F3D;
|
||||
}
|
||||
|
||||
.links li.active a img {
|
||||
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
|
||||
}
|
||||
|
||||
.links a {
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#mainProgress {
|
||||
color: #333333;
|
||||
display: none;
|
||||
@ -464,6 +536,11 @@ footer table tr td:first-child {
|
||||
background-image: url("images/icon_pptx.svg");
|
||||
}
|
||||
|
||||
.stored-edit.pdf,
|
||||
.uploadFileName.pdf {
|
||||
background-image: url("images/icon_pdf.svg");
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
@ -592,6 +669,29 @@ footer table tr td:first-child {
|
||||
width: 4%;
|
||||
}
|
||||
|
||||
.storedHeader {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.storedHeaderClearAll {
|
||||
padding-right: 52px;
|
||||
}
|
||||
|
||||
.clear-all {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
padding: 2px;
|
||||
outline: 1px solid #E5E5E5;
|
||||
text-align: center;
|
||||
cursor:pointer;
|
||||
text-transform: uppercase;
|
||||
background-color: #F5F5F5;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.select-user {
|
||||
color: #444444;
|
||||
font-family: Open Sans;
|
||||
@ -741,6 +841,16 @@ html {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.buttonsMobile.indent{
|
||||
padding-left: 35px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
@ -17,10 +17,13 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Web.Mvc;
|
||||
using OnlineEditorsExampleMVC.Helpers;
|
||||
using OnlineEditorsExampleMVC.Models;
|
||||
using System.Web.Configuration;
|
||||
|
||||
namespace OnlineEditorsExampleMVC.Controllers
|
||||
{
|
||||
@ -31,6 +34,46 @@ namespace OnlineEditorsExampleMVC.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
public ActionResult Forgotten()
|
||||
{
|
||||
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
|
||||
{
|
||||
ViewData["Message"] = "The forgotten page is disabled";
|
||||
return View("~/Views/Shared/Error.aspx");
|
||||
}
|
||||
|
||||
var files = new List<Dictionary<string, string>>();
|
||||
|
||||
try
|
||||
{
|
||||
var response = TrackManager.commandRequest("getForgottenList", null);
|
||||
ArrayList keys = (ArrayList)response["keys"];
|
||||
|
||||
// fetch all the forgotten files from the document server
|
||||
foreach (string key in keys)
|
||||
{
|
||||
var file = new Dictionary<string, string>();
|
||||
var fileResult = TrackManager.commandRequest("getForgotten", key);
|
||||
file.Add("key", fileResult["key"].ToString());
|
||||
file.Add("url", fileResult["url"].ToString());
|
||||
file.Add(
|
||||
"type",
|
||||
FileUtility.GetFileType(fileResult["url"].ToString())
|
||||
.ToString()
|
||||
.ToLower()
|
||||
);
|
||||
|
||||
files.Add(file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
return View("Forgotten", new ForgottenFilesModel(files));
|
||||
}
|
||||
|
||||
// viewing file in the editor
|
||||
public ActionResult Editor(string fileName, string editorsMode, string editorsType, string directUrl)
|
||||
{
|
||||
@ -52,7 +95,7 @@ namespace OnlineEditorsExampleMVC.Controllers
|
||||
var id = Request.Cookies.GetOrDefault("uid", null);
|
||||
var user = Users.getUser(id);
|
||||
DocManagerHelper.CreateMeta(fileName, user.id, user.name); // create meta information for the sample document
|
||||
Response.Redirect(Url.Action("Editor", "Home", new { fileName = fileName }));
|
||||
Response.Redirect(Url.Action("Editor", "Home", new { fileName = fileName, editorsMode="edit" }));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +229,10 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
|
||||
switch (errorCode)
|
||||
{
|
||||
case -9:
|
||||
// public const int c_nErrorConversionOutputFormatError = -9;
|
||||
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
|
||||
break;
|
||||
case -8:
|
||||
// public const int c_nErrorFileVKey = -8;
|
||||
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");
|
||||
|
||||
@ -282,7 +282,7 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
}
|
||||
|
||||
// create a command request
|
||||
public static void commandRequest(string method, string key, object meta = null)
|
||||
public static Dictionary<string, object> commandRequest(string method, string key, object meta = null)
|
||||
{
|
||||
DocManagerHelper.VerifySSL();
|
||||
|
||||
@ -345,6 +345,7 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
{
|
||||
throw new Exception(dataResponse);
|
||||
}
|
||||
return responseObj;
|
||||
}
|
||||
|
||||
// save file
|
||||
|
||||
@ -59,7 +59,9 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
"Can’t print the file",
|
||||
"Can create new files from the editor",
|
||||
"Can see the information about Group2 users",
|
||||
"Can’t submit forms"
|
||||
"Can’t submit forms",
|
||||
"Can't close history",
|
||||
"Can't restore the file version"
|
||||
};
|
||||
|
||||
static List<string> descr_user_0 = new List<string>()
|
||||
@ -92,7 +94,8 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
new List<string>(),
|
||||
descr_user_1,
|
||||
true,
|
||||
true
|
||||
true,
|
||||
new Goback(null, false)
|
||||
),
|
||||
new User(
|
||||
"uid-2",
|
||||
@ -111,7 +114,8 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
new List<string>(),
|
||||
descr_user_2,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
new Goback("Go to Documents", null)
|
||||
),
|
||||
new User(
|
||||
"uid-3",
|
||||
@ -130,7 +134,8 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
new List<string>() { "copy", "download", "print" },
|
||||
descr_user_3,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
null
|
||||
),
|
||||
new User(
|
||||
"uid-0",
|
||||
@ -144,7 +149,8 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
new List<string>() { "protect" },
|
||||
descr_user_0,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
null
|
||||
)
|
||||
};
|
||||
|
||||
@ -235,7 +241,9 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
public List<string> userInfoGroups;
|
||||
public bool avatar;
|
||||
|
||||
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar)
|
||||
public Goback goback;
|
||||
|
||||
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar, Goback goback)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@ -249,6 +257,21 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
this.templates = templates;
|
||||
this.userInfoGroups = userInfoGroups;
|
||||
this.avatar = avatar;
|
||||
this.goback = goback;
|
||||
}
|
||||
}
|
||||
|
||||
public class Goback
|
||||
{
|
||||
public string text;
|
||||
public bool? blank;
|
||||
|
||||
public Goback(){}
|
||||
|
||||
public Goback(string text, bool? blank)
|
||||
{
|
||||
this.text = text;
|
||||
this.blank = blank;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,18 +77,19 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
var jss = new JavaScriptSerializer();
|
||||
|
||||
var ext = Path.GetExtension(FileName).ToLower(); // get file extension
|
||||
var editorsMode = Mode ?? "edit"; // get editor mode
|
||||
var canFill = DocManagerHelper.FillFormExts.Contains(ext);
|
||||
var editorsMode = Mode ?? (canFill ? "fillForms" : "edit"); // get editor mode
|
||||
|
||||
var canEdit = DocManagerHelper.EditedExts.Contains(ext); // check if the file with such an extension can be edited
|
||||
|
||||
var id = request.Cookies.GetOrDefault("uid", null);
|
||||
var user = Users.getUser(id); // get the user
|
||||
|
||||
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && DocManagerHelper.FillFormExts.Contains(ext)) {
|
||||
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && canFill) {
|
||||
editorsMode = "fillForms";
|
||||
canEdit = true;
|
||||
}
|
||||
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1"); // check if the Submit form button is displayed or not
|
||||
var submitForm = (editorsMode.Equals("fillForms") || editorsMode.Equals("embedded")) && user.id.Equals("uid-1"); // check if the Submit form button is displayed or not
|
||||
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // set the mode parameter: change it to view if the document can't be edited
|
||||
|
||||
// favorite icon state
|
||||
@ -214,10 +215,12 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
|
||||
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
|
||||
{
|
||||
"goback", new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
|
||||
"goback", user.goback != null ? new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
|
||||
{
|
||||
{ "url", DocManagerHelper.GetServerUrl(false) } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
|
||||
}
|
||||
{ "url", DocManagerHelper.GetServerUrl(false) }, // the absolute URL to the website address which will be opened when clicking the Open file location menu button
|
||||
{ "text", user.goback.text },
|
||||
{ "blank", user.goback.blank }
|
||||
} : new Dictionary<string, object>{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,20 +292,20 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
{
|
||||
Path = HttpRuntime.AppDomainAppVirtualPath
|
||||
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
|
||||
+ "Content\\images\\logo.png"
|
||||
+ "Content\\images\\logo.svg"
|
||||
};
|
||||
|
||||
var directMailMergeUrl = new UriBuilder(DocManagerHelper.GetServerUrl(false))
|
||||
{
|
||||
Path = HttpRuntime.AppDomainAppVirtualPath
|
||||
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
|
||||
+ "Content\\images\\logo.png"
|
||||
+ "Content\\images\\logo.svg"
|
||||
};
|
||||
|
||||
// create a logo config
|
||||
var logoConfig = new Dictionary<string, object>
|
||||
{
|
||||
{ "fileType", "png"},
|
||||
{ "fileType", "svg"},
|
||||
{ "url", mailMergeUrl.ToString()}
|
||||
};
|
||||
|
||||
|
||||
@ -33,7 +33,8 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
{
|
||||
Word,
|
||||
Cell,
|
||||
Slide
|
||||
Slide,
|
||||
Pdf
|
||||
}
|
||||
|
||||
// get file type
|
||||
@ -41,6 +42,7 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
{
|
||||
var ext = Path.GetExtension(fileName).ToLower();
|
||||
|
||||
if (FormatManager.PdfExtensions().Contains(ext)) return FileType.Pdf; // pdf type for document extensions
|
||||
if (FormatManager.DocumentExtensions().Contains(ext)) return FileType.Word; // word type for document extensions
|
||||
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return FileType.Cell; // cell type for spreadsheet extensions
|
||||
if (FormatManager.PresentationExtensions().Contains(ext)) return FileType.Slide; // slide type for presentation extensions
|
||||
@ -185,6 +187,20 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<string> PdfExtensions()
|
||||
{
|
||||
return Pdfs()
|
||||
.Select(format => format.Extension())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<Format> Pdfs()
|
||||
{
|
||||
return All()
|
||||
.Where(format => format.Type == FileType.Pdf)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<string> AllExtensions()
|
||||
{
|
||||
return All()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
@ -16,16 +16,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.dto;
|
||||
using System.Collections.Generic;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
namespace OnlineEditorsExampleMVC.Models
|
||||
{
|
||||
// create file model
|
||||
public class ForgottenFilesModel
|
||||
{
|
||||
public List<Dictionary<string, string>> files { get; set; }
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ChangesHistory {
|
||||
private String created;
|
||||
private ChangesUser user;
|
||||
}
|
||||
public ForgottenFilesModel(List<Dictionary<string, string>> files) { this.files = files; }
|
||||
}
|
||||
}
|
||||
@ -116,6 +116,7 @@
|
||||
<Compile Include="Helpers\Utils.cs" />
|
||||
<Compile Include="Models\FileModel.cs" />
|
||||
<Compile Include="Models\FileUtility.cs" />
|
||||
<Compile Include="Models\ForgottenFilesModel.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="WebEditor.ashx.cs">
|
||||
<DependentUpon>WebEditor.ashx</DependentUpon>
|
||||
@ -123,6 +124,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Content\editor.css" />
|
||||
<Content Include="Content\forgotten.css" />
|
||||
<Content Include="Content\images\block-content.svg" />
|
||||
<Content Include="Content\images\cell.ico" />
|
||||
<Content Include="Content\images\close.svg" />
|
||||
@ -140,18 +142,20 @@
|
||||
<Content Include="Content\images\file_xlsx.svg" />
|
||||
<Content Include="Content\images\fill-forms.svg" />
|
||||
<Content Include="Content\images\filter.svg" />
|
||||
<Content Include="Content\images\home.svg" />
|
||||
<Content Include="Content\images\icon_docx.svg" />
|
||||
<Content Include="Content\images\icon_pptx.svg" />
|
||||
<Content Include="Content\images\icon_xlsx.svg" />
|
||||
<Content Include="Content\images\info.svg" />
|
||||
<Content Include="Content\images\loader16.gif" />
|
||||
<Content Include="Content\images\logo.png" />
|
||||
<Content Include="Content\images\logo.svg" />
|
||||
<Content Include="Content\images\mobile-fill-forms.svg" />
|
||||
<Content Include="Content\images\mobile.svg" />
|
||||
<Content Include="Content\images\notdone.svg" />
|
||||
<Content Include="Content\images\review.svg" />
|
||||
<Content Include="Content\images\slide.ico" />
|
||||
<Content Include="Content\images\uid-1.png" />
|
||||
<Content Include="Content\images\uid-2.png" />
|
||||
<Content Include="Content\images\word.ico" />
|
||||
<Content Include="Content\jquery-ui.css" />
|
||||
<Content Include="Content\media.css" />
|
||||
@ -159,6 +163,10 @@
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="LICENSE" />
|
||||
<Content Include="Scripts\forgotten.js" />
|
||||
<Content Include="Scripts\formats.js" />
|
||||
<Content Include="Scripts\jquery-3.6.4.js" />
|
||||
<Content Include="Scripts\jquery-migrate-3.4.1.js" />
|
||||
<Content Include="Scripts\jquery-ui.js" />
|
||||
<Content Include="Scripts\jquery.blockUI.js" />
|
||||
<Content Include="Scripts\jquery.dropdownToggle.js" />
|
||||
@ -166,17 +174,13 @@
|
||||
<Content Include="Scripts\jquery.iframe-transport.js" />
|
||||
<Content Include="Scripts\jscript.js" />
|
||||
<Content Include="Views\Home\Editor.aspx" />
|
||||
<Content Include="Views\Home\Forgotten.aspx" />
|
||||
<Content Include="Views\Home\Index.aspx" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Views\Shared\Error.aspx" />
|
||||
<Content Include="licenses\EntityFramework.license" />
|
||||
<Content Include="licenses\Microsoft.Web.Infrastructure.license" />
|
||||
<Content Include="licenses\Newtonsoft.Json.license" />
|
||||
<Content Include="licenses\jquery.license" />
|
||||
<Content Include="licenses\WebGrease.license" />
|
||||
<Content Include="web.appsettings.config" />
|
||||
<Content Include="WebEditor.ashx" />
|
||||
</ItemGroup>
|
||||
|
||||
19
web/documentserver-example/csharp-mvc/Scripts/forgotten.js
Executable file
@ -0,0 +1,19 @@
|
||||
function deleteFile(event) {
|
||||
let filename = event.currentTarget.getAttribute("data");
|
||||
filename = encodeURIComponent(filename);
|
||||
let url = `webeditor.ashx?type=removeforgotten&filename=${filename}`;
|
||||
|
||||
fetch(url, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
}).then(result => {
|
||||
if(result.status == 204) {
|
||||
document.location.reload(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.delete-file').forEach(el => {
|
||||
el.addEventListener('click', deleteFile);
|
||||
});
|
||||
66
web/documentserver-example/csharp-mvc/Scripts/formats.js
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
class Format {
|
||||
constructor(name, type, actions, convert, mime) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.actions = actions;
|
||||
this.convert = convert;
|
||||
this.mime = mime;
|
||||
}
|
||||
|
||||
isAutoConvertible() {
|
||||
return this.actions.includes('auto-convert');
|
||||
}
|
||||
|
||||
isEditable() {
|
||||
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
|
||||
}
|
||||
|
||||
isFillable() {
|
||||
return this.actions.includes('fill');
|
||||
}
|
||||
}
|
||||
|
||||
class FormatManager {
|
||||
formats = [];
|
||||
|
||||
constructor(formats) {
|
||||
if(Array.isArray(formats)) this.formats = formats;
|
||||
}
|
||||
|
||||
findByExtension(extension) {
|
||||
return this.formats.find(format => format.name == extension);
|
||||
}
|
||||
|
||||
isAutoConvertible(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isAutoConvertible();
|
||||
}
|
||||
|
||||
isEditable(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isEditable();
|
||||
}
|
||||
|
||||
isFillable(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isFillable();
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,27 @@
|
||||
*/
|
||||
|
||||
var directUrl;
|
||||
var formatManager;
|
||||
|
||||
window.onload = function () {
|
||||
fetch("webeditor.ashx?type=formats")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.formats) {
|
||||
let formats = [];
|
||||
data.formats.forEach(format => {
|
||||
formats.push(new Format(
|
||||
format.Name,
|
||||
format.Type,
|
||||
format.Actions,
|
||||
format.Convert,
|
||||
format.Mime
|
||||
));
|
||||
});
|
||||
formatManager = new FormatManager(formats);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof jQuery != "undefined") {
|
||||
jq = jQuery.noConflict();
|
||||
@ -87,8 +108,8 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
|
||||
var timer = null;
|
||||
var checkConvert = function (filePass) {
|
||||
filePass = filePass ? filePass : null;
|
||||
var checkConvert = function (filePass, fileType) {
|
||||
filePass = filePass ? filePass : null;
|
||||
if (timer != null) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
@ -100,10 +121,10 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#filePass").val("");
|
||||
|
||||
var fileName = jq("#hiddenFileName").val();
|
||||
var posExt = fileName.lastIndexOf('.');
|
||||
var posExt = fileName.lastIndexOf('.') + 1;
|
||||
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
|
||||
|
||||
if (ConverExtList.indexOf(posExt) == -1) {
|
||||
if (!formatManager.isAutoConvertible(posExt)) {
|
||||
jq("#step2").addClass("done").removeClass("current");
|
||||
loadScripts();
|
||||
return;
|
||||
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
|
||||
contentType: "text/xml",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({ filename: fileName, filePass: filePass }),
|
||||
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
|
||||
url: UrlConverter,
|
||||
complete: function (data) {
|
||||
var responseText = data.responseText;
|
||||
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (response.error.includes("Error conversion output format")) {
|
||||
jq("#select-file-type").removeClass("invisible");
|
||||
jq("#step2").removeClass("current");
|
||||
jq("#hiddenFileName").attr("placeholder", filePass);
|
||||
return;
|
||||
}
|
||||
jq(".current").removeClass("current");
|
||||
jq(".step:not(.done)").addClass("error");
|
||||
jq("#mainProgress .error-message").show().find("span").text(response.error);
|
||||
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#hiddenFileName").val(response.filename);
|
||||
|
||||
if (response.step && response.step < 100) {
|
||||
checkConvert(filePass);
|
||||
checkConvert(filePass, fileType);
|
||||
} else {
|
||||
jq("#step2").addClass("done").removeClass("current");
|
||||
loadScripts();
|
||||
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#beginView, #beginEmbedded").removeClass("disable");
|
||||
|
||||
var fileName = jq("#hiddenFileName").val();
|
||||
var posExt = fileName.lastIndexOf('.');
|
||||
var posExt = fileName.lastIndexOf('.') + 1;
|
||||
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
|
||||
|
||||
if (EditedExtList.indexOf(posExt) != -1 || FillExtList.indexOf(posExt) != -1) {
|
||||
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
|
||||
jq("#beginEdit").removeClass("disable");
|
||||
}
|
||||
};
|
||||
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
};
|
||||
|
||||
jq(document).on("click", ".file-type:not(.disable)", function () {
|
||||
const currentElement = jq(this);
|
||||
var fileType = currentElement.attr("data");
|
||||
var filePass = jq("#hiddenFileName").attr("placeholder");
|
||||
jq('.file-type').addClass(["disable", "pale"]);
|
||||
currentElement.removeClass("pale");
|
||||
checkConvert(filePass, fileType);
|
||||
});
|
||||
|
||||
jq(document).on("click", "#enterPass", function () {
|
||||
var filePass = jq("#filePass").val();
|
||||
if (filePass) {
|
||||
@ -294,6 +330,23 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
});
|
||||
|
||||
jq(document).on("click", ".clear-all", function () {
|
||||
if (confirm("Delete all the files?")) {
|
||||
var requestAddress = "webeditor.ashx"
|
||||
+ "?type=remove";
|
||||
jq.ajax({
|
||||
async: true,
|
||||
contentType: "text/xml",
|
||||
url: requestAddress,
|
||||
complete: function (data) {
|
||||
if (JSON.parse(data.responseText).success) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showUserTooltip (isMobile) {
|
||||
if ( jq("div#portal-info").is(":hidden") ) {
|
||||
jq("div#portal-info").show();
|
||||
@ -368,4 +421,27 @@ if (typeof jQuery != "undefined") {
|
||||
}).mouseout(function () {
|
||||
jq("div.tooltip").remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSidePanel(event) {
|
||||
event.preventDefault();
|
||||
let sidePanel = document.querySelector(".left-panel");
|
||||
let body = document.querySelector("body");
|
||||
if (sidePanel.classList.contains("active")) {
|
||||
sidePanel.classList.remove("active");
|
||||
body.classList.remove("menu-open");
|
||||
} else {
|
||||
sidePanel.classList.add("active")
|
||||
body.classList.add("menu-open");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUserDescr(event) {
|
||||
let list = event.currentTarget.querySelector("ul");
|
||||
let cursor = window.getComputedStyle(event.currentTarget).getPropertyValue("cursor");
|
||||
|
||||
if (cursor === "pointer") {
|
||||
if (list.classList.contains("active")) list.classList.remove("active");
|
||||
else list.classList.add("active");
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@
|
||||
|
||||
// the meta information of the document is changed via the meta command
|
||||
var onMetaChange = function (event) {
|
||||
if (event.data.favorite) {
|
||||
if (event.data.favorite !== undefined) {
|
||||
var favorite = !!event.data.favorite;
|
||||
var title = document.title.replace(/^\☆/g, "");
|
||||
document.title = (favorite ? "☆" : "") + title;
|
||||
@ -259,6 +259,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
<% string usersForMentions; %>
|
||||
<% Model.GetUsersMentions(Request, out usersForMentions); %>
|
||||
<% string usersInfo; %>
|
||||
<% Model.GetUsersInfo(Request, out usersInfo); %>
|
||||
<% string usersForProtect; %>
|
||||
<% Model.GetUsersProtect(Request, out usersForProtect); %>
|
||||
|
||||
var onRequestUsers = function (event) {
|
||||
if (event && event.data){
|
||||
var c = event.data.c;
|
||||
}
|
||||
switch (c) {
|
||||
case "info":
|
||||
users = [];
|
||||
var allUsers = <%= usersInfo %>;
|
||||
for (var i = 0; i < event.data.id.length; i++) {
|
||||
for (var j = 0; j < allUsers.length; j++) {
|
||||
if (allUsers[j].id == event.data.id[i]) {
|
||||
users.push(allUsers[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "protect":
|
||||
var users = <%= usersForProtect %>;
|
||||
break;
|
||||
default:
|
||||
users = <%= usersForMentions %>;
|
||||
}
|
||||
docEditor.setUsers({
|
||||
"c": c,
|
||||
"users": users,
|
||||
});
|
||||
};
|
||||
|
||||
var onRequestSendNotify = function (event) {
|
||||
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
|
||||
var data = JSON.stringify(event.data);
|
||||
innerAlert("onRequestSendNotify: " + data);
|
||||
};
|
||||
|
||||
config = <%= Model.GetDocConfig(Request, Url) %>;
|
||||
|
||||
config.width = "100%";
|
||||
@ -276,63 +318,28 @@
|
||||
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
|
||||
};
|
||||
|
||||
<% string usersForMentions; %>
|
||||
<% Model.GetUsersMentions(Request, out usersForMentions); %>
|
||||
<% string usersInfo; %>
|
||||
<% Model.GetUsersInfo(Request, out usersInfo); %>
|
||||
<% string usersForProtect; %>
|
||||
<% Model.GetUsersProtect(Request, out usersForProtect); %>
|
||||
|
||||
if (config.editorConfig.user.id) {
|
||||
// the user is trying to show the document version history
|
||||
config.events['onRequestHistory'] = onRequestHistory;
|
||||
// the user is trying to click the specific document version in the document version history
|
||||
config.events['onRequestHistoryData'] = onRequestHistoryData;
|
||||
// the user is trying to go back to the document from viewing the document version history
|
||||
config.events['onRequestHistoryClose'] = function () {
|
||||
document.location.reload();
|
||||
};
|
||||
config.events['onRequestRestore'] = onRequestRestore;
|
||||
if (config.editorConfig.user.id !== "uid-3") {
|
||||
config.events['onRequestHistoryClose'] = function () {
|
||||
document.location.reload();
|
||||
};
|
||||
config.events['onRequestRestore'] = onRequestRestore;
|
||||
}
|
||||
|
||||
// add mentions for not anonymous users
|
||||
<% if (!string.IsNullOrEmpty(usersForMentions))
|
||||
{ %>
|
||||
config.events['onRequestUsers'] = function (event) {
|
||||
if (event && event.data){
|
||||
var c = event.data.c;
|
||||
}
|
||||
switch (c) {
|
||||
case "info":
|
||||
users = [];
|
||||
var allUsers = <%= usersInfo %>;
|
||||
for (var i = 0; i < event.data.id.length; i++) {
|
||||
for (var j = 0; j < allUsers.length; j++) {
|
||||
if (allUsers[j].id == event.data.id[i]) {
|
||||
users.push(allUsers[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "protect":
|
||||
var users = <%= usersForProtect %>;
|
||||
break;
|
||||
default:
|
||||
users = <%= usersForMentions %>;
|
||||
}
|
||||
docEditor.setUsers({
|
||||
"c": c,
|
||||
"users": users,
|
||||
});
|
||||
};
|
||||
config.events['onRequestUsers'] = onRequestUsers;
|
||||
<% } %>
|
||||
|
||||
config.events['onRequestSaveAs'] = onRequestSaveAs;
|
||||
// the user is mentioned in a comment
|
||||
config.events['onRequestSendNotify'] = function (event) {
|
||||
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
|
||||
var data = JSON.stringify(event.data);
|
||||
innerAlert("onRequestSendNotify: " + data);
|
||||
};
|
||||
config.events['onRequestSendNotify'] = onRequestSendNotify;
|
||||
// prevent file renaming for anonymous users
|
||||
config.events['onRequestRename'] = onRequestRename;
|
||||
config.events['onRequestReferenceData'] = onRequestReferenceData;
|
||||
@ -341,17 +348,7 @@
|
||||
config.events['onRequestOpen'] = onRequestOpen;
|
||||
}
|
||||
|
||||
if (config.editorConfig.createUrl) {
|
||||
config.events.onRequestSaveAs = onRequestSaveAs;
|
||||
};
|
||||
|
||||
var сonnectEditor = function () {
|
||||
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
|
||||
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
|
||||
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
|
||||
return;
|
||||
}
|
||||
|
||||
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
|
||||
};
|
||||
|
||||
|
||||
144
web/documentserver-example/csharp-mvc/Views/Home/Forgotten.aspx
Executable file
@ -0,0 +1,144 @@
|
||||
<%@ Page Title="ONLYOFFICE" Language="C#" Inherits="System.Web.Mvc.ViewPage<OnlineEditorsExampleMVC.Models.ForgottenFilesModel>" %>
|
||||
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Import Namespace="System.Web.Configuration" %>
|
||||
<%@ Import Namespace="OnlineEditorsExampleMVC.Helpers" %>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html lang="en">
|
||||
<head runat="server">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content=<%= DocManagerHelper.GetVersion() %> />
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
-->
|
||||
<title>ONLYOFFICE</title>
|
||||
|
||||
<link href="<%: Url.Content("~/favicon.ico") %>" rel="shortcut icon" type="image/x-icon" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
|
||||
|
||||
<%: Styles.Render("~/Content/css") %>
|
||||
<%: Styles.Render("~/Content/forgotten") %>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="center main-nav">
|
||||
<a href="./">
|
||||
<img src ="content/images/logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</div>
|
||||
<menu class="responsive-nav">
|
||||
<li>
|
||||
<a href="#" onclick="toggleSidePanel(event)">
|
||||
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./">
|
||||
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
</menu>
|
||||
</header>
|
||||
|
||||
<div class="center main">
|
||||
<table class="table-main">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left-panel section"></td>
|
||||
<td class="section">
|
||||
<div class="main-panel">
|
||||
<menu class="links">
|
||||
<li class="home-link" >
|
||||
<a href="./">
|
||||
<img src="content/images/home.svg" alt="Home"/>
|
||||
</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="/Forgotten">Forgotten files</a>
|
||||
</li>
|
||||
</menu>
|
||||
<div class="stored-list">
|
||||
<div class="storedHeader">
|
||||
<div class="storedHeaderText">
|
||||
<span class="header-list">Forgotten files</span>
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="tableHeaderCell">Filename</td>
|
||||
<td class="tableHeaderCell">Action</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div class="scroll-table-body">
|
||||
<table cellspacing="0" cellpadding="0" width="100%">
|
||||
<tbody>
|
||||
<% foreach (var file in Model.files) { %>
|
||||
<tr class="tableRow" title="<%= file["key"] %>">
|
||||
<td>
|
||||
<a class="stored-edit action-link <%= file["type"] %>" href="<%= file["url"] %>" target="_blank">
|
||||
<span><%= file["key"] %></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<%= file["url"] %>">
|
||||
<img class="icon-download" src="content/images/download.svg" alt="Download" title="Download" /></a>
|
||||
<a class="delete-file" data="<%= file["key"] %>">
|
||||
<img class="icon-action" src="content/images/delete.svg" alt="Delete" title="Delete" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://api.onlyoffice.com/editors/howitworks" target="_blank">API Documentation</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="mailto:sales@onlyoffice.com">Submit your request</a>
|
||||
</td>
|
||||
<td class="copy">
|
||||
© Ascensio System SIA <%= DateTime.Now.Year.ToString() %>. All rights reserved.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<%: Scripts.Render("~/bundles/jquery", "~/bundles/forgotten") %>
|
||||
</body>
|
||||
</html>
|
||||
@ -41,11 +41,23 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="center">
|
||||
<a href="">
|
||||
<div class="center main-nav">
|
||||
<a href="./">
|
||||
<img src ="content/images/logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</div>
|
||||
<menu class="responsive-nav">
|
||||
<li>
|
||||
<a href="#" onclick="toggleSidePanel(event)">
|
||||
<img src="content/images/mobile-menu.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./">
|
||||
<img src ="content/images/mobile-logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
</menu>
|
||||
</header>
|
||||
|
||||
<div class="center main">
|
||||
@ -68,7 +80,7 @@
|
||||
<a class="try-editor slide" data-type="pptx">Presentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="try-editor form" data-type="docxf">PDF form</a>
|
||||
<a class="try-editor form" data-type="pdf">PDF form</a>
|
||||
</li>
|
||||
</ul>
|
||||
<label class="side-option">
|
||||
@ -122,9 +134,24 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button class="mobile-close-btn" onclick="toggleSidePanel(event)">
|
||||
<img src="content/images/close.svg" alt="">
|
||||
</button>
|
||||
</td>
|
||||
<td class="section">
|
||||
<div class="main-panel">
|
||||
<menu class="links">
|
||||
<li class="home-link active" >
|
||||
<a href="./">
|
||||
<img src="content/images/home.svg" alt="Home"/>
|
||||
</a>
|
||||
</li>
|
||||
<% if (bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"])) { %>
|
||||
<li>
|
||||
<a href="/Forgotten">Forgotten files</a>
|
||||
</li>
|
||||
<% } %>
|
||||
</menu>
|
||||
<% var storedFiles = DocManagerHelper.GetStoredFiles(); %>
|
||||
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
|
||||
<span class="portal-name">ONLYOFFICE Document Editors – Welcome!</span>
|
||||
@ -136,7 +163,7 @@
|
||||
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
|
||||
<% foreach (User user in Users.getAllUsers())
|
||||
{ %>
|
||||
<div class="user-descr">
|
||||
<div class="user-descr" onclick="toggleUserDescr(event)">
|
||||
<b><%= user.name.IsEmpty() ? "Anonymous" : user.name %></b>
|
||||
<ul>
|
||||
<% foreach (string description in user.descriptions)
|
||||
@ -151,7 +178,14 @@
|
||||
if (storedFiles.Any())
|
||||
{ %>
|
||||
<div class="stored-list">
|
||||
<span class="header-list">Your documents</span>
|
||||
<div class="storedHeader">
|
||||
<div class="storedHeaderText">
|
||||
<span class="header-list">Your documents</span>
|
||||
</div>
|
||||
<div class="storedHeaderClearAll">
|
||||
<div class="clear-all">Clear all</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -193,11 +227,13 @@
|
||||
<img src="content/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
|
||||
</a>
|
||||
</td>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
|
||||
<img src="content/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
|
||||
</a>
|
||||
</td>
|
||||
<% if (docType != "pdf") { %>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "comment", directUrl = isEnabledDirectUrl }) %>" target="_blank">
|
||||
<img src="content/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
|
||||
</a>
|
||||
</td>
|
||||
<% } %>
|
||||
<% if (docType == "word") { %>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= Url.Action("Editor", "Home", new { fileName = storedFile.Name, editorsType = "desktop", editorsMode = "review", directUrl = isEnabledDirectUrl }) %>" target="_blank">
|
||||
@ -295,6 +331,15 @@
|
||||
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
|
||||
<span id="step1" class="step">1. Loading the file.</span>
|
||||
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
|
||||
<div id="select-file-type" class="invisible">
|
||||
<br />
|
||||
<span class="step">Please select the current document type</span>
|
||||
<div class="buttonsMobile indent">
|
||||
<div class="button file-type document" data="docx">Document</div>
|
||||
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
|
||||
<div class="button file-type presentation" data="pptx">Presentation</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<span id="step2" class="step">2. Conversion.</span>
|
||||
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
|
||||
@ -357,9 +402,6 @@
|
||||
<%: Scripts.Render("~/bundles/jquery", "~/bundles/scripts") %>
|
||||
|
||||
<script language="javascript" type="text/javascript">
|
||||
var FillExtList = '<%= string.Join(",", DocManagerHelper.FillFormExts.ToArray()) %>';
|
||||
var ConverExtList = '<%= string.Join(",", DocManagerHelper.ConvertExts.ToArray()) %>';
|
||||
var EditedExtList = '<%= string.Join(",", DocManagerHelper.EditedExts.ToArray()) %>';
|
||||
var UrlConverter = '<%= Url.Content("~/webeditor.ashx?type=convert") %>';
|
||||
var UrlEditor = '<%= Url.Action("editor", "Home") %>';
|
||||
</script>
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
<hgroup>
|
||||
<h1>Error.</h1>
|
||||
<h2>An error occurred while processing your request.</h2>
|
||||
<p><%= ViewData["Message"] %></p>
|
||||
</hgroup>
|
||||
</body>
|
||||
</html>
|
||||
@ -69,6 +69,9 @@ namespace OnlineEditorsExampleMVC
|
||||
case "remove":
|
||||
Remove(context);
|
||||
break;
|
||||
case "removeforgotten":
|
||||
RemoveForgotten(context);
|
||||
break;
|
||||
case "assets":
|
||||
Assets(context);
|
||||
break;
|
||||
@ -87,6 +90,9 @@ namespace OnlineEditorsExampleMVC
|
||||
case "reference":
|
||||
Reference(context);
|
||||
break;
|
||||
case "formats":
|
||||
Formats(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,7 +246,13 @@ namespace OnlineEditorsExampleMVC
|
||||
var fileUri = DocManagerHelper.GetDownloadUrl(fileName);
|
||||
|
||||
var extension = (Path.GetExtension(fileName).ToLower() ?? "").Trim('.');
|
||||
var internalExtension = "ooxml";
|
||||
string conversionExtension = "ooxml";
|
||||
object fileExt;
|
||||
|
||||
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
|
||||
{
|
||||
conversionExtension = fileExt.ToString();
|
||||
}
|
||||
|
||||
// check if the file with such an extension can be converted
|
||||
if (DocManagerHelper.ConvertExts.Contains("." + extension))
|
||||
@ -258,7 +270,7 @@ namespace OnlineEditorsExampleMVC
|
||||
|
||||
// get the url and file type of the converted file
|
||||
Dictionary<string, string> newFileData;
|
||||
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, internalExtension, key, true, out newFileData, filePass, lang);
|
||||
var result = ServiceConverter.GetConvertedData(downloadUri.ToString(), extension, conversionExtension, key, true, out newFileData, filePass, lang);
|
||||
if (result != 100)
|
||||
{
|
||||
context.Response.Write("{ \"step\" : \"" + result + "\", \"filename\" : \"" + fileName + "\"}");
|
||||
@ -393,8 +405,17 @@ namespace OnlineEditorsExampleMVC
|
||||
context.Response.ContentType = "text/plain";
|
||||
try
|
||||
{
|
||||
var fileName = Path.GetFileName(context.Request["fileName"]);
|
||||
Remove(fileName); // remove a file and its history if it exists
|
||||
string fileName = context.Request["fileName"];
|
||||
|
||||
if (!String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = Path.GetFileName(context.Request["fileName"]);
|
||||
Remove(fileName); // remove a file and its history if it exists
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveUserDirectory(); // remove the user's directory
|
||||
}
|
||||
|
||||
context.Response.Write("{ \"success\": true }");
|
||||
}
|
||||
@ -414,6 +435,14 @@ namespace OnlineEditorsExampleMVC
|
||||
if (Directory.Exists(histDir)) Directory.Delete(histDir, true);
|
||||
}
|
||||
|
||||
// remove the user's directory
|
||||
private static void RemoveUserDirectory()
|
||||
{
|
||||
var path = DocManagerHelper.StoragePath("", null); // get the path to the user directory
|
||||
|
||||
if (Directory.Exists(path)) Directory.Delete(path, true);
|
||||
}
|
||||
|
||||
// get files information
|
||||
private static void Files(HttpContext context)
|
||||
{
|
||||
@ -951,6 +980,51 @@ namespace OnlineEditorsExampleMVC
|
||||
return history;
|
||||
}
|
||||
|
||||
// return all the supported formats
|
||||
private static void Formats(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> data = new Dictionary<string, object>
|
||||
{
|
||||
{ "formats", FormatManager.All() }
|
||||
};
|
||||
context.Response.ContentType = "application/json";
|
||||
var jss = new JavaScriptSerializer();
|
||||
|
||||
context.Response.Write(jss.Serialize(data));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
|
||||
}
|
||||
}
|
||||
|
||||
// delete a forgotten file from the document server
|
||||
private static void RemoveForgotten(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
|
||||
{
|
||||
throw new HttpException(403, "The forgotten page is disabled");
|
||||
}
|
||||
|
||||
string filename = context.Request["filename"];
|
||||
|
||||
if (!String.IsNullOrEmpty(filename))
|
||||
{
|
||||
TrackManager.commandRequest("deleteForgotten", filename);
|
||||
}
|
||||
|
||||
context.Response.StatusCode = 204;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<appSettings>
|
||||
<clear />
|
||||
<add key="version" value="1.9.0"/>
|
||||
<add key="version" value="1.10.0"/>
|
||||
|
||||
<add key="filesize-max" value="52428800"/>
|
||||
<add key="storage-path" value=""/>
|
||||
<add key="filename-max" value="50"/>
|
||||
<add key="enable-forgotten" value="true"/>
|
||||
|
||||
<add key="files.docservice.timeout" value="120000" />
|
||||
<add key="files.docservice.secret" value="" />
|
||||
|
||||
161
web/documentserver-example/csharp/App_Themes/forgotten.css
Executable file
@ -0,0 +1,161 @@
|
||||
.center {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 832px;
|
||||
margin: 0 32px;
|
||||
padding: 48px 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #E2E2E2;
|
||||
}
|
||||
|
||||
.tableRow td:first-child {
|
||||
width: 70%;
|
||||
flex-grow: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.tableHeader td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 10%;
|
||||
text-align: center;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.tableHeader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stored-edit {
|
||||
display: block;
|
||||
padding-top: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
menu.links {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scroll-table-body table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 12px;
|
||||
line-height: normal;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.stored-list {
|
||||
height: calc(100% - 58px);
|
||||
}
|
||||
|
||||
header {
|
||||
min-width:auto;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 1152px;
|
||||
}
|
||||
|
||||
@media (max-width: 1279px) and (min-width: 1024px) {
|
||||
.left-panel {
|
||||
width: 208px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 688px;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: 928px;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) and (min-width: 593px) {
|
||||
.center {
|
||||
max-width: 768px;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
|
||||
.table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
width: 208px;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: calc(100% - 32px);
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: 768px;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 592px) and (min-width: 320px) {
|
||||
.center, .table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 28px 16px;
|
||||
}
|
||||
|
||||
.tableHeader td:last-child, .tableRow td:last-child {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
header a {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 3c0-1.65685 1.34315-3 3-3h20l7 7v30c0 1.6569-1.3431 3-3 3H3c-1.65685 0-3-1.3431-3-3V3z" fill="#27ABA3"/><path d="M23 0l7 7h-4c-1.6569 0-3-1.34315-3-3V0z" fill="#008078"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 14H6v7h18v-7zm-.8182 5.9978H6.81818V15H23.1818v4.9978zM24 23H6v7h18v-7zm-.8182 5.9978H6.81818V24H23.1818v4.9978z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 463 B |
@ -0,0 +1,5 @@
|
||||
<svg width="30" height="40" viewBox="0 0 30 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 3C0 1.34315 1.34315 0 3 0H23L30 7V37C30 38.6569 28.6569 40 27 40H3C1.34315 40 0 38.6569 0 37V3Z" fill="#9E1919"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0062 15V16.0065H24V15H17.0062ZM17.0062 19V20.0163H24V19H17.0062ZM24 23H17.0062V24.0261H24V23ZM6 28V27.0293H24V28H6ZM7 16H14V23H7V16ZM6 15H7H14H15V16V23V24H14H7H6V23V16V15Z" fill="white"/>
|
||||
<path d="M23 0L30 7H26C24.3431 7 23 5.65685 23 4V0Z" fill="black" fill-opacity="0.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@ -0,0 +1,3 @@
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 17V11H12V17H17V9H20L10 0L0 9H3V17H8Z" fill="#444444"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 173 B |
@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 1h8l4 4v10H2V1z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5l-4-4H2v14h12V5zm-4-5l5 5v11H1V0h9z" fill="#BFBFBF"/><path fill="#9E1919" d="M3 10h10v4H3z"/><path d="M7 7V2H3v5h4zM8 3V2h2v1H8zM8 5V4h5v1H8zM13 6H8v1h5V6zM13 8H3v1h10V8z" fill="#BFBFBF"/><path opacity=".3" d="M9 1h1v3h4l1 1H9V1z" fill="#333"/></svg>
|
||||
|
After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="24" height="23" viewBox="0 0 24 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5332 22.2243L0.632544 17.5921C-0.210848 17.1877 -0.210848 16.5627 0.632544 16.1951L4.07945 14.5775L10.4966 17.5921C11.34 17.9965 12.6967 17.9965 13.5034 17.5921L19.9206 14.5775L23.3675 16.1951C24.2108 16.5995 24.2108 17.2245 23.3675 17.5921L13.4668 22.2243C12.6967 22.592 11.34 22.592 10.5332 22.2243Z" fill="#FF6F3D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 16.4922L0.630617 11.8546C-0.210206 11.4497 -0.210206 10.824 0.630617 10.456L3.99391 8.87329L10.5011 11.9282C11.342 12.3331 12.6946 12.3331 13.4989 11.9282L20.0061 8.87329L23.3694 10.456C24.2102 10.8608 24.2102 11.4865 23.3694 11.8546L13.4989 16.4922C12.658 16.897 11.3054 16.897 10.5011 16.4922Z" fill="#95C038"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5011 10.8195L0.630617 6.24863C-0.210206 5.84959 -0.210206 5.23289 0.630617 4.87013L10.5011 0.299281C11.342 -0.0997605 12.6946 -0.0997605 13.4989 0.299281L23.3694 4.87013C24.2102 5.26917 24.2102 5.88587 23.3694 6.24863L13.4989 10.8195C12.658 11.1822 11.3054 11.1822 10.5011 10.8195Z" fill="#5DC0E8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,5 @@
|
||||
<svg width="20" height="14" viewBox="0 0 20 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="20" height="2" rx="1" fill="white"/>
|
||||
<rect y="6" width="20" height="2" rx="1" fill="white"/>
|
||||
<rect y="12" width="20" height="2" rx="1" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 278 B |
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13H7C6.44772 13 6 12.5523 6 12C6 11.4477 6.44772 11 7 11H11V7C11 6.44772 11.4477 6 12 6C12.5523 6 13 6.44772 13 7V11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H13V17Z" fill="#444444"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
@ -79,7 +79,8 @@
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
@ -119,7 +120,8 @@
|
||||
.contentCells-icon{
|
||||
width: 5%;
|
||||
}
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
@ -175,7 +177,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 715px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
@ -263,7 +266,8 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
@ -293,7 +297,8 @@
|
||||
width: 580px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
@ -407,7 +412,8 @@
|
||||
padding: 16px 0 6px;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@ -502,6 +508,17 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.buttonsMobile.indent {
|
||||
margin-bottom: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.button.file-type:hover,
|
||||
.button.file-type {
|
||||
height: 28px;
|
||||
width: 100px;
|
||||
margin-bottom: 10px !important;
|
||||
font-size: 9px;
|
||||
}
|
||||
.button.gray{
|
||||
margin: 0;
|
||||
}
|
||||
@ -527,7 +544,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 510px) and (min-width: 470px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
@ -553,7 +571,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 470px) and (min-width: 420px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 30%;
|
||||
}
|
||||
.tableRow td:first-child{
|
||||
@ -588,7 +607,8 @@
|
||||
}
|
||||
|
||||
@media (max-width: 420px) and (min-width: 320px) {
|
||||
.tableRow {
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
@ -638,7 +658,8 @@
|
||||
}
|
||||
}
|
||||
@media (max-width: 769px) and (min-width: 715px){
|
||||
.tableRow{
|
||||
.tableRow,
|
||||
menu.links {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
@ -687,3 +708,216 @@
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 592px) and (min-width: 320px) {
|
||||
body.menu-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
min-width: auto;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
header a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
header img {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header, footer {
|
||||
position: -webkit-sticky; /* Safari */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
background-color: rgba(186, 186, 186, 0.6);
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
align-items: start;
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
height: calc(100% - 124px);
|
||||
z-index:99;
|
||||
}
|
||||
|
||||
.left-panel.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.help-block {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-color: #F5F5F5;
|
||||
width: 248px;
|
||||
padding-left: 16px;
|
||||
padding-top: 33px;
|
||||
padding-bottom: 33px;
|
||||
padding-right: 40px;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.table-main {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mobile-close-btn {
|
||||
display: block;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background-color: #E2E2E2;
|
||||
border-radius: 2px;
|
||||
border-color: #E2E2E2;
|
||||
color: #808080;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.main-panel {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
padding: 28px 16px;
|
||||
}
|
||||
|
||||
#portal-info {
|
||||
width: 100%;
|
||||
max-width: fit-content;
|
||||
}
|
||||
|
||||
menu.links {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
span.portal-name {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span.portal-descr:first-child {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
span.portal-descr {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.user-descr {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: auto;
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
padding: 12px 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.user-descr ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-descr ul.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.user-descr b {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.user-descr b::before {
|
||||
content: url("images/plus.svg");
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.storedHeader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.storedHeaderClearAll {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.scroll-table-body {
|
||||
top: 36px;
|
||||
}
|
||||
|
||||
.scroll-table-body tr:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.tableRow {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
padding: 16px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tableRow td:first-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.header-list {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.firstContentCellViewers {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.firstContentCellViewers ~ td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.downloadContentCellShift:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.responsive-nav {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0;
|
||||
align-items: center;
|
||||
column-gap: 16px;
|
||||
padding: 10px 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: calc(100% - 124px);
|
||||
}
|
||||
|
||||
.user-block-table {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +65,14 @@ header img {
|
||||
margin: 10px 0 22px 32px;
|
||||
}
|
||||
|
||||
.responsive-nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-close-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
margin: 0 auto 0;
|
||||
@ -164,7 +172,7 @@ label .checkbox {
|
||||
}
|
||||
|
||||
.try-editor.form {
|
||||
background-image: url("images/file_docxf.svg");
|
||||
background-image: url("images/file_pdf.svg");
|
||||
}
|
||||
|
||||
.side-option {
|
||||
@ -230,6 +238,33 @@ label .checkbox {
|
||||
color: #FF6F3D;
|
||||
}
|
||||
|
||||
.button.file-type {
|
||||
font-size: 11px;
|
||||
color: #FFFFFF;
|
||||
padding: 8px 8px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button.file-type.disable {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.button.file-type.pale {
|
||||
opacity: 30%;
|
||||
}
|
||||
|
||||
.button.file-type.document {
|
||||
background: #446995;
|
||||
}
|
||||
|
||||
.button.file-type.spreadsheet {
|
||||
background: #40865C;
|
||||
}
|
||||
|
||||
.button.file-type.presentation {
|
||||
background: #AA5252;
|
||||
}
|
||||
|
||||
.upload-panel {
|
||||
float: left;
|
||||
padding: 24px 0;
|
||||
@ -271,6 +306,43 @@ label .checkbox {
|
||||
border-bottom: 1px solid #D0D5DA;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
column-gap: 30px;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
border-bottom: 1px solid #E2E2E2;
|
||||
margin: 0;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.links li {
|
||||
padding: 4px;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.links li.active {
|
||||
border-bottom: 2px solid #FF6F3D;
|
||||
}
|
||||
|
||||
.links li.active a {
|
||||
color: #FF6F3D;
|
||||
}
|
||||
|
||||
.links li.active a img {
|
||||
filter: invert(55%) sepia(67%) saturate(2727%) hue-rotate(335deg) brightness(104%) contrast(101%);
|
||||
}
|
||||
|
||||
.links a {
|
||||
display: inline-block;
|
||||
padding: 2px 0;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#mainProgress {
|
||||
color: #333333;
|
||||
display: none;
|
||||
@ -468,6 +540,11 @@ footer a:hover {
|
||||
background-image: url("images/icon_pptx.svg");
|
||||
}
|
||||
|
||||
.stored-edit.pdf,
|
||||
.uploadFileName.pdf {
|
||||
background-image: url("images/icon_pdf.svg");
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
@ -596,6 +673,29 @@ footer a:hover {
|
||||
width: 4%;
|
||||
}
|
||||
|
||||
.storedHeader {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.storedHeaderClearAll {
|
||||
padding-right: 52px;
|
||||
}
|
||||
|
||||
.clear-all {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
padding: 2px;
|
||||
outline: 1px solid #E5E5E5;
|
||||
text-align: center;
|
||||
cursor:pointer;
|
||||
text-transform: uppercase;
|
||||
background-color: #F5F5F5;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.select-user {
|
||||
color: #444444;
|
||||
font-family: Open Sans;
|
||||
@ -745,6 +845,16 @@ html {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.buttonsMobile.indent{
|
||||
padding-left: 35px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
|
||||
@ -45,11 +45,23 @@
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<header>
|
||||
<div class="center">
|
||||
<a href="">
|
||||
<div class="center main-nav">
|
||||
<a href="./">
|
||||
<img src ="app_themes/images/logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</div>
|
||||
<menu class="responsive-nav">
|
||||
<li>
|
||||
<a href="#" onclick="toggleSidePanel(event)">
|
||||
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./">
|
||||
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
</menu>
|
||||
</header>
|
||||
<div class="center main">
|
||||
<table class="table-main">
|
||||
@ -71,7 +83,7 @@
|
||||
<a class="try-editor slide" data-type="slide">Presentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="try-editor form" data-type="docxf">PDF form</a>
|
||||
<a class="try-editor form" data-type="pdf">PDF form</a>
|
||||
</li>
|
||||
</ul>
|
||||
<label class="side-option">
|
||||
@ -124,10 +136,25 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button class="mobile-close-btn" onclick="toggleSidePanel(event)">
|
||||
<img src="app_themes/images/close.svg" alt="">
|
||||
</button>
|
||||
</td>
|
||||
<td class="section">
|
||||
<% var storedFiles = GetStoredFiles(); %>
|
||||
<div class="main-panel">
|
||||
<menu class="links">
|
||||
<li class="home-link active" >
|
||||
<a href="./">
|
||||
<img src="app_themes/images/home.svg" alt="Home"/>
|
||||
</a>
|
||||
</li>
|
||||
<% if (bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"])) { %>
|
||||
<li>
|
||||
<a href="/Forgotten.aspx">Forgotten files</a>
|
||||
</li>
|
||||
<% } %>
|
||||
</menu>
|
||||
<div id="portal-info" style="display: <%= storedFiles.Any() ? "none" : "table-cell" %>">
|
||||
<span class="portal-name">ONLYOFFICE Document Editors – Welcome!</span>
|
||||
<span class="portal-descr">
|
||||
@ -138,7 +165,7 @@
|
||||
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
|
||||
<% foreach (User user in Users.getAllUsers())
|
||||
{ %>
|
||||
<div class="user-descr">
|
||||
<div class="user-descr" onclick="toggleUserDescr(event)">
|
||||
<b><%= user.name.IsEmpty() ? "Anonymous" : user.name %></b>
|
||||
<ul>
|
||||
<% foreach (string description in user.descriptions)
|
||||
@ -153,7 +180,14 @@
|
||||
if (storedFiles.Any())
|
||||
{ %>
|
||||
<div class="stored-list">
|
||||
<span class="header-list">Your documents</span>
|
||||
<div class="storedHeader">
|
||||
<div class="storedHeaderText">
|
||||
<span class="header-list">Your documents</span>
|
||||
</div>
|
||||
<div class="storedHeaderClearAll">
|
||||
<div class="clear-all">Clear all</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr >
|
||||
@ -195,11 +229,13 @@
|
||||
<img src="app_themes/images/mobile.svg" alt="Open in editor for mobile devices" title="Open in editor for mobile devices"/>
|
||||
</a>
|
||||
</td>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
|
||||
<img src="app_themes/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
|
||||
</a>
|
||||
</td>
|
||||
<% if (docType != "pdf") { %>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=comment" %>" target="_blank">
|
||||
<img src="app_themes/images/comment.svg" alt="Open in editor for comment" title="Open in editor for comment"/>
|
||||
</a>
|
||||
</td>
|
||||
<% } %>
|
||||
<% if (docType == "word") { %>
|
||||
<td class="contentCells contentCells-icon">
|
||||
<a href="<%= editUrl + "&editorsType=desktop&editorsMode=review" %>" target="_blank">
|
||||
@ -297,6 +333,15 @@
|
||||
<div class="describeUpload">After these steps are completed, you can work with your document.</div>
|
||||
<span id="step1" class="step">1. Loading the file.</span>
|
||||
<span class="step-descr">The loading speed depends on file size and additional elements it contains.</span>
|
||||
<div id="select-file-type" class="invisible">
|
||||
<br />
|
||||
<span class="step">Please select the current document type</span>
|
||||
<div class="buttonsMobile indent">
|
||||
<div class="button file-type document" data="docx">Document</div>
|
||||
<div class="button file-type spreadsheet" data="xlsx">Spreadsheet</div>
|
||||
<div class="button file-type presentation" data="pptx">Presentation</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<span id="step2" class="step">2. Conversion.</span>
|
||||
<span class="step-descr">The file is converted to OOXML so that you can edit it.</span>
|
||||
@ -364,12 +409,8 @@
|
||||
<script language="javascript" type="text/javascript" src="script/jquery.iframe-transport.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="script/jquery.fileupload.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="script/jquery.dropdownToggle.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="script/formats.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="script/jscript.js"></script>
|
||||
<script language="javascript" type="text/javascript">
|
||||
var FillFormExtList = '<%= string.Join(",", FillFormsExts.ToArray()) %>';
|
||||
var ConverExtList = '<%= string.Join(",", ConvertExts.ToArray()) %>';
|
||||
var EditedExtList = '<%= string.Join(",", EditedExts.ToArray()) %>';
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -250,6 +250,7 @@ namespace OnlineEditorsExample
|
||||
{
|
||||
var ext = Path.GetExtension(fileName).ToLower();
|
||||
|
||||
if (FormatManager.PdfExtensions().Contains(ext)) return "pdf"; // pdf for pdf extensions
|
||||
if (FormatManager.DocumentExtensions().Contains(ext)) return "word"; // word for text document extensions
|
||||
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return "cell"; // cell for spreadsheet extensions
|
||||
if (FormatManager.PresentationExtensions().Contains(ext)) return "slide"; // slide for presentation extensions
|
||||
@ -437,7 +438,14 @@ namespace OnlineEditorsExample
|
||||
var lang = context.Request.Cookies.GetOrDefault("ulang", null);
|
||||
|
||||
var extension = (Path.GetExtension(_fileName).ToLower() ?? "").Trim('.');
|
||||
var internalExtension = "ooxml";
|
||||
string conversionExtension = "ooxml"; // set the default conversion extension as ooxml
|
||||
object fileExt;
|
||||
|
||||
// change the conversion extension if it was provided in the request body
|
||||
if (body.TryGetValue("fileExt", out fileExt) && !String.IsNullOrEmpty(fileExt.ToString()))
|
||||
{
|
||||
conversionExtension = fileExt.ToString();
|
||||
}
|
||||
|
||||
// check if the file with such an extension can be converted
|
||||
if (ConvertExts.Contains("." + extension))
|
||||
@ -454,7 +462,7 @@ namespace OnlineEditorsExample
|
||||
|
||||
// get the url and file type of the converted file
|
||||
Dictionary<string, string> newFileData;
|
||||
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, internalExtension, key, true, out newFileData, filePass, lang);
|
||||
var result = ServiceConverter.GetConvertedData(fileUrl.ToString() , extension, conversionExtension, key, true, out newFileData, filePass, lang);
|
||||
if (result != 100)
|
||||
{
|
||||
return "{ \"step\" : \"" + result + "\", \"filename\" : \"" + _fileName + "\"}";
|
||||
|
||||
@ -126,7 +126,7 @@
|
||||
|
||||
// the meta information of the document is changed via the meta command
|
||||
var onMetaChange = function (event) {
|
||||
if (event.data.favorite) {
|
||||
if (event.data.favorite !== undefined) {
|
||||
var favorite = !!event.data.favorite;
|
||||
var title = document.title.replace(/^\☆/g, "");
|
||||
document.title = (favorite ? "☆" : "") + title;
|
||||
@ -233,6 +233,41 @@
|
||||
}
|
||||
};
|
||||
|
||||
var onRequestUsers = function (event) {
|
||||
if (event && event.data){
|
||||
var c = event.data.c;
|
||||
}
|
||||
switch (c) {
|
||||
case "info":
|
||||
users = [];
|
||||
var allUsers = <%= UsersInfo %>;
|
||||
for (var i = 0; i < event.data.id.length; i++) {
|
||||
for (var j = 0; j < allUsers.length; j++) {
|
||||
if (allUsers[j].id == event.data.id[i]) {
|
||||
users.push(allUsers[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "protect":
|
||||
var users = <%= UsersForProtect %>;
|
||||
break;
|
||||
default:
|
||||
users = <%= UsersForMentions %>;
|
||||
}
|
||||
docEditor.setUsers({
|
||||
"c": c,
|
||||
"users": users,
|
||||
});
|
||||
};
|
||||
|
||||
var onRequestSendNotify = function (event) {
|
||||
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
|
||||
var data = JSON.stringify(event.data);
|
||||
innerAlert("onRequestSendNotify: " + data);
|
||||
};
|
||||
|
||||
config = <%= DocConfig %>;
|
||||
|
||||
config.width = "100%";
|
||||
@ -275,65 +310,37 @@
|
||||
docEditor.setHistoryData(JSON.parse(xhr.responseText)); // send the link to the document for viewing the version history
|
||||
}
|
||||
};
|
||||
config.events['onRequestHistoryClose'] = function () { // the user is trying to go back to the document from viewing the document version history
|
||||
document.location.reload();
|
||||
};
|
||||
config.events['onRequestRestore'] = function (event) {
|
||||
var fileName = "<%= FileName %>";
|
||||
var version = event.data.version;
|
||||
var data = {
|
||||
fileName: fileName,
|
||||
version: version
|
||||
if (config.editorConfig.user.id !== "uid-3") {
|
||||
config.events['onRequestHistoryClose'] = function () { // the user is trying to go back to the document from viewing the document version history
|
||||
document.location.reload();
|
||||
};
|
||||
config.events['onRequestRestore'] = function (event) {
|
||||
var fileName = "<%= FileName %>";
|
||||
var version = event.data.version;
|
||||
var data = {
|
||||
fileName: fileName,
|
||||
version: version
|
||||
};
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "webeditor.ashx?type=restore&directUrl=" + !!config.document.directUrl);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify(data));
|
||||
xhr.onload = function () {
|
||||
docEditor.refreshHistory(JSON.parse(xhr.responseText));
|
||||
}
|
||||
};
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "webeditor.ashx?type=restore&directUrl=" + !!config.document.directUrl);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify(data));
|
||||
xhr.onload = function () {
|
||||
docEditor.refreshHistory(JSON.parse(xhr.responseText));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// add mentions for not anonymous users
|
||||
<% if (!string.IsNullOrEmpty(UsersForMentions))
|
||||
{ %>
|
||||
config.events['onRequestUsers'] = function (event) {
|
||||
if (event && event.data){
|
||||
var c = event.data.c;
|
||||
}
|
||||
switch (c) {
|
||||
case "info":
|
||||
users = [];
|
||||
var allUsers = <%= UsersInfo %>;
|
||||
for (var i = 0; i < event.data.id.length; i++) {
|
||||
for (var j = 0; j < allUsers.length; j++) {
|
||||
if (allUsers[j].id == event.data.id[i]) {
|
||||
users.push(allUsers[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "protect":
|
||||
var users = <%= UsersForProtect %>;
|
||||
break;
|
||||
default:
|
||||
users = <%= UsersForMentions %>;
|
||||
}
|
||||
docEditor.setUsers({
|
||||
"c": c,
|
||||
"users": users,
|
||||
});
|
||||
};
|
||||
config.events['onRequestUsers'] = onRequestUsers;
|
||||
<% } %>
|
||||
|
||||
config.events['onRequestSaveAs'] = onRequestSaveAs;
|
||||
// the user is mentioned in a comment
|
||||
config.events['onRequestSendNotify'] = function (event) {
|
||||
event.data.actionLink = replaceActionLink(location.href, JSON.stringify(event.data.actionLink));
|
||||
var data = JSON.stringify(event.data);
|
||||
innerAlert("onRequestSendNotify: " + data);
|
||||
};
|
||||
config.events['onRequestSendNotify'] = onRequestSendNotify;
|
||||
// prevent file renaming for anonymous users
|
||||
config.events['onRequestRename'] = onRequestRename;
|
||||
config.events['onRequestReferenceData'] = onRequestReferenceData;
|
||||
@ -342,17 +349,7 @@
|
||||
config.events['onRequestOpen'] = onRequestOpen;
|
||||
}
|
||||
|
||||
if (config.editorConfig.createUrl) {
|
||||
config.events.onRequestSaveAs = onRequestSaveAs;
|
||||
};
|
||||
|
||||
var сonnectEditor = function () {
|
||||
if ((config.document.fileType === "docxf" || config.document.fileType === "oform")
|
||||
&& DocsAPI.DocEditor.version().split(".")[0] < 7) {
|
||||
innerAlert("Please update ONLYOFFICE Docs to version 7.0 to work on fillable forms online.");
|
||||
return;
|
||||
}
|
||||
|
||||
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
|
||||
};
|
||||
|
||||
|
||||
@ -135,14 +135,14 @@ namespace OnlineEditorsExample
|
||||
{
|
||||
// create demo document of a specified file type
|
||||
Try(type, Request["sample"], Request);
|
||||
Response.Redirect("doceditor.aspx?fileID=" + HttpUtility.UrlEncode(FileName));
|
||||
Response.Redirect("doceditor.aspx?editorsMode=edit&fileID=" + HttpUtility.UrlEncode(FileName));
|
||||
}
|
||||
|
||||
// get file extension
|
||||
var ext = Path.GetExtension(FileName).ToLower();
|
||||
|
||||
var canFill = _Default.FillFormsExts.Contains(ext);
|
||||
// get editor mode or set the default one (edit)
|
||||
var editorsMode = Request.GetOrDefault("editorsMode", "edit");
|
||||
var editorsMode = Request.GetOrDefault("editorsMode", canFill ? "fillForms" : "edit");
|
||||
|
||||
var canEdit = _Default.EditedExts.Contains(ext); // check if this file can be edited
|
||||
var editorsType = Request.GetOrDefault("editorsType", "desktop");
|
||||
@ -150,11 +150,11 @@ namespace OnlineEditorsExample
|
||||
var id = Request.Cookies.GetOrDefault("uid", null);
|
||||
var user = Users.getUser(id); // get the user
|
||||
|
||||
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && _Default.FillFormsExts.Contains(ext)) {
|
||||
if ((!canEdit && editorsMode.Equals("edit") || editorsMode.Equals("fillForms")) && canFill) {
|
||||
editorsMode = "fillForms";
|
||||
canEdit = true;
|
||||
}
|
||||
var submitForm = editorsMode.Equals("fillForms") && id.Equals("uid-1"); // check if the Submit form button is displayed or hidden
|
||||
var submitForm = (editorsMode.Equals("fillForms") || editorsMode.Equals("embedded")) && user.id.Equals("uid-1"); // check if the Submit form button is displayed or hidden
|
||||
var mode = canEdit && editorsMode != "view" ? "edit" : "view"; // get the editor opening mode (edit or view)
|
||||
|
||||
var jss = new JavaScriptSerializer();
|
||||
@ -282,10 +282,12 @@ namespace OnlineEditorsExample
|
||||
{ "forcesave", false }, // adds the request for the forced file saving to the callback handler
|
||||
{ "submitForm", submitForm }, // if the Submit form button is displayed or not
|
||||
{
|
||||
"goback", new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
|
||||
"goback", user.goback != null ? new Dictionary<string, object> // settings for the Open file location menu button and upper right corner button
|
||||
{
|
||||
{ "url", _Default.GetServerUrl(false) + "default.aspx" } // the absolute URL to the website address which will be opened when clicking the Open file location menu button
|
||||
}
|
||||
{ "url", _Default.GetServerUrl(false) + "default.aspx" }, // the absolute URL to the website address which will be opened when clicking the Open file location menu button
|
||||
{ "text", user.goback.text },
|
||||
{ "blank", user.goback.blank }
|
||||
} : new Dictionary<string, object>{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -338,17 +340,17 @@ namespace OnlineEditorsExample
|
||||
var InsertImageUrl = new UriBuilder(_Default.GetServerUrl(true));
|
||||
InsertImageUrl.Path = HttpRuntime.AppDomainAppVirtualPath
|
||||
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
|
||||
+ "App_Themes\\images\\logo.png";
|
||||
+ "App_Themes\\images\\logo.svg";
|
||||
|
||||
var DirectImageUrl = new UriBuilder(_Default.GetServerUrl(false));
|
||||
DirectImageUrl.Path = HttpRuntime.AppDomainAppVirtualPath
|
||||
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
|
||||
+ "App_Themes\\images\\logo.png";
|
||||
+ "App_Themes\\images\\logo.svg";
|
||||
|
||||
// create a logo config
|
||||
Dictionary<string, object> logoConfig = new Dictionary<string, object>
|
||||
{
|
||||
{ "fileType", "png"},
|
||||
{ "fileType", "svg"},
|
||||
{ "url", InsertImageUrl.ToString()}
|
||||
};
|
||||
|
||||
@ -487,8 +489,8 @@ namespace OnlineEditorsExample
|
||||
case "slide":
|
||||
ext = ".pptx"; // .pptx for slide document type
|
||||
break;
|
||||
case "docxf":
|
||||
ext = ".docxf";
|
||||
case "pdf":
|
||||
ext = ".pdf";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
@ -231,6 +231,10 @@ namespace ASC.Api.DocumentConverter
|
||||
|
||||
switch (errorCode)
|
||||
{
|
||||
case -9:
|
||||
// public const int c_nErrorConversionOutputFormatError = -9;
|
||||
errorMessage = String.Format(errorMessageTemplate, "Error conversion output format");
|
||||
break;
|
||||
case -8:
|
||||
// public const int c_nErrorFileVKey = -8;
|
||||
errorMessage = String.Format(errorMessageTemplate, "Error document VKey");
|
||||
|
||||
147
web/documentserver-example/csharp/Forgotten.aspx
Executable file
@ -0,0 +1,147 @@
|
||||
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Forgotten.aspx.cs" Inherits="OnlineEditorsExample.Forgotten" Title="ONLYOFFICE" %>
|
||||
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Import Namespace="OnlineEditorsExample" %>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head runat="server">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content=<%= GetVersion() %> />
|
||||
<title>ONLYOFFICE</title>
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
-->
|
||||
<link rel="icon" href="~/favicon.ico" type="image/x-icon" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="app_themes/stylesheet.css" />
|
||||
<link rel="stylesheet" type="text/css" href="app_themes/media.css" />
|
||||
<link rel="stylesheet" type="text/css" href="app_themes/forgotten.css" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="app_themes/jquery-ui.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<header>
|
||||
<div class="center main-nav">
|
||||
<a href="./">
|
||||
<img src ="app_themes/images/logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</div>
|
||||
<menu class="responsive-nav">
|
||||
<li>
|
||||
<a href="#">
|
||||
<img src="app_themes/images/mobile-menu.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./">
|
||||
<img src ="app_themes/images/mobile-logo.svg" alt="ONLYOFFICE" />
|
||||
</a>
|
||||
</li>
|
||||
</menu>
|
||||
</header>
|
||||
<div class="center main">
|
||||
<table class="table-main">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left-panel section"></td>
|
||||
<td class="section">
|
||||
<div class="main-panel">
|
||||
<menu class="links">
|
||||
<li class="home-link" >
|
||||
<a href="./">
|
||||
<img src="app_themes/images/home.svg" alt="Home"/>
|
||||
</a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="/Forgotten.aspx">Forgotten files</a>
|
||||
</li>
|
||||
</menu>
|
||||
<div class="stored-list">
|
||||
<div class="storedHeader">
|
||||
<div class="storedHeaderText">
|
||||
<span class="header-list">Forgotten files</span>
|
||||
</div>
|
||||
</div>
|
||||
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="tableHeaderCell">Filename</td>
|
||||
<td class="tableHeaderCell">Action</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div class="scroll-table-body">
|
||||
<table cellspacing="0" cellpadding="0" width="100%">
|
||||
<tbody>
|
||||
<% foreach (var file in GetForgottenFiles()) { %>
|
||||
<tr class="tableRow" title="<%= file["key"] %>">
|
||||
<td>
|
||||
<a class="stored-edit <%= file["type"] %>" href="<%= file["url"] %>" target="_blank">
|
||||
<span><%= file["key"] %></span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<%= file["url"] %>">
|
||||
<img class="icon-download" src="app_themes/images/download.svg" alt="Download" title="Download" /></a>
|
||||
<a class="delete-file" data="<%= file["key"] %>">
|
||||
<img class="icon-action" src="app_themes/images/delete.svg" alt="Delete" title="Delete" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="http://api.onlyoffice.com/editors/howitworks" target="_blank">API Documentation</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="mailto:sales@onlyoffice.com">Submit your request</a>
|
||||
</td>
|
||||
<td class="copy">
|
||||
© Ascensio System SIA <%= DateTime.Now.Year.ToString() %>. All rights reserved.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
<script language="javascript" type="text/javascript" src="script/forgotten.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
97
web/documentserver-example/csharp/Forgotten.aspx.cs
Executable file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.UI;
|
||||
|
||||
namespace OnlineEditorsExample
|
||||
{
|
||||
public partial class Forgotten : Page
|
||||
{
|
||||
|
||||
//get server version
|
||||
public static string GetVersion()
|
||||
{
|
||||
return WebConfigurationManager.AppSettings["version"];
|
||||
}
|
||||
|
||||
private static bool? _ismono;
|
||||
|
||||
public static bool IsMono
|
||||
{
|
||||
get { return _ismono.HasValue ? _ismono.Value : (_ismono = (bool?)(Type.GetType("Mono.Runtime") != null)).Value; }
|
||||
}
|
||||
|
||||
// get the document type
|
||||
public static string DocumentType(string fileName)
|
||||
{
|
||||
var ext = Path.GetExtension(fileName).ToLower();
|
||||
|
||||
if (FormatManager.PdfExtensions().Contains(ext)) return "pdf"; // pdf for pdf extensions
|
||||
if (FormatManager.DocumentExtensions().Contains(ext)) return "word"; // word for text document extensions
|
||||
if (FormatManager.SpreadsheetExtensions().Contains(ext)) return "cell"; // cell for spreadsheet extensions
|
||||
if (FormatManager.PresentationExtensions().Contains(ext)) return "slide"; // slide for presentation extensions
|
||||
|
||||
return "word"; // the default document type is word
|
||||
}
|
||||
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
|
||||
{
|
||||
Response.Clear();
|
||||
Response.StatusCode = 403;
|
||||
Response.End();
|
||||
}
|
||||
}
|
||||
|
||||
// fetch forgotten files from the document server
|
||||
public static List<Dictionary<string, string>> GetForgottenFiles()
|
||||
{
|
||||
var files = new List<Dictionary<string, string>>();
|
||||
|
||||
try
|
||||
{
|
||||
var response = TrackManager.commandRequest("getForgottenList", null);
|
||||
ArrayList keys = (ArrayList) response["keys"];
|
||||
|
||||
// fetch all the forgotten files from the document server
|
||||
foreach (string key in keys)
|
||||
{
|
||||
var file = new Dictionary<string, string>();
|
||||
var fileResult = TrackManager.commandRequest("getForgotten", key);
|
||||
file.Add("key", fileResult["key"].ToString());
|
||||
file.Add("url", fileResult["url"].ToString());
|
||||
file.Add("type", DocumentType(fileResult["url"].ToString()));
|
||||
|
||||
files.Add(file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
web/documentserver-example/csharp/Forgotten.aspx.designer.cs
generated
Executable file
@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace OnlineEditorsExample {
|
||||
|
||||
|
||||
public partial class Forgotten {
|
||||
|
||||
/// <summary>
|
||||
/// form1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
|
||||
}
|
||||
}
|
||||
@ -150,6 +150,20 @@ namespace OnlineEditorsExample
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<string> PdfExtensions()
|
||||
{
|
||||
return Pdfs()
|
||||
.Select(format => format.Extension())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<Format> Pdfs()
|
||||
{
|
||||
return All()
|
||||
.Where(format => format.Type == "pdf")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static List<string> AllExtensions()
|
||||
{
|
||||
return All()
|
||||
|
||||
@ -77,6 +77,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="App_Themes\forgotten.css" />
|
||||
<Content Include="App_Themes\images\block-content.svg" />
|
||||
<Content Include="App_Themes\images\cell.ico" />
|
||||
<Content Include="App_Themes\images\close.svg" />
|
||||
@ -94,6 +95,7 @@
|
||||
<Content Include="App_Themes\images\file_xlsx.svg" />
|
||||
<Content Include="App_Themes\images\fill-forms.svg" />
|
||||
<Content Include="App_Themes\images\filter.svg" />
|
||||
<Content Include="App_Themes\images\home.svg" />
|
||||
<Content Include="App_Themes\images\icon_docx.svg" />
|
||||
<Content Include="App_Themes\images\icon_pptx.svg" />
|
||||
<Content Include="App_Themes\images\icon_xlsx.svg" />
|
||||
@ -104,10 +106,16 @@
|
||||
<Content Include="App_Themes\images\notdone.svg" />
|
||||
<Content Include="App_Themes\images\review.svg" />
|
||||
<Content Include="App_Themes\images\slide.ico" />
|
||||
<Content Include="App_Themes\images\uid-1.png" />
|
||||
<Content Include="App_Themes\images\uid-2.png" />
|
||||
<Content Include="App_Themes\images\word.ico" />
|
||||
<Content Include="App_Themes\media.css" />
|
||||
<Content Include="Forgotten.aspx" />
|
||||
<Content Include="LICENSE" />
|
||||
<Content Include="licenses\jquery.license" />
|
||||
<Content Include="script\forgotten.js" />
|
||||
<Content Include="script\formats.js" />
|
||||
<Content Include="script\jquery-3.6.4.min.js" />
|
||||
<Content Include="script\jquery-migrate-3.4.1.min.js" />
|
||||
<Content Include="Web.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -119,6 +127,12 @@
|
||||
<DependentUpon>DocEditor.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="DocumentConverter.cs" />
|
||||
<Compile Include="Forgotten.aspx.cs">
|
||||
<DependentUpon>Forgotten.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forgotten.aspx.designer.cs">
|
||||
<DependentUpon>Forgotten.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormatManager.cs" />
|
||||
<Compile Include="JwtManager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@ -145,7 +159,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="App_Themes\images\loader16.gif" />
|
||||
<Content Include="App_Themes\images\logo.png" />
|
||||
<Content Include="App_Themes\jquery-ui.css" />
|
||||
<Content Include="App_Themes\stylesheet.css" />
|
||||
<Content Include="DocEditor.aspx" />
|
||||
|
||||
@ -285,7 +285,7 @@ namespace OnlineEditorsExample
|
||||
}
|
||||
|
||||
// create a command request
|
||||
public static void commandRequest(string method, string key, object meta = null)
|
||||
public static Dictionary<string, object> commandRequest(string method, string key, object meta = null)
|
||||
{
|
||||
_Default.VerifySSL();
|
||||
|
||||
@ -348,6 +348,7 @@ namespace OnlineEditorsExample
|
||||
{
|
||||
throw new Exception(dataResponse);
|
||||
}
|
||||
return responseObj;
|
||||
}
|
||||
|
||||
private static void SaveFile(byte[] data, string path)
|
||||
|
||||
@ -58,7 +58,9 @@ namespace OnlineEditorsExample
|
||||
"Can’t print the file",
|
||||
"Can create new files from the editor",
|
||||
"Can see the information about Group2 users",
|
||||
"Can’t submit forms"
|
||||
"Can’t submit forms",
|
||||
"Can't close history",
|
||||
"Can't restore the file version"
|
||||
};
|
||||
|
||||
static List<string> descr_user_0 = new List<string>()
|
||||
@ -91,7 +93,8 @@ namespace OnlineEditorsExample
|
||||
new List<string>(),
|
||||
descr_user_1,
|
||||
true,
|
||||
true
|
||||
true,
|
||||
new Goback(null, false)
|
||||
),
|
||||
new User(
|
||||
"uid-2",
|
||||
@ -110,7 +113,8 @@ namespace OnlineEditorsExample
|
||||
new List<string>(),
|
||||
descr_user_2,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
new Goback("Go to Documents",null)
|
||||
),
|
||||
new User(
|
||||
"uid-3",
|
||||
@ -129,7 +133,8 @@ namespace OnlineEditorsExample
|
||||
new List<string>() { "copy", "download", "print" },
|
||||
descr_user_3,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
null
|
||||
),
|
||||
new User(
|
||||
"uid-0",
|
||||
@ -143,7 +148,8 @@ namespace OnlineEditorsExample
|
||||
new List<string>() { "protect" },
|
||||
descr_user_0,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
null
|
||||
)
|
||||
};
|
||||
|
||||
@ -235,8 +241,9 @@ namespace OnlineEditorsExample
|
||||
public bool templates;
|
||||
public List<string> userInfoGroups;
|
||||
public bool avatar;
|
||||
public Goback goback;
|
||||
|
||||
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar)
|
||||
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, List<string> userInfoGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates, bool avatar, Goback goback)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@ -250,6 +257,21 @@ namespace OnlineEditorsExample
|
||||
this.templates = templates;
|
||||
this.userInfoGroups = userInfoGroups;
|
||||
this.avatar = avatar;
|
||||
this.goback = goback;
|
||||
}
|
||||
}
|
||||
|
||||
public class Goback
|
||||
{
|
||||
public string text;
|
||||
public bool? blank;
|
||||
|
||||
public Goback(){}
|
||||
|
||||
public Goback(string text, bool? blank)
|
||||
{
|
||||
this.text = text;
|
||||
this.blank = blank;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ namespace OnlineEditorsExample
|
||||
case "remove":
|
||||
Remove(context);
|
||||
break;
|
||||
case "removeforgotten":
|
||||
RemoveForgotten(context);
|
||||
break;
|
||||
case "assets":
|
||||
Assets(context);
|
||||
break;
|
||||
@ -87,6 +90,9 @@ namespace OnlineEditorsExample
|
||||
case "reference":
|
||||
Reference(context);
|
||||
break;
|
||||
case "formats":
|
||||
Formats(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,12 +228,22 @@ namespace OnlineEditorsExample
|
||||
context.Response.ContentType = "text/plain";
|
||||
try
|
||||
{
|
||||
var fileName = Path.GetFileName(context.Request["fileName"]);
|
||||
var path = _Default.StoragePath(fileName, HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress)));
|
||||
var histDir = _Default.HistoryDir(path);
|
||||
string fileName = context.Request["fileName"];
|
||||
string userAddress = HttpUtility.UrlEncode(_Default.CurUserHostAddress(HttpContext.Current.Request.UserHostAddress));
|
||||
|
||||
if (File.Exists(path)) File.Delete(path); // delete file
|
||||
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
|
||||
if (!String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = Path.GetFileName(fileName);
|
||||
var path = _Default.StoragePath(fileName, userAddress);
|
||||
var histDir = _Default.HistoryDir(path);
|
||||
|
||||
if (File.Exists(path)) File.Delete(path); // delete file
|
||||
if (Directory.Exists(histDir)) Directory.Delete(histDir, true); // delete file history
|
||||
} else
|
||||
{
|
||||
string userDir = _Default.StoragePath("", userAddress);
|
||||
if (Directory.Exists(userDir)) Directory.Delete(userDir, true); // delete the user's directory
|
||||
}
|
||||
|
||||
context.Response.Write("{ \"success\": true }");
|
||||
}
|
||||
@ -778,5 +794,50 @@ namespace OnlineEditorsExample
|
||||
+ userAddress;
|
||||
return fileUrl.ToString();
|
||||
}
|
||||
|
||||
// return all the supported formats
|
||||
private static void Formats(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> data = new Dictionary<string, object>
|
||||
{
|
||||
{ "formats", FormatManager.All() }
|
||||
};
|
||||
context.Response.ContentType = "application/json";
|
||||
var jss = new JavaScriptSerializer();
|
||||
|
||||
context.Response.Write(jss.Serialize(data));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
|
||||
}
|
||||
}
|
||||
|
||||
// delete a forgotten file from the document server
|
||||
private static void RemoveForgotten(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!bool.Parse(WebConfigurationManager.AppSettings["enable-forgotten"]))
|
||||
{
|
||||
throw new HttpException(403, "The forgotten page is disabled");
|
||||
}
|
||||
|
||||
string filename = context.Request["filename"];
|
||||
|
||||
if (!String.IsNullOrEmpty(filename))
|
||||
{
|
||||
TrackManager.commandRequest("deleteForgotten", filename);
|
||||
}
|
||||
|
||||
context.Response.StatusCode = 204;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.Response.Write("{ \"error\": \"" + e.Message + "\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
web/documentserver-example/csharp/script/forgotten.js
Executable file
@ -0,0 +1,19 @@
|
||||
function deleteFile(event) {
|
||||
let filename = event.currentTarget.getAttribute("data");
|
||||
filename = encodeURIComponent(filename);
|
||||
let url = `webeditor.ashx?type=removeforgotten&filename=${filename}`;
|
||||
|
||||
fetch(url, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
}).then(result => {
|
||||
if (result.status == 204) {
|
||||
document.location.reload(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.delete-file').forEach(el => {
|
||||
el.addEventListener('click', deleteFile);
|
||||
});
|
||||
66
web/documentserver-example/csharp/script/formats.js
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
class Format {
|
||||
constructor(name, type, actions, convert, mime) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.actions = actions;
|
||||
this.convert = convert;
|
||||
this.mime = mime;
|
||||
}
|
||||
|
||||
isAutoConvertible() {
|
||||
return this.actions.includes('auto-convert');
|
||||
}
|
||||
|
||||
isEditable() {
|
||||
return this.actions.includes('edit') || this.actions.includes('lossy-edit');
|
||||
}
|
||||
|
||||
isFillable() {
|
||||
return this.actions.includes('fill');
|
||||
}
|
||||
}
|
||||
|
||||
class FormatManager {
|
||||
formats = [];
|
||||
|
||||
constructor(formats) {
|
||||
if(Array.isArray(formats)) this.formats = formats;
|
||||
}
|
||||
|
||||
findByExtension(extension) {
|
||||
return this.formats.find(format => format.name == extension);
|
||||
}
|
||||
|
||||
isAutoConvertible(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isAutoConvertible();
|
||||
}
|
||||
|
||||
isEditable(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isEditable();
|
||||
}
|
||||
|
||||
isFillable(extension) {
|
||||
let format = this.findByExtension(extension);
|
||||
return format !== undefined && format.isFillable();
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,27 @@
|
||||
*/
|
||||
|
||||
var directUrl;
|
||||
var formatManager;
|
||||
|
||||
window.onload = function () {
|
||||
fetch("webeditor.ashx?type=formats")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.formats) {
|
||||
let formats = [];
|
||||
data.formats.forEach(format => {
|
||||
formats.push(new Format(
|
||||
format.Name,
|
||||
format.Type,
|
||||
format.Actions,
|
||||
format.Convert,
|
||||
format.Mime
|
||||
));
|
||||
});
|
||||
formatManager = new FormatManager(formats);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof jQuery != "undefined") {
|
||||
jq = jQuery.noConflict();
|
||||
@ -87,8 +108,8 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
|
||||
var timer = null;
|
||||
var checkConvert = function (filePass) {
|
||||
filePass = filePass ? filePass : null;
|
||||
var checkConvert = function (filePass, fileType) {
|
||||
filePass = filePass ? filePass : null;
|
||||
if (timer != null) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
@ -100,10 +121,10 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#filePass").val("");
|
||||
|
||||
var fileName = jq("#hiddenFileName").val();
|
||||
var posExt = fileName.lastIndexOf('.');
|
||||
var posExt = fileName.lastIndexOf('.') + 1;
|
||||
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
|
||||
|
||||
if (ConverExtList.indexOf(posExt) == -1) {
|
||||
if (!formatManager.isAutoConvertible(posExt)) {
|
||||
jq("#step2").addClass("done").removeClass("current");
|
||||
loadScripts();
|
||||
return;
|
||||
@ -116,7 +137,7 @@ if (typeof jQuery != "undefined") {
|
||||
contentType: "text/xml",
|
||||
type: "post",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({ filename: fileName, filePass: filePass }),
|
||||
data: JSON.stringify({ filename: fileName, filePass: filePass, fileExt: fileType }),
|
||||
url: requestAddress,
|
||||
complete: function (data) {
|
||||
var responseText = data.responseText;
|
||||
@ -132,6 +153,12 @@ if (typeof jQuery != "undefined") {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (response.error.includes("Error conversion output format")) {
|
||||
jq("#select-file-type").removeClass("invisible");
|
||||
jq("#step2").removeClass("current");
|
||||
jq("#hiddenFileName").attr("placeholder", filePass);
|
||||
return;
|
||||
}
|
||||
jq(".current").removeClass("current");
|
||||
jq(".step:not(.done)").addClass("error");
|
||||
jq("#mainProgress .error-message").show().find("span").text(response.error);
|
||||
@ -143,7 +170,7 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#hiddenFileName").val(response.filename);
|
||||
|
||||
if (response.step && response.step < 100) {
|
||||
checkConvert(filePass);
|
||||
checkConvert(filePass, fileType);
|
||||
} else {
|
||||
jq("#step2").addClass("done").removeClass("current");
|
||||
loadScripts();
|
||||
@ -178,10 +205,10 @@ if (typeof jQuery != "undefined") {
|
||||
jq("#beginView, #beginEmbedded").removeClass("disable");
|
||||
|
||||
var fileName = jq("#hiddenFileName").val();
|
||||
var posExt = fileName.lastIndexOf('.');
|
||||
var posExt = fileName.lastIndexOf('.') + 1;
|
||||
posExt = 0 <= posExt ? fileName.substring(posExt).trim().toLowerCase() : '';
|
||||
|
||||
if (EditedExtList.indexOf(posExt) != -1 || FillFormExtList.indexOf(posExt) != -1) {
|
||||
if (formatManager.isEditable(posExt) || formatManager.isFillable(posExt)) {
|
||||
jq("#beginEdit").removeClass("disable");
|
||||
}
|
||||
};
|
||||
@ -213,6 +240,15 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
};
|
||||
|
||||
jq(document).on("click", ".file-type:not(.disable)", function () {
|
||||
const currentElement = jq(this);
|
||||
var fileType = currentElement.attr("data");
|
||||
var filePass = jq("#hiddenFileName").attr("placeholder");
|
||||
jq('.file-type').addClass(["disable", "pale"]);
|
||||
currentElement.removeClass("pale");
|
||||
checkConvert(filePass, fileType);
|
||||
});
|
||||
|
||||
jq(document).on("click", "#enterPass", function () {
|
||||
var filePass = jq("#filePass").val();
|
||||
if (filePass) {
|
||||
@ -293,6 +329,24 @@ if (typeof jQuery != "undefined") {
|
||||
});
|
||||
});
|
||||
|
||||
jq(document).on("click", ".clear-all", function () {
|
||||
if (confirm("Delete all the files?")) {
|
||||
var requestAddress = "webeditor.ashx"
|
||||
+ "?type=remove";
|
||||
|
||||
jq.ajax({
|
||||
async: true,
|
||||
contentType: "text/xml",
|
||||
url: requestAddress,
|
||||
complete: function (data) {
|
||||
if (JSON.parse(data.responseText).success) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function showUserTooltip (isMobile) {
|
||||
if ( jq("div#portal-info").is(":hidden") ) {
|
||||
jq("div#portal-info").show();
|
||||
@ -367,4 +421,27 @@ if (typeof jQuery != "undefined") {
|
||||
}).mouseout(function () {
|
||||
jq("div.tooltip").remove();
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSidePanel(event) {
|
||||
event.preventDefault();
|
||||
let sidePanel = document.querySelector(".left-panel");
|
||||
let body = document.querySelector("body");
|
||||
if (sidePanel.classList.contains("active")) {
|
||||
sidePanel.classList.remove("active");
|
||||
body.classList.remove("menu-open");
|
||||
} else {
|
||||
sidePanel.classList.add("active")
|
||||
body.classList.add("menu-open");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUserDescr(event) {
|
||||
let list = event.currentTarget.querySelector("ul");
|
||||
let cursor = window.getComputedStyle(event.currentTarget).getPropertyValue("cursor");
|
||||
|
||||
if (cursor === "pointer") {
|
||||
if (list.classList.contains("active")) list.classList.remove("active");
|
||||
else list.classList.add("active");
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<appSettings>
|
||||
<clear />
|
||||
<add key="version" value="1.9.0"/>
|
||||
<add key="version" value="1.10.0"/>
|
||||
|
||||
<add key="filesize-max" value="52428800"/>
|
||||
<add key="storage-path" value=""/>
|
||||
<add key="filename-max" value="50"/>
|
||||
<add key="enable-forgotten" value="true"/>
|
||||
|
||||
<add key="files.docservice.timeout" value="120000" />
|
||||
<add key="files.docservice.secret" value="" />
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
ONLYOFFICE Applications example uses code from the following 3rd party projects:
|
||||
|
||||
|
||||
Gson - Gson is a Java library that can be used to convert Java Objects into their JSON representation. (https://github.com/google/gson/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: gson.license
|
||||
@ -13,6 +12,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
|
||||
License: Apache 2.0
|
||||
License File: jackson-databind.license
|
||||
|
||||
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: jackson-dataformat-properties.license
|
||||
|
||||
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
|
||||
License: MIT, GPL
|
||||
License File: jQuery.BlockUI.license
|
||||
@ -37,6 +40,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
|
||||
License: MIT
|
||||
License File: jQuery.UI.license
|
||||
|
||||
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
|
||||
License Public Domain
|
||||
License File: json.license
|
||||
|
||||
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: JSON.simple.license
|
||||
@ -49,14 +56,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
|
||||
License: Apache 2.0
|
||||
License File modelmapper.license
|
||||
|
||||
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: prime-jwt.license
|
||||
|
||||
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
@ -135,9 +135,9 @@ See the detailed guide to learn how to install Document Server [for Linux](https
|
||||
a) archive with Java-Spring:
|
||||
|
||||
```
|
||||
wget https://api.onlyoffice.com/app_data/editor/Java.Spring.Example.zip
|
||||
wget https://github.com/ONLYOFFICE/document-server-integration/releases/latest/download/Java.Spring.Example.zip
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
unzip Java.Spring.Example.zip
|
||||
```
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
ONLYOFFICE Applications example uses code from the following 3rd party projects:
|
||||
|
||||
|
||||
Gson - Gson is a Java library that can be used to convert Java Objects into their JSON representation. (https://github.com/google/gson/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: gson.license
|
||||
@ -13,6 +12,10 @@ Jackson Databind - General-purpose data-binding functionality and tree-model for
|
||||
License: Apache 2.0
|
||||
License File: jackson-databind.license
|
||||
|
||||
Jackson Dataformat Properties - Support for reading and writing content of "Java Properties" style configuration files as if there was implied nesting structure (by default using dots as separators). (https://github.com/FasterXML/jackson-dataformats-text/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: jackson-dataformat-properties.license
|
||||
|
||||
jQuery.BlockUI - The jQuery BlockUI Plugin lets you simulate synchronous behavior when using AJAX, without locking the browser. (https://github.com/malsup/blockui/)
|
||||
License: MIT, GPL
|
||||
License File: jQuery.BlockUI.license
|
||||
@ -37,6 +40,10 @@ jQuery.UI - jQuery UI is an open source library of interface components —
|
||||
License: MIT
|
||||
License File: jQuery.UI.license
|
||||
|
||||
JSON - JSON is a light-weight, language independent, data interchange format. (https://github.com/stleary/JSON-java/blob/master/LICENSE)
|
||||
License Public Domain
|
||||
License File: json.license
|
||||
|
||||
JSON.simple - JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. (https://github.com/fangyidong/json-simple/blob/master/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: JSON.simple.license
|
||||
@ -49,14 +56,14 @@ ModelMapper - ModelMapper is an intelligent object mapping library that automa
|
||||
License: Apache 2.0
|
||||
License File modelmapper.license
|
||||
|
||||
Prime JWT - is intended to be fast and easy to use. Prime JWT has a single external dependency on Jackson. (https://github.com/ws-apps/prime-jwt/blob/master/LICENSE)
|
||||
License: Apache 2.0
|
||||
License File: prime-jwt.license
|
||||
|
||||
Spring Boot - Helps create Spring-powered, production-grade applications and services. Has external dependencies on Spring Framework. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Web - Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
Spring Boot Devtools - Provides fast application restarts, LiveReload, and configurations for enhanced development experience. (https://github.com/spring-projects/spring-boot/blob/main/LICENSE.txt)
|
||||
License: Apache 2.0
|
||||
License File: spring-boot.license
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
Apache License
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@ -178,7 +179,7 @@ Apache License
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
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
|
||||
@ -186,7 +187,7 @@ Apache License
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -0,0 +1 @@
|
||||
Public Domain.
|
||||
@ -50,11 +50,6 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.inversoft</groupId>
|
||||
<artifactId>prime-jwt</artifactId>
|
||||
<version>1.3.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
@ -71,12 +66,39 @@
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-properties</artifactId>
|
||||
<version>2.13.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.modelmapper</groupId>
|
||||
<artifactId>modelmapper</artifactId>
|
||||
<version>2.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20231013</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.onlyoffice</groupId>
|
||||
<artifactId>docs-integration-sdk</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>ossrh</id>
|
||||
<name>Sonatype OSSRH</name>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
package com.onlyoffice.integration;
|
||||
|
||||
import com.onlyoffice.integration.documentserver.serializers.FilterState;
|
||||
import com.onlyoffice.integration.entities.Goback;
|
||||
import com.onlyoffice.integration.services.UserServices;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -92,30 +93,34 @@ public class ExampleData {
|
||||
"Can create a file from an editor",
|
||||
"Can see the information about Group2 users",
|
||||
"Can view chat",
|
||||
"Can’t submit forms"
|
||||
"Can’t submit forms",
|
||||
"Can't close history",
|
||||
"Can't restore the file version"
|
||||
);
|
||||
|
||||
// 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, true);
|
||||
List.of(FilterState.NULL.toString()), null, true, true, true,
|
||||
new Goback(null, false), 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, true);
|
||||
true, true, new Goback("Go to Documents", null), false);
|
||||
|
||||
// create user 3 with the specified parameters
|
||||
userService.createUser("Hamish Mitchell", null, descriptionUserThird,
|
||||
"group-3", List.of("group-2"), List.of("group-2", "group-3"), List.of("group-2"),
|
||||
new ArrayList<>(), List.of("group-2"), false, true, true, false);
|
||||
new ArrayList<>(), List.of("group-2"), false, true, true, false,
|
||||
null, false);
|
||||
|
||||
// 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, false);
|
||||
new ArrayList<>(), null, false, false, false, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,17 @@ package com.onlyoffice.integration;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
|
||||
import com.onlyoffice.manager.document.DocumentManager;
|
||||
import com.onlyoffice.manager.request.DefaultRequestManager;
|
||||
import com.onlyoffice.manager.request.RequestManager;
|
||||
import com.onlyoffice.manager.security.DefaultJwtManager;
|
||||
import com.onlyoffice.manager.security.JwtManager;
|
||||
import com.onlyoffice.manager.settings.SettingsManager;
|
||||
import com.onlyoffice.manager.url.UrlManager;
|
||||
import com.onlyoffice.service.command.CommandService;
|
||||
import com.onlyoffice.service.command.DefaultCommandService;
|
||||
import com.onlyoffice.service.convert.ConvertService;
|
||||
import com.onlyoffice.service.convert.DefaultConvertService;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.convention.MatchingStrategies;
|
||||
@ -30,23 +41,15 @@ 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();
|
||||
@ -67,21 +70,34 @@ public class IntegrationConfiguration {
|
||||
@PostConstruct
|
||||
public void init() { // initialize the storage path builder
|
||||
storagePathBuilder.configure(storageAddress.isBlank() ? null : storageAddress);
|
||||
if (!verifyPerrOff.isEmpty()) {
|
||||
try {
|
||||
if (verifyPerrOff.equals("true")) {
|
||||
ssl.turnOffSslChecking(); //the certificate will be ignored
|
||||
} else {
|
||||
ssl.turnOnSslChecking(); //the certificate will be verified
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() { // create the object mapper
|
||||
return new ObjectMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtManager jwtManager(final SettingsManager settingsManager) {
|
||||
return new DefaultJwtManager(settingsManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestManager requestManager(final UrlManager urlManager, final JwtManager jwtManager,
|
||||
final SettingsManager settingsManager) {
|
||||
return new DefaultRequestManager(urlManager, jwtManager, settingsManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConvertService convertService(final DocumentManager documentManager, final UrlManager urlManager,
|
||||
final RequestManager requestManager,
|
||||
final SettingsManager settingsManager) {
|
||||
return new DefaultConvertService(documentManager, urlManager, requestManager, settingsManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandService commandService(final RequestManager requestManager) {
|
||||
return new DefaultCommandService(requestManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,19 +20,21 @@ package com.onlyoffice.integration.controllers;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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.dto.UserInfo;
|
||||
import com.onlyoffice.integration.dto.Protect;
|
||||
import com.onlyoffice.integration.documentserver.models.enums.Type;
|
||||
import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
|
||||
import com.onlyoffice.integration.dto.UserInfo;
|
||||
import com.onlyoffice.integration.entities.User;
|
||||
import com.onlyoffice.integration.sdk.manager.UrlManager;
|
||||
import com.onlyoffice.integration.sdk.service.ConfigService;
|
||||
import com.onlyoffice.integration.services.UserServices;
|
||||
import com.onlyoffice.integration.services.configurers.FileConfigurer;
|
||||
import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper;
|
||||
import com.onlyoffice.manager.security.JwtManager;
|
||||
import com.onlyoffice.manager.settings.SettingsManager;
|
||||
import com.onlyoffice.model.documenteditor.Config;
|
||||
import com.onlyoffice.model.documenteditor.config.document.Type;
|
||||
import lombok.SneakyThrows;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@ -56,12 +58,6 @@ import static com.onlyoffice.integration.documentserver.util.Constants.ANONYMOUS
|
||||
@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;
|
||||
|
||||
@ -78,7 +74,13 @@ public class EditorController {
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private FileConfigurer<DefaultFileWrapper> fileConfigurer;
|
||||
private SettingsManager settingsManager;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private UrlManager urlManager;
|
||||
|
||||
@GetMapping(path = "${url.editor}")
|
||||
// process request to open the editor page
|
||||
@ -86,20 +88,18 @@ public class EditorController {
|
||||
@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;
|
||||
Action action = null;
|
||||
Type type = Type.DESKTOP;
|
||||
Locale locale = new Locale("en");
|
||||
|
||||
if (actionParam != null) {
|
||||
action = Action.valueOf(actionParam);
|
||||
}
|
||||
if (typeParam != null) {
|
||||
type = Type.valueOf(typeParam);
|
||||
type = Type.valueOf(typeParam.toUpperCase());
|
||||
}
|
||||
|
||||
List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
|
||||
@ -118,39 +118,34 @@ public class EditorController {
|
||||
return "index.html";
|
||||
}
|
||||
|
||||
User user = optionalUser.get();
|
||||
user.setImage(user.getAvatar() ? storagePathBuilder.getServerUrl(true) + "/css/img/uid-"
|
||||
+ user.getId() + ".png" : null);
|
||||
|
||||
// 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()
|
||||
Config config = configService.createConfig(
|
||||
fileName,
|
||||
action,
|
||||
type
|
||||
);
|
||||
|
||||
// add attributes to the specified model
|
||||
// add file model with the default parameters to the original model
|
||||
model.addAttribute("model", fileModel);
|
||||
JSONObject actionData = null;
|
||||
|
||||
if (actionLink != null && !actionLink.isEmpty()) {
|
||||
actionData = new JSONObject(actionLink);
|
||||
}
|
||||
|
||||
config.getEditorConfig().setActionLink(actionData);
|
||||
config.getEditorConfig().setLang(locale.toLanguageTag());
|
||||
|
||||
model.addAttribute("model", config);
|
||||
|
||||
// create the document service api URL and add it to the model
|
||||
model.addAttribute("docserviceApiUrl", docserviceSite + docserviceApiUrl);
|
||||
model.addAttribute("docserviceApiUrl", urlManager.getDocumentServerApiUrl());
|
||||
|
||||
// get an image and add it to the model
|
||||
model.addAttribute("dataInsertImage", getInsertImage(directUrl));
|
||||
model.addAttribute("dataInsertImage", getInsertImage());
|
||||
|
||||
// get a document for comparison and add it to the model
|
||||
model.addAttribute("dataDocument", getCompareFile(directUrl));
|
||||
model.addAttribute("dataDocument", getCompareFile());
|
||||
|
||||
// get recipients data for mail merging and add it to the model
|
||||
model.addAttribute("dataSpreadsheet", getSpreadsheet(directUrl));
|
||||
model.addAttribute("dataSpreadsheet", getSpreadsheet());
|
||||
|
||||
// get user data for mentions and add it to the model
|
||||
model.addAttribute("usersForMentions", getUserMentions(uid));
|
||||
@ -210,17 +205,13 @@ public class EditorController {
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private String getInsertImage(final Boolean directUrl) { // get an image that will be inserted into the document
|
||||
private String getInsertImage() { // 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");
|
||||
}
|
||||
dataInsertImage.put("fileType", "svg");
|
||||
dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.svg");
|
||||
|
||||
// check if the document token is enabled
|
||||
if (jwtManager.tokenEnabled()) {
|
||||
if (settingsManager.isSecurityEnabled()) {
|
||||
|
||||
// create token from the dataInsertImage object
|
||||
dataInsertImage.put("token", jwtManager.createToken(dataInsertImage));
|
||||
@ -232,17 +223,13 @@ public class EditorController {
|
||||
|
||||
// get a document that will be compared with the current document
|
||||
@SneakyThrows
|
||||
private String getCompareFile(final Boolean directUrl) {
|
||||
private String getCompareFile() {
|
||||
Map<String, Object> dataDocument = new HashMap<>();
|
||||
dataDocument.put("fileType", "docx");
|
||||
dataDocument.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx");
|
||||
if (directUrl) {
|
||||
dataDocument.put("directUrl", storagePathBuilder
|
||||
.getServerUrl(false) + "/assets?name=sample.docx");
|
||||
}
|
||||
|
||||
// check if the document token is enabled
|
||||
if (jwtManager.tokenEnabled()) {
|
||||
if (settingsManager.isSecurityEnabled()) {
|
||||
|
||||
// create token from the dataDocument object
|
||||
dataDocument.put("token", jwtManager.createToken(dataDocument));
|
||||
@ -252,16 +239,13 @@ public class EditorController {
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String getSpreadsheet(final Boolean directUrl) {
|
||||
private String getSpreadsheet() {
|
||||
Map<String, Object> dataSpreadsheet = new HashMap<>(); // get recipients data for mail merging
|
||||
dataSpreadsheet.put("fileType", "csv");
|
||||
dataSpreadsheet.put("url", storagePathBuilder.getServerUrl(true) + "/csv");
|
||||
if (directUrl) {
|
||||
dataSpreadsheet.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv");
|
||||
}
|
||||
|
||||
// check if the document token is enabled
|
||||
if (jwtManager.tokenEnabled()) {
|
||||
if (settingsManager.isSecurityEnabled()) {
|
||||
|
||||
// create token from the dataSpreadsheet object
|
||||
dataSpreadsheet.put("token", jwtManager.createToken(dataSpreadsheet));
|
||||
|
||||
@ -21,32 +21,38 @@ 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.history.HistoryManager;
|
||||
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.Reference;
|
||||
import com.onlyoffice.integration.dto.ReferenceData;
|
||||
import com.onlyoffice.integration.dto.Rename;
|
||||
import com.onlyoffice.integration.dto.Restore;
|
||||
import com.onlyoffice.integration.dto.SaveAs;
|
||||
import com.onlyoffice.integration.dto.Track;
|
||||
import com.onlyoffice.integration.entities.User;
|
||||
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
|
||||
import com.onlyoffice.integration.sdk.manager.DocumentManager;
|
||||
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 com.onlyoffice.manager.request.RequestManager;
|
||||
import com.onlyoffice.manager.security.JwtManager;
|
||||
import com.onlyoffice.manager.settings.SettingsManager;
|
||||
import com.onlyoffice.manager.url.UrlManager;
|
||||
import com.onlyoffice.model.commandservice.CommandRequest;
|
||||
import com.onlyoffice.model.commandservice.CommandResponse;
|
||||
import com.onlyoffice.model.commandservice.commandrequest.Command;
|
||||
import com.onlyoffice.model.commandservice.commandrequest.Meta;
|
||||
import com.onlyoffice.model.convertservice.ConvertRequest;
|
||||
import com.onlyoffice.model.convertservice.ConvertResponse;
|
||||
import com.onlyoffice.model.documenteditor.Callback;
|
||||
import com.onlyoffice.model.documenteditor.config.document.ReferenceData;
|
||||
import com.onlyoffice.service.command.CommandService;
|
||||
import com.onlyoffice.service.convert.ConvertService;
|
||||
import com.onlyoffice.service.documenteditor.callback.CallbackService;
|
||||
import org.apache.http.HttpEntity;
|
||||
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.core.io.UrlResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@ -74,7 +80,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@ -91,22 +96,6 @@ import java.util.Optional;
|
||||
@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
|
||||
@ -116,20 +105,29 @@ public class FileController {
|
||||
@Autowired
|
||||
private UserServices userService;
|
||||
@Autowired
|
||||
private CallbackHandler callbackHandler;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
@Autowired
|
||||
private ServiceConverter serviceConverter;
|
||||
@Autowired
|
||||
private CallbackManager callbackManager;
|
||||
@Autowired
|
||||
private HistoryManager historyManager;
|
||||
@Autowired
|
||||
private DocumentManager documentManager;
|
||||
@Autowired
|
||||
private ConvertService convertService;
|
||||
@Autowired
|
||||
private RequestManager requestManager;
|
||||
@Autowired
|
||||
private SettingsManager settingsManager;
|
||||
@Autowired
|
||||
private CallbackService callbackService;
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
@Autowired
|
||||
private UrlManager urlManager;
|
||||
|
||||
// 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
|
||||
// get document type
|
||||
String documentType = documentManager.getDocumentType(fullFileName).toString().toLowerCase();
|
||||
if (optionalUser.isPresent()) {
|
||||
User user = optionalUser.get();
|
||||
storageMutator.createMeta(fullFileName, // create meta information with the user ID and name specified
|
||||
@ -196,17 +194,17 @@ public class FileController {
|
||||
@CookieValue("uid") final String uid) {
|
||||
try {
|
||||
String fullFileName = file.getOriginalFilename(); // get file name
|
||||
String fileExtension = fileUtility.getFileExtension(fullFileName); // get file extension
|
||||
String fileExtension = documentManager.getExtension(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) {
|
||||
if (documentManager.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 (documentManager.getDocumentType(fullFileName) == null) {
|
||||
|
||||
// if not, write an error message to the response
|
||||
return "{ \"error\": \"File type is not supported\"}";
|
||||
@ -217,7 +215,7 @@ public class FileController {
|
||||
throw new IOException("Could not update a file"); // if the file cannot be updated, an error occurs
|
||||
}
|
||||
|
||||
fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath)
|
||||
fullFileName = documentManager.getBaseName(fileNamePath)
|
||||
+ "." + fileExtension; // get full file name
|
||||
|
||||
return createUserMetadata(uid, fullFileName); // create user metadata and return it
|
||||
@ -235,80 +233,87 @@ public class FileController {
|
||||
@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";
|
||||
// get an auto-conversion extension from the request body or set it to the ooxml extension
|
||||
String conversionExtension = body.getFileExt() != null ? body.getFileExt() : "ooxml";
|
||||
|
||||
try {
|
||||
// check if the file with such an extension can be converted
|
||||
if (fileUtility.getConvertExts().contains(fileExt)) {
|
||||
String key = serviceConverter.generateRevisionId(fileUri); // generate document key
|
||||
ConvertedData response = serviceConverter // get the URL to the converted file
|
||||
.getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
|
||||
if (documentManager.getDefaultConvertExtension(fileName) != null) {
|
||||
ConvertRequest convertRequest = ConvertRequest.builder()
|
||||
.password(filePass)
|
||||
.outputtype(conversionExtension)
|
||||
.region(lang)
|
||||
.async(true)
|
||||
.build();
|
||||
|
||||
String newFileUri = response.getUri();
|
||||
String newFileType = "." + response.getFileType();
|
||||
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
|
||||
|
||||
if (newFileUri.isEmpty()) {
|
||||
return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}";
|
||||
if (convertResponse.getError() != null || convertResponse.getFileUrl() == null) {
|
||||
return objectMapper.writeValueAsString(convertResponse);
|
||||
}
|
||||
|
||||
String newFileUri = convertResponse.getFileUrl();
|
||||
String newFileType = convertResponse.getFileType();
|
||||
|
||||
/* 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;
|
||||
final String oldFileName = fileName;
|
||||
String nameWithInternalExt = documentManager.getBaseName(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
|
||||
fileName = requestManager.executeGetRequest(newFileUri, new RequestManager.Callback<String>() {
|
||||
public String doWork(final Object response) throws IOException {
|
||||
InputStream stream = ((HttpEntity) response).getContent(); // get input stream of the converted
|
||||
// file
|
||||
|
||||
if (stream == null) {
|
||||
connection.disconnect();
|
||||
throw new RuntimeException("Input stream is null");
|
||||
}
|
||||
if (stream == null) {
|
||||
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;
|
||||
// remove source file
|
||||
storageMutator.deleteFile(oldFileName);
|
||||
|
||||
// create the converted file with input stream
|
||||
storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream);
|
||||
return 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\": \"" + e.getMessage() + "\"}";
|
||||
}
|
||||
// if the operation of file converting is unsuccessful, an error occurs
|
||||
return "{ \"error\": \"" + "The file can't be converted.\"}";
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
@ResponseBody
|
||||
public String delete(@RequestBody final Converter body) { // delete a file
|
||||
try {
|
||||
String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name
|
||||
String filename = body.getFileName();
|
||||
boolean success = false;
|
||||
|
||||
// delete a file from the storage and return the status of this operation (true or false)
|
||||
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
|
||||
if (filename != null) {
|
||||
String fullFileName = documentManager.getDocumentName(filename); // get full file name
|
||||
|
||||
// delete file history and return the status of this operation (true or false)
|
||||
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
|
||||
// delete a file from the storage and return the status of this operation (true or false)
|
||||
boolean fileSuccess = storageMutator.deleteFile(fullFileName);
|
||||
|
||||
return "{ \"success\": \"" + (fileSuccess && historySuccess) + "\"}";
|
||||
// delete file history and return the status of this operation (true or false)
|
||||
boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
|
||||
success = fileSuccess && historySuccess;
|
||||
} else {
|
||||
// delete the user's folder and return the boolean status
|
||||
success = storageMutator.deleteUserFolder();
|
||||
}
|
||||
return "{ \"success\": \"" + (success) + "\"}";
|
||||
} catch (Exception e) {
|
||||
// if the operation of file deleting is unsuccessful, an error occurs
|
||||
return "{ \"error\": \"" + e.getMessage() + "\"}";
|
||||
@ -322,13 +327,12 @@ public class FileController {
|
||||
@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 (settingsManager.isSecurityEnabled()) {
|
||||
String header = request.getHeader(settingsManager.getSecurityHeader());
|
||||
if (header != null && !header.isEmpty()) {
|
||||
String token = header
|
||||
.replace("Bearer ", ""); // token is the header without the Bearer prefix
|
||||
jwtManager.readToken(token); // read the token
|
||||
jwtManager.verify(token); // read the token
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -346,13 +350,12 @@ public class FileController {
|
||||
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 (settingsManager.isSecurityEnabled() && userAddress != null) {
|
||||
String header = request.getHeader(settingsManager.getSecurityHeader());
|
||||
if (header != null && !header.isEmpty()) {
|
||||
String token = header
|
||||
.replace("Bearer ", ""); // token is the header without the Bearer prefix
|
||||
jwtManager.readToken(token); // read the token
|
||||
jwtManager.verify(token); // read the token
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -382,10 +385,10 @@ public class FileController {
|
||||
sampleData,
|
||||
uid,
|
||||
user.get().getName()); // create a demo document with the sample data
|
||||
if (fileName.isBlank() || fileName == null) {
|
||||
if (fileName == null || fileName.isBlank()) {
|
||||
throw new RuntimeException("You must have forgotten to add asset files");
|
||||
}
|
||||
return "redirect:editor?fileName=" + URLEncoder
|
||||
return "redirect:editor?action=edit&fileName=" + URLEncoder
|
||||
.encode(fileName, StandardCharsets.UTF_8); // redirect the request
|
||||
} catch (Exception ex) {
|
||||
model.addAttribute("error", ex.getMessage());
|
||||
@ -418,28 +421,29 @@ public class FileController {
|
||||
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;
|
||||
@RequestBody final Callback body) {
|
||||
Callback callback;
|
||||
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
|
||||
String authorizationHeader = request.getHeader(settingsManager.getSecurityHeader());
|
||||
callback = callbackService.verifyCallback(body, authorizationHeader);
|
||||
|
||||
callbackService.processCallback(callback, fileName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
String message = e.getMessage();
|
||||
if (!message.contains("\"error\":1")) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
int error = callbackHandler.handle(track, fileName);
|
||||
|
||||
return "{\"error\":" + error + "}";
|
||||
return "{\"error\":\"0\"}";
|
||||
}
|
||||
|
||||
@PostMapping("/saveas")
|
||||
@ -447,24 +451,30 @@ public class FileController {
|
||||
public String saveAs(@RequestBody final SaveAs body, @CookieValue("uid") final String uid) {
|
||||
try {
|
||||
String fileName = documentManager.getCorrectName(body.getTitle());
|
||||
String curExt = fileUtility.getFileExtension(fileName);
|
||||
|
||||
if (!fileUtility.getFileExts().contains(curExt)) {
|
||||
if (documentManager.getDocumentType(fileName) == null) {
|
||||
return "{\"error\":\"File type is not supported\"}";
|
||||
}
|
||||
|
||||
URL url = new URL(body.getUrl());
|
||||
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
|
||||
InputStream stream = connection.getInputStream();
|
||||
String url = body.getUrl();
|
||||
|
||||
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);
|
||||
url = urlManager.replaceToInnerDocumentServerUrl(url);
|
||||
|
||||
return "{\"file\": \"" + fileName + "\"}";
|
||||
} catch (IOException e) {
|
||||
return requestManager.executeGetRequest(url, new RequestManager.Callback<String>() {
|
||||
@Override
|
||||
public String doWork(final Object response) throws Exception {
|
||||
InputStream stream = ((HttpEntity) response).getContent();
|
||||
|
||||
if (documentManager.getMaxFileSize() < 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 (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
|
||||
}
|
||||
@ -473,14 +483,18 @@ public class FileController {
|
||||
@PostMapping("/rename")
|
||||
@ResponseBody
|
||||
public String rename(@RequestBody final Rename body) {
|
||||
String fileName = body.getFileName();
|
||||
|
||||
HashMap<String, String> meta = new HashMap<>();
|
||||
meta.put("title", fileName + "." + body.getFileType());
|
||||
CommandRequest commandRequest = CommandRequest.builder()
|
||||
.key(body.getFileKey())
|
||||
.c(Command.META)
|
||||
.meta(Meta.builder()
|
||||
.title(body.getFileName() + "." + body.getFileType())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
try {
|
||||
callbackManager.commandRequest("meta", body.getFileKey(), meta);
|
||||
return "result ok";
|
||||
|
||||
CommandResponse commandResponse = commandService.processCommand(commandRequest, body.getFileName());
|
||||
return commandResponse.getError().getDescription();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return e.getMessage();
|
||||
@ -514,7 +528,6 @@ public class FileController {
|
||||
if (!link.contains(storagePathBuilder.getServerUrl(true))) {
|
||||
HashMap<String, String> data = new HashMap<>();
|
||||
data.put("url", link);
|
||||
data.put("directUrl", link);
|
||||
return gson.toJson(data);
|
||||
}
|
||||
|
||||
@ -529,7 +542,8 @@ public class FileController {
|
||||
if (fileName.equals("")) {
|
||||
try {
|
||||
String path = (String) body.getPath();
|
||||
path = fileUtility.getFileName(path);
|
||||
path = path.substring(path.lastIndexOf('/') + 1);
|
||||
path = path.split("\\?")[0];
|
||||
File f = new File(storagePathBuilder.getFileLocation(path));
|
||||
if (f.exists()) {
|
||||
fileName = path;
|
||||
@ -552,19 +566,18 @@ public class FileController {
|
||||
referenceData.put("fileKey", gson.toJson(fileKey));
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("fileType", fileUtility.getFileExtension(fileName));
|
||||
data.put("key", serviceConverter.generateRevisionId(
|
||||
data.put("fileType", documentManager.getDocumentName(fileName));
|
||||
data.put("key", documentManager.generateRevisionId(
|
||||
storagePathBuilder.getStorageLocation()
|
||||
+ "/" + fileName + "/"
|
||||
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified()
|
||||
));
|
||||
data.put("url", documentManager.getDownloadUrl(fileName, true));
|
||||
data.put("directUrl", body.getDirectUrl() ? documentManager.getDownloadUrl(fileName, false) : null);
|
||||
data.put("url", urlManager.getFileUrl(fileName));
|
||||
data.put("referenceData", referenceData);
|
||||
data.put("path", fileName);
|
||||
data.put("link", storagePathBuilder.getServerUrl(true) + "/editor?fileName=" + fileName);
|
||||
|
||||
if (jwtManager.tokenEnabled()) {
|
||||
if (settingsManager.isSecurityEnabled()) {
|
||||
String token = jwtManager.createToken(data);
|
||||
data.put("token", token);
|
||||
}
|
||||
@ -584,9 +597,8 @@ public class FileController {
|
||||
@GetMapping("/historydata")
|
||||
@ResponseBody
|
||||
public String history(@RequestParam("fileName") final String fileName,
|
||||
@RequestParam("version") final String version,
|
||||
@RequestParam(value = "directUrl", defaultValue = "false") final Boolean directUrl) {
|
||||
return historyManager.getHistoryData(fileName, version, directUrl);
|
||||
@RequestParam("version") final String version) {
|
||||
return historyManager.getHistoryData(fileName, version);
|
||||
}
|
||||
|
||||
@PutMapping("/restore")
|
||||
@ -599,7 +611,7 @@ public class FileController {
|
||||
String historyDirectory = storagePathBuilder.getHistoryDir(sourcePathFile.toString());
|
||||
|
||||
Integer bumpedVersion = storagePathBuilder.getFileVersion(historyDirectory, false);
|
||||
String bumpedVersionStringDirectory = documentManager.versionDir(historyDirectory, bumpedVersion, true);
|
||||
String bumpedVersionStringDirectory = historyManager.versionDir(historyDirectory, bumpedVersion, true);
|
||||
File bumpedVersionDirectory = new File(bumpedVersionStringDirectory);
|
||||
if (!bumpedVersionDirectory.exists()) {
|
||||
bumpedVersionDirectory.mkdir();
|
||||
@ -608,7 +620,7 @@ public class FileController {
|
||||
Path bumpedKeyPathFile = Paths.get(bumpedVersionStringDirectory, "key.txt");
|
||||
String bumpedKeyStringFile = bumpedKeyPathFile.toString();
|
||||
File bumpedKeyFile = new File(bumpedKeyStringFile);
|
||||
String bumpedKey = serviceConverter.generateRevisionId(
|
||||
String bumpedKey = documentManager.generateRevisionId(
|
||||
storagePathBuilder.getStorageLocation()
|
||||
+ "/"
|
||||
+ body.getFileName()
|
||||
@ -642,13 +654,13 @@ public class FileController {
|
||||
bumpedChangesFileWriter.write(bumpedChangesContent);
|
||||
bumpedChangesFileWriter.close();
|
||||
|
||||
String sourceExtension = fileUtility.getFileExtension(body.getFileName());
|
||||
String sourceExtension = documentManager.getExtension(body.getFileName());
|
||||
String previousBasename = "prev." + sourceExtension;
|
||||
|
||||
Path bumpedFile = Paths.get(bumpedVersionStringDirectory, previousBasename);
|
||||
Files.move(sourcePathFile, bumpedFile);
|
||||
|
||||
String recoveryVersionStringDirectory = documentManager.versionDir(
|
||||
String recoveryVersionStringDirectory = historyManager.versionDir(
|
||||
historyDirectory,
|
||||
body.getVersion(),
|
||||
true
|
||||
|
||||
@ -0,0 +1,121 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.controllers;
|
||||
|
||||
import com.onlyoffice.integration.dto.ForgottenFile;
|
||||
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.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.onlyoffice.model.commandservice.CommandRequest;
|
||||
import com.onlyoffice.model.commandservice.CommandResponse;
|
||||
import com.onlyoffice.model.commandservice.commandrequest.Command;
|
||||
import com.onlyoffice.manager.document.DocumentManager;
|
||||
import com.onlyoffice.service.command.CommandService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@CrossOrigin("*")
|
||||
@Controller
|
||||
public class ForgottenController {
|
||||
@Value("${server.version}")
|
||||
private String serverVersion;
|
||||
|
||||
@Value("${enable-forgotten}")
|
||||
private String enableForgotten;
|
||||
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
|
||||
@Autowired
|
||||
private DocumentManager documentManager;
|
||||
|
||||
@GetMapping("${url.forgotten}")
|
||||
public String index(final Model model) {
|
||||
if (!forgottenEnabled()) {
|
||||
model.addAttribute("error", "The forgotten page is disabled");
|
||||
return "error.html";
|
||||
}
|
||||
|
||||
model.addAttribute("files", getForgottenFiles());
|
||||
model.addAttribute("serverVersion", serverVersion);
|
||||
|
||||
return "forgotten.html";
|
||||
}
|
||||
|
||||
private ArrayList<ForgottenFile> getForgottenFiles() {
|
||||
ArrayList<ForgottenFile> files = new ArrayList<ForgottenFile>();
|
||||
try {
|
||||
CommandRequest commandRequest = CommandRequest.builder()
|
||||
.c(Command.GET_FORGOTTEN_LIST)
|
||||
.build();
|
||||
CommandResponse commandResponse = commandService.processCommand(commandRequest, null);
|
||||
List<String> keys = commandResponse.getKeys();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
commandRequest = CommandRequest.builder()
|
||||
.c(Command.GET_FORGOTTEN)
|
||||
.key(keys.get(i))
|
||||
.build();
|
||||
commandResponse = commandService.processCommand(commandRequest, null);
|
||||
ForgottenFile file = new ForgottenFile(
|
||||
commandResponse.getKey(),
|
||||
documentManager.getDocumentType(commandResponse.getUrl()).toString().toLowerCase(),
|
||||
commandResponse.getUrl()
|
||||
);
|
||||
files.add(file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private boolean forgottenEnabled() {
|
||||
return Boolean.valueOf(enableForgotten);
|
||||
}
|
||||
|
||||
@DeleteMapping("/forgotten/{filename}")
|
||||
public ResponseEntity<String> delete(@PathVariable("filename") final String filename) {
|
||||
if (!forgottenEnabled()) {
|
||||
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
try {
|
||||
CommandRequest commandRequest = CommandRequest.builder()
|
||||
.c(Command.DELETE_FORGOTTEN)
|
||||
.key(filename)
|
||||
.build();
|
||||
|
||||
CommandResponse commandResponse = commandService.processCommand(commandRequest, null);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,9 +21,11 @@ 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.sdk.manager.DocumentManager;
|
||||
import com.onlyoffice.integration.sdk.manager.UrlManager;
|
||||
import com.onlyoffice.integration.services.UserServices;
|
||||
import com.onlyoffice.integration.dto.FormatsList;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
@ -31,8 +33,8 @@ 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 org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -52,20 +54,17 @@ public class IndexController {
|
||||
@Autowired
|
||||
private FileStoragePathBuilder storagePathBuilder;
|
||||
|
||||
@Autowired
|
||||
private FileUtility fileUtility;
|
||||
|
||||
@Autowired
|
||||
private Misc mistUtility;
|
||||
|
||||
@Autowired
|
||||
private UserServices userService;
|
||||
|
||||
@Value("${files.docservice.url.site}")
|
||||
private String docserviceSite;
|
||||
@Autowired
|
||||
private DocumentManager documentManager;
|
||||
|
||||
@Value("${files.docservice.url.preloader}")
|
||||
private String docservicePreloader;
|
||||
@Autowired
|
||||
private UrlManager urlManager;
|
||||
|
||||
@Value("${url.converter}")
|
||||
private String urlConverter;
|
||||
@ -79,9 +78,11 @@ public class IndexController {
|
||||
@Value("${server.version}")
|
||||
private String serverVersion;
|
||||
|
||||
@Value("${enable-forgotten}")
|
||||
private String enableForgotten;
|
||||
|
||||
@GetMapping("${url.index}")
|
||||
public String index(@RequestParam(value = "directUrl", required = false) final Boolean directUrl,
|
||||
final Model model) {
|
||||
public String index(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<>();
|
||||
@ -105,15 +106,14 @@ public class IndexController {
|
||||
|
||||
for (java.io.File file:files) { // run through all the files
|
||||
String fileName = file.getName(); // get file name
|
||||
docTypes.add(fileUtility
|
||||
docTypes.add(documentManager
|
||||
.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
|
||||
filesEditable.add(documentManager.isEditable(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)));
|
||||
isFillFormDoc.add(documentManager.isFillable(fileName));
|
||||
}
|
||||
|
||||
// add all the parameters to the model
|
||||
@ -122,12 +122,12 @@ public class IndexController {
|
||||
model.addAttribute("files", files);
|
||||
model.addAttribute("docTypes", docTypes);
|
||||
model.addAttribute("filesEditable", filesEditable);
|
||||
model.addAttribute("datadocs", docserviceSite + docservicePreloader);
|
||||
model.addAttribute("datadocs", urlManager.getDocumentServerPreloaderApiUrl());
|
||||
model.addAttribute("tooltip", tooltip);
|
||||
model.addAttribute("users", users);
|
||||
model.addAttribute("languages", languages);
|
||||
model.addAttribute("directUrl", directUrl);
|
||||
model.addAttribute("serverVersion", serverVersion);
|
||||
model.addAttribute("enableForgotten", Boolean.valueOf(enableForgotten));
|
||||
|
||||
return "index.html";
|
||||
}
|
||||
@ -136,16 +136,16 @@ public class IndexController {
|
||||
@ResponseBody
|
||||
public HashMap<String, String> configParameters() { // get configuration parameters
|
||||
HashMap<String, String> configuration = new HashMap<>();
|
||||
|
||||
configuration.put("FillExtList", String.join(",", fileUtility
|
||||
.getFillExts())); // put a list of the extensions that can be filled to config
|
||||
configuration.put("ConverExtList", String.join(",", fileUtility
|
||||
.getConvertExts())); // put a list of the extensions that can be converted to config
|
||||
configuration.put("EditedExtList", String.join(",", fileUtility
|
||||
.getEditedExts())); // put a list of the extensions that can be edited to config
|
||||
configuration.put("UrlConverter", urlConverter);
|
||||
configuration.put("UrlEditor", urlEditor);
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@GetMapping("/formats")
|
||||
@ResponseBody
|
||||
public ResponseEntity<FormatsList> formats() { // return all the supported formats
|
||||
FormatsList list = new FormatsList(documentManager.getFormats());
|
||||
return ResponseEntity.ok(list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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
|
||||
}
|
||||
}
|
||||
@ -18,11 +18,10 @@
|
||||
|
||||
package com.onlyoffice.integration.documentserver.managers.callback;
|
||||
|
||||
import com.onlyoffice.integration.dto.Track;
|
||||
import java.util.HashMap;
|
||||
import com.onlyoffice.model.documenteditor.Callback;
|
||||
|
||||
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
|
||||
void processEditing(Callback callback, String fileName);
|
||||
void processSave(Callback callback, String fileName);
|
||||
void processForceSave(Callback callback, String fileName);
|
||||
}
|
||||
|
||||
@ -19,62 +19,60 @@
|
||||
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.managers.history.HistoryManager;
|
||||
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 com.onlyoffice.integration.sdk.manager.DocumentManager;
|
||||
import com.onlyoffice.integration.sdk.manager.UrlManager;
|
||||
import com.onlyoffice.manager.request.RequestManager;
|
||||
import com.onlyoffice.model.commandservice.CommandRequest;
|
||||
import com.onlyoffice.model.commandservice.commandrequest.Command;
|
||||
import com.onlyoffice.model.convertservice.ConvertRequest;
|
||||
import com.onlyoffice.model.convertservice.ConvertResponse;
|
||||
import com.onlyoffice.model.documenteditor.Callback;
|
||||
import com.onlyoffice.model.documenteditor.callback.Action;
|
||||
import com.onlyoffice.model.documenteditor.callback.ForcesaveType;
|
||||
import com.onlyoffice.model.documenteditor.callback.action.Type;
|
||||
import com.onlyoffice.service.command.CommandService;
|
||||
import com.onlyoffice.service.convert.ConvertService;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.http.HttpEntity;
|
||||
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.IOException;
|
||||
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;
|
||||
private ConvertService convertService;
|
||||
@Autowired
|
||||
private RequestManager requestManager;
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
@Autowired
|
||||
private HistoryManager historyManager;
|
||||
|
||||
@Autowired
|
||||
private UrlManager urlManager;
|
||||
|
||||
// download file from url
|
||||
@SneakyThrows
|
||||
@ -83,23 +81,18 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
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
|
||||
return requestManager.executeGetRequest(url, new RequestManager.Callback<byte[]>() {
|
||||
public byte[] doWork(final Object response) throws IOException {
|
||||
InputStream stream = ((HttpEntity) response).getContent(); // get input stream of the converted
|
||||
// file
|
||||
|
||||
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) {
|
||||
throw new RuntimeException("Input stream is null");
|
||||
}
|
||||
|
||||
if (stream == null) {
|
||||
connection.disconnect();
|
||||
throw new RuntimeException("Input stream is null");
|
||||
}
|
||||
|
||||
return stream.readAllBytes();
|
||||
return stream.readAllBytes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// file saving
|
||||
@ -112,40 +105,76 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
storageMutator.createOrUpdateFile(path, new ByteArrayInputStream(byteArray));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processEditing(final Callback callback, final String fileName) {
|
||||
Action action = callback.getActions().get(0); // get the user ID who is editing the document
|
||||
if (action.getType().equals(Type.CONNECTED)) { // if this value is not equal to the user ID
|
||||
String user = action.getUserid(); // get user ID
|
||||
if (!callback.getUsers().contains(user)) { // if this user is not specified in the body
|
||||
CommandRequest commandRequest = CommandRequest.builder()
|
||||
.c(Command.FORCESAVE)
|
||||
.key(callback.getKey())
|
||||
.build();
|
||||
|
||||
// create a command request to forcibly save the document being edited without closing it
|
||||
try {
|
||||
commandService.processCommand(commandRequest, fileName);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
public void processSave(final Callback callback, final String fileName) { // file saving process
|
||||
String downloadUri = callback.getUrl();
|
||||
String changesUri = callback.getChangesurl();
|
||||
String key = callback.getKey();
|
||||
String newFileName = fileName;
|
||||
|
||||
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
|
||||
String downloadExt = body.getFiletype(); // get an extension of the downloaded file
|
||||
String curExt = documentManager.getExtension(fileName); // get current file extension
|
||||
String downloadExt = callback.getFiletype(); // get an extension of the downloaded file
|
||||
String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file
|
||||
|
||||
if (!Paths.get(storagePath).toFile().exists()) {
|
||||
throw new RuntimeException("{\"error\":1, \"message\":\"file does not exist\"}");
|
||||
}
|
||||
|
||||
downloadUri = urlManager.replaceToInnerDocumentServerUrl(downloadUri);
|
||||
changesUri = urlManager.replaceToInnerDocumentServerUrl(changesUri);
|
||||
|
||||
// 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()) {
|
||||
ConvertRequest convertRequest = ConvertRequest.builder()
|
||||
.key(documentManager.generateRevisionId(downloadUri))
|
||||
.url(downloadUri)
|
||||
.outputtype(curExt)
|
||||
.async(false)
|
||||
.build();
|
||||
|
||||
// convert a file and get URL to a new file
|
||||
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
|
||||
|
||||
String newFileUri = convertResponse.getFileUrl();
|
||||
|
||||
if (newFileUri == null || newFileUri.isEmpty()) {
|
||||
newFileName = documentManager
|
||||
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "."
|
||||
.getCorrectName(documentManager.getBaseName(fileName) + "."
|
||||
+ downloadExt); // get the correct file name if it already exists
|
||||
} else {
|
||||
downloadUri = newFileUri;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
newFileName = documentManager
|
||||
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "." + downloadExt);
|
||||
.getCorrectName(documentManager.getBaseName(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
|
||||
|
||||
@ -153,7 +182,7 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath)); // get the history directory
|
||||
storageMutator.createDirectory(histDir); // and create it
|
||||
|
||||
String versionDir = documentManager
|
||||
String versionDir = historyManager
|
||||
.versionDir(histDir.toAbsolutePath().toString(), // get the file version directory
|
||||
storagePathBuilder
|
||||
.getFileVersion(histDir.toAbsolutePath().toString(), false), true);
|
||||
@ -172,13 +201,13 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
.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()
|
||||
jsonChanges.put("changes", callback.getHistory().getChanges()); // put the changes to the json object
|
||||
jsonChanges.put("serverVersion", callback.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 && callback.getHistory() != null) {
|
||||
history = objectMapper.writeValueAsString(callback.getHistory());
|
||||
}
|
||||
|
||||
if (history != null && !history.isEmpty()) {
|
||||
@ -194,82 +223,16 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
public void processForceSave(final Callback callback, final String fileNameParam) { // file force saving process
|
||||
|
||||
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 downloadUri = callback.getUrl();
|
||||
String fileName = fileNameParam;
|
||||
|
||||
String curExt = fileUtility.getFileExtension(fileName); // get current file extension
|
||||
String downloadExt = body.getFiletype(); // get an extension of the downloaded file
|
||||
String curExt = documentManager.getExtension(fileName); // get current file extension
|
||||
String downloadExt = callback.getFiletype(); // get an extension of the downloaded file
|
||||
|
||||
downloadUri = urlManager.replaceToInnerDocumentServerUrl(downloadUri);
|
||||
|
||||
Boolean newFileName = false;
|
||||
|
||||
@ -277,11 +240,19 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
// 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()) {
|
||||
ConvertRequest convertRequest = ConvertRequest.builder()
|
||||
.key(documentManager.generateRevisionId(downloadUri))
|
||||
.url(downloadUri)
|
||||
.outputtype(curExt)
|
||||
.async(false)
|
||||
.build();
|
||||
|
||||
// convert a file and get URL to a new file
|
||||
ConvertResponse convertResponse = convertService.processConvert(convertRequest, fileName);
|
||||
|
||||
String newFileUri = convertResponse.getFileUrl();
|
||||
|
||||
if (newFileUri == null || newFileUri.isEmpty()) {
|
||||
newFileName = true;
|
||||
} else {
|
||||
downloadUri = newFileUri;
|
||||
@ -296,32 +267,34 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
|
||||
// todo: Use ENUMS
|
||||
// todo: Pointless toString conversion
|
||||
boolean isSubmitForm = body.getForcesavetype().toString().equals("3");
|
||||
boolean isSubmitForm = callback.getForcesavetype().equals(ForcesaveType.SUBMIT_FORM);
|
||||
|
||||
// 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);
|
||||
.getCorrectName(documentManager
|
||||
.getBaseName(fileName) + "-form." + downloadExt);
|
||||
} else {
|
||||
fileName = documentManager
|
||||
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form." + curExt);
|
||||
.getCorrectName(documentManager.getBaseName(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);
|
||||
List<com.onlyoffice.model.documenteditor.callback.Action> actions = callback.getActions();
|
||||
com.onlyoffice.model.documenteditor.callback.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");
|
||||
|
||||
try {
|
||||
String formsDataUrl = body.getFormsdataurl();
|
||||
String formsDataUrl = callback.getFormsdataurl();
|
||||
|
||||
formsDataUrl = urlManager.replaceToInnerDocumentServerUrl(formsDataUrl);
|
||||
|
||||
if (formsDataUrl != null && !formsDataUrl.isEmpty()) {
|
||||
String formsName = documentManager.getCorrectName(fileUtility
|
||||
.getFileNameWithoutExtension(fileName) + ".txt");
|
||||
String formsName = documentManager.getCorrectName(documentManager
|
||||
.getBaseName(fileName) + ".txt");
|
||||
String formsPath = storagePathBuilder.getFileLocation(formsName);
|
||||
|
||||
byte[] byteArrayFormsData = getDownloadFile(formsDataUrl);
|
||||
@ -336,7 +309,7 @@ public class DefaultCallbackManager implements CallbackManager {
|
||||
} else {
|
||||
if (newFileName) {
|
||||
fileName = documentManager
|
||||
.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt);
|
||||
.getCorrectName(documentManager.getBaseName(fileName) + "." + downloadExt);
|
||||
}
|
||||
|
||||
forcesavePath = storagePathBuilder.getForcesavePath(fileName, false);
|
||||
|
||||
@ -1,246 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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);
|
||||
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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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
|
||||
}
|
||||
@ -20,14 +20,17 @@ 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 com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
|
||||
import com.onlyoffice.integration.sdk.manager.DocumentManager;
|
||||
import com.onlyoffice.integration.sdk.manager.UrlManager;
|
||||
import com.onlyoffice.manager.security.JwtManager;
|
||||
import com.onlyoffice.manager.settings.SettingsManager;
|
||||
import com.onlyoffice.model.common.User;
|
||||
import com.onlyoffice.model.documenteditor.HistoryData;
|
||||
import com.onlyoffice.model.documenteditor.callback.History;
|
||||
import com.onlyoffice.model.documenteditor.history.Version;
|
||||
import com.onlyoffice.model.documenteditor.historydata.Previous;
|
||||
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;
|
||||
@ -35,6 +38,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -49,15 +53,9 @@ 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;
|
||||
|
||||
@ -65,109 +63,13 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private ServiceConverter serviceConverter;
|
||||
private SettingsManager settingsManager;
|
||||
|
||||
// todo: Refactoring
|
||||
@SneakyThrows
|
||||
public String[] getHistory(final Document document) { // get document history
|
||||
@Autowired
|
||||
private UrlManager urlManager;
|
||||
|
||||
// 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()));
|
||||
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[]{"", ""};
|
||||
}
|
||||
@Autowired
|
||||
private DocumentManager documentManager;
|
||||
|
||||
// todo: Refactoring
|
||||
@SneakyThrows
|
||||
@ -178,16 +80,14 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
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<>();
|
||||
List<Version> history = new ArrayList<>();
|
||||
|
||||
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
|
||||
Map<String, Object> obj = new HashMap<String, Object>();
|
||||
String verDir = documentManager
|
||||
.versionDir(histDir, i, true); // get the path to the given file version
|
||||
String verDir = versionDir(histDir, i, true); // get the path to the given file version
|
||||
|
||||
String key;
|
||||
if (i == curVer) {
|
||||
key = serviceConverter
|
||||
key = documentManager
|
||||
.generateRevisionId(storagePathBuilder.getStorageLocation()
|
||||
+ "/" + fileName + "/"
|
||||
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
|
||||
@ -195,8 +95,10 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
|
||||
}
|
||||
|
||||
obj.put("key", key);
|
||||
obj.put("version", i);
|
||||
Version version = Version.builder()
|
||||
.key(key)
|
||||
.version(String.valueOf(i))
|
||||
.build();
|
||||
|
||||
if (i == 1) { // check if the version number is equal to 1
|
||||
String createdInfo = readFileToEnd(new File(histDir
|
||||
@ -204,33 +106,35 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
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);
|
||||
version.setCreated(String.valueOf(json.get("created")));
|
||||
version.setUser(User.builder()
|
||||
.id(String.valueOf(json.get("id")))
|
||||
.name(String.valueOf(json.get("name")))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
InputStream changesSteam = new FileInputStream(
|
||||
versionDir(histDir, i - 1, true) + File.separator + "changes.json");
|
||||
|
||||
History changes = objectMapper.readValue(changesSteam, History.class);
|
||||
|
||||
// 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"));
|
||||
version.setChanges(changes.getChanges());
|
||||
version.setServerVersion(changes.getServerVersion());
|
||||
version.setCreated(changes.getChanges().get(0).getCreated());
|
||||
version.setUser(changes.getChanges().get(0).getUser());
|
||||
}
|
||||
|
||||
hist.add(obj);
|
||||
history.add(version);
|
||||
}
|
||||
|
||||
// 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);
|
||||
histObj.put("history", history);
|
||||
|
||||
try {
|
||||
return objectMapper.writeValueAsString(histObj);
|
||||
@ -243,74 +147,65 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
|
||||
// todo: Refactoring
|
||||
@SneakyThrows
|
||||
public String getHistoryData(final String fileName, final String version, final Boolean directUrl) {
|
||||
public String getHistoryData(final String fileName, final String version) {
|
||||
// get history directory
|
||||
String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(fileName));
|
||||
Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version
|
||||
|
||||
if (curVer > 0) { // check if the current file version is greater than 0
|
||||
Map<String, Object> histData = new HashMap<>();
|
||||
Map<String, HistoryData> historyDataMap = new HashMap<>();
|
||||
|
||||
for (Integer i = 1; i <= curVer; i++) { // run through all the file versions
|
||||
Map<String, Object> dataObj = new HashMap<String, Object>();
|
||||
String verDir = documentManager
|
||||
.versionDir(histDir, i, true); // get the path to the given file version
|
||||
String verDir = versionDir(histDir, i, true); // get the path to the given file version
|
||||
|
||||
String key;
|
||||
if (i == curVer) {
|
||||
key = serviceConverter
|
||||
key = documentManager
|
||||
.generateRevisionId(storagePathBuilder.getStorageLocation()
|
||||
+ "/" + fileName + "/"
|
||||
+ new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
|
||||
} else {
|
||||
key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
|
||||
}
|
||||
HistoryData historyData = HistoryData.builder()
|
||||
.fileType(documentManager.getExtension(fileName))
|
||||
.key(key)
|
||||
.url(i == curVer ? urlManager.getFileUrl(fileName)
|
||||
: urlManager.getHistoryFileUrl(fileName, i, "prev" + documentManager
|
||||
.getExtension(fileName), true))
|
||||
.build();
|
||||
|
||||
dataObj.put("fileType", fileUtility
|
||||
.getFileExtension(fileName).replace(".", ""));
|
||||
dataObj.put("key", key);
|
||||
dataObj.put("url", i == curVer ? documentManager.getDownloadUrl(fileName, true)
|
||||
: documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
|
||||
.getFileExtension(fileName), true));
|
||||
if (directUrl) {
|
||||
dataObj.put("directUrl", i == curVer
|
||||
? documentManager.getDownloadUrl(fileName, false)
|
||||
: documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
|
||||
.getFileExtension(fileName), false));
|
||||
}
|
||||
dataObj.put("version", i);
|
||||
historyData.setVersion(String.valueOf(i));
|
||||
|
||||
if (i > 1) { //check if the version number is greater than 1
|
||||
Integer verdiff = i - 1;
|
||||
// get the history data from the previous file version
|
||||
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(verdiff));
|
||||
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 (directUrl) {
|
||||
prevInfo.put("directUrl", prev.get("directUrl"));
|
||||
}
|
||||
HistoryData historyDataPrev = historyDataMap.get(Integer.toString(verdiff));
|
||||
Previous previous = Previous.builder()
|
||||
.fileType(historyDataPrev.getFileType())
|
||||
.key(historyDataPrev.getKey())
|
||||
.url(historyDataPrev.getUrl())
|
||||
.build();
|
||||
|
||||
// write information about previous file version to the data object
|
||||
dataObj.put("previous", prevInfo);
|
||||
historyData.setPrevious(previous);
|
||||
|
||||
if (diffExists(histDir, verdiff)) {
|
||||
// write the path to the diff.zip archive with differences in this file version
|
||||
dataObj.put("changesUrl", documentManager
|
||||
historyData.setChangesUrl(urlManager
|
||||
.getHistoryFileUrl(fileName, verdiff, "diff.zip", true));
|
||||
}
|
||||
}
|
||||
|
||||
if (jwtManager.tokenEnabled()) {
|
||||
dataObj.put("token", jwtManager.createToken(dataObj));
|
||||
if (settingsManager.isSecurityEnabled()) {
|
||||
historyData.setToken(jwtManager.createToken(historyData));
|
||||
}
|
||||
|
||||
histData.put(Integer.toString(i), dataObj);
|
||||
historyDataMap.put(Integer.toString(i), historyData);
|
||||
}
|
||||
|
||||
try {
|
||||
return objectMapper.writeValueAsString(histData.get(version));
|
||||
return objectMapper.writeValueAsString(historyDataMap.get(version));
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -318,6 +213,14 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// read a file
|
||||
private String readFileToEnd(final File file) {
|
||||
|
||||
@ -21,6 +21,6 @@ package com.onlyoffice.integration.documentserver.managers.history;
|
||||
// specify the history manager functions
|
||||
public interface HistoryManager {
|
||||
String getHistory(String fileName); // get document history
|
||||
|
||||
String getHistoryData(String fileName, String version, Boolean directUrl); // get document history data
|
||||
String getHistoryData(String fileName, String version); // get document history data
|
||||
String versionDir(String path, Integer version, boolean historyPath);
|
||||
}
|
||||
|
||||
@ -1,130 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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
|
||||
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
|
||||
public boolean tokenEnabled() {
|
||||
return tokenSecret != null && !tokenSecret.isEmpty();
|
||||
}
|
||||
|
||||
public boolean tokenUseForRequest() {
|
||||
return Boolean.parseBoolean(tokenUseForRequest) && !tokenUseForRequest.isEmpty();
|
||||
}
|
||||
|
||||
// read document token
|
||||
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
|
||||
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.isBlank()) { // 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.isBlank()) {
|
||||
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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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,36 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package com.onlyoffice.integration.documentserver.models;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Format {
|
||||
private String name;
|
||||
private DocumentType type;
|
||||
private List<String> actions;
|
||||
private List<String> convert;
|
||||
private List<String> mime;
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 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 = true; // 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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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,48 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.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,24 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2024
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.onlyoffice.integration.documentserver.models.enums;
|
||||
|
||||
public enum Mode {
|
||||
edit,
|
||||
view
|
||||
}
|
||||