mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
added more comments/docstrings
This commit is contained in:
parent
3f29ff6204
commit
3b3e001eb9
@ -34,6 +34,12 @@ class Node(Base):
|
|||||||
source = Column(Text, nullable=False)
|
source = Column(Text, nullable=False)
|
||||||
|
|
||||||
def nested_comments(self, username, moderator):
|
def nested_comments(self, username, moderator):
|
||||||
|
"""Create a tree of comments. First get all comments that are
|
||||||
|
descendents of this node, then convert them to a tree form.
|
||||||
|
|
||||||
|
:param username: the name of the user to get comments for.
|
||||||
|
:param moderator: whether the user is moderator.
|
||||||
|
"""
|
||||||
session = Session()
|
session = Session()
|
||||||
|
|
||||||
if username:
|
if username:
|
||||||
@ -45,24 +51,30 @@ class Node(Base):
|
|||||||
cvalias = aliased(CommentVote, sq)
|
cvalias = aliased(CommentVote, sq)
|
||||||
q = session.query(Comment, cvalias.value).outerjoin(cvalias)
|
q = session.query(Comment, cvalias.value).outerjoin(cvalias)
|
||||||
else:
|
else:
|
||||||
|
# If a username is not provided, we don't need to join with
|
||||||
|
# CommentVote.
|
||||||
q = session.query(Comment)
|
q = session.query(Comment)
|
||||||
|
|
||||||
# Filter out all comments not descending from this node.
|
# Filter out all comments not descending from this node.
|
||||||
q = q.filter(Comment.path.like(str(self.id) + '.%'))
|
q = q.filter(Comment.path.like(str(self.id) + '.%'))
|
||||||
# Filter out non-displayed comments if this isn't a moderator.
|
|
||||||
if not moderator:
|
if not moderator:
|
||||||
q = q.filter(Comment.displayed == True)
|
q = q.filter(Comment.displayed == True)
|
||||||
|
|
||||||
# Retrieve all results. Results must be ordered by Comment.path
|
# Retrieve all results. Results must be ordered by Comment.path
|
||||||
# so that we can easily transform them from a flat list to a tree.
|
# so that we can easily transform them from a flat list to a tree.
|
||||||
results = q.order_by(Comment.path).all()
|
results = q.order_by(Comment.path).all()
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
# We now need to convert the flat list of results to a nested
|
|
||||||
# lists to form the comment tree. Results will by ordered by
|
|
||||||
# the materialized path.
|
|
||||||
return self._nest_comments(results, username)
|
return self._nest_comments(results, username)
|
||||||
|
|
||||||
def _nest_comments(self, results, username):
|
def _nest_comments(self, results, username):
|
||||||
|
"""Given the flat list of results, convert the list into a
|
||||||
|
tree.
|
||||||
|
|
||||||
|
:param results: the flat list of comments
|
||||||
|
:param username: the name of the user requesting the comments.
|
||||||
|
"""
|
||||||
comments = []
|
comments = []
|
||||||
list_stack = [comments]
|
list_stack = [comments]
|
||||||
for r in results:
|
for r in results:
|
||||||
@ -87,6 +99,7 @@ class Node(Base):
|
|||||||
self.source = source
|
self.source = source
|
||||||
|
|
||||||
class Comment(Base):
|
class Comment(Base):
|
||||||
|
"""An individual Comment being stored."""
|
||||||
__tablename__ = db_prefix + 'comments'
|
__tablename__ = db_prefix + 'comments'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
@ -110,6 +123,9 @@ class Comment(Base):
|
|||||||
self.proposal_diff = proposal_diff
|
self.proposal_diff = proposal_diff
|
||||||
|
|
||||||
def set_path(self, node_id, parent_id):
|
def set_path(self, node_id, parent_id):
|
||||||
|
"""Set the materialized path for this comment."""
|
||||||
|
# This exists because the path can't be set until the session has
|
||||||
|
# been flushed and this Comment has an id.
|
||||||
if node_id:
|
if node_id:
|
||||||
self.path = '%s.%s' % (node_id, self.id)
|
self.path = '%s.%s' % (node_id, self.id)
|
||||||
else:
|
else:
|
||||||
@ -120,6 +136,9 @@ class Comment(Base):
|
|||||||
self.path = '%s.%s' % (parent_path, self.id)
|
self.path = '%s.%s' % (parent_path, self.id)
|
||||||
|
|
||||||
def serializable(self, vote=0):
|
def serializable(self, vote=0):
|
||||||
|
"""Creates a serializable representation of the comment. This is
|
||||||
|
converted to JSON, and used on the client side.
|
||||||
|
"""
|
||||||
delta = datetime.now() - self.time
|
delta = datetime.now() - self.time
|
||||||
|
|
||||||
time = {'year': self.time.year,
|
time = {'year': self.time.year,
|
||||||
@ -149,6 +168,9 @@ class Comment(Base):
|
|||||||
'children': []}
|
'children': []}
|
||||||
|
|
||||||
def pretty_delta(self, delta):
|
def pretty_delta(self, delta):
|
||||||
|
"""Create a pretty representation of the Comment's age.
|
||||||
|
(e.g. 2 minutes).
|
||||||
|
"""
|
||||||
days = delta.days
|
days = delta.days
|
||||||
seconds = delta.seconds
|
seconds = delta.seconds
|
||||||
hours = seconds / 3600
|
hours = seconds / 3600
|
||||||
@ -162,6 +184,7 @@ class Comment(Base):
|
|||||||
return '%s %s ago' % dt if dt[0] == 1 else '%s %ss ago' % dt
|
return '%s %s ago' % dt if dt[0] == 1 else '%s %ss ago' % dt
|
||||||
|
|
||||||
class CommentVote(Base):
|
class CommentVote(Base):
|
||||||
|
"""A vote a user has made on a Comment."""
|
||||||
__tablename__ = db_prefix + 'commentvote'
|
__tablename__ = db_prefix + 'commentvote'
|
||||||
|
|
||||||
username = Column(String(64), primary_key=True)
|
username = Column(String(64), primary_key=True)
|
||||||
|
@ -14,39 +14,18 @@ from cgi import escape
|
|||||||
from difflib import Differ
|
from difflib import Differ
|
||||||
|
|
||||||
class CombinedHtmlDiff(object):
|
class CombinedHtmlDiff(object):
|
||||||
|
"""Create an HTML representation of the differences between two pieces
|
||||||
|
of text.
|
||||||
|
"""
|
||||||
highlight_regex = re.compile(r'([\+\-\^]+)')
|
highlight_regex = re.compile(r'([\+\-\^]+)')
|
||||||
|
|
||||||
def _highlight_text(self, text, next, tag):
|
|
||||||
next = next[2:]
|
|
||||||
new_text = []
|
|
||||||
start = 0
|
|
||||||
for match in self.highlight_regex.finditer(next):
|
|
||||||
new_text.append(text[start:match.start()])
|
|
||||||
new_text.append('<%s>' % tag)
|
|
||||||
new_text.append(text[match.start():match.end()])
|
|
||||||
new_text.append('</%s>' % tag)
|
|
||||||
start = match.end()
|
|
||||||
new_text.append(text[start:])
|
|
||||||
return ''.join(new_text)
|
|
||||||
|
|
||||||
def _handle_line(self, line, next=None):
|
|
||||||
prefix = line[0]
|
|
||||||
text = line[2:]
|
|
||||||
|
|
||||||
if prefix == ' ':
|
|
||||||
return text
|
|
||||||
elif prefix == '?':
|
|
||||||
return ''
|
|
||||||
|
|
||||||
if next is not None and next[0] == '?':
|
|
||||||
tag = 'ins' if prefix == '+' else 'del'
|
|
||||||
text = self._highlight_text(text, next, tag)
|
|
||||||
css_class = 'prop_added' if prefix == '+' else 'prop_removed'
|
|
||||||
|
|
||||||
return '<span class="%s">%s</span>\n' % (css_class, text.rstrip())
|
|
||||||
|
|
||||||
def make_html(self, source, proposal):
|
def make_html(self, source, proposal):
|
||||||
|
"""Return the HTML representation of the differences between
|
||||||
|
`source` and `proposal`.
|
||||||
|
|
||||||
|
:param source: the original text
|
||||||
|
:param proposal: the proposed text
|
||||||
|
"""
|
||||||
proposal = escape(proposal)
|
proposal = escape(proposal)
|
||||||
|
|
||||||
differ = Differ()
|
differ = Differ()
|
||||||
@ -64,3 +43,37 @@ class CombinedHtmlDiff(object):
|
|||||||
self._handle_line(line)
|
self._handle_line(line)
|
||||||
break
|
break
|
||||||
return ''.join(html)
|
return ''.join(html)
|
||||||
|
|
||||||
|
def _handle_line(self, line, next=None):
|
||||||
|
"""Handle an individual line in a diff."""
|
||||||
|
prefix = line[0]
|
||||||
|
text = line[2:]
|
||||||
|
|
||||||
|
if prefix == ' ':
|
||||||
|
return text
|
||||||
|
elif prefix == '?':
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if next is not None and next[0] == '?':
|
||||||
|
tag = 'ins' if prefix == '+' else 'del'
|
||||||
|
text = self._highlight_text(text, next, tag)
|
||||||
|
css_class = 'prop_added' if prefix == '+' else 'prop_removed'
|
||||||
|
|
||||||
|
return '<span class="%s">%s</span>\n' % (css_class, text.rstrip())
|
||||||
|
|
||||||
|
def _highlight_text(self, text, next, tag):
|
||||||
|
"""Highlight the specific changes made to a line by adding
|
||||||
|
<ins> and <del> tags.
|
||||||
|
"""
|
||||||
|
next = next[2:]
|
||||||
|
new_text = []
|
||||||
|
start = 0
|
||||||
|
for match in self.highlight_regex.finditer(next):
|
||||||
|
new_text.append(text[start:match.start()])
|
||||||
|
new_text.append('<%s>' % tag)
|
||||||
|
new_text.append(text[match.start():match.end()])
|
||||||
|
new_text.append('</%s>' % tag)
|
||||||
|
start = match.end()
|
||||||
|
new_text.append(text[start:])
|
||||||
|
return ''.join(new_text)
|
||||||
|
|
||||||
|
@ -18,6 +18,9 @@ from sphinx.websupport.storage.db import Base, Node, Comment, CommentVote,\
|
|||||||
from sphinx.websupport.storage.differ import CombinedHtmlDiff
|
from sphinx.websupport.storage.differ import CombinedHtmlDiff
|
||||||
|
|
||||||
class SQLAlchemyStorage(StorageBackend):
|
class SQLAlchemyStorage(StorageBackend):
|
||||||
|
"""A :class:`~sphinx.websupport.storage.StorageBackend` using
|
||||||
|
SQLAlchemy.
|
||||||
|
"""
|
||||||
def __init__(self, engine):
|
def __init__(self, engine):
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
Base.metadata.bind = engine
|
Base.metadata.bind = engine
|
||||||
@ -40,6 +43,7 @@ class SQLAlchemyStorage(StorageBackend):
|
|||||||
def add_comment(self, text, displayed, username, time,
|
def add_comment(self, text, displayed, username, time,
|
||||||
proposal, node_id, parent_id, moderator):
|
proposal, node_id, parent_id, moderator):
|
||||||
session = Session()
|
session = Session()
|
||||||
|
proposal_diff = None
|
||||||
|
|
||||||
if node_id and proposal:
|
if node_id and proposal:
|
||||||
node = session.query(Node).filter(Node.id == node_id).one()
|
node = session.query(Node).filter(Node.id == node_id).one()
|
||||||
@ -51,19 +55,18 @@ class SQLAlchemyStorage(StorageBackend):
|
|||||||
if not parent.displayed:
|
if not parent.displayed:
|
||||||
raise CommentNotAllowedError(
|
raise CommentNotAllowedError(
|
||||||
"Can't add child to a parent that is not displayed")
|
"Can't add child to a parent that is not displayed")
|
||||||
proposal_diff = None
|
|
||||||
else:
|
|
||||||
proposal_diff = None
|
|
||||||
|
|
||||||
comment = Comment(text, displayed, username, 0,
|
comment = Comment(text, displayed, username, 0,
|
||||||
time or datetime.now(), proposal, proposal_diff)
|
time or datetime.now(), proposal, proposal_diff)
|
||||||
session.add(comment)
|
session.add(comment)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
# We have to flush the session before setting the path so the
|
||||||
|
# Comment has an id.
|
||||||
comment.set_path(node_id, parent_id)
|
comment.set_path(node_id, parent_id)
|
||||||
session.commit()
|
session.commit()
|
||||||
comment = comment.serializable()
|
d = comment.serializable()
|
||||||
session.close()
|
session.close()
|
||||||
return comment
|
return d
|
||||||
|
|
||||||
def delete_comment(self, comment_id, username, moderator):
|
def delete_comment(self, comment_id, username, moderator):
|
||||||
session = Session()
|
session = Session()
|
||||||
@ -72,6 +75,7 @@ class SQLAlchemyStorage(StorageBackend):
|
|||||||
if moderator or comment.username == username:
|
if moderator or comment.username == username:
|
||||||
comment.username = '[deleted]'
|
comment.username = '[deleted]'
|
||||||
comment.text = '[deleted]'
|
comment.text = '[deleted]'
|
||||||
|
comment.proposal = ''
|
||||||
session.commit()
|
session.commit()
|
||||||
session.close()
|
session.close()
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user