mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Lots of documentation and a few small API changes
This commit is contained in:
@@ -1,22 +1,32 @@
|
||||
.. _websupportapi:
|
||||
|
||||
Web Support API
|
||||
===============
|
||||
.. currentmodule:: sphinx.websupport
|
||||
|
||||
The WebSupport Class
|
||||
====================
|
||||
|
||||
.. module:: sphinx.websupport.api
|
||||
.. class:: WebSupport
|
||||
|
||||
The :class:`WebSupport` class provides a central interface for
|
||||
working with Sphinx documentation.
|
||||
The main API class for the web support package. All interactions
|
||||
with the web support package should occur through this class.
|
||||
|
||||
.. method:: init(srcdir='', outdir='')
|
||||
:param srcdir: the directory containing the reStructuredText files
|
||||
:param outdir: the directory in which to place the built data
|
||||
:param search: the search system to use
|
||||
:param comments: an instance of a CommentBackend
|
||||
|
||||
Methods
|
||||
~~~~~~~
|
||||
|
||||
Initialize attributes.
|
||||
.. automethod:: sphinx.websupport.WebSupport.build
|
||||
|
||||
.. method:: build()
|
||||
.. automethod:: sphinx.websupport.WebSupport.get_document
|
||||
|
||||
Build the data used by the web support package.
|
||||
.. automethod:: sphinx.websupport.WebSupport.get_comments
|
||||
|
||||
.. method:: get_document(docname)
|
||||
.. automethod:: sphinx.websupport.WebSupport.add_comment
|
||||
|
||||
.. automethod:: sphinx.websupport.WebSupport.process_vote
|
||||
|
||||
.. automethod:: sphinx.websupport.WebSupport.get_search_results
|
||||
|
||||
Retrieve the context dictionary corresponding to the *docname*.
|
||||
|
||||
@@ -3,118 +3,215 @@
|
||||
Web Support Quick Start
|
||||
=======================
|
||||
|
||||
Getting Started
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
To use the :ref:`websupportapi` in your application you must import
|
||||
the :class:`~sphinx.websupport.api.WebSupport` object::
|
||||
|
||||
from sphinx.websupport import support
|
||||
|
||||
This provides a reference to a :class:`~sphinx.websupport.api.WebSupport`
|
||||
object. You will then need to provide some information about your
|
||||
environment::
|
||||
|
||||
support.init(srcdir='/path/to/rst/sources/',
|
||||
outdir='/path/to/build/outdir',
|
||||
search='xapian')
|
||||
|
||||
Note: You only need to provide a srcdir if you are building documentation.
|
||||
|
||||
Building Documentation Data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In order to use the web support package in a webapp, you will need to
|
||||
build the data it uses. This data includes document data used to display
|
||||
documentation and search indexes. To build this data, call the build method::
|
||||
To make use of the web support package in your application you will
|
||||
need to build that data it uses. This data includes pickle files representing
|
||||
documents, search indices, and node data that is used to track where
|
||||
comments and other things are in a document. Do do this you will need
|
||||
to create an instance of the :class:`~sphinx.websupport.api.WebSupport`
|
||||
class and call it's :meth:`~sphinx.websupport.WebSupport.build` method::
|
||||
|
||||
from sphinx.websupport import WebSupport
|
||||
|
||||
support = WebSupport(srcdir='/path/to/rst/sources/',
|
||||
outdir='/path/to/build/outdir',
|
||||
search='xapian')
|
||||
|
||||
support.build()
|
||||
|
||||
This will create the data the web support package needs and place
|
||||
it in *outdir*.
|
||||
This will read reStructuredText sources from `srcdir` and place the
|
||||
necessary data in `outdir`. This directory contains all the data needed
|
||||
to display documents, search through documents, and add comments to
|
||||
documents.
|
||||
|
||||
Accessing Document Data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Integrating Sphinx Documents Into Your Webapp
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To access document data, call the get_document(docname) method. For example,
|
||||
to retrieve the "contents" document, do this::
|
||||
|
||||
contents_doc = support.get_document('contents')
|
||||
|
||||
This will return a dictionary containing the context you need to render
|
||||
a document.
|
||||
|
||||
Performing Searches
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To perform a search, call the get_search_results(q) method, with *q* being
|
||||
the string to be searched for::
|
||||
|
||||
q = request.GET['q']
|
||||
search_doc = support.get_search_results(q)
|
||||
|
||||
This will return a dictionary in the same format as get_document() returns.
|
||||
|
||||
Full Example
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A more useful example, in the form of a `Flask <http://flask.pocoo.org/>`_
|
||||
application is::
|
||||
|
||||
from flask import Flask, render_template
|
||||
from sphinx.websupport import support
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
support.init(outdir='/path/to/sphinx/data')
|
||||
Now that you have the data, it's time to use it for something useful.
|
||||
Start off by creating a :class:`~sphinx.websupport.WebSupport` object
|
||||
for your application::
|
||||
|
||||
@app.route('/docs/<path:docname>')
|
||||
from sphinx.websupport import WebSupport
|
||||
|
||||
support = WebSupport(datadir='/path/to/the/data',
|
||||
search='xapian')
|
||||
|
||||
You'll only need one of these for each set of documentation you will be
|
||||
working with. You can then call it's
|
||||
:meth:`~sphinx.websupport.WebSupport.get_document` method to access
|
||||
individual documents.
|
||||
|
||||
contents = support.get_document('contents')
|
||||
|
||||
This will return a dictionary containing the following items:
|
||||
|
||||
* **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
|
||||
|
||||
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 <http://jinja.pocoo.org/2/>`_ is:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
{%- extends "layout.html" %}
|
||||
|
||||
{%- block title %}
|
||||
{{ document.title }}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block relbar %}
|
||||
{{ document.relbar|safe }}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block body %}
|
||||
{{ document.body|safe }}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block sidebar %}
|
||||
{{ document.sidebar|safe }}
|
||||
{%- endblock %}
|
||||
|
||||
Most likely you'll want to create one function that can handle all of
|
||||
document requests. An example `Flask <http://flask.pocoo.org/>`_ function
|
||||
that performs this is::
|
||||
|
||||
@app.route('/<path:docname>')
|
||||
def doc(docname):
|
||||
document = support.get_document(docname)
|
||||
return render_template('doc.html', document=document)
|
||||
|
||||
@app.route('/docs/search')
|
||||
This captures the request path, and passes it directly to
|
||||
:meth:`~sphinx.websupport.WebSupport.get_document`, which retrieves
|
||||
the correct document.
|
||||
|
||||
.. note::
|
||||
|
||||
This only works 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::
|
||||
|
||||
@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 :meth:`~sphinx.websupport.WebSupport.get_search_results` method
|
||||
to retrieve search results. In `Flask <http://flask.pocoo.org/>`_ that
|
||||
would be like this::
|
||||
|
||||
@app.route('/search')
|
||||
def search():
|
||||
document = support.get_search_results(request.args.get('q', ''))
|
||||
return render_template('doc.html', document=document)
|
||||
q = request.args.get('q')
|
||||
document = support.get_search_results(q)
|
||||
return render_template('doc.html', document=document)
|
||||
|
||||
In the previous example the doc.html template would look something
|
||||
like this::
|
||||
Note that we used the same template to render our search results as we
|
||||
did to render our documents. That's because
|
||||
:meth:`~sphinx.websupport.WebSupport.get_search_results` returns a context
|
||||
dict in the same format as
|
||||
:meth:`~sphinx.websupport.WebSupport.get_document`.
|
||||
|
||||
{% extends "base.html" %}
|
||||
Comments
|
||||
~~~~~~~~
|
||||
|
||||
{% block title %}
|
||||
{{ document.title }}
|
||||
{% endblock %}
|
||||
The web support package provides a way to attach comments to some nodes
|
||||
in your document. It marks these nodes by adding a class and id to these
|
||||
nodes. A client side script can then locate these nodes, and manipulate
|
||||
them to allow commenting. A jquery script is also being developed that will
|
||||
be included when it's complete. For now you can find the script here:
|
||||
`websupport.js <http://bit.ly/cyaRaF>`_.
|
||||
|
||||
{% block extra_js %}
|
||||
<script type="text/javascript" src="/static/jquery.js"></script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
$(document).ready(function() {
|
||||
$(".spxcmt").append(' <a href="#" class="sphinx_comment"><img src="/static/comment.png" /></a>');
|
||||
$("a.sphinx_comment").click(function() {
|
||||
id = $(this).parent().attr('id');
|
||||
alert('[ comment stub ' + id + ' ]');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
-->
|
||||
</script>
|
||||
{% endblock %}
|
||||
If you use the script that is included, you will have to define some
|
||||
simple templates that the script uses to display comments. The first
|
||||
template defines the layout for the popup div used to display comments:
|
||||
|
||||
{% block relbar %}
|
||||
{{ document.relbar|safe }}
|
||||
{% endblock %}
|
||||
.. sourcecode:: guess
|
||||
|
||||
{% block body %}
|
||||
{{ document.body|safe }}
|
||||
{% endblock %}
|
||||
<script type="text/html" id="popup_template">
|
||||
<div class="popup_comment">
|
||||
<a id="comment_close" href="#">x</a>
|
||||
<h1>Comments</h1>
|
||||
<form method="post" id="comment_form" action="/docs/add_comment">
|
||||
<textarea name="comment"></textarea>
|
||||
<input type="submit" value="add comment" id="comment_button" />
|
||||
<input type="hidden" name="parent" />
|
||||
<p class="sort_options">
|
||||
Sort by:
|
||||
<a href="#" class="sort_option" id="rating">top</a>
|
||||
<a href="#" class="sort_option" id="ascage">newest</a>
|
||||
<a href="#" class="sort_option" id="age">oldest</a>
|
||||
</p>
|
||||
</form>
|
||||
<h3 id="comment_notification">loading comments... <img src="/static/ajax-loader.gif" alt="" /></h3>
|
||||
<ul id="comment_ul"></ul>
|
||||
</div>
|
||||
<div id="focuser"></div>
|
||||
</script>
|
||||
|
||||
{% block sidebar %}
|
||||
{{ document.sidebar|safe }}
|
||||
{% endblock %}
|
||||
The next templat is an `li` that contains the form used to
|
||||
reply to a comment:
|
||||
|
||||
.. sourcecode:: guess
|
||||
|
||||
<script type="text/html" id="reply_template">
|
||||
<li>
|
||||
<div class="reply_div" id="rd<%id%>">
|
||||
<form id="rf<%id%>">
|
||||
<textarea name="comment"></textarea>
|
||||
<input type="submit" value="add reply" />
|
||||
<input type="hidden" name="parent" value="c<%id%>" />
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
</script>
|
||||
|
||||
The final template contains HTML that will be used to display comments
|
||||
in the comment tree:
|
||||
|
||||
.. sourcecode:: guess
|
||||
|
||||
<script type="text/html" id="comment_template">
|
||||
<div id="cd<%id%>" class="spxcdiv">
|
||||
<div class="vote">
|
||||
<div class="arrow">
|
||||
<a href="#" id="uv<%id%>" class="vote">
|
||||
<img src="<%upArrow%>" />
|
||||
</a>
|
||||
<a href="#" id="uu<%id%>" class="un vote">
|
||||
<img src="<%upArrowPressed%>" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="arrow">
|
||||
<a href="#" id="dv<%id%>" class="vote">
|
||||
<img src="<%downArrow%>" id="da<%id%>" />
|
||||
</a>
|
||||
<a href="#" id="du<%id%>" class="un vote">
|
||||
<img src="<%downArrowPressed%>" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment_content">
|
||||
<p class="tagline comment">
|
||||
<span class="user_id"><%username%></span>
|
||||
<span class="rating"><%pretty_rating%></span>
|
||||
<span class="delta"><%time.delta%></span>
|
||||
</p>
|
||||
<p class="comment_text comment"><%text%></p>
|
||||
<p class="comment_opts comment">
|
||||
<a href="#" class="reply" id="rl<%id%>">reply</a>
|
||||
<a href="#" class="close_reply" id="cr<%id%>">hide</a>
|
||||
</p>
|
||||
<ul class="children" id="cl<%id%>"></ul>
|
||||
</div>
|
||||
<div class="clearleft"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
{% block relbar %}
|
||||
{{ document.relbar|safe }}
|
||||
{% endblock %}
|
||||
@@ -27,18 +27,25 @@ class WebSupportApp(Sphinx):
|
||||
Sphinx.__init__(self, *args, **kwargs)
|
||||
|
||||
class WebSupport(object):
|
||||
def __init__(self, srcdir='', outdir='', search=None,
|
||||
"""The main API class for the web support package. All interactions
|
||||
with the web support package should occur through this class.
|
||||
"""
|
||||
|
||||
def __init__(self, srcdir='', outdir='', datadir='', search=None,
|
||||
comments=None):
|
||||
self.srcdir = srcdir
|
||||
self.outdir = outdir or path.join(self.srcdir, '_build',
|
||||
'websupport')
|
||||
self.init_templating()
|
||||
if search is not None:
|
||||
self.init_search(search)
|
||||
self._init_templating()
|
||||
|
||||
self.init_comments(comments)
|
||||
self.outdir = outdir or datadir
|
||||
|
||||
if search is not None:
|
||||
self._init_search(search)
|
||||
|
||||
self._init_comments(comments)
|
||||
|
||||
def init_comments(self, comments):
|
||||
def _init_comments(self, comments):
|
||||
if isinstance(comments, sphinxcomments.CommentBackend):
|
||||
self.comments = comments
|
||||
else:
|
||||
@@ -51,14 +58,14 @@ class WebSupport(object):
|
||||
engine = create_engine('sqlite:///%s' % db_path)
|
||||
self.comments = SQLAlchemyComments(engine)
|
||||
|
||||
def init_templating(self):
|
||||
def _init_templating(self):
|
||||
import sphinx
|
||||
template_path = path.join(path.dirname(sphinx.__file__),
|
||||
'themes', 'basic')
|
||||
loader = FileSystemLoader(template_path)
|
||||
self.template_env = Environment(loader=loader)
|
||||
|
||||
def init_search(self, search):
|
||||
def _init_search(self, search):
|
||||
mod, cls = search_adapters[search]
|
||||
search_class = getattr(__import__('sphinx.websupport.search.' + mod,
|
||||
None, None, [cls]), cls)
|
||||
@@ -67,24 +74,65 @@ class WebSupport(object):
|
||||
self.results_template = \
|
||||
self.template_env.get_template('searchresults.html')
|
||||
|
||||
def build(self, **kwargs):
|
||||
doctreedir = kwargs.pop('doctreedir',
|
||||
path.join(self.outdir, 'doctrees'))
|
||||
def build(self):
|
||||
"""Build the documentation. Places the data into the `outdir`
|
||||
directory. Use it like this::
|
||||
|
||||
support = WebSupport(srcdir, outdir, search)
|
||||
support.build()
|
||||
|
||||
This will read reStructured text files from `srcdir`. Then it
|
||||
build the pickles and search index, placing them into `outdir`.
|
||||
It will also save node data to the database.
|
||||
"""
|
||||
doctreedir = path.join(self.outdir, 'doctrees')
|
||||
app = WebSupportApp(self.srcdir, self.srcdir,
|
||||
self.outdir, doctreedir, 'websupport',
|
||||
search=self.search,
|
||||
comments=self.comments)
|
||||
# TODO:
|
||||
# Hook comments into Sphinx signals.
|
||||
self.comments.pre_build()
|
||||
app.build()
|
||||
self.comments.post_build()
|
||||
|
||||
def get_document(self, docname):
|
||||
"""Load and return a document from a pickle. The document will
|
||||
be a dict object which can be used to render a template::
|
||||
|
||||
support = WebSupport(outdir=outdir)
|
||||
support.get_document('index')
|
||||
|
||||
In most cases `docname` will be taken from the request path and
|
||||
passed directly to this function. In Flask, that would be something
|
||||
like this::
|
||||
|
||||
@app.route('/<path:docname>')
|
||||
def index(docname):
|
||||
q = request.args.get('q')
|
||||
document = support.get_search_results(q)
|
||||
render_template('doc.html', document=document)
|
||||
|
||||
The document dict that is returned contains the following items
|
||||
to be used during template rendering.
|
||||
|
||||
:param docname: the name of the document to load.
|
||||
"""
|
||||
infilename = path.join(self.outdir, docname + '.fpickle')
|
||||
f = open(infilename, 'rb')
|
||||
document = pickle.load(f)
|
||||
return document
|
||||
|
||||
def get_search_results(self, q):
|
||||
"""Perform a search for the query `q`, and create a set
|
||||
of search results. Then render the search results as html and
|
||||
return a context dict like the one created by
|
||||
:meth:`get_document`::
|
||||
|
||||
document = support.get_search_results(q)
|
||||
|
||||
:param q: the search query
|
||||
"""
|
||||
results, results_found, results_displayed = self.search.query(q)
|
||||
ctx = {'search_performed': True,
|
||||
'search_results': results,
|
||||
@@ -94,14 +142,89 @@ class WebSupport(object):
|
||||
document['title'] = 'Search Results'
|
||||
return document
|
||||
|
||||
def get_comments(self, node_id, user_id):
|
||||
def get_comments(self, node_id, user_id=None):
|
||||
"""Get the comments associated with `node_id`. If `user_id` is
|
||||
given vote information will be included with the returned comments.
|
||||
The default CommentBackend returns a list of dicts. Each dict
|
||||
represents a comment, and has the following items:
|
||||
|
||||
============ ======================================================
|
||||
Key Contents
|
||||
============ ======================================================
|
||||
text The comment text.
|
||||
username The username that was stored with the comment.
|
||||
id The comment's unique identifier.
|
||||
rating The comment's current rating.
|
||||
age The time in seconds since the comment was added.
|
||||
time A dict containing time information. It contains the
|
||||
following keys: year, month, day, hour, minute, second,
|
||||
iso, and delta. `iso` is the time formatted in ISO
|
||||
8601 format. `delta` is a printable form of how old
|
||||
the comment is (e.g. "3 hours ago").
|
||||
vote If `user_id` was given, this will be an integer
|
||||
representing the vote. 1 for an upvote, -1 for a
|
||||
downvote, or 0 if unvoted.
|
||||
node The node that the comment is attached to. If the
|
||||
comment's parent is another comment rather than a
|
||||
node, this will be null.
|
||||
parent The id of the comment that this comment is attached
|
||||
to if it is not attached to a node.
|
||||
children A list of all children, in this format.
|
||||
============ ======================================================
|
||||
|
||||
:param node_id: the id of the node to get comments for.
|
||||
:param user_id: the id of the user viewing the comments.
|
||||
"""
|
||||
return self.comments.get_comments(node_id, user_id)
|
||||
|
||||
def add_comment(self, parent_id, text, displayed=True, username=None,
|
||||
rating=0, time=None):
|
||||
"""Add a comment to a node or another comment. `parent_id` will have
|
||||
a one letter prefix, distinguishing between node parents and
|
||||
comment parents, 'c' and 's' respectively. This function will
|
||||
return the comment in the same format as :meth:`get_comments`.
|
||||
Usage is simple::
|
||||
|
||||
comment = support.add_comment(parent_id, text)
|
||||
|
||||
If you would like to store a username with the comment, pass
|
||||
in the optional `username` keyword argument::
|
||||
|
||||
comment = support.add_comment(parent_id, text, username=username)
|
||||
|
||||
:param parent_id: the prefixed id of the comment's parent.
|
||||
:param text: the text of the comment.
|
||||
:param displayed: for future use...
|
||||
:param username: the username of the user making the comment.
|
||||
:param rating: the starting rating of the comment, defaults to 0.
|
||||
:param time: the time the comment was created, defaults to now.
|
||||
"""
|
||||
return self.comments.add_comment(parent_id, text, displayed,
|
||||
username, rating, time)
|
||||
|
||||
def process_vote(self, comment_id, user_id, value):
|
||||
"""Process a user's vote. The web support package relies
|
||||
on the API user to perform authentication. The API user will
|
||||
typically receive a comment_id and value from a form, and then
|
||||
make sure the user is authenticated. A unique integer `user_id`
|
||||
(usually the User primary key) must be passed in, which will
|
||||
also be used to retrieve the user's past voting information.
|
||||
An example, once again in Flask::
|
||||
|
||||
@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"
|
||||
|
||||
:param comment_id: the comment being voted on
|
||||
:param user_id: the unique integer id of the user voting
|
||||
:param value: 1 for an upvote, -1 for a downvote, 0 for an unvote.
|
||||
"""
|
||||
value = int(value)
|
||||
self.comments.process_vote(comment_id, user_id, value)
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.websupport.api
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All API functions.
|
||||
|
||||
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import cPickle as pickle
|
||||
from os import path
|
||||
from datetime import datetime
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.websupport.search import search_adapters
|
||||
from sphinx.websupport import comments as sphinxcomments
|
||||
|
||||
class WebSupportApp(Sphinx):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.search = kwargs.pop('search', None)
|
||||
self.comments = kwargs.pop('comments', None)
|
||||
Sphinx.__init__(self, *args, **kwargs)
|
||||
|
||||
class WebSupport(object):
|
||||
def __init__(self, srcdir='', outdir='', search=None,
|
||||
comments=None):
|
||||
self.srcdir = srcdir
|
||||
self.outdir = outdir or path.join(self.srcdir, '_build',
|
||||
'websupport')
|
||||
self.init_templating()
|
||||
if search is not None:
|
||||
self.init_search(search)
|
||||
|
||||
self.init_comments(comments)
|
||||
|
||||
def init_comments(self, comments):
|
||||
if isinstance(comments, sphinxcomments.CommentBackend):
|
||||
self.comments = comments
|
||||
else:
|
||||
# If a CommentBackend isn't provided, use the default
|
||||
# SQLAlchemy backend with an SQLite db.
|
||||
from sphinx.websupport.comments import SQLAlchemyComments
|
||||
from sqlalchemy import create_engine
|
||||
db_path = path.join(self.outdir, 'comments', 'comments.db')
|
||||
ensuredir(path.dirname(db_path))
|
||||
engine = create_engine('sqlite:///%s' % db_path)
|
||||
self.comments = SQLAlchemyComments(engine)
|
||||
|
||||
def init_templating(self):
|
||||
import sphinx
|
||||
template_path = path.join(path.dirname(sphinx.__file__),
|
||||
'themes', 'basic')
|
||||
loader = FileSystemLoader(template_path)
|
||||
self.template_env = Environment(loader=loader)
|
||||
|
||||
def init_search(self, search):
|
||||
mod, cls = search_adapters[search]
|
||||
search_class = getattr(__import__('sphinx.websupport.search.' + mod,
|
||||
None, None, [cls]), cls)
|
||||
search_path = path.join(self.outdir, 'search')
|
||||
self.search = search_class(search_path)
|
||||
self.results_template = \
|
||||
self.template_env.get_template('searchresults.html')
|
||||
|
||||
def build(self, **kwargs):
|
||||
doctreedir = kwargs.pop('doctreedir',
|
||||
path.join(self.outdir, 'doctrees'))
|
||||
app = WebSupportApp(self.srcdir, self.srcdir,
|
||||
self.outdir, doctreedir, 'websupport',
|
||||
search=self.search,
|
||||
comments=self.comments)
|
||||
self.comments.pre_build()
|
||||
app.build()
|
||||
self.comments.post_build()
|
||||
|
||||
def get_document(self, docname):
|
||||
infilename = path.join(self.outdir, docname + '.fpickle')
|
||||
f = open(infilename, 'rb')
|
||||
document = pickle.load(f)
|
||||
return document
|
||||
|
||||
def get_search_results(self, q):
|
||||
results, results_found, results_displayed = self.search.query(q)
|
||||
ctx = {'search_performed': True,
|
||||
'search_results': results,
|
||||
'q': q}
|
||||
document = self.get_document('search')
|
||||
document['body'] = self.results_template.render(ctx)
|
||||
document['title'] = 'Search Results'
|
||||
return document
|
||||
|
||||
def get_comments(self, node_id, user_id):
|
||||
return self.comments.get_comments(node_id, user_id)
|
||||
|
||||
def add_comment(self, parent_id, text, displayed=True, username=None,
|
||||
rating=0, time=None):
|
||||
return self.comments.add_comment(parent_id, text, displayed,
|
||||
username, rating, time)
|
||||
|
||||
def process_vote(self, comment_id, user_id, value):
|
||||
value = int(value)
|
||||
self.comments.process_vote(comment_id, user_id, value)
|
||||
Reference in New Issue
Block a user