ONLYOFFICE’s diary

OSSドキュメントエディタの使い方やヒントをご紹介します

お使いのアプリ内でドキュメントの共同編集を可能にする方法

前回の記事では、ONLYOFFICEを使って、ドキュメントの閲覧・編集をあらゆるWebアプリに導入する方法をご紹介しました。

今回は、強力なドキュメント共同編集機能をユーザーに提供することに焦点を当てます。共同編集の仕組みについて簡単に説明し、既存の統合アプリのコードサンプルをご提供いたます。

統合の基本

ONLYOFFICE Docsは、オープンソースのオフィススイートです。そのオープンAPIは、さまざまな同期・共有ソリューション、DMS、CMS、そしてドキュメント、スプレッドシート、スライド編集機能を必要とする他のあらゆるプラットフォームと統合することを可能にします。

基本的な統合は次のようなものです。

  • ONLYOFFICE Docsを使用してオフィスファイルを開くオプションは、エディタを実行するためのJavaScriptの初期化とともに、システムのフロントエンドに追加されます。
  • 編集したファイルを保存するためのリクエストは、バックエンドで処理されます。

簡単に言うと、DMSに保存されているオフィスファイルを開いてONLYOFFICE Docsで編集し、ストレージに戻して保存することができるということです。

基本的な統合の原則をすでにご存知でしたら、共同編集やドキュメントのバージョンの保存など、より複雑な事柄に進むことをお勧めします。

新規ファイルの作成

ONLYOFFICE Docsの主な目的は、編集や共同編集のためにDMSに保存されたファイルを開くことです。しかし、実際には、アプリ内で共同作業をするために、新しいオフィスファイル(docx、xlsx、pptx)を作成する機能を追加することができます。

この機能は、エディタには直接接続されていません。統合コードでは、さまざまな言語で用意された空のファイルテンプレートを追加します。

ユーザーが新しいファイルを作成すると、このテンプレートが指定されたフォルダーにコピーされます。その後、ファイルはエディタで開けます。

既存のAlfrescoとの統合でどのように行われるかを見てみましょう。

ここでは、ボタンを登録する方法をご説明します。

<alfresco-config>
    <config evaluator="string-compare" condition="DocumentLibrary">
        <create-content>
            <content id="document-onlyoffice-create-docx" type="javascript" label="actions.document.onlyoffice-create-docx">
                <param name="function">onOnlyofficeCreateDocx</param>
            </content>
        </create-content>
    </config>
</alfresco-config>

では、ユーザーがクリックしたときに何が起こるのか見ていきましょう。次のコードはここから引用しています。

