mirror of
https://github.com/ONLYOFFICE/document-server-integration.git
synced 2026-04-07 14:06:11 +08:00
Merge remote-tracking branch 'remotes/origin/develop' into feature/referenceData-open
# Conflicts: # CHANGELOG.md # web/documentserver-example/python/src/views/actions.py
This commit is contained in:
@ -20,15 +20,19 @@
|
||||
from http import HTTPStatus, HTTPMethod
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
|
||||
|
||||
def GET():
|
||||
return method(HTTPMethod.GET)
|
||||
|
||||
|
||||
def POST():
|
||||
return method(HTTPMethod.POST)
|
||||
|
||||
|
||||
def PUT():
|
||||
return method(HTTPMethod.PUT)
|
||||
|
||||
|
||||
def method(meth: HTTPMethod):
|
||||
def wrapper(func):
|
||||
def inner(request: HttpRequest, *args, **kwargs):
|
||||
|
||||
@ -23,10 +23,12 @@ from . import http
|
||||
# Under the hood, HttpRequest uses a settings object.
|
||||
settings.configure()
|
||||
|
||||
|
||||
@http.GET()
|
||||
def endpoint(_: HttpRequest) -> HttpResponse:
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
class HTTPMethodTests(TestCase):
|
||||
def test_returns_a_response_from_the_endpoint(self):
|
||||
request = HttpRequest()
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def boolean(string: Optional[str], default: bool = False) -> bool:
|
||||
'''
|
||||
Converts a string that represents a boolean value to its corresponding
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
from unittest import TestCase
|
||||
from .string import boolean
|
||||
|
||||
|
||||
class BooleanDefaultTests(TestCase):
|
||||
def test_converts_to_the_default_value(self):
|
||||
value = boolean("unknown")
|
||||
@ -30,6 +31,7 @@ class BooleanDefaultTests(TestCase):
|
||||
value = boolean("unknown", True)
|
||||
self.assertTrue(value)
|
||||
|
||||
|
||||
class BooleanOptionalTests(TestCase):
|
||||
def test_converts_to_the_default_value(self):
|
||||
value = boolean(None)
|
||||
@ -43,12 +45,14 @@ class BooleanOptionalTests(TestCase):
|
||||
value = boolean(None, True)
|
||||
self.assertTrue(value)
|
||||
|
||||
|
||||
class BooleanNegativeTests(TestCase):
|
||||
def test_converts_a_negative_string_to_the_negative_value(self):
|
||||
for string in ["false", "f", "no", "n", "0"]:
|
||||
value = boolean(string)
|
||||
self.assertFalse(value)
|
||||
|
||||
|
||||
class BooleanPositiveTests(TestCase):
|
||||
def test_converts_a_positive_string_to_the_positive_value(self):
|
||||
for string in ["true", "t", "yes", "y", "1"]:
|
||||
|
||||
@ -20,6 +20,7 @@ from typing import Optional
|
||||
from urllib.parse import ParseResult, urlparse, urljoin
|
||||
from src.common import string
|
||||
|
||||
|
||||
class ConfigurationManager:
|
||||
version = '1.7.0'
|
||||
|
||||
|
||||
@ -20,11 +20,13 @@ from unittest.mock import patch
|
||||
from urllib.parse import urlparse
|
||||
from . import ConfigurationManager
|
||||
|
||||
|
||||
class ConfigurationManagerTests(TestCase):
|
||||
def test_corresponds_the_latest_version(self):
|
||||
config_manager = ConfigurationManager()
|
||||
self.assertEqual(config_manager.version, '1.6.0')
|
||||
|
||||
|
||||
class ConfigurationManagerExampleURLTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -39,6 +41,7 @@ class ConfigurationManagerExampleURLTests(TestCase):
|
||||
url = config_manager.example_url()
|
||||
self.assertEqual(url.geturl(), 'http://localhost')
|
||||
|
||||
|
||||
class ConfigurationManagerDocumentServerPublicURLTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -53,6 +56,7 @@ class ConfigurationManagerDocumentServerPublicURLTests(TestCase):
|
||||
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()
|
||||
@ -67,6 +71,7 @@ class ConfigurationManagerDocumentServerPrivateURLTests(TestCase):
|
||||
url = config_manager.document_server_private_url()
|
||||
self.assertEqual(url.geturl(), 'http://localhost')
|
||||
|
||||
|
||||
class ConfigurationManagerDocumentServerAPIURLTests(TestCase):
|
||||
@patch.object(
|
||||
ConfigurationManager,
|
||||
@ -97,6 +102,7 @@ class ConfigurationManagerDocumentServerAPIURLTests(TestCase):
|
||||
'http://localhost/api'
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationManagerDocumentServerPreloaderURLTests(TestCase):
|
||||
@patch.object(
|
||||
ConfigurationManager,
|
||||
@ -127,6 +133,7 @@ class ConfigurationManagerDocumentServerPreloaderURLTests(TestCase):
|
||||
'http://localhost/preloader'
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationManagerDocumentServerCommandURLTests(TestCase):
|
||||
@patch.object(
|
||||
ConfigurationManager,
|
||||
@ -157,6 +164,7 @@ class ConfigurationManagerDocumentServerCommandURLTests(TestCase):
|
||||
'http://localhost/command'
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationManagerDocumentServerConverterURLTests(TestCase):
|
||||
@patch.object(
|
||||
ConfigurationManager,
|
||||
@ -187,6 +195,7 @@ class ConfigurationManagerDocumentServerConverterURLTests(TestCase):
|
||||
'http://localhost/converter'
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationManagerJWTSecretTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -201,6 +210,7 @@ class ConfigurationManagerJWTSecretTests(TestCase):
|
||||
secret = config_manager.jwt_secret()
|
||||
self.assertEqual(secret, 'your-256-bit-secret')
|
||||
|
||||
|
||||
class ConfigurationManagerJWTHeaderTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -215,6 +225,7 @@ class ConfigurationManagerJWTHeaderTests(TestCase):
|
||||
header = config_manager.jwt_header()
|
||||
self.assertEqual(header, 'Proxy-Authorization')
|
||||
|
||||
|
||||
class ConfigurationManagerJWTUseForRequest(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -229,6 +240,7 @@ class ConfigurationManagerJWTUseForRequest(TestCase):
|
||||
use = config_manager.jwt_use_for_request()
|
||||
self.assertFalse(use)
|
||||
|
||||
|
||||
class ConfigurationManagerSSLTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -243,6 +255,7 @@ class ConfigurationManagerSSLTests(TestCase):
|
||||
enabled = config_manager.ssl_verify_peer_mode_enabled()
|
||||
self.assertTrue(enabled)
|
||||
|
||||
|
||||
class ConfigurationManagerStoragePathTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -267,6 +280,7 @@ class ConfigurationManagerStoragePathTests(TestCase):
|
||||
path = config_manager.storage_path()
|
||||
self.assertEqual(f'{path}', '/directory')
|
||||
|
||||
|
||||
class ConfigurationManagerMaximumFileSizeTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
@ -281,6 +295,7 @@ class ConfigurationManagerMaximumFileSizeTests(TestCase):
|
||||
size = config_manager.maximum_file_size()
|
||||
self.assertEqual(size, 10)
|
||||
|
||||
|
||||
class ConfigurationManagerConversionTimeoutTests(TestCase):
|
||||
def test_assigns_a_default_value(self):
|
||||
config_manager = ConfigurationManager()
|
||||
|
||||
@ -19,6 +19,7 @@ from msgspec.json import decode
|
||||
from msgspec import Struct
|
||||
from src.memoize import memoize
|
||||
|
||||
|
||||
class Format(Struct):
|
||||
name: str
|
||||
type: str
|
||||
@ -29,6 +30,7 @@ class Format(Struct):
|
||||
def extension(self) -> str:
|
||||
return f'.{self.name}'
|
||||
|
||||
|
||||
class FormatManager():
|
||||
def fillable_extensions(self) -> list[str]:
|
||||
formats = self.fillable()
|
||||
|
||||
@ -19,6 +19,7 @@ from unittest import TestCase
|
||||
from msgspec.json import decode
|
||||
from . import Format, FormatManager
|
||||
|
||||
|
||||
class FormatTests(TestCase):
|
||||
json = \
|
||||
'''
|
||||
@ -35,6 +36,7 @@ class FormatTests(TestCase):
|
||||
form = decode(self.json, type=Format)
|
||||
self.assertEqual(form.extension(), '.djvu')
|
||||
|
||||
|
||||
class FormatManagerAllTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -42,6 +44,7 @@ class FormatManagerAllTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerDocumentsTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -49,6 +52,7 @@ class FormatManagerDocumentsTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerPresentationsTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -56,6 +60,7 @@ class FormatManagerPresentationsTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerSpreadsheetsTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -63,6 +68,7 @@ class FormatManagerSpreadsheetsTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerConvertibleTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -70,6 +76,7 @@ class FormatManagerConvertibleTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerEditableTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -77,6 +84,7 @@ class FormatManagerEditableTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerViewableTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
@ -84,6 +92,7 @@ class FormatManagerViewableTests(TestCase):
|
||||
empty = len(formats) == 0
|
||||
self.assertFalse(empty)
|
||||
|
||||
|
||||
class FormatManagerFillableTests(TestCase):
|
||||
def test_loads(self):
|
||||
format_manager = FormatManager()
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
from unittest import TestCase
|
||||
from . import memoize
|
||||
|
||||
|
||||
class MemoizeMock():
|
||||
counter: int = 1
|
||||
|
||||
@ -24,6 +25,7 @@ class MemoizeMock():
|
||||
def method(self) -> int:
|
||||
return self.counter
|
||||
|
||||
|
||||
class MemoizeTests(TestCase):
|
||||
def test(self):
|
||||
mock = MemoizeMock()
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
from urllib.parse import ParseResult
|
||||
from src.configuration import ConfigurationManager
|
||||
|
||||
|
||||
class ProxyManager():
|
||||
config_manager: ConfigurationManager
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ from urllib.parse import urlparse
|
||||
from src.configuration import ConfigurationManager
|
||||
from . import ProxyManager
|
||||
|
||||
|
||||
class ProxyManagerTests(TestCase):
|
||||
@patch.object(
|
||||
ConfigurationManager,
|
||||
|
||||
@ -18,6 +18,7 @@ from http import HTTPStatus
|
||||
from json import dumps
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
class ErrorResponse(HttpResponse):
|
||||
def __init__(self, message: str, status: HTTPStatus):
|
||||
payload = {
|
||||
|
||||
@ -21,13 +21,13 @@ import os
|
||||
import shutil
|
||||
import io
|
||||
import re
|
||||
import requests
|
||||
import time
|
||||
import urllib.parse
|
||||
import requests
|
||||
import magic
|
||||
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse, HttpResponseRedirect, FileResponse
|
||||
from django.http import FileResponse
|
||||
from src.configuration import ConfigurationManager
|
||||
from src.format import FormatManager
|
||||
from . import fileUtils, historyManager
|
||||
@ -35,25 +35,31 @@ from . import fileUtils, historyManager
|
||||
config_manager = ConfigurationManager()
|
||||
format_manager = FormatManager()
|
||||
|
||||
|
||||
def isCanFillForms(ext):
|
||||
return ext in format_manager.fillable_extensions()
|
||||
|
||||
|
||||
# check if the file extension can be viewed
|
||||
def isCanView(ext):
|
||||
return ext in format_manager.viewable_extensions()
|
||||
|
||||
|
||||
# check if the file extension can be edited
|
||||
def isCanEdit(ext):
|
||||
return ext in format_manager.editable_extensions()
|
||||
|
||||
|
||||
# check if the file extension can be converted
|
||||
def isCanConvert(ext):
|
||||
return ext in format_manager.convertible_extensions()
|
||||
|
||||
|
||||
# check if the file extension is supported by the editor (it can be viewed or edited or converted)
|
||||
def isSupportedExt(ext):
|
||||
return isCanView(ext) | isCanEdit(ext) | isCanConvert(ext) | isCanFillForms(ext)
|
||||
|
||||
|
||||
# get internal extension for a given file type
|
||||
def getInternalExtension(fileType):
|
||||
mapping = {
|
||||
@ -63,7 +69,8 @@ def getInternalExtension(fileType):
|
||||
'docxf': '.docxf'
|
||||
}
|
||||
|
||||
return mapping.get(fileType, '.docx') # the default file type is .docx
|
||||
return mapping.get(fileType, '.docx') # the default file type is .docx
|
||||
|
||||
|
||||
# get image url for templates
|
||||
def getTemplateImageUrl(fileType, request):
|
||||
@ -74,28 +81,32 @@ def getTemplateImageUrl(fileType, request):
|
||||
'slide': path + 'file_pptx.svg'
|
||||
}
|
||||
|
||||
return mapping.get(fileType, path + 'file_docx.svg') # the default file type
|
||||
return mapping.get(fileType, path + 'file_docx.svg') # the default file type
|
||||
|
||||
|
||||
# get file name with an index if such a file name already exists
|
||||
def getCorrectName(filename, req):
|
||||
basename = fileUtils.getFileNameWithoutExt(filename)
|
||||
maxName = 50
|
||||
basename = fileUtils.getFileNameWithoutExt(filename)[0:maxName] + ('', '[...]')[len(filename) > maxName]
|
||||
ext = fileUtils.getFileExt(filename)
|
||||
name = f'{basename}{ext}'
|
||||
|
||||
i = 1
|
||||
while os.path.exists(getStoragePath(name, req)): # if file with such a name already exists
|
||||
while os.path.exists(getStoragePath(name, req)): # if file with such a name already exists
|
||||
name = f'{basename} ({i}){ext}' # add an index to its name
|
||||
i += 1
|
||||
|
||||
return name
|
||||
|
||||
|
||||
# get server url
|
||||
def getServerUrl (forDocumentServer, req):
|
||||
def getServerUrl(forDocumentServer, req):
|
||||
example_url = config_manager.example_url()
|
||||
if (forDocumentServer and example_url is not None):
|
||||
return example_url.geturl()
|
||||
else:
|
||||
return req.headers.get("x-forwarded-proto") or req.scheme + "://" + req.get_host()
|
||||
|
||||
return req.headers.get("x-forwarded-proto") or req.scheme + "://" + req.get_host()
|
||||
|
||||
|
||||
# get file url
|
||||
def getFileUri(filename, forDocumentServer, req):
|
||||
@ -103,23 +114,27 @@ def getFileUri(filename, forDocumentServer, req):
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}{settings.STATIC_URL}{curAdr}/{filename}'
|
||||
|
||||
|
||||
# get absolute URL to the document storage service
|
||||
def getCallbackUrl(filename, req):
|
||||
host = getServerUrl(True, req)
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}/track?filename={filename}&userAddress={curAdr}'
|
||||
|
||||
|
||||
# get url to the created file
|
||||
def getCreateUrl(fileType, req):
|
||||
host = getServerUrl(False, req)
|
||||
return f'{host}/create?fileType={fileType}'
|
||||
|
||||
|
||||
# get url to download a file
|
||||
def getDownloadUrl(filename, req, isServerUrl = True):
|
||||
def getDownloadUrl(filename, req, isServerUrl=True):
|
||||
host = getServerUrl(isServerUrl, req)
|
||||
curAdr = f'&userAddress={req.META["REMOTE_ADDR"]}' if isServerUrl else ""
|
||||
return f'{host}/download?fileName={filename}{curAdr}'
|
||||
|
||||
|
||||
# get root folder for the current file
|
||||
def getRootFolder(req):
|
||||
if isinstance(req, str):
|
||||
@ -130,11 +145,12 @@ def getRootFolder(req):
|
||||
storage_directory = config_manager.storage_path()
|
||||
directory = storage_directory.joinpath(curAdr)
|
||||
|
||||
if not os.path.exists(directory): # if such a directory does not exist, make it
|
||||
if not os.path.exists(directory): # if such a directory does not exist, make it
|
||||
os.makedirs(directory)
|
||||
|
||||
return directory
|
||||
|
||||
|
||||
# get the file history path
|
||||
def getHistoryPath(filename, file, version, req):
|
||||
if isinstance(req, str):
|
||||
@ -144,19 +160,21 @@ def getHistoryPath(filename, file, version, req):
|
||||
|
||||
storage_directory = config_manager.storage_path()
|
||||
directory = storage_directory.joinpath(curAdr)
|
||||
if not os.path.exists(directory): # the directory with host address doesn't exist
|
||||
if not os.path.exists(directory): # the directory with host address doesn't exist
|
||||
filePath = os.path.join(getRootFolder(req), f'{filename}-hist', version, file)
|
||||
else:
|
||||
filePath = os.path.join(directory, f'{filename}-hist', version, file)
|
||||
|
||||
return filePath
|
||||
|
||||
|
||||
# get the file path
|
||||
def getStoragePath(filename, req):
|
||||
directory = getRootFolder(req)
|
||||
|
||||
return os.path.join(directory, fileUtils.getFileName(filename))
|
||||
|
||||
|
||||
# get the path to the forcesaved file version
|
||||
def getForcesavePath(filename, req, create):
|
||||
if isinstance(req, str):
|
||||
@ -166,142 +184,165 @@ def getForcesavePath(filename, req, create):
|
||||
|
||||
storage_directory = config_manager.storage_path()
|
||||
directory = storage_directory.joinpath(curAdr)
|
||||
if not os.path.exists(directory): # the directory with host address doesn't exist
|
||||
if not os.path.exists(directory): # the directory with host address doesn't exist
|
||||
return ""
|
||||
|
||||
directory = os.path.join(directory, f'{filename}-hist') # get the path to the history of the given file
|
||||
if (not os.path.exists(directory)):
|
||||
if create: # if the history directory doesn't exist
|
||||
os.makedirs(directory) # create history directory if it doesn't exist
|
||||
else: # the history directory doesn't exist and we are not supposed to create it
|
||||
|
||||
directory = os.path.join(directory, f'{filename}-hist') # get the path to the history of the given file
|
||||
if not os.path.exists(directory):
|
||||
if create: # if the history directory doesn't exist
|
||||
os.makedirs(directory) # create history directory if it doesn't exist
|
||||
else: # the history directory doesn't exist and we are not supposed to create it
|
||||
return ""
|
||||
|
||||
directory = os.path.join(directory, filename) # and get the path to the given file
|
||||
directory = os.path.join(directory, filename) # and get the path to the given file
|
||||
if (not os.path.exists(directory) and not create):
|
||||
return ""
|
||||
|
||||
return directory
|
||||
|
||||
|
||||
# get information about all the stored files
|
||||
def getStoredFiles(req):
|
||||
directory = getRootFolder(req)
|
||||
|
||||
files = os.listdir(directory)
|
||||
files.sort(key=lambda x: os.path.getmtime(os.path.join(directory, x)), reverse=True) # sort files by time of last modification
|
||||
|
||||
# sort files by time of last modification
|
||||
files.sort(key=lambda x: os.path.getmtime(os.path.join(directory, x)), reverse=True)
|
||||
|
||||
fileInfos = []
|
||||
|
||||
for f in files:
|
||||
if os.path.isfile(os.path.join(directory, f)):
|
||||
fileInfos.append({'isFillFormDoc': isCanFillForms(fileUtils.getFileExt(f)),'version':historyManager.getFileVersion(historyManager.getHistoryDir(getStoragePath(f, req))), 'type': fileUtils.getFileType(f), 'title': f, 'url': getFileUri(f, True, req), 'canEdit': isCanEdit(fileUtils.getFileExt(f))}) # write information about file type, title and url
|
||||
fileInfos.append({
|
||||
'isFillFormDoc': isCanFillForms(fileUtils.getFileExt(f)),
|
||||
'version': historyManager.getFileVersion(historyManager.getHistoryDir(getStoragePath(f, req))),
|
||||
'type': fileUtils.getFileType(f),
|
||||
'title': f,
|
||||
'url': getFileUri(f, True, req),
|
||||
'canEdit': isCanEdit(fileUtils.getFileExt(f))
|
||||
}) # write information about file type, title and url
|
||||
|
||||
return fileInfos
|
||||
|
||||
|
||||
# create a file
|
||||
def createFile(stream, path, req = None, meta = False):
|
||||
def createFile(stream, path, req=None, meta=False):
|
||||
bufSize = 8192
|
||||
with io.open(path, 'wb') as out: # write data to the file by streams
|
||||
with io.open(path, 'wb') as out: # write data to the file by streams
|
||||
read = stream.read(bufSize)
|
||||
while len(read) > 0:
|
||||
out.write(read)
|
||||
read = stream.read(bufSize)
|
||||
if meta:
|
||||
historyManager.createMeta(path, req) # create meta data for the file if needed
|
||||
return
|
||||
historyManager.createMeta(path, req) # create meta data for the file if needed
|
||||
|
||||
|
||||
# save file
|
||||
def saveFile(response, path):
|
||||
with open(path, 'wb') as file:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
file.write(chunk)
|
||||
return
|
||||
|
||||
# download file from the given url
|
||||
def downloadFileFromUri(uri, path = None, withSave = False):
|
||||
resp = requests.get(uri, stream=True, verify = config_manager.ssl_verify_peer_mode_enabled(), timeout=5)
|
||||
|
||||
# download file from the given url
|
||||
def downloadFileFromUri(uri, path=None, withSave=False):
|
||||
resp = requests.get(uri, stream=True, verify=config_manager.ssl_verify_peer_mode_enabled(), timeout=5)
|
||||
status_code = resp.status_code
|
||||
if status_code != 200: # checking status code
|
||||
raise RuntimeError('Document editing service returned status: %s' % status_code)
|
||||
raise RuntimeError(f'Document editing service returned status: {status_code}')
|
||||
if withSave:
|
||||
if path is None:
|
||||
raise RuntimeError('Path for saving file is null')
|
||||
saveFile(resp, path)
|
||||
return resp
|
||||
|
||||
|
||||
# create sample file
|
||||
def createSample(fileType, sample, req):
|
||||
ext = getInternalExtension(fileType) # get the internal extension of the given file type
|
||||
ext = getInternalExtension(fileType) # get the internal extension of the given file type
|
||||
|
||||
if not sample:
|
||||
sample = 'false'
|
||||
|
||||
sampleName = 'sample' if sample == 'true' else 'new' # create sample or new template
|
||||
|
||||
filename = getCorrectName(f'{sampleName}{ext}', req) # get file name with an index if such a file name already exists
|
||||
sampleName = 'sample' if sample == 'true' else 'new' # create sample or new template
|
||||
# get file name with an index if such a file name already exists
|
||||
filename = getCorrectName(f'{sampleName}{ext}', req)
|
||||
path = getStoragePath(filename, req)
|
||||
|
||||
with io.open(os.path.join('assets', 'document-templates', 'sample' if sample == 'true' else 'new', f'{sampleName}{ext}'), 'rb') as stream: # create sample file of the necessary extension in the directory
|
||||
# create sample file of the necessary extension in the directory
|
||||
with io.open(os.path.join('assets', 'document-templates', 'sample' if sample == 'true' else 'new',
|
||||
f'{sampleName}{ext}'), 'rb') as stream:
|
||||
createFile(stream, path, req, True)
|
||||
return filename
|
||||
|
||||
|
||||
# remove file from the directory
|
||||
def removeFile(filename, req):
|
||||
path = getStoragePath(filename, req)
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
histDir = historyManager.getHistoryDir(path) # get history directory
|
||||
if os.path.exists(histDir): # remove all the history information about this file
|
||||
histDir = historyManager.getHistoryDir(path) # get history directory
|
||||
if os.path.exists(histDir): # remove all the history information about this file
|
||||
shutil.rmtree(histDir)
|
||||
|
||||
|
||||
# generate file key
|
||||
def generateFileKey(filename, req):
|
||||
path = getStoragePath(filename, req)
|
||||
uri = getFileUri(filename, False, req)
|
||||
stat = os.stat(path) # get the directory parameters
|
||||
|
||||
h = str(hash(f'{uri}_{stat.st_mtime_ns}')) # get the hash value of the file url and the date of its last modification and turn it into a string format
|
||||
stat = os.stat(path) # get the directory parameters
|
||||
# get the hash value of the file url and the date of its last modification and turn it into a string format
|
||||
h = str(hash(f'{uri}_{stat.st_mtime_ns}'))
|
||||
replaced = re.sub(r'[^0-9-.a-zA-Z_=]', '_', h)
|
||||
return replaced[:20] # take the first 20 characters for the key
|
||||
return replaced[:20] # take the first 20 characters for the key
|
||||
|
||||
|
||||
# generate the document key value
|
||||
def generateRevisionId(expectedKey):
|
||||
if (len(expectedKey) > 20):
|
||||
if len(expectedKey) > 20:
|
||||
expectedKey = str(hash(expectedKey))
|
||||
|
||||
key = re.sub(r'[^0-9-.a-zA-Z_=]', '_', expectedKey)
|
||||
return key[:20]
|
||||
|
||||
|
||||
# get files information
|
||||
def getFilesInfo(req):
|
||||
fileId = req.GET.get('fileId') if req.GET.get('fileId') else None
|
||||
|
||||
result = []
|
||||
resultID = []
|
||||
for f in getStoredFiles(req): # run through all the files from the directory
|
||||
stats = os.stat(os.path.join(getRootFolder(req), f.get("title"))) # get file information
|
||||
result.append( # write file parameters to the file object
|
||||
{ "version" : historyManager.getFileVersion(historyManager.getHistoryDir(getStoragePath(f.get("title"), req))),
|
||||
"id" : generateFileKey(f.get("title"), req),
|
||||
"contentLength" : "%.2f KB" % (stats.st_size/1024),
|
||||
"pureContentLength" : stats.st_size,
|
||||
"title" : f.get("title"),
|
||||
"updated" : time.strftime("%Y-%m-%dT%X%z",time.gmtime(stats.st_mtime))
|
||||
})
|
||||
if fileId : # if file id is defined
|
||||
if fileId == generateFileKey(f.get("title"), req) : # and it is equal to the file key value
|
||||
resultID.append(result[-1]) # add file object to the response array
|
||||
for f in getStoredFiles(req): # run through all the files from the directory
|
||||
stats = os.stat(os.path.join(getRootFolder(req), f.get("title"))) # get file information
|
||||
result.append( # write file parameters to the file object
|
||||
{
|
||||
"version": historyManager.getFileVersion(historyManager.getHistoryDir(
|
||||
getStoragePath(f.get("title"), req)
|
||||
)),
|
||||
"id": generateFileKey(f.get("title"), req),
|
||||
"contentLength": f"{(stats.st_size/1024):.2f} KB",
|
||||
"pureContentLength": stats.st_size,
|
||||
"title": f.get("title"),
|
||||
"updated": time.strftime("%Y-%m-%dT%X%z", time.gmtime(stats.st_mtime))
|
||||
})
|
||||
if fileId: # if file id is defined
|
||||
if fileId == generateFileKey(f.get("title"), req): # and it is equal to the file key value
|
||||
resultID.append(result[-1]) # add file object to the response array
|
||||
|
||||
if fileId:
|
||||
if len(resultID) > 0:
|
||||
return resultID
|
||||
return "File not found"
|
||||
|
||||
return result
|
||||
|
||||
if fileId :
|
||||
if len(resultID) > 0 : return resultID
|
||||
else : return "File not found"
|
||||
else :
|
||||
return result
|
||||
|
||||
# download the file
|
||||
def download(filePath):
|
||||
response = FileResponse(open(filePath, 'rb'), True) # write headers to the response object
|
||||
response['Content-Length'] = os.path.getsize(filePath)
|
||||
response['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + urllib.parse.quote_plus(os.path.basename(filePath))
|
||||
response = FileResponse(open(filePath, 'rb'), True) # write headers to the response object
|
||||
response['Content-Length'] = os.path.getsize(filePath)
|
||||
response['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + \
|
||||
urllib.parse.quote_plus(os.path.basename(filePath))
|
||||
response['Content-Type'] = magic.from_file(filePath, mime=True)
|
||||
response['Access-Control-Allow-Origin'] = "*"
|
||||
return response
|
||||
return response
|
||||
|
||||
@ -22,26 +22,30 @@ from src.format import FormatManager
|
||||
config_manager = ConfigurationManager()
|
||||
format_manager = FormatManager()
|
||||
|
||||
|
||||
# get file name from the document url
|
||||
def getFileName(str):
|
||||
ind = str.rfind('/')
|
||||
return str[ind+1:]
|
||||
def getFileName(uri):
|
||||
ind = uri.rfind('/')
|
||||
return uri[ind+1:]
|
||||
|
||||
|
||||
# get file name without extension from the document url
|
||||
def getFileNameWithoutExt(str):
|
||||
fn = getFileName(str)
|
||||
def getFileNameWithoutExt(uri):
|
||||
fn = getFileName(uri)
|
||||
ind = fn.rfind('.')
|
||||
return fn[:ind]
|
||||
|
||||
|
||||
# get file extension from the document url
|
||||
def getFileExt(str):
|
||||
fn = getFileName(str)
|
||||
def getFileExt(uri):
|
||||
fn = getFileName(uri)
|
||||
ind = fn.rfind('.')
|
||||
return fn[ind:].lower()
|
||||
|
||||
|
||||
# get file type
|
||||
def getFileType(str):
|
||||
ext = getFileExt(str)
|
||||
def getFileType(uri):
|
||||
ext = getFileExt(uri)
|
||||
if ext in format_manager.document_extensions():
|
||||
return 'word'
|
||||
if ext in format_manager.spreadsheet_extensions():
|
||||
@ -49,4 +53,4 @@ def getFileType(str):
|
||||
if ext in format_manager.presentation_extensions():
|
||||
return 'slide'
|
||||
|
||||
return 'word' # default file type is word
|
||||
return 'word' # default file type is word
|
||||
|
||||
@ -20,90 +20,99 @@ import os
|
||||
import io
|
||||
import json
|
||||
|
||||
from . import users, fileUtils
|
||||
from datetime import datetime
|
||||
from src.utils import docManager
|
||||
from src.utils import jwtManager
|
||||
|
||||
from . import users, fileUtils
|
||||
|
||||
|
||||
# get the path to the history direction
|
||||
def getHistoryDir(storagePath):
|
||||
return f'{storagePath}-hist'
|
||||
|
||||
|
||||
# get the path to the given file version
|
||||
def getVersionDir(histDir, version):
|
||||
return os.path.join(histDir, str(version))
|
||||
|
||||
|
||||
# get file version of the given history directory
|
||||
def getFileVersion(histDir):
|
||||
if not os.path.exists(histDir): # if the history directory doesn't exist
|
||||
return 0 # file version is 0
|
||||
if not os.path.exists(histDir): # if the history directory doesn't exist
|
||||
return 0 # file version is 0
|
||||
|
||||
cnt = 1
|
||||
|
||||
for f in os.listdir(histDir): # run through all the files in the history directory
|
||||
if not os.path.isfile(os.path.join(histDir, f)): # and count the number of files
|
||||
for f in os.listdir(histDir): # run through all the files in the history directory
|
||||
if not os.path.isfile(os.path.join(histDir, f)): # and count the number of files
|
||||
cnt += 1
|
||||
|
||||
|
||||
return cnt
|
||||
|
||||
|
||||
# get the path to the next file version
|
||||
def getNextVersionDir(histDir):
|
||||
v = getFileVersion(histDir) # get file version of the given history directory
|
||||
path = getVersionDir(histDir, v) # get the path to the next file version
|
||||
v = getFileVersion(histDir) # get file version of the given history directory
|
||||
path = getVersionDir(histDir, v) # get the path to the next file version
|
||||
|
||||
if not os.path.exists(path): # if this path doesn't exist
|
||||
os.makedirs(path) # make the directory for this file version
|
||||
if not os.path.exists(path): # if this path doesn't exist
|
||||
os.makedirs(path) # make the directory for this file version
|
||||
return path
|
||||
|
||||
|
||||
# get the path to a file archive with differences in the given file version
|
||||
def getChangesZipPath(verDir):
|
||||
return os.path.join(verDir, 'diff.zip')
|
||||
|
||||
|
||||
# get the path to a json file with changes of the given file version
|
||||
def getChangesHistoryPath(verDir):
|
||||
return os.path.join(verDir, 'changes.json')
|
||||
|
||||
|
||||
# get the path to the previous file version
|
||||
def getPrevFilePath(verDir, ext):
|
||||
return os.path.join(verDir, f'prev{ext}')
|
||||
|
||||
|
||||
# get the path to a txt file with a key information in it
|
||||
def getKeyPath(verDir):
|
||||
return os.path.join(verDir, 'key.txt')
|
||||
|
||||
|
||||
# get the path to a json file with meta data about this file
|
||||
def getMetaPath(histDir):
|
||||
return os.path.join(histDir, 'createdInfo.json')
|
||||
|
||||
|
||||
# create a json file with file meta data using the storage path and request
|
||||
def createMeta(storagePath, req):
|
||||
histDir = getHistoryDir(storagePath)
|
||||
path = getMetaPath(histDir) # get the path to a json file with meta data about file
|
||||
path = getMetaPath(histDir) # get the path to a json file with meta data about file
|
||||
|
||||
if not os.path.exists(histDir):
|
||||
os.makedirs(histDir)
|
||||
|
||||
user = users.getUserFromReq(req) # get the user information (id and name)
|
||||
user = users.getUserFromReq(req) # get the user information (id and name)
|
||||
|
||||
obj = { # create the meta data object
|
||||
obj = { # create the meta data object
|
||||
'created': datetime.today().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'uid': user.id,
|
||||
'uname': user.name
|
||||
}
|
||||
|
||||
writeFile(path, json.dumps(obj))
|
||||
|
||||
return
|
||||
|
||||
|
||||
# create a json file with file meta data using the file name, user id, user name and user address
|
||||
def createMetaData(filename, uid, uname, usAddr):
|
||||
histDir = getHistoryDir(docManager.getStoragePath(filename, usAddr))
|
||||
path = getMetaPath(histDir) # get the path to a json file with meta data about file
|
||||
path = getMetaPath(histDir) # get the path to a json file with meta data about file
|
||||
|
||||
if not os.path.exists(histDir):
|
||||
os.makedirs(histDir)
|
||||
|
||||
obj = { # create the meta data object
|
||||
obj = { # create the meta data object
|
||||
'created': datetime.today().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'uid': uid,
|
||||
'uname': uname
|
||||
@ -111,52 +120,54 @@ def createMetaData(filename, uid, uname, usAddr):
|
||||
|
||||
writeFile(path, json.dumps(obj))
|
||||
|
||||
return
|
||||
|
||||
# create file with a given content in it
|
||||
def writeFile(path, content):
|
||||
with io.open(path, 'w') as out:
|
||||
out.write(content)
|
||||
return
|
||||
|
||||
|
||||
# read a file
|
||||
def readFile(path):
|
||||
with io.open(path, 'r') as stream:
|
||||
return stream.read()
|
||||
|
||||
|
||||
# get the url to the history file version with a given extension
|
||||
def getPublicHistUri(filename, ver, file, req, isServerUrl=True):
|
||||
host = docManager.getServerUrl(isServerUrl, req)
|
||||
curAdr = f'&userAddress={req.META["REMOTE_ADDR"]}' if isServerUrl else ''
|
||||
return f'{host}/downloadhistory?fileName={filename}&ver={ver}&file={file}{curAdr}'
|
||||
|
||||
|
||||
# get the meta data of the file
|
||||
def getMeta(storagePath):
|
||||
histDir = getHistoryDir(storagePath)
|
||||
path = getMetaPath(histDir)
|
||||
|
||||
if os.path.exists(path): # check if the json file with file meta data exists
|
||||
if os.path.exists(path): # check if the json file with file meta data exists
|
||||
with io.open(path, 'r') as stream:
|
||||
return json.loads(stream.read()) # turn meta data into python format
|
||||
|
||||
return json.loads(stream.read()) # turn meta data into python format
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# get the document history of a given file
|
||||
def getHistoryObject(storagePath, filename, docKey, docUrl, isEnableDirectUrl, req):
|
||||
histDir = getHistoryDir(storagePath)
|
||||
version = getFileVersion(histDir)
|
||||
if version > 0: # if the file was modified (the file version is greater than 0)
|
||||
if version > 0: # if the file was modified (the file version is greater than 0)
|
||||
hist = []
|
||||
histData = {}
|
||||
|
||||
for i in range(1, version + 1): # run through all the file versions
|
||||
|
||||
for i in range(1, version + 1): # run through all the file versions
|
||||
obj = {}
|
||||
dataObj = {}
|
||||
prevVerDir = getVersionDir(histDir, i - 1) # get the path to the previous file version
|
||||
verDir = getVersionDir(histDir, i) # get the path to the given file version
|
||||
prevVerDir = getVersionDir(histDir, i - 1) # get the path to the previous file version
|
||||
verDir = getVersionDir(histDir, i) # get the path to the given file version
|
||||
|
||||
try:
|
||||
key = docKey if i == version else readFile(getKeyPath(verDir)) # get document key
|
||||
key = docKey if i == version else readFile(getKeyPath(verDir)) # get document key
|
||||
|
||||
obj['key'] = key
|
||||
obj['version'] = i
|
||||
@ -164,56 +175,62 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, isEnableDirectUrl, r
|
||||
dataObj['key'] = key
|
||||
dataObj['version'] = i
|
||||
|
||||
if i == 1: # check if the version number is equal to 1
|
||||
meta = getMeta(storagePath) # get meta data of this file
|
||||
if meta: # write meta information to the object (user information and creation date)
|
||||
if i == 1: # check if the version number is equal to 1
|
||||
meta = getMeta(storagePath) # get meta data of this file
|
||||
if meta: # write meta information to the object (user information and creation date)
|
||||
obj['created'] = meta['created']
|
||||
obj['user'] = {
|
||||
'id': meta['uid'],
|
||||
'name': meta['uname']
|
||||
}
|
||||
|
||||
dataObj['url'] = docUrl if i == version else getPublicHistUri(filename, i, "prev" + fileUtils.getFileExt(filename), req) # write file url to the data object
|
||||
# write file url to the data object
|
||||
dataObj['url'] = docUrl if i == version else getPublicHistUri(
|
||||
filename, i, "prev" + fileUtils.getFileExt(filename), req
|
||||
)
|
||||
if isEnableDirectUrl:
|
||||
dataObj['directUrl'] = docManager.getDownloadUrl(filename, req, False) if i == version else getPublicHistUri(filename, i, "prev" + fileUtils.getFileExt(filename), req, False) # write file direct url to the data object
|
||||
# write file direct url to the data object
|
||||
dataObj['directUrl'] = docManager.getDownloadUrl(filename, req, False) if i == version \
|
||||
else getPublicHistUri(filename, i, "prev" + fileUtils.getFileExt(filename), req, False)
|
||||
|
||||
if i > 1: # check if the version number is greater than 1 (the file was modified)
|
||||
changes = json.loads(readFile(getChangesHistoryPath(prevVerDir))) # get the path to the changes.json file
|
||||
if i > 1: # check if the version number is greater than 1 (the file was modified)
|
||||
# get the path to the changes.json file
|
||||
changes = json.loads(readFile(getChangesHistoryPath(prevVerDir)))
|
||||
change = changes['changes'][0]
|
||||
|
||||
obj['changes'] = changes['changes'] if change else None # write information about changes to the object
|
||||
# write information about changes to the object
|
||||
obj['changes'] = changes['changes'] if change else None
|
||||
obj['serverVersion'] = changes['serverVersion']
|
||||
obj['created'] = change['created'] if change else None
|
||||
obj['user'] = change['user'] if change else None
|
||||
|
||||
prev = histData[str(i - 2)] # get the history data from the previous file version
|
||||
prevInfo = { # write key and url information about previous file version
|
||||
prev = histData[str(i - 2)] # get the history data from the previous file version
|
||||
prevInfo = { # write key and url information about previous file version
|
||||
'fileType': prev['fileType'],
|
||||
'key': prev['key'],
|
||||
'url': prev['url'],
|
||||
'directUrl': prev['directUrl']
|
||||
} if isEnableDirectUrl else { # write key and url information about previous file version
|
||||
} if isEnableDirectUrl else { # write key and url information about previous file version
|
||||
'fileType': prev['fileType'],
|
||||
'key': prev['key'],
|
||||
'url': prev['url']
|
||||
}
|
||||
dataObj['previous'] = prevInfo # write information about previous file version to the data object
|
||||
dataObj['changesUrl'] = getPublicHistUri(filename, i - 1, "diff.zip", req) # write the path to the diff.zip archive with differences in this file version
|
||||
dataObj['previous'] = prevInfo # write information about previous file version to the data object
|
||||
# write the path to the diff.zip archive with differences in this file version
|
||||
dataObj['changesUrl'] = getPublicHistUri(filename, i - 1, "diff.zip", req)
|
||||
|
||||
if jwtManager.isEnabled():
|
||||
dataObj['token'] = jwtManager.encode(dataObj)
|
||||
dataObj['token'] = jwtManager.encode(dataObj)
|
||||
|
||||
hist.append(obj) # add object dictionary to the hist list
|
||||
histData[str(i - 1)] = dataObj # write data object information to the history data
|
||||
hist.append(obj) # add object dictionary to the hist list
|
||||
histData[str(i - 1)] = dataObj # write data object information to the history data
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
histObj = { # write history information about the current file version to the history object
|
||||
|
||||
histObj = { # write history information about the current file version to the history object
|
||||
'currentVersion': version,
|
||||
'history': hist
|
||||
}
|
||||
|
||||
return { 'history': histObj, 'historyData': histData }
|
||||
return {'history': histObj, 'historyData': histData}
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
@ -21,18 +21,22 @@ from src.configuration import ConfigurationManager
|
||||
|
||||
config_manager = ConfigurationManager()
|
||||
|
||||
|
||||
# check if a secret key to generate token exists or not
|
||||
def isEnabled():
|
||||
return bool(config_manager.jwt_secret())
|
||||
|
||||
|
||||
# check if a secret key to generate token exists or not
|
||||
def useForRequest():
|
||||
return config_manager.jwt_use_for_request()
|
||||
|
||||
|
||||
# encode a payload object into a token using a secret key and decodes it into the utf-8 format
|
||||
def encode(payload):
|
||||
return jwt.encode(payload, config_manager.jwt_secret(), algorithm='HS256')
|
||||
|
||||
|
||||
# decode a token into a payload object using a secret key
|
||||
def decode(string):
|
||||
return jwt.decode(string, config_manager.jwt_secret(), algorithms=['HS256'])
|
||||
return jwt.decode(string, config_manager.jwt_secret(), algorithms=['HS256'])
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
|
||||
"""
|
||||
|
||||
import json
|
||||
import requests
|
||||
|
||||
from src.configuration import ConfigurationManager
|
||||
@ -24,14 +23,15 @@ from . import fileUtils, jwtManager
|
||||
|
||||
config_manager = ConfigurationManager()
|
||||
|
||||
|
||||
# convert file and give url to a new file
|
||||
def getConvertedData(docUri, fromExt, toExt, docKey, isAsync, filePass = None, lang = None):
|
||||
if not fromExt: # check if the extension from the request matches the real file extension
|
||||
fromExt = fileUtils.getFileExt(docUri) # if not, overwrite the extension value
|
||||
def getConvertedData(docUri, fromExt, toExt, docKey, isAsync, filePass=None, lang=None):
|
||||
if not fromExt: # check if the extension from the request matches the real file extension
|
||||
fromExt = fileUtils.getFileExt(docUri) # if not, overwrite the extension value
|
||||
|
||||
title = fileUtils.getFileName(docUri)
|
||||
|
||||
payload = { # write all the necessary data to the payload object
|
||||
payload = { # write all the necessary data to the payload object
|
||||
'url': docUri,
|
||||
'outputtype': toExt.replace('.', ''),
|
||||
'filetype': fromExt.replace('.', ''),
|
||||
@ -41,24 +41,27 @@ def getConvertedData(docUri, fromExt, toExt, docKey, isAsync, filePass = None, l
|
||||
'region': lang
|
||||
}
|
||||
|
||||
headers={'accept': 'application/json'}
|
||||
headers = {'accept': 'application/json'}
|
||||
|
||||
if (isAsync): # check if the operation is asynchronous
|
||||
payload.setdefault('async', True) # and write this information to the payload object
|
||||
if isAsync: # check if the operation is asynchronous
|
||||
payload.setdefault('async', True) # and write this information to the payload object
|
||||
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # check if a secret key to generate token exists or not
|
||||
headerToken = jwtManager.encode({'payload': payload}) # encode a payload object into a header token
|
||||
payload['token'] = jwtManager.encode(payload) # encode a payload object into a body token
|
||||
headers[config_manager.jwt_header()] = f'Bearer {headerToken}' # add a header Authorization with a header token with Authorization prefix in it
|
||||
|
||||
response = requests.post(config_manager.document_server_converter_url().geturl(), json=payload, headers=headers, verify = config_manager.ssl_verify_peer_mode_enabled(), timeout=5) # send the headers and body values to the converter and write the result to the response
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # check if a secret key to generate token exists or not
|
||||
headerToken = jwtManager.encode({'payload': payload}) # encode a payload object into a header token
|
||||
payload['token'] = jwtManager.encode(payload) # encode a payload object into a body token
|
||||
# add a header Authorization with a header token with Authorization prefix in it
|
||||
headers[config_manager.jwt_header()] = f'Bearer {headerToken}'
|
||||
# send the headers and body values to the converter and write the result to the response
|
||||
response = requests.post(config_manager.document_server_converter_url().geturl(), json=payload, headers=headers,
|
||||
verify=config_manager.ssl_verify_peer_mode_enabled(), timeout=5)
|
||||
status_code = response.status_code
|
||||
if status_code != 200: # checking status code
|
||||
raise RuntimeError('Convertation service returned status: %s' % status_code)
|
||||
raise RuntimeError(f'Convertation service returned status: {status_code}')
|
||||
json = response.json()
|
||||
|
||||
return getResponseUri(json)
|
||||
|
||||
|
||||
# get response url
|
||||
def getResponseUri(json):
|
||||
isEnd = json.get('endConvert')
|
||||
@ -67,7 +70,8 @@ def getResponseUri(json):
|
||||
processError(error)
|
||||
|
||||
if isEnd:
|
||||
return { 'uri': json.get('fileUrl'), 'fileType': json.get('fileType') }
|
||||
return {'uri': json.get('fileUrl'), 'fileType': json.get('fileType')}
|
||||
|
||||
|
||||
# display an error that occurs during conversion
|
||||
def processError(error):
|
||||
@ -84,4 +88,4 @@ def processError(error):
|
||||
'-1': f'{prefix}Error convertation unknown'
|
||||
}
|
||||
|
||||
raise Exception(mapping.get(str(error), f'Error Code: {error}'))
|
||||
raise Exception(mapping.get(str(error), f'Error Code: {error}'))
|
||||
|
||||
@ -28,101 +28,110 @@ from . import jwtManager, docManager, historyManager, fileUtils, serviceConverte
|
||||
config_manager = ConfigurationManager()
|
||||
proxy_manager = ProxyManager(config_manager=config_manager)
|
||||
|
||||
|
||||
# read request body
|
||||
def readBody(request):
|
||||
body = json.loads(request.body)
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # if the secret key to generate token exists
|
||||
token = body.get('token') # get the document token
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # if the secret key to generate token exists
|
||||
token = body.get('token') # get the document token
|
||||
|
||||
if (not token): # if JSON web token is not received
|
||||
token = request.headers.get(config_manager.jwt_header()) # get it from the Authorization header
|
||||
if not token: # if JSON web token is not received
|
||||
token = request.headers.get(config_manager.jwt_header()) # get it from the Authorization header
|
||||
if token:
|
||||
token = token[len('Bearer '):] # and save it without Authorization prefix
|
||||
token = token[len('Bearer '):] # and save it without Authorization prefix
|
||||
|
||||
if (not token): # if the token is not received
|
||||
raise Exception('Expected JWT') # an error occurs
|
||||
if not token: # if the token is not received
|
||||
raise Exception('Expected JWT') # an error occurs
|
||||
|
||||
body = jwtManager.decode(token)
|
||||
if (body.get('payload')): # get the payload object from the request body
|
||||
if body.get('payload'): # get the payload object from the request body
|
||||
body = body['payload']
|
||||
return body
|
||||
|
||||
|
||||
# file saving process
|
||||
def processSave(raw_body, filename, usAddr):
|
||||
body = resolve_process_save_body(raw_body)
|
||||
|
||||
download = body.get('url')
|
||||
if (download is None):
|
||||
if download is None:
|
||||
raise Exception("DownloadUrl is null")
|
||||
changesUri = body.get('changesurl')
|
||||
newFilename = filename
|
||||
|
||||
curExt = fileUtils.getFileExt(filename) # get current file extension
|
||||
curExt = fileUtils.getFileExt(filename) # get current file extension
|
||||
|
||||
downloadExt = "." + body.get('filetype') # get the extension of the downloaded file
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
if (curExt != downloadExt):
|
||||
if curExt != downloadExt:
|
||||
try:
|
||||
convertedData = serviceConverter.getConvertedData(download, downloadExt, curExt, docManager.generateRevisionId(download), False) # convert file and give url to a new file
|
||||
# convert file and give url to a new file
|
||||
convertedData = serviceConverter.getConvertedData(download, downloadExt, curExt,
|
||||
docManager.generateRevisionId(download), False)
|
||||
if not convertedData:
|
||||
newFilename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + downloadExt, usAddr) # get the correct file name if it already exists
|
||||
newFilename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + downloadExt,
|
||||
usAddr) # get the correct file name if it already exists
|
||||
else:
|
||||
download = convertedData['uri']
|
||||
except Exception:
|
||||
newFilename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + downloadExt, usAddr)
|
||||
|
||||
path = docManager.getStoragePath(newFilename, usAddr) # get the file path
|
||||
path = docManager.getStoragePath(newFilename, usAddr) # get the file path
|
||||
|
||||
data = docManager.downloadFileFromUri(download) # download document file
|
||||
if (data is None):
|
||||
if data is None:
|
||||
raise Exception("Downloaded document is null")
|
||||
|
||||
histDir = historyManager.getHistoryDir(path) # get the path to the history direction
|
||||
if not os.path.exists(histDir): # if the path doesn't exist
|
||||
os.makedirs(histDir) # create it
|
||||
histDir = historyManager.getHistoryDir(path) # get the path to the history direction
|
||||
if not os.path.exists(histDir): # if the path doesn't exist
|
||||
os.makedirs(histDir) # create it
|
||||
|
||||
versionDir = historyManager.getNextVersionDir(histDir) # get the path to the next file version
|
||||
versionDir = historyManager.getNextVersionDir(histDir) # get the path to the next file version
|
||||
|
||||
os.rename(docManager.getStoragePath(filename, usAddr), historyManager.getPrevFilePath(versionDir, curExt)) # get the path to the previous file version and rename the storage path with it
|
||||
# get the path to the previous file version and rename the storage path with it
|
||||
os.rename(docManager.getStoragePath(filename, usAddr), historyManager.getPrevFilePath(versionDir, curExt))
|
||||
|
||||
docManager.saveFile(data, path) # save document file
|
||||
|
||||
dataChanges = docManager.downloadFileFromUri(changesUri) # download changes file
|
||||
if (dataChanges is None):
|
||||
dataChanges = docManager.downloadFileFromUri(changesUri) # download changes file
|
||||
if dataChanges is None:
|
||||
raise Exception("Downloaded changes is null")
|
||||
docManager.saveFile(dataChanges, historyManager.getChangesZipPath(versionDir)) # save file changes to the diff.zip archive
|
||||
# save file changes to the diff.zip archive
|
||||
docManager.saveFile(dataChanges, historyManager.getChangesZipPath(versionDir))
|
||||
|
||||
hist = None
|
||||
hist = body.get('changeshistory')
|
||||
if (not hist) & ('history' in body):
|
||||
hist = json.dumps(body.get('history'))
|
||||
if hist:
|
||||
historyManager.writeFile(historyManager.getChangesHistoryPath(versionDir), hist) # write the history changes to the changes.json file
|
||||
# write the history changes to the changes.json file
|
||||
historyManager.writeFile(historyManager.getChangesHistoryPath(versionDir), hist)
|
||||
# write the key value to the key.txt file
|
||||
historyManager.writeFile(historyManager.getKeyPath(versionDir), body.get('key'))
|
||||
# get the path to the forcesaved file version
|
||||
forcesavePath = docManager.getForcesavePath(newFilename, usAddr, False)
|
||||
if forcesavePath != "": # if the forcesaved file version exists
|
||||
os.remove(forcesavePath) # remove it
|
||||
|
||||
historyManager.writeFile(historyManager.getKeyPath(versionDir), body.get('key')) # write the key value to the key.txt file
|
||||
|
||||
forcesavePath = docManager.getForcesavePath(newFilename, usAddr, False) # get the path to the forcesaved file version
|
||||
if (forcesavePath != ""): # if the forcesaved file version exists
|
||||
os.remove(forcesavePath) # remove it
|
||||
|
||||
return
|
||||
|
||||
# file force saving process
|
||||
def processForceSave(body, filename, usAddr):
|
||||
download = body.get('url')
|
||||
if (download is None):
|
||||
if download is None:
|
||||
raise Exception("DownloadUrl is null")
|
||||
curExt = fileUtils.getFileExt(filename) # get current file extension
|
||||
curExt = fileUtils.getFileExt(filename) # get current file extension
|
||||
|
||||
downloadExt = "." + body.get('filetype') # get the extension of the downloaded file
|
||||
|
||||
newFilename = False
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
if (curExt != downloadExt):
|
||||
if curExt != downloadExt:
|
||||
try:
|
||||
convertedData = serviceConverter.getConvertedData(download, downloadExt, curExt, docManager.generateRevisionId(download), False) # convert file and give url to a new file
|
||||
# convert file and give url to a new file
|
||||
convertedData = serviceConverter.getConvertedData(download, downloadExt, curExt,
|
||||
docManager.generateRevisionId(download), False)
|
||||
if not convertedData:
|
||||
newFilename = True
|
||||
else:
|
||||
@ -131,56 +140,59 @@ def processForceSave(body, filename, usAddr):
|
||||
newFilename = True
|
||||
|
||||
data = docManager.downloadFileFromUri(download) # download document file
|
||||
if (data is None):
|
||||
if data is None:
|
||||
raise Exception("Downloaded document is null")
|
||||
|
||||
isSubmitForm = body.get('forcesavetype') == 3 # SubmitForm
|
||||
isSubmitForm = body.get('forcesavetype') == 3 # SubmitForm
|
||||
|
||||
if(isSubmitForm):
|
||||
if (newFilename):
|
||||
filename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + "-form" + downloadExt, usAddr) # get the correct file name if it already exists
|
||||
else :
|
||||
if isSubmitForm:
|
||||
if newFilename:
|
||||
filename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + "-form" + downloadExt,
|
||||
usAddr) # get the correct file name if it already exists
|
||||
else:
|
||||
filename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + "-form" + curExt, usAddr)
|
||||
forcesavePath = docManager.getStoragePath(filename, usAddr)
|
||||
else:
|
||||
if (newFilename):
|
||||
if newFilename:
|
||||
filename = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + downloadExt, usAddr)
|
||||
forcesavePath = docManager.getForcesavePath(filename, usAddr, False)
|
||||
if (forcesavePath == ""):
|
||||
if forcesavePath == "":
|
||||
forcesavePath = docManager.getForcesavePath(filename, usAddr, True)
|
||||
|
||||
docManager.saveFile(download, forcesavePath) # save document file
|
||||
docManager.saveFile(download, forcesavePath) # save document file
|
||||
|
||||
if isSubmitForm:
|
||||
uid = body['actions'][0]['userid'] # get the user id
|
||||
historyManager.createMetaData(filename, uid, "Filling Form", usAddr) # create meta data for forcesaved file
|
||||
|
||||
if(isSubmitForm):
|
||||
uid = body['actions'][0]['userid'] # get the user id
|
||||
historyManager.createMetaData(filename, uid, "Filling Form", usAddr) # create meta data for forcesaved file
|
||||
return
|
||||
|
||||
# create a command request
|
||||
def commandRequest(method, key, meta = None):
|
||||
def commandRequest(method, key, meta=None):
|
||||
payload = {
|
||||
'c': method,
|
||||
'key': key
|
||||
}
|
||||
|
||||
if (meta):
|
||||
if meta:
|
||||
payload['meta'] = meta
|
||||
|
||||
headers = {'accept': 'application/json'}
|
||||
|
||||
headers={'accept': 'application/json'}
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # check if a secret key to generate token exists or not
|
||||
headerToken = jwtManager.encode({'payload': payload}) # encode a payload object into a header token
|
||||
# add a header Authorization with a header token with Authorization prefix in it
|
||||
headers[config_manager.jwt_header()] = f'Bearer {headerToken}'
|
||||
|
||||
if (jwtManager.isEnabled() and jwtManager.useForRequest()): # check if a secret key to generate token exists or not
|
||||
headerToken = jwtManager.encode({'payload': payload}) # encode a payload object into a header token
|
||||
headers[config_manager.jwt_header()] = f'Bearer {headerToken}' # add a header Authorization with a header token with Authorization prefix in it
|
||||
payload['token'] = jwtManager.encode(payload) # encode a payload object into a body token
|
||||
response = requests.post(config_manager.document_server_command_url().geturl(), json=payload, headers=headers,
|
||||
verify=config_manager.ssl_verify_peer_mode_enabled(), timeout=5)
|
||||
|
||||
payload['token'] = jwtManager.encode(payload) # encode a payload object into a body token
|
||||
response = requests.post(config_manager.document_server_command_url().geturl(), json=payload, headers=headers, verify = config_manager.ssl_verify_peer_mode_enabled())
|
||||
|
||||
if (meta):
|
||||
if meta:
|
||||
return response
|
||||
|
||||
return
|
||||
|
||||
|
||||
def resolve_process_save_body(body):
|
||||
copied = deepcopy(body)
|
||||
|
||||
|
||||
@ -18,9 +18,11 @@
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class User:
|
||||
def __init__(self, id, name, email, group, reviewGroups, commentGroups, userInfoGroups, favorite, deniedPermissions, descriptions, templates):
|
||||
self.id = id
|
||||
def __init__(self, uid, name, email, group, reviewGroups, commentGroups, userInfoGroups, favorite,
|
||||
deniedPermissions, descriptions, templates):
|
||||
self.id = uid
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.group = group
|
||||
@ -32,6 +34,7 @@ class User:
|
||||
self.templates = templates
|
||||
self.userInfoGroups = userInfoGroups
|
||||
|
||||
|
||||
descr_user_1 = [
|
||||
"File author by default",
|
||||
"Doesn’t belong to any group",
|
||||
@ -45,7 +48,8 @@ descr_user_1 = [
|
||||
descr_user_2 = [
|
||||
"Belongs to Group2",
|
||||
"Can review only his own changes or changes made by users with no group",
|
||||
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
|
||||
("Can view comments, edit his own comments and comments left by users with no group."
|
||||
"Can remove his own comments only"),
|
||||
"This file is marked as favorite",
|
||||
"Can create new files from the editor",
|
||||
"Can see the information about users from Group2 and users who don’t belong to any group"
|
||||
@ -80,57 +84,61 @@ descr_user_0 = [
|
||||
|
||||
USERS = [
|
||||
User('uid-1', 'John Smith', 'smith@example.com',
|
||||
'', None, {}, None,
|
||||
None, [], descr_user_1, True),
|
||||
'', None, {}, None,
|
||||
None, [], descr_user_1, True),
|
||||
User('uid-2', 'Mark Pottato', 'pottato@example.com',
|
||||
'group-2', ['group-2', ''], {
|
||||
'view': "",
|
||||
'edit': ["group-2", ""],
|
||||
'remove': ["group-2"]
|
||||
},
|
||||
'group-2', ['group-2', ''], {
|
||||
'view': "",
|
||||
'edit': ["group-2", ""],
|
||||
'remove': ["group-2"]
|
||||
},
|
||||
['group-2', ''],
|
||||
True, [], descr_user_2, False),
|
||||
True, [], descr_user_2, False),
|
||||
User('uid-3', 'Hamish Mitchell', 'mitchell@example.com',
|
||||
'group-3', ['group-2'], {
|
||||
'view': ["group-3", "group-2"],
|
||||
'edit': ["group-2"],
|
||||
'remove': []
|
||||
}, ['group-2'],
|
||||
False, ["copy", "download", "print"], descr_user_3, False),
|
||||
'group-3', ['group-2'], {
|
||||
'view': ["group-3", "group-2"],
|
||||
'edit': ["group-2"],
|
||||
'remove': []
|
||||
}, ['group-2'],
|
||||
False, ["copy", "download", "print"], descr_user_3, False),
|
||||
User('uid-0', None, None,
|
||||
'', None, {}, [],
|
||||
None, ["protect"], descr_user_0, False)
|
||||
'', None, {}, [],
|
||||
None, ["protect"], descr_user_0, False)
|
||||
]
|
||||
|
||||
DEFAULT_USER = USERS[0]
|
||||
|
||||
|
||||
# get all users
|
||||
def getAllUsers():
|
||||
return USERS
|
||||
|
||||
|
||||
# get user information from the request
|
||||
def getUserFromReq(req):
|
||||
uid = req.COOKIES.get('uid')
|
||||
|
||||
for user in USERS:
|
||||
if (user.id == uid):
|
||||
if user.id == uid:
|
||||
return user
|
||||
|
||||
return DEFAULT_USER
|
||||
|
||||
|
||||
# get users data for mentions
|
||||
def getUsersForMentions(uid):
|
||||
usersData = []
|
||||
for user in USERS:
|
||||
if(user.id != uid and user.name != None and user.email != None):
|
||||
usersData.append({'name':user.name, 'email':user.email})
|
||||
if (user.id != uid and user.name is not None and user.email is not None):
|
||||
usersData.append({'name': user.name, 'email': user.email})
|
||||
return usersData
|
||||
|
||||
def find_user(id: Optional[str]) -> User:
|
||||
if id is None:
|
||||
|
||||
def find_user(searchId: Optional[str]) -> User:
|
||||
if searchId is None:
|
||||
return DEFAULT_USER
|
||||
for user in USERS:
|
||||
if not user.id == id:
|
||||
if not user.id == searchId:
|
||||
continue
|
||||
return user
|
||||
return DEFAULT_USER
|
||||
|
||||
@ -32,23 +32,27 @@ from src.utils import docManager, fileUtils, serviceConverter, users, jwtManager
|
||||
|
||||
config_manager = ConfigurationManager()
|
||||
|
||||
|
||||
# upload a file from the document storage service to the document editing service
|
||||
def upload(request):
|
||||
response = {}
|
||||
|
||||
try:
|
||||
fileInfo = request.FILES['uploadedFile']
|
||||
if ((fileInfo.size > config_manager.maximum_file_size()) | (fileInfo.size <= 0)): # check if the file size exceeds the maximum size allowed (5242880)
|
||||
# check if the file size exceeds the maximum size allowed (5242880)
|
||||
if (fileInfo.size > config_manager.maximum_file_size()) | (fileInfo.size <= 0):
|
||||
raise Exception('File size is incorrect')
|
||||
|
||||
curExt = fileUtils.getFileExt(fileInfo.name)
|
||||
if not docManager.isSupportedExt(curExt): # check if the file extension is supported by the document manager
|
||||
raise Exception('File type is not supported')
|
||||
|
||||
name = docManager.getCorrectName(fileInfo.name, request) # get file name with an index if such a file name already exists
|
||||
# get file name with an index if such a file name already exists
|
||||
name = docManager.getCorrectName(fileInfo.name, request)
|
||||
path = docManager.getStoragePath(name, request)
|
||||
|
||||
docManager.createFile(fileInfo.file, path, request, True) # create file with meta information in the storage directory
|
||||
# create file with meta information in the storage directory
|
||||
docManager.createFile(fileInfo.file, path, request, True)
|
||||
|
||||
response.setdefault('filename', name)
|
||||
response.setdefault('documentType', fileUtils.getFileType(name))
|
||||
@ -58,6 +62,7 @@ def upload(request):
|
||||
|
||||
return HttpResponse(json.dumps(response), content_type='application/json') # return http response in json format
|
||||
|
||||
|
||||
# convert a file from one format to another
|
||||
def convert(request):
|
||||
response = {}
|
||||
@ -67,32 +72,39 @@ def convert(request):
|
||||
filename = fileUtils.getFileName(body.get("filename"))
|
||||
filePass = body.get("filePass")
|
||||
lang = request.COOKIES.get('ulang') if request.COOKIES.get('ulang') else 'en'
|
||||
fileUri = docManager.getDownloadUrl(filename,request)
|
||||
fileUri = docManager.getDownloadUrl(filename, request)
|
||||
fileExt = fileUtils.getFileExt(filename)
|
||||
newExt = 'ooxml' # convert to .ooxml
|
||||
|
||||
if docManager.isCanConvert(fileExt): # check if the file extension is available for converting
|
||||
key = docManager.generateFileKey(filename, request) # generate the file key
|
||||
|
||||
convertedData = serviceConverter.getConvertedData(fileUri, fileExt, newExt, key, True, filePass, lang) # get the url of the converted file
|
||||
# get the url of the converted file
|
||||
convertedData = serviceConverter.getConvertedData(fileUri, fileExt, newExt, key, True, filePass, lang)
|
||||
|
||||
if not convertedData: # if the converter url is not received, the original file name is passed to the response
|
||||
# if the converter url is not received, the original file name is passed to the response
|
||||
if not convertedData:
|
||||
response.setdefault('step', '0')
|
||||
response.setdefault('filename', filename)
|
||||
else:
|
||||
correctName = docManager.getCorrectName(fileUtils.getFileNameWithoutExt(filename) + '.' + convertedData['fileType'], request) # otherwise, create a new name with the necessary extension
|
||||
correctName = docManager.getCorrectName(
|
||||
fileUtils.getFileNameWithoutExt(filename) + '.' + convertedData['fileType'], request
|
||||
) # otherwise, create a new name with the necessary extension
|
||||
path = docManager.getStoragePath(correctName, request)
|
||||
docManager.downloadFileFromUri(convertedData['uri'], path, True) # save the file from the new url in the storage directory
|
||||
# save the file from the new url in the storage directory
|
||||
docManager.downloadFileFromUri(convertedData['uri'], path, True)
|
||||
docManager.removeFile(filename, request) # remove the original file
|
||||
response.setdefault('filename', correctName) # pass the name of the converted file to the response
|
||||
else:
|
||||
response.setdefault('filename', filename) # if the file can't be converted, the original file name is passed to the response
|
||||
# if the file can't be converted, the original file name is passed to the response
|
||||
response.setdefault('filename', filename)
|
||||
|
||||
except Exception as e:
|
||||
response.setdefault('error', e.args[0])
|
||||
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# create a new file
|
||||
def createNew(request):
|
||||
response = {}
|
||||
@ -110,6 +122,7 @@ def createNew(request):
|
||||
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# save file as...
|
||||
def saveAs(request):
|
||||
response = {}
|
||||
@ -121,9 +134,10 @@ def saveAs(request):
|
||||
|
||||
filename = docManager.getCorrectName(title, request)
|
||||
path = docManager.getStoragePath(filename, request)
|
||||
resp = requests.get(saveAsFileUrl, verify = config_manager.ssl_verify_peer_mode_enabled())
|
||||
resp = requests.get(saveAsFileUrl, verify=config_manager.ssl_verify_peer_mode_enabled(), timeout=5)
|
||||
|
||||
if ((len(resp.content) > config_manager.maximum_file_size()) | (len(resp.content) <= 0)): # check if the file size exceeds the maximum size allowed (5242880)
|
||||
# check if the file size exceeds the maximum size allowed (5242880)
|
||||
if (len(resp.content) > config_manager.maximum_file_size()) | (len(resp.content) <= 0):
|
||||
response.setdefault('error', 'File size is incorrect')
|
||||
raise Exception('File size is incorrect')
|
||||
|
||||
@ -132,7 +146,8 @@ def saveAs(request):
|
||||
response.setdefault('error', 'File type is not supported')
|
||||
raise Exception('File type is not supported')
|
||||
|
||||
docManager.downloadFileFromUri(saveAsFileUrl, path, True) # save the file from the new url in the storage directory
|
||||
# save the file from the new url in the storage directory
|
||||
docManager.downloadFileFromUri(saveAsFileUrl, path, True)
|
||||
|
||||
response.setdefault('file', filename)
|
||||
except Exception as e:
|
||||
@ -141,6 +156,7 @@ def saveAs(request):
|
||||
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# rename file
|
||||
def rename(request):
|
||||
response = {}
|
||||
@ -150,7 +166,7 @@ def rename(request):
|
||||
|
||||
origExt = '.' + body['ext']
|
||||
curExt = fileUtils.getFileExt(newfilename)
|
||||
if (origExt != curExt):
|
||||
if origExt != curExt:
|
||||
newfilename += origExt
|
||||
|
||||
dockey = body['dockey']
|
||||
@ -162,32 +178,36 @@ def rename(request):
|
||||
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# edit a file
|
||||
def edit(request):
|
||||
filename = fileUtils.getFileName(request.GET['filename'])
|
||||
isEnableDirectUrl = request.GET['directUrl'].lower() in ("true") if 'directUrl' in request.GET else False
|
||||
isEnableDirectUrl = request.GET['directUrl'].lower() in ("true") if 'directUrl' in request.GET else False
|
||||
|
||||
ext = fileUtils.getFileExt(filename)
|
||||
|
||||
fileUri = docManager.getFileUri(filename, True, request)
|
||||
fileUriUser = docManager.getDownloadUrl(filename, request) + "&dmode=emb"
|
||||
directUrl = docManager.getDownloadUrl(filename, request, False)
|
||||
docKey = docManager.generateFileKey(filename, request)
|
||||
fileType = fileUtils.getFileType(filename)
|
||||
user = users.getUserFromReq(request) # get user
|
||||
|
||||
edMode = request.GET.get('mode') if request.GET.get('mode') else 'edit' # get the editor mode: view/edit/review/comment/fillForms/embedded (the default mode is edit)
|
||||
# get the editor mode: view/edit/review/comment/fillForms/embedded (the default mode is edit)
|
||||
edMode = request.GET.get('mode') if request.GET.get('mode') else 'edit'
|
||||
canEdit = docManager.isCanEdit(ext) # check if the file with this extension can be edited
|
||||
|
||||
if (((not canEdit) and edMode == 'edit') or edMode == 'fillForms') and docManager.isCanFillForms(ext) :
|
||||
if (((not canEdit) and edMode == 'edit') or edMode == 'fillForms') and docManager.isCanFillForms(ext):
|
||||
edMode = 'fillForms'
|
||||
canEdit = True
|
||||
submitForm = edMode == 'fillForms' and user.id == 'uid-1' and False # if the Submit form button is displayed or hidden
|
||||
# if the Submit form button is displayed or hidden
|
||||
submitForm = edMode == 'fillForms' and user.id == 'uid-1' and False
|
||||
mode = 'edit' if canEdit & (edMode != 'view') else 'view' # if the file can't be edited, the mode is view
|
||||
|
||||
types = ['desktop', 'mobile', 'embedded']
|
||||
edType = request.GET.get('type') if request.GET.get('type') in types else 'desktop' # get the editor type: embedded/mobile/desktop (the default type is desktop)
|
||||
lang = request.COOKIES.get('ulang') if request.COOKIES.get('ulang') else 'en' # get the editor language (the default language is English)
|
||||
# get the editor type: embedded/mobile/desktop (the default type is desktop)
|
||||
edType = request.GET.get('type') if request.GET.get('type') in types else 'desktop'
|
||||
# get the editor language (the default language is English)
|
||||
lang = request.COOKIES.get('ulang') if request.COOKIES.get('ulang') else 'en'
|
||||
|
||||
storagePath = docManager.getStoragePath(filename, request)
|
||||
meta = historyManager.getMeta(storagePath) # get the document meta data
|
||||
@ -196,7 +216,8 @@ def edit(request):
|
||||
actionData = request.GET.get('actionLink') # get the action data that will be scrolled to (comment or bookmark)
|
||||
actionLink = json.loads(actionData) if actionData else None
|
||||
|
||||
templatesImageUrl = docManager.getTemplateImageUrl(fileType, request) # templates image url in the "From Template" section
|
||||
# templates image url in the "From Template" section
|
||||
templatesImageUrl = docManager.getTemplateImageUrl(fileType, request)
|
||||
createUrl = docManager.getCreateUrl(edType, request)
|
||||
templates = [
|
||||
{
|
||||
@ -211,7 +232,7 @@ def edit(request):
|
||||
}
|
||||
]
|
||||
|
||||
if (meta): # if the document meta data exists,
|
||||
if meta: # if the document meta data exists,
|
||||
infObj = { # write author and creation time parameters to the information object
|
||||
'owner': meta['uname'],
|
||||
'uploaded': meta['created']
|
||||
@ -234,24 +255,28 @@ def edit(request):
|
||||
'key': docKey,
|
||||
'info': infObj,
|
||||
'permissions': { # the permission for the document to be edited and downloaded or not
|
||||
'comment': (edMode != 'view') & (edMode != 'fillForms') & (edMode != 'embedded') & (edMode != "blockcontent"),
|
||||
'comment': (edMode != 'view') & (edMode != 'fillForms') & (edMode != 'embedded') \
|
||||
& (edMode != "blockcontent"),
|
||||
'copy': 'copy' not in user.deniedPermissions,
|
||||
'download': 'download' not in user.deniedPermissions,
|
||||
'edit': canEdit & ((edMode == 'edit') | (edMode == 'view') | (edMode == 'filter') | (edMode == "blockcontent")),
|
||||
'edit': canEdit & ((edMode == 'edit') | (edMode == 'view') | (edMode == 'filter') \
|
||||
| (edMode == "blockcontent")),
|
||||
'print': 'print' not in user.deniedPermissions,
|
||||
'fillForms': (edMode != 'view') & (edMode != 'comment') & (edMode != 'embedded') & (edMode != "blockcontent"),
|
||||
'fillForms': (edMode != 'view') & (edMode != 'comment') & (edMode != 'embedded') \
|
||||
& (edMode != "blockcontent"),
|
||||
'modifyFilter': edMode != 'filter',
|
||||
'modifyContentControl': edMode != "blockcontent",
|
||||
'review': canEdit & ((edMode == 'edit') | (edMode == 'review')),
|
||||
'chat': user.id !='uid-0',
|
||||
'chat': user.id != 'uid-0',
|
||||
'reviewGroups': user.reviewGroups,
|
||||
'commentGroups': user.commentGroups,
|
||||
'userInfoGroups': user.userInfoGroups,
|
||||
'protect': 'protect' not in user.deniedPermissions
|
||||
},
|
||||
'referenceData' : {
|
||||
'instanceId' : docManager.getServerUrl(False, request),
|
||||
'fileKey' : json.dumps({'fileName' : filename, 'userAddress': request.META['REMOTE_ADDR']}) if user.id !='uid-0' else None
|
||||
'referenceData': {
|
||||
'instanceId': docManager.getServerUrl(False, request),
|
||||
'fileKey': json.dumps({'fileName': filename,
|
||||
'userAddress': request.META['REMOTE_ADDR']}) if user.id != 'uid-0' else None
|
||||
}
|
||||
},
|
||||
'editorConfig': {
|
||||
@ -260,31 +285,35 @@ def edit(request):
|
||||
'lang': lang,
|
||||
'callbackUrl': docManager.getCallbackUrl(filename, request), # absolute URL to the document storage service
|
||||
'coEditing': {
|
||||
"mode": "strict",
|
||||
"change": False
|
||||
}
|
||||
if edMode == 'view' and user.id =='uid-0' else None,
|
||||
'createUrl' : createUrl if user.id !='uid-0' else None,
|
||||
'templates' : templates if user.templates else None,
|
||||
"mode": "strict",
|
||||
"change": False
|
||||
}
|
||||
if edMode == 'view' and user.id == 'uid-0' else None,
|
||||
'createUrl': createUrl if user.id != 'uid-0' else None,
|
||||
'templates': templates if user.templates else None,
|
||||
'user': { # the user currently viewing or editing the document
|
||||
'id': user.id if user.id !='uid-0' else None,
|
||||
'id': user.id if user.id != 'uid-0' else None,
|
||||
'name': user.name,
|
||||
'group': user.group
|
||||
},
|
||||
'embedded': { # the parameters for the embedded document type
|
||||
'saveUrl': directUrl, # the absolute URL that will allow the document to be saved onto the user personal computer
|
||||
'embedUrl': directUrl, # the absolute URL to the document serving as a source file for the document embedded into the web page
|
||||
# the absolute URL that will allow the document to be saved onto the user personal computer
|
||||
'saveUrl': directUrl,
|
||||
# the absolute URL to the document serving as a source file for the document embedded into the web page
|
||||
'embedUrl': directUrl,
|
||||
'shareUrl': directUrl, # the absolute URL that will allow other users to share this document
|
||||
'toolbarDocked': 'top' # the place for the embedded viewer toolbar (top or bottom)
|
||||
},
|
||||
'customization': { # the parameters for the editor interface
|
||||
'about': True, # the About section display
|
||||
'comments': True,
|
||||
'comments': True,
|
||||
'feedback': True, # the Feedback & Support menu button display
|
||||
'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': { # settings for the Open file location menu button and upper right corner button
|
||||
'url': docManager.getServerUrl(False, request) # the absolute URL to the website address which will be opened when clicking the Open file location menu button
|
||||
'goback': { # settings for the Open file location menu button and upper right corner button
|
||||
# the absolute URL to the website address
|
||||
# which will be opened when clicking the Open file location menu button
|
||||
'url': docManager.getServerUrl(False, request)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,7 +350,7 @@ def edit(request):
|
||||
}
|
||||
|
||||
# users data for mentions
|
||||
usersForMentions = users.getUsersForMentions(user.id)
|
||||
usersForMentions = users.getUsersForMentions(user.id)
|
||||
|
||||
if jwtManager.isEnabled(): # if the secret key to generate token exists
|
||||
edConfig['token'] = jwtManager.encode(edConfig) # encode the edConfig object into a token
|
||||
@ -329,21 +358,26 @@ def edit(request):
|
||||
dataDocument['token'] = jwtManager.encode(dataDocument) # encode the dataDocument object into a token
|
||||
dataSpreadsheet['token'] = jwtManager.encode(dataSpreadsheet) # encode the dataSpreadsheet object into a token
|
||||
|
||||
hist = historyManager.getHistoryObject(storagePath, filename, docKey, fileUri, isEnableDirectUrl, request) # get the document history
|
||||
# get the document history
|
||||
hist = historyManager.getHistoryObject(storagePath, filename, docKey, fileUri, isEnableDirectUrl, request)
|
||||
|
||||
context = { # the data that will be passed to the template
|
||||
'cfg': json.dumps(edConfig), # the document config in json format
|
||||
'history': json.dumps(hist['history']) if 'history' in hist else None, # the information about the current version
|
||||
'historyData': json.dumps(hist['historyData']) if 'historyData' in hist else None, # the information about the previous document versions if they exist
|
||||
# the information about the current version
|
||||
'history': json.dumps(hist['history']) if 'history' in hist else None,
|
||||
# the information about the previous document versions if they exist
|
||||
'historyData': json.dumps(hist['historyData']) if 'historyData' in hist else None,
|
||||
'fileType': fileType, # the file type of the document (text, spreadsheet or presentation)
|
||||
'apiUrl': config_manager.document_server_api_url().geturl(), # the absolute URL to the api
|
||||
'dataInsertImage': json.dumps(dataInsertImage)[1 : len(json.dumps(dataInsertImage)) - 1], # the image which will be inserted into the document
|
||||
# the image which will be inserted into the document
|
||||
'dataInsertImage': json.dumps(dataInsertImage)[1: len(json.dumps(dataInsertImage)) - 1],
|
||||
'dataDocument': dataDocument, # document which will be compared with the current document
|
||||
'dataSpreadsheet': json.dumps(dataSpreadsheet), # recipient data for mail merging
|
||||
'usersForMentions': json.dumps(usersForMentions) if user.id !='uid-0' else None
|
||||
'usersForMentions': json.dumps(usersForMentions) if user.id != 'uid-0' else None
|
||||
}
|
||||
return render(request, 'editor.html', context) # execute the "editor.html" template with context data
|
||||
|
||||
|
||||
# track the document changes
|
||||
def track(request):
|
||||
response = {}
|
||||
@ -352,11 +386,12 @@ def track(request):
|
||||
body = trackManager.readBody(request) # read request body
|
||||
status = body['status'] # and get status from it
|
||||
|
||||
if (status == 1): # editing
|
||||
if status == 1: # editing
|
||||
if (body['actions'] and body['actions'][0]['type'] == 0): # finished edit
|
||||
user = body['actions'][0]['userid'] # the user who finished editing
|
||||
if (not user in body['users']):
|
||||
trackManager.commandRequest('forcesave', body['key']) # create a command request with the forcasave method
|
||||
if user not in body['users']:
|
||||
# create a command request with the forcasave method
|
||||
trackManager.commandRequest('forcesave', body['key'])
|
||||
|
||||
filename = fileUtils.getFileName(request.GET['filename'])
|
||||
usAddr = request.GET['userAddress']
|
||||
@ -367,12 +402,15 @@ def track(request):
|
||||
trackManager.processForceSave(body, filename, usAddr)
|
||||
|
||||
except Exception as e:
|
||||
response.setdefault("error", 1) # set the default error value as 1 (document key is missing or no document with such key could be found)
|
||||
# set the default error value as 1 (document key is missing or no document with such key could be found)
|
||||
response.setdefault("error", 1)
|
||||
response.setdefault("message", str(e.args[0]))
|
||||
|
||||
response.setdefault('error', 0) # if no exceptions are raised, the default error value is 0 (no errors)
|
||||
# the response status is 200 if the changes are saved successfully; otherwise, it is equal to 500
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=200 if response['error'] == 0 else 500)
|
||||
return HttpResponse(json.dumps(response), content_type='application/json',
|
||||
status=200 if response['error'] == 0 else 500)
|
||||
|
||||
|
||||
# remove a file
|
||||
def remove(request):
|
||||
@ -385,6 +423,7 @@ def remove(request):
|
||||
response.setdefault('success', True)
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# get file information
|
||||
def files(request):
|
||||
try:
|
||||
@ -394,12 +433,14 @@ def files(request):
|
||||
response.setdefault('error', e.args[0])
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# download a csv file
|
||||
def csv(request):
|
||||
def csv():
|
||||
filePath = os.path.join('assets', 'document-templates', 'sample', "csv.csv")
|
||||
response = docManager.download(filePath)
|
||||
return response
|
||||
|
||||
|
||||
# download a file
|
||||
def download(request):
|
||||
try:
|
||||
@ -407,21 +448,22 @@ def download(request):
|
||||
userAddress = request.GET.get('userAddress')
|
||||
isEmbedded = request.GET.get('dmode')
|
||||
|
||||
if (jwtManager.isEnabled() and isEmbedded == None and userAddress and jwtManager.useForRequest()):
|
||||
if (jwtManager.isEnabled() and isEmbedded is None and userAddress and jwtManager.useForRequest()):
|
||||
token = request.headers.get(config_manager.jwt_header())
|
||||
if token:
|
||||
token = token[len('Bearer '):]
|
||||
|
||||
try:
|
||||
body = jwtManager.decode(token)
|
||||
jwtManager.decode(token)
|
||||
except Exception:
|
||||
return HttpResponse('JWT validation failed', status=403)
|
||||
|
||||
if (userAddress == None):
|
||||
if userAddress is None:
|
||||
userAddress = request
|
||||
|
||||
filePath = docManager.getForcesavePath(fileName, userAddress, False) # get the path to the forcesaved file version
|
||||
if (filePath == ""):
|
||||
# get the path to the forcesaved file version
|
||||
filePath = docManager.getForcesavePath(fileName, userAddress, False)
|
||||
if filePath == "":
|
||||
filePath = docManager.getStoragePath(fileName, userAddress) # get file from the storage directory
|
||||
response = docManager.download(filePath) # download this file
|
||||
return response
|
||||
@ -430,6 +472,7 @@ def download(request):
|
||||
response.setdefault('error', 'File not found')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# download a history file
|
||||
def downloadhistory(request):
|
||||
try:
|
||||
@ -439,12 +482,12 @@ def downloadhistory(request):
|
||||
version = fileUtils.getFileName(request.GET['ver'])
|
||||
isEmbedded = request.GET.get('dmode')
|
||||
|
||||
if (jwtManager.isEnabled() and isEmbedded == None and jwtManager.useForRequest()):
|
||||
if (jwtManager.isEnabled() and isEmbedded is None and jwtManager.useForRequest()):
|
||||
token = request.headers.get(config_manager.jwt_header())
|
||||
if token:
|
||||
token = token[len('Bearer '):]
|
||||
try:
|
||||
body = jwtManager.decode(token)
|
||||
jwtManager.decode(token)
|
||||
except Exception:
|
||||
return HttpResponse('JWT validation failed', status=403)
|
||||
else:
|
||||
@ -459,6 +502,7 @@ def downloadhistory(request):
|
||||
response.setdefault('error', 'File not found')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=404)
|
||||
|
||||
|
||||
# referenceData
|
||||
def reference(request):
|
||||
response = {}
|
||||
@ -479,38 +523,39 @@ def reference(request):
|
||||
userAddress = fileKey['userAddress']
|
||||
if userAddress == request.META['REMOTE_ADDR']:
|
||||
fileName = fileKey['fileName']
|
||||
|
||||
|
||||
if fileName is None:
|
||||
try:
|
||||
path = fileUtils.getFileName(body['path'])
|
||||
if os.path.exists(docManager.getStoragePath(path,request)):
|
||||
fileName = path
|
||||
if os.path.exists(docManager.getStoragePath(path, request)):
|
||||
fileName = path
|
||||
except KeyError:
|
||||
response.setdefault('error', 'Path not found')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=404)
|
||||
|
||||
|
||||
if fileName is None:
|
||||
response.setdefault('error', 'File not found')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=404)
|
||||
|
||||
|
||||
data = {
|
||||
'fileType' : fileUtils.getFileExt(fileName).replace('.', ''),
|
||||
'key': docManager.generateFileKey(fileName,request),
|
||||
'url' : docManager.getDownloadUrl(fileName, request),
|
||||
'directUrl' : docManager.getDownloadUrl(fileName, request, False) if body["directUrl"] else None,
|
||||
'referenceData' : {
|
||||
'instanceId' : docManager.getServerUrl(False, request),
|
||||
'fileKey' : json.dumps({'fileName' : fileName, 'userAddress': request.META['REMOTE_ADDR']})
|
||||
'fileType': fileUtils.getFileExt(fileName).replace('.', ''),
|
||||
'key': docManager.generateFileKey(fileName, request),
|
||||
'url': docManager.getDownloadUrl(fileName, request),
|
||||
'directUrl': docManager.getDownloadUrl(fileName, request, False) if body["directUrl"] else None,
|
||||
'referenceData': {
|
||||
'instanceId': docManager.getServerUrl(False, request),
|
||||
'fileKey': json.dumps({'fileName': fileName, 'userAddress': request.META['REMOTE_ADDR']})
|
||||
},
|
||||
'path' : fileName,
|
||||
'link' : docManager.getServerUrl(False, request) + '/edit?filename=' + fileName
|
||||
'path': fileName,
|
||||
'link': docManager.getServerUrl(False, request) + '/edit?filename=' + fileName
|
||||
}
|
||||
|
||||
if (jwtManager.isEnabled()):
|
||||
if jwtManager.isEnabled():
|
||||
data['token'] = jwtManager.encode(data)
|
||||
|
||||
|
||||
return HttpResponse(json.dumps(data), content_type='application/json')
|
||||
|
||||
|
||||
@http.PUT()
|
||||
def restore(request: HttpRequest) -> HttpResponse:
|
||||
try:
|
||||
|
||||
@ -16,8 +16,6 @@
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
|
||||
from django.shortcuts import render
|
||||
@ -30,11 +28,13 @@ from src.utils import docManager
|
||||
config_manager = ConfigurationManager()
|
||||
format_manager = FormatManager()
|
||||
|
||||
|
||||
def getDirectUrlParam(request):
|
||||
if ('directUrl' in request.GET):
|
||||
if 'directUrl' in request.GET:
|
||||
return request.GET['directUrl'].lower() in ("true")
|
||||
else:
|
||||
return False;
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def default(request): # default parameters that will be passed to the template
|
||||
context = {
|
||||
@ -47,4 +47,5 @@ def default(request): # default parameters that will be passed to the template
|
||||
'fillExt': json.dumps(format_manager.fillable_extensions()),
|
||||
'directUrl': str(getDirectUrlParam(request)).lower
|
||||
}
|
||||
return render(request, 'index.html', context) # execute the "index.html" template with context data and return http response in json format
|
||||
# execute the "index.html" template with context data and return http response in json format
|
||||
return render(request, 'index.html', context)
|
||||
|
||||
Reference in New Issue
Block a user