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: The main body of the document as HTML
sidebar: The sidebar of the document as HTML
relbar: A div containing links to related documents
title: The title of the document
css: Links to CSS files used by Sphinx
script: JavaScript containing comment options
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 %}
Authentication¶
To use certain features such as voting, it must be possible to authenticate
users. The details of the authentication are left to your application. Once a
user has been authenticated you can pass the user’s details to certain
WebSupport
methods using the username and moderator keyword
arguments. The web support package will store the username with comments and
votes. The only caveat is that if you allow users to change their username you
must update the websupport package’s data:
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
.
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)
The first thing to notice is that the docname is just the request path. This
makes accessing the correct document easy from a single view. If the user is
authenticated, then the username and moderation status are passed along with the
docname to get_document()
. The web support package will then
add this data to the COMMENT_OPTIONS
that are used in the template.
备注
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>')
Performing Searches¶
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)
Note that we used the same template to render our search results as we did to
render our documents. That’s because get_search_results()
returns a context dict in the same format that get_document()
does.
Comment Moderation¶
By default, all comments added through add_comment()
are
automatically displayed. If you wish to have some form of moderation, you can
pass the displayed
keyword argument:
comment = support.add_comment(text, node_id='node_id',
parent_id='parent_id',
username=username, proposal=proposal,
displayed=False)
You can then create a new view to handle the moderation of comments. It will be called when a moderator decides a comment should be accepted and displayed:
@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'
Rejecting comments happens via comment deletion.
To perform a custom action (such as emailing a moderator) when a new comment is
added but not displayed, you can pass callable to the WebSupport
class when instantiating your support object:
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 add_comment()
.
Comments & Proposals¶
Now that this is done it’s time to define the functions that handle the AJAX calls from the script. You will need three functions. The first function is used to add a new comment, and will call the web support method
add_comment()
:You’ll notice that both a
parent_id
andnode_id
are sent with the request. If the comment is being attached directly to a node,parent_id
will be empty. If the comment is a child of another comment, thennode_id
will be empty. Then next function handles the retrieval of comments for a specific node, and is aptly namedget_data()
:The final function that is needed will call
process_vote()
, and will handle user votes on comments: