Web Support 快速入門

建立文件資料

為了在您的應用程式中使用 web support 套件,您需要建立其使用的資料。此資料包含代表文件的 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

然後,此字典可以用作範本的上下文。目標是易於與您現有的範本系統整合。以下是使用 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 方法,使用 usernamemoderator 關鍵字引數。web support 套件將使用者名稱與意見和投票一起儲存。唯一的注意事項是,如果您允許使用者變更其使用者名稱,則必須更新 websupport 套件的資料

support.update_username(old_username, new_username)

username 應該是識別使用者的唯一字串,而 moderator 應該是一個布林值,表示使用者是否具有審核權限。moderator 的預設值為 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)

首先要注意的是 docname 只是請求路徑。這使得從單一視圖輕鬆存取正確的文件。如果使用者通過身份驗證,則使用者名稱和審核狀態將與 docname 一起傳遞給 get_document()。然後,web support 套件會將此資料新增至範本中使用的 COMMENT_OPTIONS

注意

這僅在您的文件從文件根目錄提供時才有效。如果它從另一個目錄提供,您將需要使用該目錄作為 url 路由的前綴,並在建立 web support 物件時提供 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 support 方法 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'

拒絕意見是透過刪除意見來實現的。

若要在新增但未顯示新意見時執行自訂動作(例如,透過電子郵件通知審核者),您可以在實例化支援物件時將可呼叫物件傳遞給 WebSupport 類別

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

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

審核回呼必須接受一個引數,該引數將是 WebSupport.add_comment() 傳回的相同意見字典。