Webサポートクイックスタート

ドキュメントデータのビルド

アプリケーションの中でウェブサポートパッケージを使用する場合は、まずはデータを作る必要があります。データには、pickle化されたドキュメントや検索インデックス、コメントなどがどのドキュメントに付加されたのかを追跡するためのノードデータが含まれます。これを行うためには、 WebSupport クラスのインスタンスを作り、 build() メソッドを呼ぶ必要があります:

from sphinxcontrib.websupport import WebSupport

support = WebSupport(srcdir='/path/to/rst/sources/',
                     builddir='/path/to/build/outdir',
                     search='xapian')

support.build()

このコードは、reStructuredTextのソースコードを srcdir から読み込み、必要なデータを builddir に書き出します。 builddir は二つのサブディレクトリを含みます。 "data" には、ドキュメントを表示したり、ドキュメントを検索したり、ドキュメントにコメントを付けるのに必要なデータがすべて含まれます。もう一つの "static" ディレクトリは、 "/static" からファイルを配信するための、静的ファイルを含みます。

注釈

もし "/static" 以外のパスから静的ファイルの配信をしたい場合には、 WebSupport オブジェクトを作る時に、 staticdir キーワード引数を指定してください。

Sphinxドキュメントをウェブアプリケーションに統合

データができましたので、次はこれを使う番です。アプリケーションのための WebSupport オブジェクトを作るところから始めます:

from sphinxcontrib.websupport import WebSupport

support = WebSupport(datadir='/path/to/the/data',
                     search='xapian')

次に、個々のドキュメントに対する処理を作っていきます。 get_document() メソッドを呼ぶと、個々のドキュメントにアクセスできます:

contents = support.get_document('contents')

このメソッドは、次のキーを持つ辞書を返します:

  • body: HTML形式のドキュメント本体です。

  • sidebar: HTML形式のサイドバーです。

  • relbar: このdivは、関連ドキュメントへのリンクを含んでいます。

  • title: ドキュメントのタイトルです。

  • css: Sphinxが使用するCSSファイルへのリンクです。

  • script: JavaScriptはコメントオプションを含みます。

This dict can then be used as context for templates. The goal is to be easy to integrate with your existing templating system. An example using Jinja2 is:

{%- extends "layout.html" %}

{%- block title %}
    {{ document.title }}
{%- endblock %}

{% block css %}
    {{ super() }}
    {{ document.css|safe }}
    <link rel="stylesheet" href="/static/websupport-custom.css" type="text/css">
{% endblock %}

{%- block script %}
    {{ super() }}
    {{ document.script|safe }}
{%- endblock %}

{%- block relbar %}
    {{ document.relbar|safe }}
{%- endblock %}

{%- block body %}
    {{ document.body|safe }}
{%- endblock %}

{%- block sidebar %}
    {{ document.sidebar|safe }}
{%- endblock %}

認証

投票のような機能を実装する場合、ユーザ認証ができる必要があります。認証をどのように実装するかはアプリケーションに任されています。ユーザが認証されたら、ユーザの情報を WebSupport のメソッドの usernamemoderator キーワード引数に渡すことができます。ウェブサポートパッケージはユーザ名を、コメントや投票と一緒に保存します。注意点を1つあげるとすれば、もしユーザに対して名前の変更を行えるようにするのであれば、ウェブサポートパッケージの内部のユーザ名のデータも更新する必要があります:

support.update_username(old_username, new_username)

username はユーザを識別できる一意な文字列であるべきで、 moderator はboolean型のユーザが適切な権限を持つかどうかを表すべきです。 moderator のデフォルト値は False です。

An example Flask function that checks whether a user is logged in and then retrieves a document is:

from sphinxcontrib.websupport.errors import *

@app.route('/<path:docname>')
def doc(docname):
    username = g.user.name if g.user else ''
    moderator = g.user.moderator if g.user else False
    try:
        document = support.get_document(docname, username, moderator)
    except DocumentNotFoundError:
        abort(404)
    return render_template('doc.html', document=document)

まず、 docname が要求されたパスを表すことに気づきます。これにより、正しいドキュメントへのアクセスが行えます。もしユーザの認証が行われていたら、ユーザ名とモデレート権限情報が get_document() に渡されます。ウェブサポートパッケージは、テンプレートの中で使用される COMMENT_OPTIONS をこのデータに付加します。

注釈

This only works if your documentation is served from your document root. If it is served from another directory, you will need to prefix the url route with that directory, and give the docroot keyword argument when creating the web support object:

support = WebSupport(..., docroot='docs')

@app.route('/docs/<path:docname>')

検索の実行

To use the search form built-in to the Sphinx sidebar, create a function to handle requests to the URL 'search' relative to the documentation root. The user's search query will be in the GET parameters, with the key q. Then use the get_search_results() method to retrieve search results. In Flask that would be like this:

@app.route('/search')
def search():
    q = request.args.get('q')
    document = support.get_search_results(q)
    return render_template('doc.html', document=document)

ドキュメントと検索結果の表示には、同じテンプレートを使用しています。これは、 get_search_results() メソッドが、 get_document() と同じ形式のコンテキスト辞書を返すからです。

コメント&提案

それでは、コメントなどをAJAXで処理するための関数を定義します。3つの関数を定義する必要があります。1つ目は、新しいコメントが投稿されたときに、ウェブサポートオブジェクトの add_comment() メソッドを呼び出すものです:

@app.route('/docs/add_comment', methods=['POST'])
def add_comment():
    parent_id = request.form.get('parent', '')
    node_id = request.form.get('node', '')
    text = request.form.get('text', '')
    proposal = request.form.get('proposal', '')
    username = g.user.name if g.user is not None else 'Anonymous'
    comment = support.add_comment(text, node_id='node_id',
                                  parent_id='parent_id',
                                  username=username, proposal=proposal)
    return jsonify(comment=comment)

リクエストには、 parent_idnode_id を送っています。コメントが他のノードに直接追加された場合には、 parent_id は空になります。また、コメントが他のコメントの子供として付加された場合には、 node_id が空になります。次の関数は、 get_data() メソッドを利用して、特定のノードに対するコメントを取り扱います:

@app.route('/docs/get_comments')
def get_comments():
    username = g.user.name if g.user else None
    moderator = g.user.moderator if g.user else False
    node_id = request.args.get('node', '')
    data = support.get_data(node_id, username, moderator)
    return jsonify(**data)

最後の関数は、 process_vote() を呼び出して、コメントに対するユーザの投票を取り扱う関数です:

@app.route('/docs/process_vote', methods=['POST'])
def process_vote():
    if g.user is None:
        abort(401)
    comment_id = request.form.get('comment_id')
    value = request.form.get('value')
    if value is None or comment_id is None:
        abort(400)
    support.process_vote(comment_id, g.user.id, value)
    return "success"

コメントのモデレート

デフォルトでは、 add_comment() を使って追加したすべてのコメントは表示されます。もし、モデレーションを行って、承認されたコメントだけを表示したいのであれば、 displayed キーワード引数を渡します:

comment = support.add_comment(text, node_id='node_id',
                              parent_id='parent_id',
                              username=username, proposal=proposal,
                              displayed=False)

コメントのモデレートを取り扱うビューを追加する必要があります。モデレータがコメントを受け入れて、表示するかどうかを決定するときに、この関数が呼び出されます:

@app.route('/docs/accept_comment', methods=['POST'])
def accept_comment():
    moderator = g.user.moderator if g.user else False
    comment_id = request.form.get('id')
    support.accept_comment(comment_id, moderator=moderator)
    return 'OK'

リジェクトされると、コメントは削除されます。

非表示の新しいコメントが追加されたときに、Eメールによるモデレートなど、カスタムのアクションを行いたい場合には、 WebSupport のインスタンスを作る時に、呼び出し可能なオブジェクトを渡します:

def moderation_callback(comment):
    """Do something..."""

support = WebSupport(..., moderation_callback=moderation_callback)

The moderation callback must take one argument, which will be the same comment dict that is returned by WebSupport.add_comment().