(function () {
    // function registration
    YAHOO.Bubbling.fire("registerAction",
    {
        actionName: "onOnlyofficeCreateDocx",
        fn: function (obj) {
            // opening the generated file
            window.open("onlyoffice-edit?nodeRef=" + obj.nodeRef + "&new=application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        }
    });
})();

共同編集の導入

リアルタイムでのドキュメント、スプレッドシート、スライドの共同編集は、ONLYOFFICEの最も重要な機能の1つです。これは、異なるユーザーが同時に開いた1つのドキュメントに、同じdocument.keyを使用することで実装されています。

このキーは、エディタがドキュメントを認識するためのユニークな識別子です。編集後にドキュメントを保存するたびに更新されるため、システムのデータベースからファイルIDを使用できません。また、ファイルへのパスを使うのもよくありません(たとえば、Nextcloudでは、異なるユーザーが同じファイルを異なる名前で共有していることがあります)。

よくあるのは、システムで一意なファイルハッシュを持っていて、ファイルを変更したときに更新されるものです。これは document.key に完全に適合します。

以下は、Confluence 用の統合アプリに実装されている方法です。

public static String getKeyOfFile(Long attachmentId) {
    String hashCode = AttachmentUtil.getHashCode(attachmentId); // built-in function for getting hash
    return hashCode;
}

強制保存の仕組みもサポートする予定であれば、共同編集をもたらす状況は、少しニュアンスが変わってきます。

強制保存が有効な場合、我々のユーザーが保存をクリックするか、Ctrl+Sを使用するたびに、ファイルの中間バージョンがストレージに保存されます。 しかし、中間バージョンのハッシュを使用して共同編集に接続することはできません。この場合、編集セッションの開始から終了まで、強制保存後もドキュメントを開いたすべてのユーザーに対して使用される document.key を追加で保存するように実装する必要があります。

注意:編集セッションは、最初のユーザーがドキュメントを開いたときに始まり、最後のユーザーがドキュメントを閉じたときに終わります。 Nextcloudとの連携では、このようになります。

public function getKey($file) {
    $fileId = $file->getId();
    // searching for the key
    $key = KeyManager::get($fileId);

    // if the key is empty, the file is not being edited
    if (empty($key) ) {
        // generate a unique key
        $key = $instanceId . "_" . $this->GUID();
        // save the key to the database for the next co-editing session
        KeyManager::set($fileId, $key);
    }
    return $key;
}

共有権限

通常、システムはユーザーが閲覧または編集のためにドキュメントを開くことを許可します。ONLYOFFICE Docsでは、これらのモードの両方が利用可能ですが、そのAPIはいくつかの高度なオプションも提供しています。例えば、ダウンロード印刷を制限したり、クリップボードにデータをコピーすることも可能です。

また、レビューコメントなどのためのドキュメント共有を実装することも可能です。もし、お使いのアプリにこれが必要なら、既存のownCloudとの統合をご検討ください。

// configuring editors initialization
$params = [
    "document" => [
        "fileType" => $ext,
        "key" => $key,
        "permissions" => [],
        "title" => $fileName,
        "url" => $fileUrl,
    ],
    "documentType" => $format["type"]
];
// file permissions for the current user
$storageShare = $file->getStorage()->getShare();
// file permissions attributes for the current user
$attributes = $storageShare->getAttributes();
// permission to download file
$params["document"]["permissions"]["download"] = $attributes->getAttribute("permissions", "download"); === true;
// permission to review file
$params["document"]["permissions"]["review"] = $attributes->getAttribute($this->appName, "review") === true;
// permission to fill forms
$params["document"]["permissions"]["fillForms"] = $attributes->getAttribute($this->appName, "fillForms") === true;
// permission to comment
$params["document"]["permissions"]["comment"] = $attributes->getAttribute($this->appName, "comment") ===

これらの権限を追加するための詳細情報は、こちらの記事でご確認ください。

インスタンス間でのファイルの共有と共同編集

アプリが複数のマシンにデプロイされ、インスタンスが何らかのロジックで接続されている場合(例えば、大学のネットワーク内にある複数のインスタンス)、あるインスタンスに保存されているファイルを、別のインスタンスに登録されている特定のユーザーと共有することは全く可能です。

例えば、NextcloudやownCloudには、異なるインスタンス間でファイルを共有する機能があります。この機能はFederated Shareと呼ばれています。

Federated Shareに対応するために、1つのドキュメントサーバーに対して複数のインスタンスを接続して共同編集できるようにしました。ドキュメントサーバーはファイルを開くときに、それが他のインスタンスに保存されているかどうかを常にチェックし、そのネイティブな document.key を要求します。

以下は、ownCloudとの統合で行われる方法です。

// сhecking if file is from another instance
if ($file->getStorage()->instanceOfStorage(SharingExternalStorage::class)) {
    // making a request to get the key to the instance where file is stored
    $response = \OC::$server->getHTTPClientService()->newClient()->post($file->getStorage()->getRemote() . "/ocs/v2.php/apps/" . $this->appName . "/api/v1/key?format=json", [
        "body" => [
            "shareToken" => $file->getStorage()->getToken(), // file sharing token
            "path" => $file->getInternalPath() // path to file
        ]
    ]);
    // processing request response
    $body = \json_decode($response->getBody(), true);
    // extracting the key
    $key = $body["ocs"]["data"]["key"];
    // using the key 
    if (!empty($key)) {
        return $key;
    }
}
// getting key for current instance
$key = KeyManager::get($fileId);

セキュリティの確保

オンライン・ドキュメント・エディタを統合する場合、セキュリティは最優先事項の1つです。ドキュメントサーバーだけが、ファイルの読み取りと保存を行えるようにする必要があります。 さらに、ユーザーがアクセス許可されている以上のデータにアクセスできないようにする必要があります。

そのセキュリティを確保するために、エディタとその内部サービス、ストレージの間のコマンドはすべてシクレットキーに基づく暗号化署名で保護されています。エディタ側では、キーは設定ファイルに記述されますが、ストレージ側では、通常、設定の一部として含まれます。

署名にはJSON Web Tokenを使用し、すべてのリクエストファイルのオープンを含む、データに対して特定の操作を行う権利を検証します。

以下は、Ploneでの実装方法です。

# editors initialization configuration
config = {
    'documentType': fileUtils.getFileType(filename),
    'document': {
        'fileType': filetype,
        'key': url,
        'title': filename,
        'url': url
    },
    'editorConfig': {
        'callbackUrl': callbackUrl
    }
}
# adding token for configuration
config['token'] = jwt.encode(config, jwtSecret, algorithm="HS256").decode("utf-8")

バージョン履歴

DMSがファイルのバージョン保存をサポートしている場合、編集履歴を閲覧したり、以前のバージョンを復元したりすることができます。

追加情報の保存が可能なシステムでは、ハイライトされた変更を含む開封履歴を追加できます。ONLYOFFICEは、ファイルそのものと変更履歴を別々に保存するため、それが可能なのです。そのため、ユーザーがバージョン履歴を開くと、変更履歴がエディタに渡されます

ownCloudとの連携からの例です。

var docEditor = new DocsAPI.DocEditor("iframeEditor", { // editor intialiazation
    ....
    events: { // subscribing to events
        ....
        "onRequestHistory": function (version) { // processing the event of opening history
            $.get(historyUrl, // requesting history from server
                function onSuccess(response) {
                    data = {
                        history: response, // forming data to open history
                    };
                    docEditor.refreshHistory(data); // passing history to the editor
                })
            }
    };
})

これらは、ユーザーにより良い文書編集体験を提供するために使用できる最も重要な統合機能です(しかしすべてではありません!)。もし、これらのトピックのうち、より詳細な説明が必要な場合は、コメントでお知らせください。