added more comments/docstrings

This commit is contained in:
Jacob Mason 2010-08-09 15:22:52 -05:00
parent 3f29ff6204
commit 3b3e001eb9
3 changed files with 80 additions and 40 deletions

View File

@ -34,6 +34,12 @@ class Node(Base):
source = Column(Text, nullable=False)
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()
if username:
@ -45,24 +51,30 @@ class Node(Base):
cvalias = aliased(CommentVote, sq)
q = session.query(Comment, cvalias.value).outerjoin(cvalias)
else:
# If a username is not provided, we don't need to join with
# CommentVote.
q = session.query(Comment)
# Filter out all comments not descending from this node.
q = q.filter(Comment.path.like(str(self.id) + '.%'))
# Filter out non-displayed comments if this isn't a moderator.
if not moderator:
q = q.filter(Comment.displayed == True)
# Retrieve all results. Results must be ordered by Comment.path
# so that we can easily transform them from a flat list to a tree.
results = q.order_by(Comment.path).all()
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)
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 = []
list_stack = [comments]
for r in results:
@ -87,6 +99,7 @@ class Node(Base):
self.source = source
class Comment(Base):
"""An individual Comment being stored."""
__tablename__ = db_prefix + 'comments'
id = Column(Integer, primary_key=True)
@ -110,6 +123,9 @@ class Comment(Base):
self.proposal_diff = proposal_diff
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:
self.path = '%s.%s' % (node_id, self.id)
else:
@ -120,6 +136,9 @@ class Comment(Base):
self.path = '%s.%s' % (parent_path, self.id)
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
time = {'year': self.time.year,
@ -149,6 +168,9 @@ class Comment(Base):
'children': []}
def pretty_delta(self, delta):
"""Create a pretty representation of the Comment's age.
(e.g. 2 minutes).
"""
days = delta.days
seconds = delta.seconds
hours = seconds / 3600
@ -162,6 +184,7 @@ class Comment(Base):
return '%s %s ago' % dt if dt[0] == 1 else '%s %ss ago' % dt
class CommentVote(Base):
"""A vote a user has made on a Comment."""
__tablename__ = db_prefix + 'commentvote'
username = Column(String(64), primary_key=True)

View File

@ -14,39 +14,18 @@ from cgi import escape
from difflib import Differ
class CombinedHtmlDiff(object):
"""Create an HTML representation of the differences between two pieces
of text.
"""
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):
"""Return the HTML representation of the differences between
`source` and `proposal`.
:param source: the original text
:param proposal: the proposed text
"""
proposal = escape(proposal)
differ = Differ()
@ -64,3 +43,37 @@ class CombinedHtmlDiff(object):
self._handle_line(line)
break
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)

View File

@ -18,6 +18,9 @@ from sphinx.websupport.storage.db import Base, Node, Comment, CommentVote,\
from sphinx.websupport.storage.differ import CombinedHtmlDiff
class SQLAlchemyStorage(StorageBackend):
"""A :class:`~sphinx.websupport.storage.StorageBackend` using
SQLAlchemy.
"""
def __init__(self, engine):
self.engine = engine
Base.metadata.bind = engine
@ -40,6 +43,7 @@ class SQLAlchemyStorage(StorageBackend):
def add_comment(self, text, displayed, username, time,
proposal, node_id, parent_id, moderator):
session = Session()
proposal_diff = None
if node_id and proposal:
node = session.query(Node).filter(Node.id == node_id).one()
@ -51,19 +55,18 @@ class SQLAlchemyStorage(StorageBackend):
if not parent.displayed:
raise CommentNotAllowedError(
"Can't add child to a parent that is not displayed")
proposal_diff = None
else:
proposal_diff = None
comment = Comment(text, displayed, username, 0,
time or datetime.now(), proposal, proposal_diff)
session.add(comment)
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)
session.commit()
comment = comment.serializable()
d = comment.serializable()
session.close()
return comment
return d
def delete_comment(self, comment_id, username, moderator):
session = Session()
@ -72,6 +75,7 @@ class SQLAlchemyStorage(StorageBackend):
if moderator or comment.username == username:
comment.username = '[deleted]'
comment.text = '[deleted]'
comment.proposal = ''
session.commit()
session.close()
else: