Web支持快速入门

构建文档数据

要在应用程序中使用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()

这将从 srcdir 读取reStructuredText源,并将必要的数据放置在 builddir 中。 builddir 将包含两个子目录:一个名为"data",其中包含显示文档、搜索文档和向文档添加注释所需的所有数据。另一个目录将称为"static",其中包含应从"/static"提供的静态文件。

备注

如果您希望从"/static"以外的路径提供静态文件,可以在创建 WebSupport 对象时提供 staticdir 关键字参数。

将Sphinx文档集成到您的Web应用程序中

现在数据已经生成完毕,是时候做一些有用的事了。首先为您的应用程序创建一个 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

然后可以将此dict用作模板的上下文。目标是轻松与您现有的模板系统集成。一个使用 Jinja2 的例子:

{%- 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 方法。 Web支持包将存储带有注释和投票的用户名。唯一需要注意的是,如果您允许用户更改其用户名,则必须更新websupport包的数据:

support.update_username(old_username, new_username)

username should be a unique string which identifies a user, and moderator should be a boolean representing whether the user has moderation privileges. The default value for moderator is False.

例如 Flask 函数检查用户是否登录,检索文档是:

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)

首先要注意的是 文件名 只是请求路径。这样可以从单个视图轻松访问正确的文档。如果用户已通过身份验证,则用户名和审核状态将与文件名一起传递到 get_document()。然后,Web支持包将此数据添加到模板中使用的 COMMENT_OPTIONS

备注

这仅在您的文档从文档根目录提供时才有效。如果它是从另一个目录提供的,您将需要使用该目录作为URL路由的前缀,并在创建Web支持对象时提供 docroot 关键字参数:

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

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

执行搜索

要使用内置于Sphinx侧边栏的搜索表单,请创建一个函数来处理相对于文档根目录的URL 'search'的请求。用户的搜索查询将位于GET参数中,键为 q。然后使用 get_search_results() 方法来检索搜索结果。在 Flask 中,如下所示:

@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调用的函数。您将需要三个函数。第一个函数用于添加新注释,并将调用Web支持方法 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'

通过删除注释来拒绝注释。

要在添加新注释但未显示时执行自定义操作(例如通过电子邮件发送至审核人),可以在实例化支持对象时将callable传递给 WebSupport 类:

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

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

审核回调必须接受一个参数,该参数将与 WebSupport.add_comment() 返回的注释字典相同。