diff --git a/3rd-Party.license b/3rd-Party.license new file mode 100644 index 0000000..8551d43 --- /dev/null +++ b/3rd-Party.license @@ -0,0 +1,6 @@ +Plone ONLYOFFICE integration plugin uses code from the following 3rd party projects: + + +PyJWT - A Python implementation of JWT (https://opensource.org/licenses/MIT) +License: MIT +License File: PyJWT.license diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d1184..cf17b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 2.0.0 +## Added + - JWT support +## Fixed + - Issue when files inside unpublished folders couldn't be edited + ## 1.0.0 ## Added - Edit option for DOCX, XLSX, PPTX. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..93640ba --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,17 @@ +include *.js +include *.json +include *.py +include *.md +include *.txt +include *.cfg +recursive-include src *.css +recursive-include src *.js +recursive-include src *.map +recursive-include src *.po +recursive-include src *.pot +recursive-include src *.pt +recursive-include src *.py +recursive-include src *.sh +recursive-include src *.txt +recursive-include src *.xml +recursive-include src *.zcml \ No newline at end of file diff --git a/README.md b/README.md index 1042dee..53a1387 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Plone ONLYOFFICE integration plugin -This plugin allows users to edit office documents within [Plone](https://plone.org/) using ONLYOFFICE Document Server - [Community or Integration Edition](#onlyoffice-document-server-editions). +This plugin allows users to edit office documents within [Plone](https://plone.org/) using ONLYOFFICE Docs packaged as Document Server - [Community or Enterprise Edition](#onlyoffice-docs-editions). ## Features @@ -15,39 +15,99 @@ Supported formats: * For viewing and editing: DOCX, XLSX, PPTX. * For viewing only: PDF, ODT, ODS, ODP, DOC, XLS, PPT. -## Installing ONLYOFFICE Document Server +## Installing ONLYOFFICE Docs -You will need an instance of ONLYOFFICE Document Server that is resolvable and connectable both from Plone and any end-clients. ONLYOFFICE Document Server must also be able to POST to Plone directly. +You will need an instance of ONLYOFFICE Docs (Document Server) that is resolvable and connectable both from Plone and any end-clients. ONLYOFFICE Document Server must also be able to POST to Plone directly. -You can install free Community version of ONLYOFFICE Document Server or scalable enterprise-level Integration Edition. +You can install free Community version of ONLYOFFICE Docs or scalable Enterprise Edition with pro features. To install free Community version, use [Docker](https://github.com/onlyoffice/Docker-DocumentServer) (recommended) or follow [these instructions](https://helpcenter.onlyoffice.com/server/linux/document/linux-installation.aspx) for Debian, Ubuntu, or derivatives. -To install Integration Edition, follow instructions [here](https://helpcenter.onlyoffice.com/server/integration-edition/index.aspx). +To install Enterprise Edition, follow instructions [here](https://helpcenter.onlyoffice.com/server/integration-edition/index.aspx). -Community Edition vs Integration Edition comparison can be found [here](#onlyoffice-document-server-editions). +Community Edition vs Enterprise Edition comparison can be found [here](#onlyoffice-docs-editions). ## Installing Plone ONLYOFFICE integration plugin -Install plugin by adding it to your `buildout.cfg`: +1. Install plugin by adding it to your `buildout.cfg`: + ``` + [buildout] -``` -[buildout] + ... -... + eggs = + onlyoffice.connector + ``` +2. Run `bin/buildout`. +3. Go to `Site Setup` -> `Add-ons`and press the `Install` button to enable plugin. -eggs = - onlyoffice.connector +You could also install plugin via Docker ``` - -and then running `bin/buildout` - -To enable plugin, go to `Site Setup` -> `Add-ons`and press the `Install` button. +docker run --rm -p 8080:8080 -e ADDONS="onlyoffice.connector" plone +``` +Both options will automatically install plugin from [PyPi](https://pypi.org/project/onlyoffice.connector/). ## Configuring Plone ONLYOFFICE integration plugin To configure plugin go to `Site Setup`. Scroll down to `Add-ons Configuration` section and press the `ONLYOFFICE Configuration` button. +## Developing Plone ONLYOFFICE plugin + +1. Clone repository and change directory: + ``` + git clone --branch deploy git@github.com:ONLYOFFICE/onlyoffice-plone.git + cd onlyoffice-plone + ``` +2. Create a virtualenv in the package. +3. Install requirements with pip. +4. Run buildout: + ``` + virtualenv . + ./bin/pip install -r requirements.txt + ./bin/buildout + ``` +5. Start Plone in foreground: + ``` + ./bin/instance fg + ``` +If you have a working Plone instance, you can install plugin by adding the project files to the src directory: +1. In the src directory create the onlyoffice.connector directory. +2. Put your project files received by git into the onlyoffice.connector directory. +3. Edit the buildout.cfg file: + ``` + [buildout] + + ... + + eggs = + onlyoffice.connector + + develop = + src/onlyoffice.connector + ``` +4. Rerun buildout for the changes to take effect: + ``` + ./bin/buildout + ``` +5. Then start or restart your Plone instance. + +Note that Plone is based on Zope server and will not run as `root` user. If you intend to run it as `root` user. You must supply [effective-user directive](https://zope.readthedocs.io/en/2.12/SETUID.html). In order to do so add `effective-user ` line to `./parts/instance/etc/zope.conf`. + +## Upgrade Plone ONLYOFFICE integration plugin +1. If you specified a concrete plugin version in your buildout.cfg file (so-called “pinning”, and a recommended practice), + like onlyoffice.connector = 1.0.0, update this reference to point to the newer version. If the plugin version is not + specified, then the latest version will be automatically loaded: + ``` + [versions] + + ... + + onlyoffice.connector = 1.0.1 + ``` +2. Run bin/buildout. Wait until the new version is downloaded and installed. +3. Restart Plone - your site may look weird, or even be inaccessible until you have performed the next step. +4. Navigate to the Add-on screen (add /prefs_install_products_form to your site URL) and in the Upgrades list select onlyoffice.connector and click "Upgrade onlyoffice.connector". + ## How it works The ONLYOFFICE integration follows the API documented [here](https://api.onlyoffice.com/editors/basic): @@ -66,73 +126,44 @@ The ONLYOFFICE integration follows the API documented [here](https://api.onlyoff * After 10 seconds of inactivity, ONLYOFFICE Document Server sends a POST to the `callback` URL letting Plone know that the clients have finished editing the document and closed it. * Plone downloads the new version of the document, replacing the old one. -## Developing Plone ONLYOFFICE plugin - -- Clone repository and change directory - -``` -git clone --branch deploy git@github.com:ONLYOFFICE/onlyoffice-plone.git -cd onlyoffice-plone -``` - - - Create a virtualenv in the package - - Install requirements with pip - - Run buildout - -``` -virtualenv --clear . -./bin/pip install -r requirements.txt -./bin/buildout -``` - - - Start Plone in foreground - -``` -./bin/instance fg -``` - -Note that Plone is based on Zope server and will not run as `root` user. If you intend to run it as `root` user. You must supply [effective-user directive](https://zope.readthedocs.io/en/2.12/SETUID.html). In order to do so add `effective-user ` line to `./parts/instance/etc/zope.conf`. - -## ONLYOFFICE Document Server editions +## ONLYOFFICE Docs editions ONLYOFFICE offers different versions of its online document editors that can be deployed on your own servers. -**ONLYOFFICE Document Server:** - * Community Edition (`onlyoffice-documentserver` package) -* Integration Edition (`onlyoffice-documentserver-ie` package) +* Enterprise Edition (`onlyoffice-documentserver-ie` package) The table below will help you make the right choice. -| Pricing and licensing | Community Edition | Integration Edition | +| Pricing and licensing | Community Edition | Enterprise Edition | | ------------- | ------------- | ------------- | -| | [Get it now](https://www.onlyoffice.com/download.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | [Start Free Trial](https://www.onlyoffice.com/connectors-request.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | -| Cost | FREE | [Go to the pricing page](https://www.onlyoffice.com/integration-edition-prices.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | +| | [Get it now](https://www.onlyoffice.com/download.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | [Start Free Trial](https://www.onlyoffice.com/enterprise-edition-free.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | +| Cost | FREE | [Go to the pricing page](https://www.onlyoffice.com/enterprise-edition.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | | Simultaneous connections | up to 20 maximum | As in chosen pricing plan | | Number of users | up to 20 recommended | As in chosen pricing plan | | License | GNU AGPL v.3 | Proprietary | -| **Support** | **Community Edition** | **Integration Edition** | +| **Support** | **Community Edition** | **Enterprise Edition** | | Documentation | [Help Center](https://helpcenter.onlyoffice.com/server/docker/opensource/index.aspx) | [Help Center](https://helpcenter.onlyoffice.com/server/integration-edition/index.aspx) | | Standard support | [GitHub](https://github.com/ONLYOFFICE/DocumentServer/issues) or paid | One year support included | | Premium support | [Buy Now](https://www.onlyoffice.com/support.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | [Buy Now](https://www.onlyoffice.com/support.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | -| **Services** | **Community Edition** | **Integration Edition** | +| **Services** | **Community Edition** | **Enterprise Edition** | | Conversion Service | + | + | | Document Builder Service | + | + | -| **Interface** | **Community Edition** | **Integration Edition** | +| **Interface** | **Community Edition** | **Enterprise Edition** | | Tabbed interface | + | + | | White Label | - | - | | Integrated test example (node.js) | - | + | -| **Plugins & Macros** | **Community Edition** | **Integration Edition** | +| **Plugins & Macros** | **Community Edition** | **Enterprise Edition** | | Plugins | + | + | | Macros | + | + | -| **Collaborative capabilities** | **Community Edition** | **Integration Edition** | +| **Collaborative capabilities** | **Community Edition** | **Enterprise Edition** | | Two co-editing modes | + | + | | Comments | + | + | | Built-in chat | + | + | | Review and tracking changes | + | + | | Display modes of tracking changes | + | + | | Version history | + | + | -| **Document Editor features** | **Community Edition** | **Integration Edition** | +| **Document Editor features** | **Community Edition** | **Enterprise Edition** | | Font and paragraph formatting | + | + | | Object insertion | + | + | | Adding Content control | - | + | @@ -141,20 +172,23 @@ The table below will help you make the right choice. | Table of contents | + | + | | Navigation panel | + | + | | Comparing Documents | - | +* | -| **Spreadsheet Editor features** | **Community Edition** | **Integration Edition** | +| **Spreadsheet Editor features** | **Community Edition** | **Enterprise Edition** | | Font and paragraph formatting | + | + | | Object insertion | + | + | | Functions, formulas, equations | + | + | | Table templates | + | + | -| Pivot tables | +** | +** | -| **Presentation Editor features** | **Community Edition** | **Integration Edition** | +| Pivot tables | + | + | +| Conditional formatting for viewing | +** | +** | +| Sheet views | - | + | +| **Presentation Editor features** | **Community Edition** | **Enterprise Edition** | | Font and paragraph formatting | + | + | | Object insertion | + | + | | Animations | + | + | | Presenter mode | + | + | | Notes | + | + | -| | [Get it now](https://www.onlyoffice.com/download.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | [Start Free Trial](https://www.onlyoffice.com/connectors-request.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | +| | [Get it now](https://www.onlyoffice.com/download.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | [Start Free Trial](https://www.onlyoffice.com/enterprise-edition-free.aspx?utm_source=github&utm_medium=cpc&utm_campaign=GitHubPlone) | \* It's possible to add documents for comparison from your local drive and from URL. Adding files for comparison from storage is not available yet. -\** Changing style and deleting (Full support coming soon) +\** Support for all conditions and gradient. Adding/Editing capabilities are coming soon + diff --git a/base.cfg b/base.cfg new file mode 100644 index 0000000..89ffef3 --- /dev/null +++ b/base.cfg @@ -0,0 +1,107 @@ +[buildout] +show-picked-versions = true +extensions = + mr.developer + +index = https://pypi.python.org/simple/ + +parts = + instance + test + code-analysis + coverage + test-coverage + createcoverage + releaser + i18ndude + omelette + robot + plone-helper-scripts +develop = . + + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +environment-vars = + zope_i18n_compile_mo_files true +eggs = + Plone + Pillow + plone.app.debugtoolbar + onlyoffice.connector [test] + + +[code-analysis] +recipe = plone.recipe.codeanalysis +directory = ${buildout:directory}/src/onlyoffice +return-status-codes = False + + +[omelette] +recipe = collective.recipe.omelette +eggs = ${instance:eggs} + + +[test] +recipe = zc.recipe.testrunner +eggs = ${instance:eggs} +initialization = + os.environ['TZ'] = 'UTC' +defaults = ['-s', 'onlyoffice.connector', '--auto-color', '--auto-progress'] + + +[coverage] +recipe = zc.recipe.egg +eggs = coverage + + +[test-coverage] +recipe = collective.recipe.template +input = inline: + #!/bin/bash + export TZ=UTC + ${buildout:directory}/bin/coverage run bin/test $* + ${buildout:directory}/bin/coverage html + ${buildout:directory}/bin/coverage report -m --fail-under=90 + # Fail (exit status 1) if coverage returns exit status 2 (this happens + # when test coverage is below 100%. +output = ${buildout:directory}/bin/test-coverage +mode = 755 + + +[createcoverage] +recipe = zc.recipe.egg +eggs = createcoverage + + +[robot] +recipe = zc.recipe.egg +eggs = + ${test:eggs} + plone.app.robotframework[debug,reload] + + +[releaser] +recipe = zc.recipe.egg +eggs = zest.releaser + + +[i18ndude] +recipe = zc.recipe.egg +eggs = i18ndude + +[plone-helper-scripts] +recipe = zc.recipe.egg +eggs = + Products.CMFPlone + ${instance:eggs} +interpreter = zopepy +scripts = + zopepy + plone-compile-resources + +[versions] +# Don't use a released version of onlyoffice.connector +onlyoffice.connector = diff --git a/buildout.cfg b/buildout.cfg new file mode 100644 index 0000000..80d7a7f --- /dev/null +++ b/buildout.cfg @@ -0,0 +1,9 @@ +[buildout] + +# use this extend one of the buildout configuration: +extends = +# -*- mrbob: extra extends -*- +# test_plone43.cfg +# test_plone50.cfg +# test_plone51.cfg + test_plone52.cfg diff --git a/constraints_plone52.txt b/constraints_plone52.txt new file mode 100644 index 0000000..d96fee0 --- /dev/null +++ b/constraints_plone52.txt @@ -0,0 +1,3 @@ +-c https://dist.plone.org/release/5.2-latest/requirements.txt +# setuptools==40.2.0 +# zc.buildout==2.12.2 diff --git a/licenses/3rd-Party.license b/licenses/3rd-Party.license new file mode 100644 index 0000000..8551d43 --- /dev/null +++ b/licenses/3rd-Party.license @@ -0,0 +1,6 @@ +Plone ONLYOFFICE integration plugin uses code from the following 3rd party projects: + + +PyJWT - A Python implementation of JWT (https://opensource.org/licenses/MIT) +License: MIT +License File: PyJWT.license diff --git a/licenses/PyJWT.license b/licenses/PyJWT.license new file mode 100644 index 0000000..bdc7819 --- /dev/null +++ b/licenses/PyJWT.license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 José Padilla + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fa2f614 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +-c constraints_plone52.txt +setuptools +zc.buildout diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..e920041 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,19 @@ +[check-manifest] +ignore = + *.cfg + .coveragerc + .editorconfig + .gitattributes + +[isort] +# for details see +# http://docs.plone.org/develop/styleguide/python.html#grouping-and-sorting +force_alphabetical_sort = True +force_single_line = True +lines_after_imports = 2 +line_length = 200 +not_skip = __init__.py + +[flake8] +exclude = bootstrap.py,docs,*.egg.,omelette +max-complexity = 15 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..4924fcf --- /dev/null +++ b/setup.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +"""Installer for the onlyoffice.connector package.""" + +from setuptools import find_packages +from setuptools import setup + + +long_description = '\n\n'.join([ + open('README.md').read(), + open('AUTHORS.md').read(), + open('CHANGELOG.md').read(), +]) + + +setup( + name='onlyoffice.connector', + version='2.0.0', + description="Plone ONLYOFFICE integration plugin", + long_description=long_description, + long_description_content_type="text/markdown", + # Get more from https://pypi.org/classifiers/ + classifiers=[ + "Environment :: Web Environment", + "Framework :: Plone", + "Framework :: Plone :: Addon", + "Framework :: Plone :: 5.1", + "Framework :: Plone :: 5.2", + "Programming Language :: Python", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Operating System :: OS Independent", + "License :: OSI Approved :: GNU Affero General Public License v3", + ], + keywords='Python Plone', + author='Ascensio System SIA', + author_email='integration@onlyoffice.com', + url='https://github.com/ONLYOFFICE/onlyoffice-plone', + project_urls={ + 'PyPI': 'https://pypi.python.org/pypi/onlyoffice.connector', + 'Source': 'https://github.com/ONLYOFFICE/onlyoffice-plone', + 'Tracker': 'https://github.com/ONLYOFFICE/onlyoffice-plone/issues', + # 'Documentation': 'https://onlyoffice.connector.readthedocs.io/en/latest/', + }, + license='AGPL version 3', + packages=find_packages('src', exclude=['ez_setup']), + namespace_packages=['onlyoffice'], + package_dir={'': 'src'}, + include_package_data=True, + zip_safe=False, + python_requires=">=3.4", + install_requires=[ + 'setuptools', + # -*- Extra requirements: -*- + 'z3c.jbot', + 'plone.api>=1.8.4', + 'plone.restapi', + 'plone.app.dexterity', + ], + extras_require={ + 'test': [ + 'plone.app.testing', + # Plone KGS does not use this version, because it would break + # Remove if your package shall be part of coredev. + # plone_coredev tests as of 2016-04-01. + 'plone.testing>=5.0.0', + 'plone.app.contenttypes', + 'plone.app.robotframework[debug]', + ], + }, + entry_points=""" + [z3c.autoinclude.plugin] + target = plone + [console_scripts] + update_locale = onlyoffice.connector.locales.update:update_locale + """, +) diff --git a/src/onlyoffice/connector/browser/api.py b/src/onlyoffice/connector/browser/api.py index aad1bd5..559a7d4 100644 --- a/src/onlyoffice/connector/browser/api.py +++ b/src/onlyoffice/connector/browser/api.py @@ -1,16 +1,35 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + from Acquisition import aq_inner from AccessControl import getSecurityManager -from Products.CMFCore.utils import getToolByName from Products.Five.browser import BrowserView from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from plone.namedfile.browser import Download from plone.namedfile.file import NamedBlobFile +from plone.rfc822.interfaces import IPrimaryFieldInfo from plone.registry.interfaces import IRegistry from z3c.form import form from zope.component import getMultiAdapter from zope.component import getUtility +from zope.publisher.interfaces import NotFound from onlyoffice.connector.core.config import Config from onlyoffice.connector.core import fileUtils from onlyoffice.connector.core import utils +from onlyoffice.connector.interfaces import logger from urllib.request import urlopen import json @@ -20,11 +39,11 @@ def isAvailable(self): filename = self.context.file.filename return fileUtils.canEdit(filename) - cfg = None + docUrl = None editorCfg = None def __call__(self): - self.cfg = Config(getUtility(IRegistry)) + self.docUrl = Config(getUtility(IRegistry)).docUrl self.editorCfg = get_config(self, True) if not self.editorCfg: index = ViewPageTemplateFile("templates/error.pt") @@ -36,11 +55,11 @@ def isAvailable(self): filename = self.context.file.filename return fileUtils.canView(filename) - cfg = None + docUrl = None editorCfg = None def __call__(self): - self.cfg = Config(getUtility(IRegistry)) + self.docUrl = Config(getUtility(IRegistry)).docUrl self.editorCfg = get_config(self, False) if not self.editorCfg: index = ViewPageTemplateFile("templates/error.pt") @@ -48,15 +67,16 @@ def __call__(self): return self.index() def get_config(self, forEdit): - def viewURLFor(self, item): - cstate = getMultiAdapter((item, item.REQUEST), name='plone_context_state') - return cstate.view_url() + # def viewURLFor(self, item): + # cstate = getMultiAdapter((item, item.REQUEST), name='plone_context_state') + # return cstate.view_url() def portal_state(self): context = aq_inner(self.context) portal_state = getMultiAdapter((context, self.request), name=u'plone_portal_state') return portal_state + logger.info("getting config for " + self.context.absolute_url()) canEdit = forEdit and bool(getSecurityManager().checkPermission('Modify portal content', self.context)) filename = self.context.file.filename @@ -67,12 +87,13 @@ def portal_state(self): state = portal_state(self) user = state.member() + securityToken = utils.createSecurityTokenFromContext(self.context) config = { 'type': 'desktop', 'documentType': fileUtils.getFileType(filename), 'document': { 'title': filename, - 'url': self.context.absolute_url() + '/@@download', + 'url': self.context.absolute_url() + '/onlyoffice-dl?token=' + securityToken, 'fileType': fileUtils.getFileExt(filename)[1:], 'key': utils.getDocumentKey(self.context), 'info': { @@ -91,18 +112,23 @@ def portal_state(self): 'name': user.getUserName() }, 'customization': { - 'about': True, 'feedback': True } } } if canEdit: - config['editorConfig']['callbackUrl'] = self.context.absolute_url() + '/onlyoffice-callback' + config['editorConfig']['callbackUrl'] = self.context.absolute_url() + '/onlyoffice-callback?token=' + securityToken + + if utils.isJwtEnabled(): + config['token'] = utils.createSecurityToken(config) return json.dumps(config) class Callback(BrowserView): def __call__(self): + logger.info("got callback request for " + self.context.absolute_url()) + logger.debug(vars(self.request)) + utils.checkSecurityToken(self.context, utils.getTokenFromRequest(self.request)) self.request.response.setHeader('Content-Type', 'application/json') error = None @@ -110,17 +136,34 @@ def __call__(self): try: body = json.loads(self.request.get('BODY')) + logger.debug(body) + + if utils.isJwtEnabled(): + token = body.get('token') + + if (not token): + token = utils.getTokenFromHeader(self.request) + + if (not token): + raise Exception('Expected JWT') + + body = utils.decodeSecurityToken(token) + if (body.get('payload')): + body = body['payload'] + status = body['status'] download = body.get('url') if (status == 2) | (status == 3): # mustsave, corrupted - + logger.info("saving file " + self.context.absolute_url()) self.context.file = NamedBlobFile(urlopen(download).read(), filename=self.context.file.filename) self.context.reindexObject() + logger.info("saved " + self.context.absolute_url()) except Exception as e: error = str(e) if error: + logger.warn("error while saving " + self.context.absolute_url() + ": " + error) response['error'] = 1 response['message'] = error self.request.response.status = 500 @@ -128,4 +171,32 @@ def __call__(self): response['error'] = 0 self.request.response.status = 200 - return json.dumps(response) \ No newline at end of file + return json.dumps(response) + +class ODownload(Download): + def _getFile(self): + logger.info("got download request for " + self.context.absolute_url()) + + if utils.isJwtEnabled(): + token = utils.getTokenFromHeader(self.request) + + if (not token): + raise Exception('Expected JWT') + + utils.decodeSecurityToken(token) + + utils.checkSecurityToken(self.context, utils.getTokenFromRequest(self.request)) + + if not self.fieldname: + info = IPrimaryFieldInfo(self.context, None) + if info is None: + # Ensure that we have at least a fieldname + raise NotFound(self, '', self.request) + self.fieldname = info.fieldname + + file = info.value + + if file is None: + raise NotFound(self, self.fieldname, self.request) + + return file \ No newline at end of file diff --git a/src/onlyoffice/connector/browser/configure.zcml b/src/onlyoffice/connector/browser/configure.zcml index d1f8bd9..06c38ee 100644 --- a/src/onlyoffice/connector/browser/configure.zcml +++ b/src/onlyoffice/connector/browser/configure.zcml @@ -41,7 +41,14 @@ name="onlyoffice-callback" for="plone.app.contenttypes.interfaces.IFile" class=".api.Callback" - permission="zope2.View" + permission="zope2.Public" + /> + + + +
ONLYOFFICE can't open this file.
diff --git a/src/onlyoffice/connector/browser/templates/view.pt b/src/onlyoffice/connector/browser/templates/view.pt index 5754552..5cd56fb 100644 --- a/src/onlyoffice/connector/browser/templates/view.pt +++ b/src/onlyoffice/connector/browser/templates/view.pt @@ -6,16 +6,39 @@ metal:use-macro="here/main_template/macros/master" i18n:domain="onlyoffice.connector"> + +
+ - +
diff --git a/src/onlyoffice/connector/configure.zcml b/src/onlyoffice/connector/configure.zcml index 1e62a30..8dd5f80 100644 --- a/src/onlyoffice/connector/configure.zcml +++ b/src/onlyoffice/connector/configure.zcml @@ -15,8 +15,10 @@ + + - 1000 + 2000 diff --git a/src/onlyoffice/connector/profiles/upgrades/to_2/registry.xml b/src/onlyoffice/connector/profiles/upgrades/to_2/registry.xml new file mode 100644 index 0000000..ef90ebd --- /dev/null +++ b/src/onlyoffice/connector/profiles/upgrades/to_2/registry.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/onlyoffice/connector/setuphandlers.py b/src/onlyoffice/connector/setuphandlers.py index 71e9c63..a71826c 100644 --- a/src/onlyoffice/connector/setuphandlers.py +++ b/src/onlyoffice/connector/setuphandlers.py @@ -1,3 +1,19 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + # -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import INonInstallable from zope.interface import implementer diff --git a/src/onlyoffice/connector/testing.py b/src/onlyoffice/connector/testing.py index 72af69a..0c4c77d 100644 --- a/src/onlyoffice/connector/testing.py +++ b/src/onlyoffice/connector/testing.py @@ -1,3 +1,19 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + # -*- coding: utf-8 -*- from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE diff --git a/src/onlyoffice/connector/tests/test_robot.py b/src/onlyoffice/connector/tests/test_robot.py index 8c3657e..095e604 100644 --- a/src/onlyoffice/connector/tests/test_robot.py +++ b/src/onlyoffice/connector/tests/test_robot.py @@ -1,3 +1,19 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + # -*- coding: utf-8 -*- from onlyoffice.connector.testing import ONLYOFFICE_CONNECTOR_ACCEPTANCE_TESTING # noqa: E501 from plone.app.testing import ROBOT_TEST_LEVEL diff --git a/src/onlyoffice/connector/tests/test_setup.py b/src/onlyoffice/connector/tests/test_setup.py index ecb944e..bd2c983 100644 --- a/src/onlyoffice/connector/tests/test_setup.py +++ b/src/onlyoffice/connector/tests/test_setup.py @@ -1,3 +1,19 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + # -*- coding: utf-8 -*- """Setup tests for this package.""" from onlyoffice.connector.testing import ONLYOFFICE_CONNECTOR_INTEGRATION_TESTING # noqa: E501 diff --git a/src/onlyoffice/connector/upgrades.py b/src/onlyoffice/connector/upgrades.py new file mode 100644 index 0000000..46ad97b --- /dev/null +++ b/src/onlyoffice/connector/upgrades.py @@ -0,0 +1,23 @@ +# +# (c) Copyright Ascensio System SIA 2021 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +PROFILE_ID = 'onlyoffice.connector:default' + +def upgrade_to_2(context): + context.runImportStepFromProfile( + PROFILE_ID.replace('default', 'to_2'), + 'plone.app.registry', + ) \ No newline at end of file diff --git a/src/onlyoffice/connector/upgrades.zcml b/src/onlyoffice/connector/upgrades.zcml new file mode 100644 index 0000000..094ade2 --- /dev/null +++ b/src/onlyoffice/connector/upgrades.zcml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/test_plone52.cfg b/test_plone52.cfg new file mode 100644 index 0000000..f8a7c22 --- /dev/null +++ b/test_plone52.cfg @@ -0,0 +1,11 @@ +[buildout] + +extends = + https://raw.github.com/collective/buildout.plonetest/master/test-5.2.x.cfg + https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg + base.cfg + +update-versions-file = test_plone52.cfg + +[versions] +plone.testing = 7.0.1