Integrate online documents editors, into a Python web app using ONLYOFFICE

0
860

ONLYOFFICE is an open-source collaborative office suite distributed under the terms of GNU AGPL v.3 license. It contains three editors for text documents, spreadsheets, and presentations and features the following:

  • Viewing, editing and co-editing docx, .xlsx, pptx files. OOXML as a core format ensures high compatibility with Microsoft Word, Excel and PowerPoint files.
  • Editing other popular formats (.odt, .rtf, .txt, .html, .ods., .csv, .odp) with inner conversion to OOXML.
  • Familiar tabbed interface.
  • Collaboration tools: two co-editing modes (fast and strict), track changes, comments and integrated chat.
  • Flexible access rights management: full access, read only, review, form filling and comment.
  • Building your own add-ons using the API.
  • 250 languages available and hieroglyphic alphabets.

API allows the developers integrate ONLYOFFICE editors into their own web sites and apps written in any programming language and setup and manage the editors.

To integrate ONLYOFFICE editors, we will need an integration app connecting the editors (ONLYOFFICE Document Server) and the third party service. To use editors within its interface, the service should grant to ONLYOFFICE the following permissions :

  • Adding and executing custom code.
  • Anonymous access for downloading and saving files. It means that the editors only communicate with the service on the server side without involving any user authorization data from the client side (browser cookies).
  • Adding new buttons to UI (for example, “Open in ONLYOFFICE”, “Edit in ONLYOFFICE”).
  • Оpening a new page where ONLYOFFICE can execute the script to add an editor.
  • Ability to specify Document Server connection settings.

There are several cases of successful integration with popular collaboration solutions such as Nextcloud, ownCloud, Alfresco, Confluence and SharePoint, via official ready-to-use connectors offered by ONLYOFFICE.

One of the most actual integration cases is the integration of ONLYOFFICE editors with its open-source collaboration platform written in C#. ONLYOFFICE platform features document and project management, CRM, email aggregator, calendar, user database, blogs, forums, polls, wiki, and instant messenger. Work with documents is performed not only within the DMS, but also within CRM, Projects, and Mail.

Integrating online editors with CRM and Projects modules, we can:

  • Attach documents to CRM opportunities and cases, or to project tasks and discussions, or even create a separate folder with documents, spreadsheets, and presentations related to the project.
  • Create new docs, sheets, and presentations right in CRM or in the Project module.
  • Open and edit attached documents, or download and delete them.
  • Import contacts to our CRM in bulk from a CSV file as well as export the customer database as a CSV file.

In the Mail module, we can attach files stored in the Documents module or insert a link to the needed document into the message body. When ONLYOFFICE users receive a message with an attached document, they are able to: download the attachment, view the file in the browser, open the file for editing or save it to the Documents module. As mentioned above, if the format differs from OOXML, the file will be automatically converted to .docx/.xlsx/.pptx and its copy will be saved in the original format as well.

In this article, you will see the integration process of ONLYOFFICE into the Document Management System written in Python, one of the most popular programming languages. The following steps will show you how to create all the necessary elements to make possible work and collaboration on documents within DMS interface: viewing, editing, co-editing, saving files and users access management and may serve as an example of integration into your Python app.

1. What we will need

Let’s start off by creating key components of the integration process: ONLYOFFICE Document Server and DMS written in Python.

1.1 To install ONLYOFFICE Document Server we can choose from multiple installation options: compile the source code available on GitHub, use .deb or .rpm packages or the Docker image. If we choose this method, we need the latest Docker version installed.
We recommend installing Document Server and all the necessary dependencies with only one command using the Docker image. Please note, that choosing this method, you need the latest Docker version installed.

docker run -itd -p 80:80 onlyoffice/documentserver-de

1.2 In this part, we will develop DMS in Python to show integration with ONLYOFFICE on its example. This DMS should meet the following conditions:

  • Has a list of files we need to open for viewing/editing
  • Allows downloading files

For the app, we will use a Bottle framework. We will install it in the working directory using the following command:

  pip install bottle

Then we create the app’s code  main.py  and the template index.tpl .
We add the following code into this  main.py  file:

from bottle import route, run, template, get, static_file # connecting the framework and the necessary components
@route('/') # setting up routing for requests for /
def index():
return template('index.tpl') # showing template in response to request
run(host="localhost", port=8080) # running the application on port 8080

Once we run the app, an empty page will be rendered on http://localhost:8080 .

To make the Document Server able to create new docs, add default files and form a list of their names in the template, we should create a folder  files , and put 3 files (.docx, .xlsx and .pptx) in there.

To read these files’ names, we use the listdir component.

from os import listdir

Now let’s create a variable for all the file names from the files folder:

sample_files = [f for f in listdir('files')]

To use this variable in the template, we need to pass it through the template method:

def index():
return template('index.tpl', sample_files=sample_files)

Here’s this variable in the template:
%for file in sample_files:
<div>
<span>{{file}}</span>
</div>
% end

We restart the application to see the list of filenames on the page.
Here’s the method to make these files available for all the app users:

@get("/files/<filepath:re:.*\.*>")
def show_sample_files(filepath):
return static_file(filepath, root="files")

2. How to view docs in ONLYOFFICE within the Python App
Once all the components are ready, let’s add functions to make editors operational within the app interface.

The first option enables users to open and view docs. Let’s connect document editors API in the template:

<script type="text/javascript" src="editor_url/web-apps/apps/api/documents/api.js"></script>

editor_url  is a link to document editors.

A button to open each file for viewing:

<button onclick="view('files/{{file}}')">view</button>

Now we need to add a div with  id , in which the document editor will be opened:

<div id="editor"></div>

