リモートワークやハイブリッドワークモデルの採用が増える中、コラボレーションアプリの開発への関心は依然として高いですね。COVID19のパンデミック規制のほとんどが解除されたにもかかわらず、企業やチームは柔軟性のメリットをすべて体験することができ、新しいニッチなソフトウェアに対する需要を刺激することができました。
データを扱うのに最も人気のある言語の1つは間違いなくPythonです。ファイルストレージと共有の上にコラボレーション機能を提供するアプリを構築してみてはいかがでしょうか。
この記事では、APIを使ってPython上の文書管理システムにONLYOFFICEドキュメントエディタの機能を追加する方法をご紹介します。思ったより簡単にできそうですね。
PythonでのDMSについて
このパートでは、Pythonアプリを書き、ONLYOFFICEとの統合をその例でご紹介します。エディタを統合しようと思っているアプリは、閲覧/編集のために開く必要のあるオフィスファイルを扱う可能性が高いです。実際の設定でケースを説明するために、DMSの機能に似たアプリを作成することにします。このアプリでは、ファイルのダウンロードもできるようにする必要があります。
このアプリには、Bottleフレームワークを使用します。pip install bottle
コマンドで作業ディレクトリにインストールできます。次に、main.py
(アプリのコード)とindex.tpl
(テンプレート)を作成し、main.py
ファイルに次のコードを追加します。
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
アプリを起動すると、http: // localhost:8080
に空のページが表示されます。ここで、開くためのファイルを追加して、テンプレートにその名前のリストを作成する必要があります。次に、files
フォルダを作成し、そこに3つのファイル(docx, xlsx, pptx)を置きます。
そのファイル名を読み取るために、listdir
コンポーネントを使用します。
from os import listdir
では、files
フォルダーにあるすべてのファイル名の変数を作ってみましょう。
sample_files = [f for f in listdir('files')]
この変数をテンプレートで使用するには、template
メソッドに渡す必要があります。
def index():
return template('index.tpl', sample_files=sample_files)
この変数をテンプレートに表示してみましょう:html
%for file in sample_files:
<div>
<span>{{file}}</span>
</div>
% end
アプリを再起動すると、ページ上にファイル名のリストが表示されます。さて、これらのファイルをすべてのアプリ利用者が利用できるようにする必要があります。
ここでは、そのための新しい方法をご紹介します。
@get("/files/<filepath:re:.*\.*>")
def show_sample_files(filepath):
return static_file(filepath, root="files")
Pythonアプリでドキュメントを表示する
ONLYOFFICEエディタを使ってDocument Serverをインストールします。インストール方法はたくさんありますが、Dockerを使うことをお勧めします。
docker run -itd -p 80:80 onlyoffice/documentserver
テンプレート内のドキュメントエディターAPIを接続します。
<script type="text/javascript" src="editor_url/web-apps/apps/api/documents/api.js"></script>
editor_url
はドキュメントエディタへのリンクです。
各ファイルを開いて閲覧するためのボタンは:
<button onclick="view('files/{{file}}')">view</button>
ここで、id
を持つdivを追加する必要があります。
<div id="editor"></div>
このdivの中でドキュメントエディタが開かれます。しかし、エディタを開く関数を呼び出した後でなければなりません。
<script>
function view(filename) {
if (/docx$/.exec(filename)) {
filetype = 'word'
}
if (/xlsx$/.exec(filename)) {
filetype = 'cell'
}
if (/pptx$/.exec(filename)) {
filetype = 'slide'
}
new DocsAPI.DocEditor('editor',
{
documentType: filetype,
document: {
url: "host_url" + '/' + filename,
title: filename
},
editorConfig: {mode: 'view'}
});
}
</script>
DocEditor関数の引数は2つです。エディタを開く要素の id
と、エディタの設定を指定するjsonです。
すべてのパラメータは、公式のAPIドキュメントに記載されています。この例では、必須パラメータである documentType
, document.url
と editorConfig.mode
を使用します。また、 title
も追加してみよう。これはエディタに表示されるファイル名です。
ドキュメントの種類 (documentType
) は、そのフォーマットによって識別されます (docxはword、xlsxはcell、pptxはslide)。
document.url
に注目してください。これはこれから開こうとしているファイルへのリンクです。
これで、Pythonアプリでドキュメントを表示するためのすべてが揃いました。
ファイルの編集
「編集」ボタンを追加してみましょう。
<button onclick="edit('files/{{file}}')">edit</button>
次に、ファイルを開いて編集するための新しい関数を作成する必要があります。これは「表示」関数に似ているので、共通部分を別の関数にしましょう。
これで3つの関数ができました。
<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 'word'
}
if (/xlsx$/.exec(filename)) {
return 'cell'
}
if (/pptx$/.exec(filename)) {
return 'slide'
}
}
</script>
destroyEditor
はエディタを開いていた場合、そのエディタを閉じます。
デフォルトでは、 editorConfig
パラメータの値は {"mode": "edit"}
という値を持っています。そのため、 edit()
関数にはこのパラメータがありません。
これで、ファイルが編集用に開かれるようになります。
文書の共同編集
共同編集は、エディタの設定で同じドキュメントに対して同じ document.key を使用することで実装されています。このキーがない場合、エディタはファイルを開くたびに編集セッションを作成します。
共同編集のために同じ編集セッションに接続させるためには、それぞれのdocにユニークなキーを設定する必要があります。ここでは、filename + "_key"
という形式のキーを使用することにしましょう。これを document
が存在するすべての設定に追加する必要がある。
json
document: {
url: "host_url" + '/' + filepath,
title: filename,
key: filename + '_key'
},
ファイルの保存
ONLYOFFICEは通常、作業中にドキュメントに加えたすべての変更点を保存します。エディタを閉じた後、Document Serverは保存するファイルのバージョンをビルドして、callbackUrlアドレスにリクエストを送信します。このリクエストには document.key
とビルドされたばかりのファイルへのリンクが含まれています。
実運用では、document.key
を使用して古いバージョンのファイルを見つけ、新しいものに置き換えます。今回のケースでは、データベースがないので、callbackUrlを使用してファイル名を送信します。
editorConfig.callbackUrlの設定で、callbackUrl
を指定します。このパラメータを追加すると、edit()
メソッドは次のようになります。
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
}
});
}
次に、POST リクエストを /callback
アドレスに取得した後にファイルを保存するメソッドを記述する必要があります。
@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}"
これで、エディタを閉じた後、新しいバージョンのファイルがストレージに保存されるようになりました。
ユーザーの管理
アプリ内にユーザーがいる場合、エディタ設定にユーザーの識別子(idとname)を記述してください。こうすることで、誰がドキュメントを編集しているのかを確認することができます。
例として、インターフェイスでユーザーを選択する機能を追加してみましょう。
<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>
pick_user()
という関数の呼び出しを <script>
というタグの最初に追加しましょう。この関数の中で、idとユーザー名を表す変数を初期化します。
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;
}
次に、エディタ設定に editorConfig.user.id
と editorConfig.user.name
を使って、ユーザーの設定を追加します。これらのパラメータを、ファイル編集機能のエディタ設定に追加してみましょう。
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
}
}
});
}
このシンプルな例が、あなたのPythonアプリにONLYOFFICEを統合する助けになることを願っています。
もしあなたがPython開発者であれば、お考えやご経験をここで共有していただければ、Pythonベースの環境へのONLYOFFICE機能の統合について、さらに詳しく説明することができます。