Compare commits

..

28 Commits

Author SHA1 Message Date
c9baa474be python-raw: add sr-only 2023-08-11 18:42:23 +04:00
48185674d4 python-raw: up html 2023-08-11 18:42:12 +04:00
dbca11e85c python-raw: move js 2023-08-11 18:41:45 +04:00
d21a732859 python-raw: move css 2023-08-11 18:40:57 +04:00
b96a6fac53 python-raw: add js 2023-08-08 14:43:34 +04:00
b01af348a7 python-raw: add html 2023-08-08 14:43:17 +04:00
c2443d3106 python-raw: add styles 2023-08-08 14:42:56 +04:00
5fa3f4c57f python-raw: add formats endpoint 2023-08-08 14:41:58 +04:00
efd7e1b6e7 python-raw: add format methods 2023-08-08 14:41:20 +04:00
259ee63eea python-raw: temp hide server 2023-08-08 14:41:00 +04:00
453b9835b7 python-raw: fix formats 2023-08-08 14:40:27 +04:00
89e6544b79 Merge branch 'feature/python-matrix-formats' into feature/python-conversion 2023-08-04 12:31:53 +04:00
32a60c09aa python: add public and private document-server urls to the compose 2023-08-02 10:49:34 +04:00
5a03024cd3 python: add support for the internal network for the track endpoint 2023-08-02 10:49:34 +04:00
cb6416c481 python: sort imports 2023-08-02 10:49:34 +04:00
55e4247687 python: add tests for proxy manager 2023-08-02 10:49:34 +04:00
a0620905b2 python: add proxy manager to resolve the document-server url 2023-08-02 10:49:34 +04:00
3fcef4096a python: remove the strict CORS hint 2023-08-02 10:49:34 +04:00
4e5349c1c4 python: add tests for specifying public and private document-server urls 2023-08-02 10:49:34 +04:00
538eec1ff3 python: add support for specifying public and private document-server urls 2023-08-02 10:49:34 +04:00
c06f2a5a29 python: replace the previous implementation of formats 2023-07-28 18:01:05 +04:00
8aed04753c python: add tests for the format module 2023-07-28 18:01:01 +04:00
15ed02e556 python: add format module 2023-07-28 12:06:30 +04:00
fb66dc8423 python: add tests for the codable module 2023-07-28 12:06:30 +04:00
541ace8132 python: add codable module 2023-07-28 12:06:30 +04:00
8b5cebeb3f python: add document-formats submodule 2023-07-28 12:06:30 +04:00
419fbf90f9 python: update paths to the new location of templates 2023-07-27 17:10:50 +04:00
2d637b88df python: move document-templates to the assets directory 2023-07-27 17:10:50 +04:00
115 changed files with 2498 additions and 299 deletions

12
.gitmodules vendored
View File

@ -2,10 +2,6 @@
path = web/documentserver-example/java/src/main/resources/assets
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
[submodule "web/documentserver-example/python/assets"]
path = web/documentserver-example/python/assets
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
[submodule "web/documentserver-example/csharp-mvc/assets"]
path = web/documentserver-example/csharp-mvc/assets
url = https://github.com/ONLYOFFICE/document-templates
@ -38,3 +34,11 @@
path = web/documentserver-example/php/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = master
[submodule "web/documentserver-example/python/assets/document-templates"]
path = web/documentserver-example/python/assets/document-templates
url = https://github.com/ONLYOFFICE/document-templates
branch = main/en
[submodule "web/documentserver-example/python/assets/document-formats"]
path = web/documentserver-example/python/assets/document-formats
url = https://github.com/ONLYOFFICE/document-formats
branch = master

View File

@ -1,6 +1,5 @@
# Change Log
- nodejs: key in referenceData
- nodejs: change reference source
- php: using a repo with a list of formats
- nodejs: using a repo with a list of formats

View File

@ -521,7 +521,6 @@ app.post('/reference', (req, res) => { // define a handler for renaming file
const data = {
fileType: fileUtility.getFileExtension(fileName).slice(1),
key: req.DocManager.getKey(fileName),
url: req.DocManager.getDownloadUrl(fileName, true),
directUrl: req.body.directUrl ? req.DocManager.getDownloadUrl(fileName) : null,
referenceData: {
@ -712,7 +711,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
const downloadExt = `.${body.fileType}`;
const isSubmitForm = body.forcesavetype === 3; // SubmitForm
let correctName = fileName;
let correctName = '';
let forcesavePath = '';
if (isSubmitForm) {

View File

@ -69,4 +69,12 @@ test: # Run tests recursively.
--display-errors \
--display-notices \
--display-warnings \
src
common
@./vendor/bin/phpunit \
--test-suffix "Tests.php" \
--display-incomplete \
--display-deprecations \
--display-errors \
--display-notices \
--display-warnings \
configuration

View File

@ -15,14 +15,14 @@
* limitations under the License.
*/
namespace Example;
namespace OnlineEditorsExamplePhp;
use Exception;
use Example\Common\Path;
use Example\Configuration\ConfigurationManager;
use Example\Helpers\ConfigManager;
use Example\Helpers\ExampleUsers;
use Example\Helpers\JwtManager;
use OnlineEditorsExamplePhp\Common\Path;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Helpers\ConfigManager;
use OnlineEditorsExamplePhp\Helpers\ExampleUsers;
use OnlineEditorsExamplePhp\Helpers\JwtManager;
/**
* Check if the request is an AJAX request
@ -340,7 +340,7 @@ function files()
function assets()
{
$fileName = basename($_GET["name"]);
$filePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' .
$filePath = dirname(__FILE__) .
DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . "document-templates"
. DIRECTORY_SEPARATOR . "sample" . DIRECTORY_SEPARATOR . $fileName;
downloadFile($filePath);
@ -354,7 +354,7 @@ function assets()
function csv()
{
$fileName = "csv.csv";
$filePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' .
$filePath = dirname(__FILE__) .
DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR . "document-templates"
. DIRECTORY_SEPARATOR . "sample" . DIRECTORY_SEPARATOR . $fileName;
downloadFile($filePath);

View File

@ -15,7 +15,7 @@
// limitations under the License.
//
namespace Example\Common;
namespace OnlineEditorsExamplePhp\Common;
enum HTTPStatus: int {
case not_found = 404;

View File

@ -15,7 +15,7 @@
// limitations under the License.
//
namespace Example\Common;
namespace OnlineEditorsExamplePhp\Common;
final class Path {
private string $separator = DIRECTORY_SEPARATOR;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\Path;
use OnlineEditorsExamplePhp\Common\Path;
final class PathAbsolutePOSIXTests extends TestCase {
public function test_recognizes_an_empty_as_a_non_absolute() {

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\Path;
use OnlineEditorsExamplePhp\Common\Path;
final class PathJoinPOSIXTests extends TestCase {
public function test_joins_a_relative_to_an_empty_one() {

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\Path;
use OnlineEditorsExamplePhp\Common\Path;
final class PathNormalizePOSIXTests extends TestCase {
public function test_normalizes() {

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\Path;
use OnlineEditorsExamplePhp\Common\Path;
final class PathStringPOSIXTests extends TestCase {
public function test_generates_with_an_empty() {

View File

@ -15,7 +15,7 @@
// limitations under the License.
//
namespace Example\Common;
namespace OnlineEditorsExamplePhp\Common;
final class URL {
private string $string;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\URL;
use OnlineEditorsExamplePhp\Common\URL;
final class URLFromComponentsTests extends TestCase {
public function test_creates() {

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\URL;
use OnlineEditorsExamplePhp\Common\URL;
final class URLJoinPathTests extends TestCase {
public function test_joins_a_relative_to_an_empty_one() {

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Common\URL;
use OnlineEditorsExamplePhp\Common\URL;
final class URLStringTests extends TestCase {
public function test_generates() {

View File

@ -9,10 +9,11 @@
},
"autoload": {
"psr-4": {
"Example\\Common\\": "src/common/",
"Example\\Configuration\\" : "src/configuration/",
"Example\\Helpers\\" : "src/helpers/",
"Example\\Views\\" : "src/views/"
"OnlineEditorsExamplePhp\\" : "",
"OnlineEditorsExamplePhp\\Common\\": "common/",
"OnlineEditorsExamplePhp\\Configuration\\" : "configuration/",
"OnlineEditorsExamplePhp\\Helpers\\" : "helpers/",
"OnlineEditorsExamplePhp\\Views\\" : "views/"
}
}
}

View File

@ -15,10 +15,10 @@
// limitations under the License.
//
namespace Example\Configuration;
namespace OnlineEditorsExamplePhp\Configuration;
use Example\Common\Path;
use Example\Common\URL;
use OnlineEditorsExamplePhp\Common\Path;
use OnlineEditorsExamplePhp\Common\URL;
final class ConfigurationManager {
public string $version = '1.6.0';
@ -98,7 +98,6 @@ final class ConfigurationManager {
$storage_string_directory = $storage_directory->string();
$current_directory = new Path(__DIR__);
$directory = $current_directory
->join_path('..')
->join_path('..')
->join_path($storage_string_directory);
return $directory->normalize();

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerConversionTimeoutTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerDocumentServerAPIURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerDocumentServerCommandURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerDocumentServerConverterURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerDocumentServerPreloaderURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerDocumentServerURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerExampleURLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerJWTHeaderTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerJWTSecretTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerJWTUseForRequest extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerMaximumFileSizeTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerSSLTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerSingleUserTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerStoragePathTests extends TestCase {
public array $env;

View File

@ -16,7 +16,7 @@
//
use PHPUnit\Framework\TestCase;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class ConfigurationManagerTests extends TestCase {
public function test_corresponds_the_latest_version() {

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 781 B

After

Width:  |  Height:  |  Size: 781 B

View File

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 547 B

View File

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 425 B

View File

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 331 B

View File

Before

Width:  |  Height:  |  Size: 507 B

After

Width:  |  Height:  |  Size: 507 B

View File

Before

Width:  |  Height:  |  Size: 757 B

After

Width:  |  Height:  |  Size: 757 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 593 B

View File

Before

Width:  |  Height:  |  Size: 738 B

After

Width:  |  Height:  |  Size: 738 B

View File

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

View File

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 691 B

View File

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 992 B

View File

Before

Width:  |  Height:  |  Size: 1004 B

After

Width:  |  Height:  |  Size: 1004 B

View File

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

View File

Before

Width:  |  Height:  |  Size: 233 B

After

Width:  |  Height:  |  Size: 233 B

View File

Before

Width:  |  Height:  |  Size: 832 B

After

Width:  |  Height:  |  Size: 832 B

View File

Before

Width:  |  Height:  |  Size: 631 B

After

Width:  |  Height:  |  Size: 631 B

View File

Before

Width:  |  Height:  |  Size: 832 B

After

Width:  |  Height:  |  Size: 832 B

View File

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 488 B

View File

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 790 B

View File

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 506 B

View File

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

View File

Before

Width:  |  Height:  |  Size: 438 B

After

Width:  |  Height:  |  Size: 438 B

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -151,19 +151,19 @@ label .checkbox {
}
.try-editor.word {
background-image: url("/assets/images/file_docx.svg");
background-image: url("images/file_docx.svg");
}
.try-editor.cell {
background-image: url("/assets/images/file_xlsx.svg");
background-image: url("images/file_xlsx.svg");
}
.try-editor.slide {
background-image: url("/assets/images/file_pptx.svg");
background-image: url("images/file_pptx.svg");
}
.try-editor.form {
background-image: url("/assets/images/file_docxf.svg");
background-image: url("images/file_docxf.svg");
}
.side-option {
@ -235,7 +235,7 @@ label .checkbox {
}
.file-upload {
background: url("/assets/images/file_upload.svg") no-repeat 0 transparent;
background: url("images/file_upload.svg") no-repeat 0 transparent;
cursor: pointer;
display: block;
font-size: 14px;
@ -308,7 +308,7 @@ label .checkbox {
}
.error-message {
background: url("/assets/images/error.svg") no-repeat scroll 4px 10px;
background: url("images/error.svg") no-repeat scroll 4px 10px;
color: #CB0000;
display: none;
line-height: 160%;
@ -329,15 +329,15 @@ label .checkbox {
}
.current {
background-image: url("/assets/images/loader16.gif");
background-image: url("images/loader16.gif");
}
.done {
background-image: url("/assets/images/done.svg");
background-image: url("images/done.svg");
}
.error {
background-image: url("/assets/images/notdone.svg");
background-image: url("images/notdone.svg");
}
.step-descr {
@ -451,17 +451,17 @@ footer table tr td:first-child {
.stored-edit.word,
.uploadFileName.word {
background-image: url("/assets/images/icon_docx.svg");
background-image: url("images/icon_docx.svg");
}
.stored-edit.cell,
.uploadFileName.cell {
background-image: url("/assets/images/icon_xlsx.svg");
background-image: url("images/icon_xlsx.svg");
}
.stored-edit.slide,
.uploadFileName.slide {
background-image: url("/assets/images/icon_pptx.svg");
background-image: url("images/icon_pptx.svg");
}
.stored-edit span {
@ -490,7 +490,7 @@ footer table tr td:first-child {
}
.dialog-close {
background: url("/assets/images/close.svg") no-repeat scroll left top;
background: url("images/close.svg") no-repeat scroll left top;
cursor: pointer;
float: right;
font-size: 1px;
@ -766,4 +766,4 @@ html {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
}

View File

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -15,14 +15,14 @@
* limitations under the License.
*/
namespace Example;
namespace OnlineEditorsExamplePhp;
use Exception;
use Example\Configuration\ConfigurationManager;
use Example\Helpers\ConfigManager;
use Example\Helpers\ExampleUsers;
use Example\Helpers\JwtManager;
use Example\Helpers\Users;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Helpers\ConfigManager;
use OnlineEditorsExamplePhp\Helpers\ExampleUsers;
use OnlineEditorsExamplePhp\Helpers\JwtManager;
use OnlineEditorsExamplePhp\Helpers\Users;
/**
* Put log files into the log folder
@ -159,7 +159,7 @@ function getInternalExtension($filename)
function getTemplateImageUrl($filename)
{
$ext = mb_strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$path = serverPath(true) . "/assets/images/";
$path = serverPath(true) . "/css/images/";
$configManager = new ConfigManager();
foreach ($configManager->getSuppotredFormats() as $format) {
@ -827,7 +827,6 @@ function tryGetDefaultByType($createExt, $user)
$sample = isset($_GET["sample"]) && $_GET["sample"];
$demoName = ($sample ? "sample." : "new.") . $createExt;
$demoPath =
'..' . DIRECTORY_SEPARATOR .
"assets" . DIRECTORY_SEPARATOR .
"document-templates" . DIRECTORY_SEPARATOR .
($sample ? "sample" : "new") . DIRECTORY_SEPARATOR;

View File

@ -1,6 +1,6 @@
<?php
namespace Example\Helpers;
namespace OnlineEditorsExamplePhp\Helpers;
/**
* (c) Copyright Ascensio System SIA 2023

View File

@ -1,8 +1,8 @@
<?php
namespace Example\Helpers;
namespace OnlineEditorsExamplePhp\Helpers;
use function Example\sendlog;
use function OnlineEditorsExamplePhp\sendlog;
/**
* (c) Copyright Ascensio System SIA 2023

View File

@ -1,6 +1,6 @@
<?php
namespace Example\Helpers;
namespace OnlineEditorsExamplePhp\Helpers;
/**
* (c) Copyright Ascensio System SIA 2023
@ -20,7 +20,7 @@ namespace Example\Helpers;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Example\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
final class JwtManager
{

View File

@ -1,6 +1,6 @@
<?php
namespace Example\Helpers;
namespace OnlineEditorsExamplePhp\Helpers;
/**
* (c) Copyright Ascensio System SIA 2023

View File

@ -15,18 +15,18 @@
* limitations under the License.
*/
namespace Example;
namespace OnlineEditorsExamplePhp;
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/src/ajax.php';
require_once __DIR__ . '/src/functions.php';
require_once __DIR__ . '/src/trackmanager.php';
require_once __DIR__ . '/ajax.php';
require_once __DIR__ . '/functions.php';
require_once __DIR__ . '/trackmanager.php';
use Example\Common\HTTPStatus;
use Example\Common\URL;
use Example\Configuration\ConfigurationManager;
use Example\Views\DocEditorView;
use Example\Views\IndexView;
use OnlineEditorsExamplePhp\Common\HTTPStatus;
use OnlineEditorsExamplePhp\Common\URL;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Views\DocEditorView;
use OnlineEditorsExamplePhp\Views\IndexView;
function configure() {
$config_manager = new ConfigurationManager();

View File

@ -6,7 +6,7 @@
maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="icon" href="assets/images/{docType}.ico" type="image/x-icon" />
<link rel="icon" href="css/images/{docType}.ico" type="image/x-icon" />
<title>ONLYOFFICE</title>
<style>

View File

@ -5,21 +5,21 @@
<meta name="viewport" content="width=device-width" />
<title>ONLYOFFICE Document Editors</title>
<link rel="icon" href="assets/images/favicon.ico" type="image/x-icon" />
<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="assets/css/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="assets/css/media.css">
<link rel="stylesheet" type="text/css" href="assets/css/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="css/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="css/media.css">
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css" />
</head>
<body>
<form id="form1">
<header>
<div class="center">
<a href="">
<img src ="assets/images/logo.svg" alt="ONLYOFFICE" />
<img src ="css/images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
</header>
@ -66,7 +66,7 @@
<tr>
<td valign="middle">
<span class="select-user">Username</span>
<img id="info" class="info" src="assets/images/info.svg" />
<img id="info" class="info" src="css/images/info.svg" />
<select class="select-user" id="user">
{userOpts}
</select>
@ -77,7 +77,7 @@
<span class="select-user">Language</span>
<img class="info info-tooltip" data-id="language"
data-tooltip="Choose the language for ONLYOFFICE editors interface"
src="assets/images/info.svg" />
src="css/images/info.svg" />
<select class="select-user" id="language">
{langs}
</select>
@ -92,7 +92,7 @@
data-id="directUrlInfo" data-tooltip=
"Some files can be opened in the user's
browser without connecting to the document server."
src="assets/images/info.svg" />
src="css/images/info.svg" />
</label>
</td>
</tr>
@ -203,14 +203,14 @@
</footer>
</form>
<script type="text/javascript" src="assets/js/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="assets/js/jquery-migrate-3.4.1.min.js"></script>
<script type="text/javascript" src="assets/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="assets/js/jquery.blockUI.js"></script>
<script type="text/javascript" src="assets/js/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="assets/js/jquery.fileupload.js"></script>
<script type="text/javascript" src="assets/js/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="assets/js/jscript.js"></script>
<script type="text/javascript" src="js/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="js/jquery-migrate-3.4.1.min.js"></script>
<script type="text/javascript" src="js/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/jquery.blockUI.js"></script>
<script type="text/javascript" src="js/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="js/jquery.fileupload.js"></script>
<script type="text/javascript" src="js/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="js/jscript.js"></script>
<script type="text/javascript">
var FillFormsExtList = '{fillFormsExtList}';
var ConverExtList = '{converExtList}';

View File

@ -15,12 +15,12 @@
* limitations under the License.
*/
namespace Example;
namespace OnlineEditorsExamplePhp;
use Exception;
use Example\Configuration\ConfigurationManager;
use Example\Helpers\ConfigManager;
use Example\Helpers\JwtManager;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Helpers\ConfigManager;
use OnlineEditorsExamplePhp\Helpers\JwtManager;
/**
* Read request body

View File

@ -15,25 +15,25 @@
* limitations under the License.
*/
namespace Example\Views;
namespace OnlineEditorsExamplePhp\Views;
use Example\Configuration\ConfigurationManager;
use Example\Helpers\ConfigManager;
use Example\Helpers\ExampleUsers;
use Example\Helpers\JwtManager;
use function Example\doUpload;
use function Example\fileUri;
use function Example\getCallbackUrl;
use function Example\getCreateUrl;
use function Example\getDocEditorKey;
use function Example\getDocumentType;
use function Example\getDownloadUrl;
use function Example\getHistory;
use function Example\getStoragePath;
use function Example\getTemplateImageUrl;
use function Example\serverPath;
use function Example\tryGetDefaultByType;
use function Example\getCurUserHostAddress;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Helpers\ConfigManager;
use OnlineEditorsExamplePhp\Helpers\ExampleUsers;
use OnlineEditorsExamplePhp\Helpers\JwtManager;
use function OnlineEditorsExamplePhp\doUpload;
use function OnlineEditorsExamplePhp\fileUri;
use function OnlineEditorsExamplePhp\getCallbackUrl;
use function OnlineEditorsExamplePhp\getCreateUrl;
use function OnlineEditorsExamplePhp\getDocEditorKey;
use function OnlineEditorsExamplePhp\getDocumentType;
use function OnlineEditorsExamplePhp\getDownloadUrl;
use function OnlineEditorsExamplePhp\getHistory;
use function OnlineEditorsExamplePhp\getStoragePath;
use function OnlineEditorsExamplePhp\getTemplateImageUrl;
use function OnlineEditorsExamplePhp\serverPath;
use function OnlineEditorsExamplePhp\tryGetDefaultByType;
use function OnlineEditorsExamplePhp\getCurUserHostAddress;
final class DocEditorView extends View
{
@ -191,11 +191,11 @@ final class DocEditorView extends View
// an image for inserting
$dataInsertImage = $isEnableDirectUrl ? [
"fileType" => "png",
"url" => serverPath(true) . "/assets/images/logo.png",
"directUrl" => serverPath(false) . "/assets/images/logo.png",
"url" => serverPath(true) . "/css/images/logo.png",
"directUrl" => serverPath(false) . "/css/images/logo.png",
] : [
"fileType" => "png",
"url" => serverPath(true) . "/assets/images/logo.png",
"url" => serverPath(true) . "/css/images/logo.png",
];
// a document for comparing

View File

@ -15,12 +15,12 @@
* limitations under the License.
*/
namespace Example\Views;
namespace OnlineEditorsExamplePhp\Views;
use function Example\getStoredFiles;
use function Example\getFileVersion;
use function Example\getHistoryDir;
use function Example\getStoragePath;
use function OnlineEditorsExamplePhp\getStoredFiles;
use function OnlineEditorsExamplePhp\getFileVersion;
use function OnlineEditorsExamplePhp\getHistoryDir;
use function OnlineEditorsExamplePhp\getStoragePath;
class IndexStoredListView extends View
{
@ -58,35 +58,35 @@ class IndexStoredListView extends View
$layout .= ' <td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user=' . htmlentities($user).$directUrlArg.
'&action=edit&type=desktop" target="_blank">'.
'<img src="assets/images/desktop.svg" alt="Open in editor for full size screens"'.
'<img src="css/images/desktop.svg" alt="Open in editor for full size screens"'.
' title="Open in editor for full size screens"/></a></td>'.
' <td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user=' . htmlentities($user).$directUrlArg.
'&action=edit&type=mobile" target="_blank">'.
'<img src="assets/images/mobile.svg" alt="Open in editor for mobile devices"'.
'<img src="css/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="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=comment&type=desktop" target="_blank">'.
' <img src="assets/images/comment.svg" alt="Open in editor for comment"'.
' <img src="css/images/comment.svg" alt="Open in editor for comment"'.
' title="Open in editor for comment" /></a></td>';
if ($storeFile->documentType == "word") {
$layout .= '<td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=review&type=desktop" target="_blank">'.
' <img src="assets/images/review.svg" alt="Open in editor for review"'.
' <img src="css/images/review.svg" alt="Open in editor for review"'.
' title="Open in editor for review" /></a></td>'.
' <td class="contentCells contentCells-icon "> <a href="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=blockcontent&type=desktop" target="_blank">'.
' <img src="assets/images/block-content.svg"'.
' <img src="css/images/block-content.svg"'.
' alt="Open in editor without content control modification"'.
' title="Open in editor without content control modification"</a></td>';
} elseif ($storeFile->documentType == "cell") {
$layout .= '<td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=filter&type=desktop" target="_blank">'.
' <img src="assets/images/filter.svg" alt="Open in editor without access to change the filter"'.
' <img src="css/images/filter.svg" alt="Open in editor without access to change the filter"'.
' title="Open in editor without access to change the filter" /></a></td>';
} else {
$layout .= '<td class="contentCells contentCells-icon"></td>';
@ -98,7 +98,7 @@ class IndexStoredListView extends View
' <a href="editor?fileID='.urlencode($storeFile->name).
'&user='.htmlentities($user).$directUrlArg.
'&action=fillForms&type=desktop" target="_blank">'.
' <img src="assets/images/fill-forms.svg" alt="Open in editor for filling in forms"'.
' <img src="css/images/fill-forms.svg" alt="Open in editor for filling in forms"'.
' title="Open in editor for filling in forms" /></a></td>';
} else {
$layout .= '<td class="contentCells contentCells-shift contentCells-icon'.
@ -108,7 +108,7 @@ class IndexStoredListView extends View
$layout .= '<td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=fillForms&type=desktop" target="_blank">'.
' <img src="assets/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms'.
' <img src="css/images/mobile-fill-forms.svg" alt="Open in editor for filling in forms'.
'for mobile devices" title="Open in editor for filling in forms for mobile devices" /></a></td>'.
'<td class="contentCells contentCells-icon"></td>'.
'<td class="contentCells contentCells-icon"></td>'.
@ -116,7 +116,7 @@ class IndexStoredListView extends View
'<td class="contentCells contentCells-shift contentCells-icon firstContentCellShift">'.
'<a href="editor?fileID='.urlencode($storeFile->name).'&user='.htmlentities($user).
$directUrlArg.'&action=fillForms&type=desktop" target="_blank">'.
'<img src="assets/images/fill-forms.svg" alt="Open in editor for filling in forms"'.
'<img src="css/images/fill-forms.svg" alt="Open in editor for filling in forms"'.
' title="Open in editor for filling in forms"/></a></td>';
} else {
$layout .= '<td class="contentCells contentCells-shift contentCells-icon' .
@ -125,25 +125,25 @@ class IndexStoredListView extends View
$layout .= '<td class="contentCells contentCells-icon firstContentCellViewers">'.
' <a href="editor?fileID='.urlencode($storeFile->name).'&user='.htmlentities($user).
$directUrlArg.'&action=view&type=desktop" target="_blank">'.
' <img src="assets/images/desktop.svg" alt="Open in viewer for full size screens"'.
' <img src="css/images/desktop.svg" alt="Open in viewer for full size screens"'.
' title="Open in viewer for full size screens" /></a></td>'.
' <td class="contentCells contentCells-icon"> <a href="editor?fileID='.
urlencode($storeFile->name).'&user='.htmlentities($user).$directUrlArg.
'&action=view&type=mobile" target="_blank">'.
' <img src="assets/images/mobile.svg" alt="Open in viewer for mobile devices"'.
' <img src="css/images/mobile.svg" alt="Open in viewer for mobile devices"'.
' title="Open in viewer for mobile devices" /></a></td>'.
' <td class="contentCells contentCells-icon contentCells-shift">'.
' <a href="editor?fileID='.urlencode($storeFile->name).'&user='.htmlentities($user).
$directUrlArg.'&action=embedded&type=embedded" target="_blank">'.
' <img src="assets/images/embeded.svg" alt="Open in embedded mode"'.
' <img src="css/images/embeded.svg" alt="Open in embedded mode"'.
' title="Open in embedded mode" /></a>'.
' <td class="contentCells contentCells-icon contentCells-shift downloadContentCellShift">'.
'<a href="download?fileName='.urlencode($storeFile->name).'">'.
' <img class="icon-download" src="assets/images/download.svg" alt="Download" title="Download"'.
' <img class="icon-download" src="css/images/download.svg" alt="Download" title="Download"'.
' /></a></td>'.
'<td class="contentCells contentCells-icon contentCells-shift">'.
' <a class="delete-file" data="'.$storeFile->name.'">'.
' <img class="icon-delete" src="assets/images/delete.svg" alt="Delete" title="Delete" /></a>'.
' <img class="icon-delete" src="css/images/delete.svg" alt="Delete" title="Delete" /></a>'.
'</td></tr>';
}
}

View File

@ -15,12 +15,12 @@
* limitations under the License.
*/
namespace Example\Views;
namespace OnlineEditorsExamplePhp\Views;
use Example\Configuration\ConfigurationManager;
use Example\Helpers\ConfigManager;
use Example\Helpers\ExampleUsers;
use function Example\getStoredFiles;
use OnlineEditorsExamplePhp\Configuration\ConfigurationManager;
use OnlineEditorsExamplePhp\Helpers\ConfigManager;
use OnlineEditorsExamplePhp\Helpers\ExampleUsers;
use function OnlineEditorsExamplePhp\getStoredFiles;
final class IndexView extends View
{

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
namespace Example\Views;
namespace OnlineEditorsExamplePhp\Views;
class View
{

View File

@ -1,13 +1,13 @@
version: "3.8"
services:
document-server:
container_name: document-server
image: onlyoffice/documentserver:7.3.3.50
expose:
- "80"
environment:
- JWT_SECRET=your-256-bit-secret
# document-server:
# container_name: document-server
# image: onlyoffice/documentserver:7.3.3.50
# expose:
# - "80"
# environment:
# - JWT_SECRET=your-256-bit-secret
example:
container_name: example
@ -17,7 +17,8 @@ services:
- "80"
environment:
- ADDRESS=0.0.0.0
- DOCUMENT_SERVER_URL=http://localhost:8080
- DOCUMENT_SERVER_PRIVATE_URL=http://proxy:8080
- DOCUMENT_SERVER_PUBLIC_URL=http://localhost:8080
- EXAMPLE_URL=http://proxy
- JWT_SECRET=your-256-bit-secret
- PORT=80

View File

@ -67,6 +67,7 @@ def routers():
path('downloadhistory', actions.downloadhistory),
path('edit', actions.edit),
path('files', actions.files),
path('formats-convertible', actions.formats_convertible),
path('reference', actions.reference),
path('remove', actions.remove),
path('rename', actions.rename),

View File

@ -17,22 +17,22 @@ http {
}
}
server {
listen 8080;
server_name localhost;
# server {
# listen 8080;
# server_name localhost;
location / {
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_pass http://document-server;
proxy_redirect off;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Real-IP $remote_addr;
}
}
# location / {
# client_max_body_size 100m;
# proxy_http_version 1.1;
# proxy_pass http://document-server;
# proxy_redirect off;
# proxy_set_header Connection "upgrade";
# proxy_set_header Host $http_host;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
# proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
# proxy_set_header X-Real-IP $remote_addr;
# }
# }
}

View File

@ -0,0 +1,35 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
'''
The Codable module provides the ability to decode a string JSON into a class
instance and encode it back. It also provides the ability to remap JSON keys and
work with nested Codable instances.
```python
from dataclasses import dataclass
from src.codable import Codable, CodingKey
@dataclass
class Fruit(Codable):
class CodingKeys(CodingKey):
native_for_python: 'foreignForPython'
native_for_python: str
```
'''
from .codable import Codable, CodingKey

View File

@ -0,0 +1,189 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import annotations
from copy import deepcopy
from enum import StrEnum
from json import JSONDecoder, JSONEncoder
from typing import Any, Optional, Self, Type, get_args, get_origin, get_type_hints
class Monkey():
key: str
def __init__(self, key: str = '_slugs'):
self.key = key
def patch(self, obj: dict[str, Any]) -> dict[str, Any]:
def inner(slug: list[str], value: Any):
if isinstance(value, dict):
value[self.key] = slug
for child_slug, child_value in value.items():
inner(slug + [child_slug], child_value)
return
if isinstance(value, list):
for child_value in value:
inner(slug, child_value)
copied = deepcopy(obj)
inner([], copied)
return copied
def slugs(self, obj: dict[str, Any]) -> list[str]:
return obj[self.key]
def clean(self, obj: dict[str, Any]) -> dict[str, Any]:
copied = deepcopy(obj)
del copied[self.key]
return copied
class CodingKey(StrEnum):
@classmethod
def keywords(cls, obj: dict[str, Any]) -> dict[str, Any]:
words = {}
for pair in list(cls):
# Errors are false positives.
native = pair.name # type: ignore
foreign = pair.value # type: ignore
value = obj.get(foreign)
words[native] = value
return words
class Codable():
__decoder = JSONDecoder()
__encoder = JSONEncoder()
__monkey = Monkey()
class CodingKeys(CodingKey):
pass
@classmethod
def decode(cls, content: str) -> Self:
decoded = cls.__decoder.decode(content)
patched = cls.__monkey.patch(decoded)
encoded = cls.__encoder.encode(patched)
decoder = Decoder(
monkey=cls.__monkey,
cls=cls
)
return decoder.decode(encoded)
def encode(self) -> str:
cls = type(self)
encoder = Encoder(
decoder=self.__decoder,
cls=cls
)
return encoder.encode(self)
class Decoder(JSONDecoder):
monkey: Monkey
cls: Type[Codable]
def __init__(
self,
monkey: Monkey,
cls: Type[Codable],
**kwargs
):
self.monkey = monkey
self.cls = cls
kwargs['object_hook'] = self.__object_hook
super().__init__(**kwargs)
def __object_hook(self, obj):
cls = self.cls
for foreign in self.monkey.slugs(obj):
native = cls.CodingKeys(foreign).name
if native is None:
return self.monkey.clean(obj)
types = get_type_hints(cls)
cls = self.__find_codable(types[native])
if cls is None:
return self.monkey.clean(obj)
cleaned = self.monkey.clean(obj)
return self.__init_codable(cls, cleaned)
def __find_codable(self, cls: Type) -> Optional[Type[Codable]]:
if issubclass(cls, Codable):
return cls
if get_origin(cls) is list:
item = get_args(cls)[0]
return self.__find_codable(item)
return None
def __init_codable(self, cls: Type[Codable], obj: dict[str, Any]) -> Codable:
keywords = cls.CodingKeys.keywords(obj)
return cls(**keywords)
class Encoder(JSONEncoder):
decoder: JSONDecoder
cls: Type[Codable]
def __init__(
self,
decoder: JSONDecoder,
cls: Type[Codable],
indent: int = 2,
**kwargs
):
self.decoder = decoder
self.cls = cls
kwargs['indent'] = indent
super().__init__(**kwargs)
def default(self, o):
obj = {}
for pair in list(self.cls.CodingKeys):
native = pair.name
foreign = pair.value
if not hasattr(o, native):
continue
value = getattr(o, native)
obj[foreign] = self.__prepare_value(value)
return obj
def __prepare_value(self, value: Any) -> Any:
if isinstance(value, Codable):
return self.__prepare_codable(value)
if isinstance(value, list):
return self.__prepare_list(value)
return value
def __prepare_codable(self, value: Codable) -> Any:
content = value.encode()
return self.decoder.decode(content)
def __prepare_list(self, value: list[Any]) -> list[Any]:
mapped = map(self.__prepare_value, value)
return list(mapped)

View File

@ -0,0 +1,154 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import annotations
from dataclasses import dataclass
from textwrap import dedent
from typing import Optional
from unittest import TestCase
from . import Codable, CodingKey
@dataclass
class Fruit(Codable):
class CodingKeys(CodingKey):
name = 'fruit_name'
weight = 'fruitWeight'
texture = 'fruit_texture'
vitamins = 'fruitVitamins'
organic = 'fruit_organic'
name: str
weight: int
texture: Optional[str]
vitamins: list[str]
organic: bool
class CodablePlainTests(TestCase):
json = (
dedent(
'''
{
"fruit_name": "kiwi",
"fruitWeight": 100,
"fruit_texture": null,
"fruitVitamins": [
"Vitamin C",
"Vitamin K"
],
"fruit_organic": true
}
'''
)
.strip()
)
def test_decodes(self):
fruit = Fruit.decode(self.json)
self.assertEqual(fruit.name, 'kiwi')
self.assertEqual(fruit.weight, 100)
self.assertIsNone(fruit.texture)
self.assertEqual(fruit.vitamins, ['Vitamin C', 'Vitamin K'])
self.assertTrue(fruit.organic)
def test_encodes(self):
fruit = Fruit(
name='kiwi',
weight=100,
texture=None,
vitamins=['Vitamin C', 'Vitamin K'],
organic=True
)
content = fruit.encode()
self.assertEqual(content, self.json)
@dataclass
class Smoothie(Codable):
class CodingKeys(CodingKey):
recipe = 'recipe'
recipe: Recipe
@dataclass
class Recipe(Codable):
class CodingKeys(CodingKey):
ingredients = 'ingredients'
ingredients: list[Ingredient]
@dataclass
class Ingredient(Codable):
class CodingKeys(CodingKey):
name = 'name'
name: str
class CodableNestedTests(TestCase):
json = (
dedent(
'''
{
"recipe": {
"ingredients": [
{
"name": "kiwi"
}
]
}
}
'''
)
.strip()
)
def test_decodes(self):
smoothie = Smoothie.decode(self.json)
self.assertEqual(smoothie.recipe.ingredients[0].name, 'kiwi')
def test_encodes(self):
ingredient = Ingredient(name='kiwi')
recipe = Recipe(ingredients=[ingredient])
smoothie = Smoothie(recipe=recipe)
content = smoothie.encode()
self.assertEqual(content, self.json)
@dataclass
class Vegetable(Codable):
class CodingKeys(CodingKey):
name = 'name'
name: Optional[str]
class CodableMissedTests(TestCase):
source_json = '{}'
distribute_json = (
dedent(
'''
{
"name": null
}
'''
)
.strip()
)
def test_decodes(self):
vegetable = Vegetable.decode(self.source_json)
self.assertIsNone(vegetable.name)
def test_encodes(self):
vegetable = Vegetable(name=None)
content = vegetable.encode()
self.assertEqual(content, self.distribute_json)

View File

@ -29,15 +29,21 @@ class ConfigurationManager:
return None
return urlparse(url)
def document_server_url(self) -> ParseResult:
def document_server_public_url(self) -> ParseResult:
url = (
environ.get('DOCUMENT_SERVER_URL') or
environ.get('DOCUMENT_SERVER_PUBLIC_URL') or
'http://document-server'
)
return urlparse(url)
def document_server_private_url(self) -> ParseResult:
url = environ.get('DOCUMENT_SERVER_PRIVATE_URL')
if not url:
return self.document_server_public_url()
return urlparse(url)
def document_server_api_url(self) -> ParseResult:
server_url = self.document_server_url()
server_url = self.document_server_public_url()
base_url = server_url.geturl()
path = (
environ.get('DOCUMENT_SERVER_API_PATH') or
@ -47,7 +53,7 @@ class ConfigurationManager:
return urlparse(url)
def document_server_preloader_url(self) -> ParseResult:
server_url = self.document_server_url()
server_url = self.document_server_public_url()
base_url = server_url.geturl()
path = (
environ.get('DOCUMENT_SERVER_PRELOADER_PATH') or
@ -57,7 +63,7 @@ class ConfigurationManager:
return urlparse(url)
def document_server_command_url(self) -> ParseResult:
server_url = self.document_server_url()
server_url = self.document_server_private_url()
base_url = server_url.geturl()
path = (
environ.get('DOCUMENT_SERVER_COMMAND_PATH') or
@ -67,7 +73,7 @@ class ConfigurationManager:
return urlparse(url)
def document_server_converter_url(self) -> ParseResult:
server_url = self.document_server_url()
server_url = self.document_server_private_url()
base_url = server_url.geturl()
path = (
environ.get('DOCUMENT_SERVER_CONVERTER_PATH') or
@ -111,78 +117,6 @@ class ConfigurationManager:
return int(timeout)
return 120 * 1000
def fillable_file_extensions(self) -> list[str]:
return [
'.docx',
'.oform'
]
def viewable_file_extensions(self) -> list[str]:
return [
'.djvu',
'.oxps',
'.pdf',
'.xps'
]
def editable_file_extensions(self) -> list[str]:
return [
'.csv', '.docm', '.docx',
'.docxf', '.dotm', '.dotx',
'.epub', '.fb2', '.html',
'.odp', '.ods', '.odt',
'.otp', '.ots', '.ott',
'.potm', '.potx', '.ppsm',
'.ppsx', '.pptm', '.pptx',
'.rtf', '.txt', '.xlsm',
'.xlsx', '.xltm', '.xltx'
]
def convertible_file_extensions(self) -> list[str]:
return [
'.doc', '.dot', '.dps', '.dpt',
'.epub', '.et', '.ett', '.fb2',
'.fodp', '.fods', '.fodt', '.htm',
'.html', '.mht', '.mhtml', '.odp',
'.ods', '.odt', '.otp', '.ots',
'.ott', '.pot', '.pps', '.ppt',
'.rtf', '.stw', '.sxc', '.sxi',
'.sxw', '.wps', '.wpt', '.xls',
'.xlsb', '.xlt', '.xml'
]
def spreadsheet_file_extensions(self) -> list[str]:
return [
'.xls', '.xlsx',
'.xlsm', '.xlsb',
'.xlt', '.xltx',
'.xltm', '.ods',
'.fods', '.ots',
'.csv'
]
def presentation_file_extensions(self) -> list[str]:
return [
'.pps', '.ppsx',
'.ppsm', '.ppt',
'.pptx', '.pptm',
'.pot', '.potx',
'.potm', '.odp',
'.fodp', '.otp'
]
def document_file_extensions(self) -> list[str]:
return [
'.doc', '.docx', '.docm',
'.dot', '.dotx', '.dotm',
'.odt', '.fodt', '.ott',
'.rtf', '.txt', '.html',
'.htm', '.mht', '.xml',
'.pdf', '.djvu', '.fb2',
'.epub', '.xps', '.oxps',
'.oform'
]
def languages(self) -> dict[str, str]:
return {
'en': 'English',

View File

@ -17,6 +17,7 @@
from os import environ
from unittest import TestCase
from unittest.mock import patch
from urllib.parse import urlparse
from . import ConfigurationManager
class ConfigurationManagerTests(TestCase):
@ -38,98 +39,152 @@ class ConfigurationManagerExampleURLTests(TestCase):
url = config_manager.example_url()
self.assertEqual(url.geturl(), 'http://localhost')
class ConfigurationManagerDocumentServerURLTests(TestCase):
class ConfigurationManagerDocumentServerPublicURLTests(TestCase):
def test_assigns_a_default_value(self):
config_manager = ConfigurationManager()
url = config_manager.document_server_url()
url = config_manager.document_server_public_url()
self.assertEqual(url.geturl(), 'http://document-server')
@patch.dict(environ, {
'DOCUMENT_SERVER_URL': 'http://localhost'
'DOCUMENT_SERVER_PUBLIC_URL': 'http://localhost'
})
def test_assigns_a_value_from_the_environment(self):
config_manager = ConfigurationManager()
url = config_manager.document_server_url()
url = config_manager.document_server_public_url()
self.assertEqual(url.geturl(), 'http://localhost')
class ConfigurationManagerDocumentServerPrivateURLTests(TestCase):
def test_assigns_a_default_value(self):
config_manager = ConfigurationManager()
url = config_manager.document_server_private_url()
self.assertEqual(url.geturl(), 'http://document-server')
@patch.dict(environ, {
'DOCUMENT_SERVER_PRIVATE_URL': 'http://localhost'
})
def test_assigns_a_value_from_the_environment(self):
config_manager = ConfigurationManager()
url = config_manager.document_server_private_url()
self.assertEqual(url.geturl(), 'http://localhost')
class ConfigurationManagerDocumentServerAPIURLTests(TestCase):
def test_assigns_a_default_value(self):
@patch.object(
ConfigurationManager,
'document_server_public_url',
return_value=urlparse('http://localhost')
)
def test_assigns_a_default_value(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_api_url()
self.assertEqual(
url.geturl(),
'http://document-server/web-apps/apps/api/documents/api.js'
'http://localhost/web-apps/apps/api/documents/api.js'
)
@patch.object(
ConfigurationManager,
'document_server_public_url',
return_value=urlparse('http://localhost')
)
@patch.dict(environ, {
'DOCUMENT_SERVER_API_PATH': '/api'
})
def test_assigns_a_value_from_the_environment(self):
def test_assigns_a_value_from_the_environment(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_api_url()
self.assertEqual(
url.geturl(),
'http://document-server/api'
'http://localhost/api'
)
class ConfigurationManagerDocumentServerPreloaderURLTests(TestCase):
def test_assigns_a_default_value(self):
@patch.object(
ConfigurationManager,
'document_server_public_url',
return_value=urlparse('http://localhost')
)
def test_assigns_a_default_value(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_preloader_url()
self.assertEqual(
url.geturl(),
'http://document-server/web-apps/apps/api/documents/cache-scripts.html'
'http://localhost/web-apps/apps/api/documents/cache-scripts.html'
)
@patch.object(
ConfigurationManager,
'document_server_public_url',
return_value=urlparse('http://localhost')
)
@patch.dict(environ, {
'DOCUMENT_SERVER_PRELOADER_PATH': '/preloader'
})
def test_assigns_a_value_from_the_environment(self):
def test_assigns_a_value_from_the_environment(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_preloader_url()
self.assertEqual(
url.geturl(),
'http://document-server/preloader'
'http://localhost/preloader'
)
class ConfigurationManagerDocumentServerCommandURLTests(TestCase):
def test_assigns_a_default_value(self):
@patch.object(
ConfigurationManager,
'document_server_private_url',
return_value=urlparse('http://localhost')
)
def test_assigns_a_default_value(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_command_url()
self.assertEqual(
url.geturl(),
'http://document-server/coauthoring/CommandService.ashx'
'http://localhost/coauthoring/CommandService.ashx'
)
@patch.object(
ConfigurationManager,
'document_server_private_url',
return_value=urlparse('http://localhost')
)
@patch.dict(environ, {
'DOCUMENT_SERVER_COMMAND_PATH': '/command'
})
def test_assigns_a_value_from_the_environment(self):
def test_assigns_a_value_from_the_environment(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_command_url()
self.assertEqual(
url.geturl(),
'http://document-server/command'
'http://localhost/command'
)
class ConfigurationManagerDocumentServerConverterURLTests(TestCase):
def test_assigns_a_default_value(self):
@patch.object(
ConfigurationManager,
'document_server_private_url',
return_value=urlparse('http://localhost')
)
def test_assigns_a_default_value(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_converter_url()
self.assertEqual(
url.geturl(),
'http://document-server/ConvertService.ashx'
'http://localhost/ConvertService.ashx'
)
@patch.object(
ConfigurationManager,
'document_server_private_url',
return_value=urlparse('http://localhost')
)
@patch.dict(environ, {
'DOCUMENT_SERVER_CONVERTER_PATH': '/converter'
})
def test_assigns_a_value_from_the_environment(self):
def test_assigns_a_value_from_the_environment(self, _):
config_manager = ConfigurationManager()
url = config_manager.document_server_converter_url()
self.assertEqual(
url.geturl(),
'http://document-server/converter'
'http://localhost/converter'
)
class ConfigurationManagerJWTSecretTests(TestCase):

View File

@ -0,0 +1,17 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from .format import *

View File

@ -0,0 +1,177 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from dataclasses import dataclass
from json import dumps, loads
from pathlib import Path
from src.codable import Codable, CodingKey
@dataclass
class Format(Codable):
class CodingKeys(CodingKey):
name = 'name'
type = 'type'
actions = 'actions'
convert = 'convert'
mime = 'mime'
name: str
type: str
actions: list[str]
convert: list[str]
mime: list[str]
def extension(self) -> str:
return f'.{self.name}'
class FormatManager():
def spreadsheet_extensions(self) -> list[str]:
formats = self.spreadsheets()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def spreadsheets(self) -> list[Format]:
formats = self.all()
mapped = filter(lambda format: format.type == 'cell', formats)
return list(mapped)
def presentation_extensions(self) -> list[str]:
formats = self.presentations()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def presentations(self) -> list[Format]:
formats = self.all()
mapped = filter(lambda format: format.type == 'slide', formats)
return list(mapped)
def document_extensions(self) -> list[str]:
formats = self.documents()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def documents(self) -> list[Format]:
formats = self.all()
mapped = filter(lambda format: format.type == 'word', formats)
return list(mapped)
def fillable_extensions(self) -> list[str]:
formats = self.fillable()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def fillable(self) -> list[Format]:
formats = self.all()
mapped = filter(lambda format: 'fill' in format.actions, formats)
return list(mapped)
def viewable_extensions(self) -> list[str]:
formats = self.viewable()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def viewable(self) -> list[Format]:
formats = self.all()
mapped = filter(lambda format: 'view' in format.actions, formats)
return list(mapped)
def editable_extensions(self) -> list[str]:
formats = self.editable()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def editable(self) -> list[Format]:
formats = self.all()
mapped = filter(
lambda format: (
'edit' in format.actions or
'lossy-edit' in format.actions
),
formats
)
return list(mapped)
def convertible_to_names(self, extension) -> list[str]:
formats = self.convertible_to(extension)
mapped = map(lambda format: format.name, formats)
return list(mapped)
def convertible_to(self, extension) -> list[Format]:
formats = self.all()
filtered: list[Format] = []
names: list[str] = []
for format in formats:
if format.extension() == extension:
names = format.convert
break
for name in names:
for format in formats:
if format.name == name:
filtered.append(format)
break
return list(filtered)
def convertible_extensions(self) -> list[str]:
formats = self.convertible()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def convertible(self) -> list[Format]:
formats = self.all()
filtered = filter(
lambda format: (
format.type == 'cell' and 'xlsx' in format.convert or
format.type == 'slide' and 'pptx' in format.convert or
format.type == 'word' and 'docx' in format.convert
),
formats
)
return list(filtered)
def all_extensions(self) -> list[str]:
formats = self.all()
mapped = map(lambda format: format.extension(), formats)
return list(mapped)
def all(self) -> list[Format]:
path = self.__file()
formats: list[Format] = []
with open(path, 'r', encoding='utf-8') as file:
content = file.read()
array = loads(content)
for obj in array:
raw = dumps(obj)
decoded = Format.decode(raw)
formats.append(decoded)
return formats
def __file(self) -> Path:
directory = self.__directory()
return directory.joinpath('onlyoffice-docs-formats.json')
def __directory(self) -> Path:
current_file = Path(__file__)
directory = current_file.joinpath(
'..',
'..',
'..',
'assets',
'document-formats'
)
return directory.resolve()

View File

@ -0,0 +1,104 @@
#
# (c) Copyright Ascensio System SIA 2023
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import annotations
from unittest import TestCase
from . import Format, FormatManager
class FormatTests(TestCase):
json = \
'''
{
"name": "djvu",
"type": "word",
"actions": ["view"],
"convert": ["bmp", "gif", "jpg", "pdf", "pdfa", "png"],
"mime": ["image/vnd.djvu"]
}
'''
def test_generates_extension(self):
form = Format.decode(self.json)
self.assertEqual(form.extension(), '.djvu')
class FormatManagerAllTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.all()
empty = len(formats) == 0
self.assertFalse(empty)
class FormatManagerDocumentsTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.documents()
mapped = map(lambda format: format.type == 'word', formats)
self.assertTrue(all(mapped))
class FormatManagerPresentationsTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.presentations()
mapped = map(lambda format: format.type == 'slide', formats)
self.assertTrue(all(mapped))
class FormatManagerSpreadsheetsTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.spreadsheets()
mapped = map(lambda format: format.type == 'cell', formats)
self.assertTrue(all(mapped))
class FormatManagerConvertibleTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.convertible()
mapped = map(
lambda format: (
format.type == 'cell' and 'xlsx' in format.actions or
format.type == 'slide' and 'pptx' in format.actions or
format.type == 'word' and 'docx' in format.actions
),
formats
)
self.assertTrue(all(mapped))
class FormatManagerEditableTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.editable()
mapped = map(
lambda format: (
'edit' in format.actions or
'lossy-edit' in format.actions
),
formats
)
self.assertTrue(all(mapped))
class FormatManagerViewableTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.viewable()
mapped = map(lambda format: 'view' in format.actions, formats)
self.assertTrue(all(mapped))
class FormatManagerFillableTests(TestCase):
def test_loads(self):
format_manager = FormatManager()
formats = format_manager.fillable()
mapped = map(lambda format: 'fill' in format.actions, formats)
self.assertTrue(all(mapped))

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