To open the editor, we have to call a function:

<script>
function view(filename) {
if (/docx$/.exec(filename)) {
filetype = "text"
}
if (/xlsx$/.exec(filename)) {
filetype = "spreadsheet"
}
if (/pptx$/.exec(filename)) {
filetype = "presentation",
title: filename
}
new DocsAPI.DocEditor("editor",
{
documentType: filetype,
document: {
url: "host_url" + '/' + filename,
title: filename
},
editorConfig: {mode: 'view'}
});
}
</script>

There are two arguments for the DocEditor function: id of the element where the editors will be opened and a JSON with the editors’ settings.
In this example, the following mandatory parameters are used:

  • documentType is identified by its format (.docx, .xlsx, .pptx for texts, spreadsheets and presentations accordingly)
  • document.url is the link to the file we are going to open.
  • editorConfig.mode.

We can also add title that will be displayed in the editors.

So, now we have everything to view docs in our Python app.

3. How to edit docs in ONLYOFFICE within the Python App
First of all, let’s add the “Edit” button:

<button onclick="edit('files/{{file}}')">edit</button>

Then we need to create a new function that will open files for editing. It is similar to the View function.
Now we have 3 functions:

<script>
var editor;
function view(filename) {
if (editor) {
editor.destroyEditor()
}
editor = new DocsAPI.DocEditor("editor",
{
documentType: get_file_type(filename),
document: {
url: "host_url" + '/' + filename,
title: filename
},
editorConfig: {mode: 'view'}
});
}
function edit(filename) {
if (editor) {
editor.destroyEditor()
}
editor = new DocsAPI.DocEditor("editor",
{
documentType: get_file_type(filename),
document: {
url: "host_url" + '/' + filename,
title: filename
}
});
}
function get_file_type(filename) {
if (/docx$/.exec(filename)) {
return "text"
}
if (/xlsx$/.exec(filename)) {
return "spreadsheet"
}
if (/pptx$/.exec(filename)) {
return "presentation"
}
}
</script>

destroyEditor  is called to close an open editor.
As we can see, the editorConfig parameter is absent from the edit() function, because it has by default the value  {“mode”: “edit”}.

Now we have everything to open docs for co-editing in our Python app.

4. How to co-edit docs in ONLYOFFICE within the Python App
Co-editing is implemented by using the same document.key for the same document in the editors’ settings. Without this key, the editors will create the editing session each time we open the file.

Let’s set unique keys for each doc to make users connect to the same editing session for co-editing. The format of the key should be the following:  filename + “_key”. The next step is to add it to all of the configs where document is present.

document: {
url: "host_url" + '/' + filepath,
title: filename,
key: filename + '_key'
},

5. How to save docs in ONLYOFFICE within the Python App
Every time we change and save the file, ONLYOFFICE stores all its versions. Let’s see closely how it works. After we close the editor, Document Server builds the file version to be saved and sends the request to callbackUrl address. This request contains document.key and the link to the just built file.
document.key is used to find the old version of the file and replace it with the new one. As we do not have any database here, we just send the filename using callbackUrl.
Specify callbackUrl parameter in the setting in editorConfig.callbackUrl and add it to the edit()method:

function edit(filename) {
const filepath = 'files/' + filename;
if (editor) {
editor.destroyEditor()
}
editor = new DocsAPI.DocEditor("editor",
{
documentType: get_file_type(filepath),
document: {
url: "host_url" + '/' + filepath,
title: filename, 
key: filename + '_key'
}
,
editorConfig: {
mode: 'edit',
callbackUrl: "host_url" + '/callback' + '&filename=' + filename // add file name as a request parameter
}
});
}

Let’s write a method that will save file after getting the POST request to /callback address:

@post("/callback") # processing post requests for /callback
def callback():
if request.json['status'] == 2:
file = requests.get(request.json['url']).content
with open('files/' + request.query['filename'], 'wb') as f:
f.write(file)
return "{\"error\":0}"

 # status 2  is the built file.

When we close the editor, the new version of the file will be saved to storage.

6. How to manage users in ONLYOFFICE within the Python App
As there are users in our app, we need to see who exactly is editing a doc, we should write their identifiers (id and name) in the editors’ configuration.
Let’s add the ability to select a user in the interface:

<select id="user_selector" onchange="pick_user()">
<option value="1" selected="selected">JD</option>
<option value="2">Turk</option>
<option value="3">Elliot</option>
<option value="4">Carla</option>
</select>

If we add the call of the function pick_user()at the beginning of the tag <script>, it will initialize, in the function itself, the variables responsible for the id and the user name.

function pick_user() {
const user_selector = document.getElementById("user_selector");
this.current_user_name = user_selector.options[user_selector.selectedIndex].text;
this.current_user_id = user_selector.options[user_selector.selectedIndex].value;
}

We make use of editorConfig.user.id and  editorConfig.user.name to configure user’s settings. We add these parameters to the editors’ configuration in the file editing function.

function edit(filename) {
const filepath = 'files/' + filename;
if (editor) {
editor.destroyEditor()
}
editor = new DocsAPI.DocEditor("editor",
{
documentType: get_file_type(filepath),
document: {
url: "host_url" + '/' + filepath,
title: filename
},
editorConfig: {
mode: 'edit',
callbackUrl: "host_url" + '/callback' + '?filename=' + filename,
user: {
id: this.current_user_id,
name: this.current_user_name
}
}
});
}

Using this approach, we can integrate ONLYOFFICE editors into our app written in Python and get all the necessary tools for working and collaborating on docs. For more integration examples (Java, Node.js, PHP, Ruby), please, refer to the official API documentation.

LEAVE A REPLY

Please enter your comment!
Please enter your name here