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/fix-filename
# Conflicts: # web/documentserver-example/java/src/main/java/controllers/IndexServlet.java # web/documentserver-example/python/src/views/actions.py
This commit is contained in:
@ -4,21 +4,22 @@ Django settings for example project.
|
||||
Generated by 'django-admin startproject' using Django 2.2.6.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.2/topics/settings/
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/2.2/ref/settings/
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
import config
|
||||
import mimetypes
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '7a5qnm_bv)iskjhx%4cbwwdmjev03%zewm=3@4s*uz)el#ds5o'
|
||||
@ -66,19 +67,19 @@ WSGI_APPLICATION = 'src.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = []
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
@ -92,8 +93,9 @@ USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
mimetypes.add_type("text/javascript", ".js", True)
|
||||
STATIC_ROOT = ''
|
||||
STATIC_URL = '/static/'
|
||||
STATICFILES_DIRS = ( os.path.join('static'), os.path.join(config.STORAGE_PATH) )
|
||||
STATICFILES_DIRS = ( os.path.join('static'), os.path.join(config.STORAGE_PATH), os.path.join('assets/sample'))
|
||||
@ -36,7 +36,9 @@ urlpatterns = [
|
||||
path('create', actions.createNew),
|
||||
path('edit', actions.edit),
|
||||
path('track', actions.track),
|
||||
path('remove', actions.remove)
|
||||
path('remove', actions.remove),
|
||||
path('csv', actions.csv),
|
||||
path('files', actions.files)
|
||||
]
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
@ -31,6 +31,7 @@ import shutil
|
||||
import io
|
||||
import re
|
||||
import requests
|
||||
import time
|
||||
|
||||
from src import settings
|
||||
from . import fileUtils, historyManager
|
||||
@ -102,15 +103,21 @@ def getCorrectName(filename, req):
|
||||
|
||||
return name
|
||||
|
||||
def getFileUri(filename, req):
|
||||
host = config.EXAMPLE_DOMAIN.rstrip('/')
|
||||
def getServerUrl (forDocumentServer, req):
|
||||
if (forDocumentServer and config.EXAMPLE_DOMAIN is not None):
|
||||
return config.EXAMPLE_DOMAIN
|
||||
else:
|
||||
return req.headers.get("x-forwarded-proto") or req.scheme + "://" + req.get_host()
|
||||
|
||||
def getFileUri(filename, forDocumentServer, req):
|
||||
host = getServerUrl(forDocumentServer, req)
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}{settings.STATIC_URL}{curAdr}/{filename}'
|
||||
|
||||
def getCallbackUrl(filename, req):
|
||||
host = config.EXAMPLE_DOMAIN
|
||||
host = getServerUrl(True, req)
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}track?filename={filename}&userAddress={curAdr}'
|
||||
return f'{host}/track?filename={filename}&userAddress={curAdr}'
|
||||
|
||||
def getRootFolder(req):
|
||||
if isinstance(req, str):
|
||||
@ -140,7 +147,7 @@ def getStoredFiles(req):
|
||||
|
||||
for f in files:
|
||||
if os.path.isfile(os.path.join(directory, f)):
|
||||
fileInfos.append({ 'type': fileUtils.getFileType(f), 'title': f, 'url': getFileUri(f, req) })
|
||||
fileInfos.append({ 'type': fileUtils.getFileType(f), 'title': f, 'url': getFileUri(f, True, req) })
|
||||
|
||||
return fileInfos
|
||||
|
||||
@ -173,7 +180,7 @@ def createSample(fileType, sample, req):
|
||||
filename = getCorrectName(f'{sampleName}{ext}', req)
|
||||
path = getStoragePath(filename, req)
|
||||
|
||||
with io.open(os.path.join('samples', f'{sampleName}{ext}'), 'rb') as stream:
|
||||
with io.open(os.path.join('assets', 'sample' if sample == 'true' else 'new', f'{sampleName}{ext}'), 'rb') as stream:
|
||||
createFile(stream, path, req, True)
|
||||
return filename
|
||||
|
||||
@ -187,9 +194,34 @@ def removeFile(filename, req):
|
||||
|
||||
def generateFileKey(filename, req):
|
||||
path = getStoragePath(filename, req)
|
||||
uri = getFileUri(filename, req)
|
||||
uri = getFileUri(filename, False, req)
|
||||
stat = os.stat(path)
|
||||
|
||||
h = str(hash(f'{uri}_{stat.st_mtime_ns}'))
|
||||
replaced = re.sub(r'[^0-9-.a-zA-Z_=]', '_', h)
|
||||
return replaced[:20]
|
||||
|
||||
def getFilesInfo(req):
|
||||
fileId = req.GET.get('fileId') if req.GET.get('fileId') else None
|
||||
|
||||
result = []
|
||||
resultID = []
|
||||
for f in getStoredFiles(req):
|
||||
stats = os.stat(os.path.join(getRootFolder(req), f.get("title")))
|
||||
result.append(
|
||||
{ "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 fileId == generateFileKey(f.get("title"), req) :
|
||||
resultID.append(result[-1])
|
||||
|
||||
if fileId :
|
||||
if len(resultID) > 0 : return resultID
|
||||
else : return "File not found"
|
||||
else :
|
||||
return result
|
||||
@ -32,6 +32,8 @@ import config
|
||||
from . import users, fileUtils
|
||||
from datetime import datetime
|
||||
from src import settings
|
||||
from src.utils import docManager
|
||||
from src.utils import jwtManager
|
||||
|
||||
def getHistoryDir(storagePath):
|
||||
return f'{storagePath}-hist'
|
||||
@ -43,7 +45,7 @@ def getFileVersion(histDir):
|
||||
if not os.path.exists(histDir):
|
||||
return 0
|
||||
|
||||
cnt = 0
|
||||
cnt = 1
|
||||
|
||||
for f in os.listdir(histDir):
|
||||
if not os.path.isfile(os.path.join(histDir, f)):
|
||||
@ -53,7 +55,7 @@ def getFileVersion(histDir):
|
||||
|
||||
def getNextVersionDir(histDir):
|
||||
v = getFileVersion(histDir)
|
||||
path = getVersionDir(histDir, v + 1)
|
||||
path = getVersionDir(histDir, v)
|
||||
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
@ -84,7 +86,7 @@ def createMeta(storagePath, req):
|
||||
user = users.getUserFromReq(req)
|
||||
|
||||
obj = {
|
||||
'created': datetime.today().strftime('%d.%m.%Y %H:%M:%S'),
|
||||
'created': datetime.today().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'uid': user['uid'],
|
||||
'uname': user['uname']
|
||||
}
|
||||
@ -103,12 +105,12 @@ def readFile(path):
|
||||
return stream.read()
|
||||
|
||||
def getPrevUri(filename, ver, ext, req):
|
||||
host = config.EXAMPLE_DOMAIN.rstrip('/')
|
||||
host = docManager.getServerUrl(True, req)
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}{settings.STATIC_URL}{curAdr}/{filename}-hist/{ver}/prev{ext}'
|
||||
|
||||
def getZipUri(filename, ver, req):
|
||||
host = config.EXAMPLE_DOMAIN.rstrip('/')
|
||||
host = docManager.getServerUrl(True, req)
|
||||
curAdr = req.META['REMOTE_ADDR']
|
||||
return f'{host}{settings.STATIC_URL}{curAdr}/{filename}-hist/{ver}/diff.zip'
|
||||
|
||||
@ -128,12 +130,12 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, req):
|
||||
if version > 0:
|
||||
hist = []
|
||||
histData = {}
|
||||
|
||||
for i in range(version + 1):
|
||||
|
||||
for i in range(1, version + 1):
|
||||
obj = {}
|
||||
dataObj = {}
|
||||
prevVerDir = getVersionDir(histDir, i)
|
||||
verDir = getVersionDir(histDir, i + 1)
|
||||
prevVerDir = getVersionDir(histDir, i - 1)
|
||||
verDir = getVersionDir(histDir, i)
|
||||
|
||||
try:
|
||||
key = docKey if i == version else readFile(getKeyPath(verDir))
|
||||
@ -143,7 +145,7 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, req):
|
||||
dataObj['key'] = key
|
||||
dataObj['version'] = i
|
||||
|
||||
if i == 0:
|
||||
if i == 1:
|
||||
meta = getMeta(storagePath)
|
||||
if meta:
|
||||
obj['created'] = meta['created']
|
||||
@ -152,9 +154,9 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, req):
|
||||
'name': meta['uname']
|
||||
}
|
||||
|
||||
dataObj['url'] = docUrl if i == version else getPrevUri(filename, i + 1, fileUtils.getFileExt(filename), req)
|
||||
dataObj['url'] = docUrl if i == version else getPrevUri(filename, i, fileUtils.getFileExt(filename), req)
|
||||
|
||||
if i > 0:
|
||||
if i > 1:
|
||||
changes = json.loads(readFile(getChangesHistoryPath(prevVerDir)))
|
||||
change = changes['changes'][0]
|
||||
|
||||
@ -163,16 +165,19 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, req):
|
||||
obj['created'] = change['created']
|
||||
obj['user'] = change['user']
|
||||
|
||||
prev = histData[str(i - 1)]
|
||||
prev = histData[str(i - 2)]
|
||||
prevInfo = {
|
||||
'key': prev['key'],
|
||||
'url': prev['url']
|
||||
}
|
||||
dataObj['previous'] = prevInfo
|
||||
dataObj['changesUrl'] = getZipUri(filename, i, req)
|
||||
dataObj['changesUrl'] = getZipUri(filename, i - 1, req)
|
||||
|
||||
if jwtManager.isEnabled():
|
||||
dataObj['token'] = jwtManager.encode(dataObj)
|
||||
|
||||
hist.append(obj)
|
||||
histData[str(i)] = dataObj
|
||||
histData[str(i - 1)] = dataObj
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
@ -50,11 +50,12 @@ def getConverterUri(docUri, fromExt, toExt, docKey, isAsync):
|
||||
payload.setdefault('async', True)
|
||||
|
||||
if jwtManager.isEnabled():
|
||||
jwtHeader = 'Authorization' if config.DOC_SERV_JWT_HEADER is None or config.DOC_SERV_JWT_HEADER == '' else config.DOC_SERV_JWT_HEADER
|
||||
headerToken = jwtManager.encode({'payload': payload})
|
||||
payload['token'] = jwtManager.encode(payload)
|
||||
headers['Authorization'] = f'Bearer {headerToken}'
|
||||
headers[jwtHeader] = f'Bearer {headerToken}'
|
||||
|
||||
response = requests.post(config.DOC_SERV_CONVERTER_URL, json=payload, headers=headers )
|
||||
response = requests.post(config.DOC_SERV_SITE_URL + config.DOC_SERV_CONVERTER_URL, json=payload, headers=headers )
|
||||
json = response.json()
|
||||
|
||||
return getResponseUri(json)
|
||||
|
||||
@ -27,9 +27,11 @@
|
||||
import config
|
||||
import json
|
||||
import os
|
||||
import urllib.parse
|
||||
import magic
|
||||
|
||||
from datetime import datetime
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.http import HttpResponse, HttpResponseRedirect, FileResponse
|
||||
from django.shortcuts import render
|
||||
from src.utils import docManager, fileUtils, serviceConverter, users, jwtManager, historyManager
|
||||
|
||||
@ -64,7 +66,7 @@ def convert(request):
|
||||
|
||||
try:
|
||||
filename = fileUtils.getFileName(request.GET['filename'])
|
||||
fileUri = docManager.getFileUri(filename, request)
|
||||
fileUri = docManager.getFileUri(filename, True,request)
|
||||
fileExt = fileUtils.getFileExt(filename)
|
||||
fileType = fileUtils.getFileType(filename)
|
||||
newExt = docManager.getInternalExtension(fileType)
|
||||
@ -112,7 +114,8 @@ def edit(request):
|
||||
|
||||
ext = fileUtils.getFileExt(filename)
|
||||
|
||||
fileUri = docManager.getFileUri(filename, request)
|
||||
fileUri = docManager.getFileUri(filename, True, request)
|
||||
fileUriUser = docManager.getFileUri(filename, False, request)
|
||||
docKey = docManager.generateFileKey(filename, request)
|
||||
fileType = fileUtils.getFileType(filename)
|
||||
user = users.getUserFromReq(request)
|
||||
@ -133,15 +136,15 @@ def edit(request):
|
||||
|
||||
if (meta):
|
||||
infObj = {
|
||||
'author': meta['uname'],
|
||||
'created': meta['created']
|
||||
'owner': meta['uname'],
|
||||
'uploaded': meta['created']
|
||||
}
|
||||
else:
|
||||
infObj = {
|
||||
'author': 'Me',
|
||||
'created': datetime.today().strftime('%d.%m.%Y %H:%M:%S')
|
||||
'owner': 'Me',
|
||||
'uploaded': datetime.today().strftime('%d.%m.%Y %H:%M:%S')
|
||||
}
|
||||
|
||||
infObj['favorite'] = request.COOKIES.get('uid') == 'uid-2' if request.COOKIES.get('uid') else None
|
||||
edConfig = {
|
||||
'type': edType,
|
||||
'documentType': fileType,
|
||||
@ -171,23 +174,41 @@ def edit(request):
|
||||
'name': user['uname']
|
||||
},
|
||||
'embedded': {
|
||||
'saveUrl': fileUri,
|
||||
'embedUrl': fileUri,
|
||||
'shareUrl': fileUri,
|
||||
'saveUrl': fileUriUser,
|
||||
'embedUrl': fileUriUser,
|
||||
'shareUrl': fileUriUser,
|
||||
'toolbarDocked': 'top'
|
||||
},
|
||||
'customization': {
|
||||
'about': True,
|
||||
'feedback': True,
|
||||
'goback': {
|
||||
'url': config.EXAMPLE_DOMAIN
|
||||
'url': docManager.getServerUrl(False, request)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataInsertImage = {
|
||||
'fileType': 'png',
|
||||
'url': docManager.getServerUrl(True, request) + 'static/images/logo.png'
|
||||
}
|
||||
|
||||
dataCompareFile = {
|
||||
'fileType': 'docx',
|
||||
'url': docManager.getServerUrl(True, request) + 'static/sample.docx'
|
||||
}
|
||||
|
||||
dataMailMergeRecipients = {
|
||||
'fileType': 'csv',
|
||||
'url': docManager.getServerUrl(True, request) + 'csv'
|
||||
}
|
||||
|
||||
if jwtManager.isEnabled():
|
||||
edConfig['token'] = jwtManager.encode(edConfig)
|
||||
dataInsertImage['token'] = jwtManager.encode(dataInsertImage)
|
||||
dataCompareFile['token'] = jwtManager.encode(dataCompareFile)
|
||||
dataMailMergeRecipients['token'] = jwtManager.encode(dataMailMergeRecipients)
|
||||
|
||||
hist = historyManager.getHistoryObject(storagePath, filename, docKey, fileUri, request)
|
||||
|
||||
@ -196,7 +217,10 @@ def edit(request):
|
||||
'history': json.dumps(hist['history']) if 'history' in hist else None,
|
||||
'historyData': json.dumps(hist['historyData']) if 'historyData' in hist else None,
|
||||
'fileType': fileType,
|
||||
'apiUrl': config.DOC_SERV_API_URL
|
||||
'apiUrl': config.DOC_SERV_SITE_URL + config.DOC_SERV_API_URL,
|
||||
'dataInsertImage': json.dumps(dataInsertImage)[1 : len(json.dumps(dataInsertImage)) - 1],
|
||||
'dataCompareFile': dataCompareFile,
|
||||
'dataMailMergeRecipients': json.dumps(dataMailMergeRecipients)
|
||||
}
|
||||
return render(request, 'editor.html', context)
|
||||
|
||||
@ -213,7 +237,8 @@ def track(request):
|
||||
token = body.get('token')
|
||||
|
||||
if (not token):
|
||||
token = request.headers.get('Authorization')
|
||||
jwtHeader = 'Authorization' if config.DOC_SERV_JWT_HEADER is None or config.DOC_SERV_JWT_HEADER == '' else config.DOC_SERV_JWT_HEADER
|
||||
token = request.headers.get(jwtHeader)
|
||||
if token:
|
||||
token = token[len('Bearer '):]
|
||||
|
||||
@ -261,4 +286,20 @@ def remove(request):
|
||||
docManager.removeFile(filename, request)
|
||||
|
||||
response.setdefault('success', True)
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
def files(request):
|
||||
try:
|
||||
response = docManager.getFilesInfo(request)
|
||||
except Exception as e:
|
||||
response = {}
|
||||
response.setdefault('error', e.args[0])
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
def csv(request):
|
||||
filePath = os.path.join('assets', 'sample', "csv.csv")
|
||||
response = FileResponse(open(filePath, 'rb'), True)
|
||||
response['Content-Length'] = os.path.getsize(filePath)
|
||||
response['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + urllib.parse.unquote(os.path.basename(filePath))
|
||||
response['Content-Type'] = magic.from_file(filePath, mime=True)
|
||||
return response
|
||||
@ -36,7 +36,7 @@ def default(request):
|
||||
context = {
|
||||
'users': users.USERS,
|
||||
'languages': docManager.LANGUAGES,
|
||||
'preloadurl': config.DOC_SERV_PRELOADER_URL,
|
||||
'preloadurl': config.DOC_SERV_SITE_URL + config.DOC_SERV_PRELOADER_URL,
|
||||
'editExt': json.dumps(config.DOC_SERV_EDITED),
|
||||
'convExt': json.dumps(config.DOC_SERV_CONVERT),
|
||||
'files': docManager.getStoredFiles(request)
|
||||
|
||||
@ -4,7 +4,7 @@ WSGI config for example project.
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
|
||||
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
Reference in New Issue
Block a user