1.1 --- a/actions/PostComment.py Sat Nov 02 20:08:45 2013 +0100
1.2 +++ b/actions/PostComment.py Sun Nov 03 00:45:49 2013 +0100
1.3 @@ -8,11 +8,23 @@
1.4
1.5 from MoinMoin.action import ActionBase
1.6 from MoinMoin.PageEditor import PageEditor
1.7 +from MoinMoin.security import Permissions
1.8 from MoinMoin.wikiutil import escape
1.9 from MoinSupport import getPagesForSearch, getPagesFromResults, ActionSupport
1.10
1.11 Dependencies = ['pages']
1.12
1.13 +class SpecialPermissions(Permissions):
1.14 +
1.15 + "Permit saving of ACL-enabled comment pages."
1.16 +
1.17 + def __init__(self, user, pagename):
1.18 + Permissions.__init__(self, user)
1.19 + self.pagename = pagename
1.20 +
1.21 + def admin(self, pagename):
1.22 + return pagename == self.pagename
1.23 +
1.24 class PostComment(ActionBase, ActionSupport):
1.25
1.26 "Post a comment to the wiki."
1.27 @@ -62,14 +74,35 @@
1.28
1.29 # Write the new page.
1.30
1.31 - new_page = PageEditor(request, "%s/%04d" % (self.pagename, last_comment_pagename + 1))
1.32 + comment_pagename = "%s/%04d" % (self.pagename, last_comment_pagename + 1)
1.33 + new_page = PageEditor(request, comment_pagename)
1.34 + username = request.user.name
1.35
1.36 try:
1.37 - new_page.saveText(comment, 0)
1.38 + # To add a page with an ACL, a special policy is required.
1.39 +
1.40 + may = request.user.may
1.41 + request.user.may = SpecialPermissions(request.user, comment_pagename)
1.42 +
1.43 + # Save the page, labelling it with the actual username.
1.44 +
1.45 + try:
1.46 + new_page.saveText(comment_template % (username, username, comment), 0)
1.47 +
1.48 + # Restore the superusers.
1.49 +
1.50 + finally:
1.51 + request.user.may = may
1.52 +
1.53 return 1, _("Comment added.")
1.54 except new_page.SaveError, exc:
1.55 return 0, unicode(exc)
1.56
1.57 +comment_template = """\
1.58 +#acl %s:read,write,delete,revert All:read
1.59 +#pragma comment-owner %s
1.60 +%s"""
1.61 +
1.62 def get_comment_numbers(pagename, request):
1.63
1.64 """
2.1 --- a/convert.py Sat Nov 02 20:08:45 2013 +0100
2.2 +++ b/convert.py Sun Nov 03 00:45:49 2013 +0100
2.3 @@ -476,9 +476,13 @@
2.4
2.5 # Add an ACL to comment pages so that people cannot change other
2.6 # people's comments.
2.7 + # NOTE: This should match the PostComment action.
2.8
2.9 if type == "Comment":
2.10 - text = "#acl %s:read,write,delete,revert All:read\n%s" % (username, text or read(filename))
2.11 + text = """\
2.12 +#acl %s:read,write,delete,revert All:read
2.13 +#pragma comment-owner %s
2.14 +%s""" % (username, username, text or read(filename))
2.15
2.16 # Add child page information to the content.
2.17
3.1 --- a/css/includecomments.css Sat Nov 02 20:08:45 2013 +0100
3.2 +++ b/css/includecomments.css Sun Nov 03 00:45:49 2013 +0100
3.3 @@ -16,6 +16,17 @@
3.4 padding: 1em;
3.5 }
3.6
3.7 +.included-comment-owner {
3.8 + float: left;
3.9 + clear: left;
3.10 + margin-right: 1em;
3.11 + padding: 0.5em;
3.12 + background-color: #ddd;
3.13 + color: #000;
3.14 + font-weight: bold;
3.15 + font-size: larger;
3.16 +}
3.17 +
3.18 /* Hide the link to the comment form when showing the form. */
3.19
3.20 #includecomments-anchor:target > a {
4.1 --- a/macros/IncludeComments.py Sat Nov 02 20:08:45 2013 +0100
4.2 +++ b/macros/IncludeComments.py Sun Nov 03 00:45:49 2013 +0100
4.3 @@ -4,10 +4,24 @@
4.4
4.5 @copyright: 2013 by Paul Boddie <paul@boddie.org.uk>
4.6 @license: GNU GPL (v2 or later), see COPYING.txt for details.
4.7 +
4.8 + Code from the Include macro:
4.9 +
4.10 + @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
4.11 + 2000-2001 Richard Jones <richard@bizarsoftware.com.au>
4.12 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
4.13 """
4.14
4.15 +from MoinMoin.Page import Page
4.16 from MoinMoin.macro import Include
4.17 +from MoinMoin.user import User
4.18 from MoinMoin.wikiutil import escape
4.19 +import re
4.20 +
4.21 +try:
4.22 + from cStringIO import StringIO
4.23 +except ImportError:
4.24 + from StringIO import StringIO
4.25
4.26 Dependencies = ['pages']
4.27
4.28 @@ -16,14 +30,19 @@
4.29 def execute(macro, text):
4.30 request = macro.request
4.31 fmt = request.formatter
4.32 - pagename = request.page.page_name
4.33 + page = request.page
4.34 + pagename = page.page_name
4.35 _ = request.getText
4.36
4.37 - included_content = Include.execute(macro, text or "^%s/" % pagename, included_page_css_class="included-comment")
4.38 -
4.39 output = []
4.40 append = output.append
4.41
4.42 + # Add a heading.
4.43 +
4.44 + append(fmt.heading(on=1, depth=1))
4.45 + append(fmt.text(_("Comments")))
4.46 + append(fmt.heading(on=0, depth=1))
4.47 +
4.48 # Provide a form for adding new comments.
4.49
4.50 if request.user.valid and request.user.may.write(pagename):
4.51 @@ -46,9 +65,91 @@
4.52 </div>
4.53 """ % d)
4.54
4.55 + # NOTE: Much of the code below originates from the Include macro, but it
4.56 + # NOTE: excludes various options of that macro and adds comment-related
4.57 + # NOTE: output.
4.58 +
4.59 # Add included comments.
4.60
4.61 - append(included_content)
4.62 + filterfn = re.compile(ur"^%s/" % re.escape(pagename), re.U).match
4.63 + pages = request.rootpage.getPageList(filter=filterfn)
4.64 + pages.sort()
4.65 +
4.66 + ownerfn = re.compile("^#pragma comment-owner (.*?)$", re.MULTILINE | re.UNICODE).search
4.67 +
4.68 + # Track included pages.
4.69 +
4.70 + if not hasattr(page, '_macroInclude_pagelist'):
4.71 + page._macroInclude_pagelist = {}
4.72 +
4.73 + # Visit each comment page.
4.74 +
4.75 + for inc_name in pages:
4.76 +
4.77 + # Skip unreadable or already included pages.
4.78 +
4.79 + if not request.user.may.read(inc_name):
4.80 + continue
4.81 + if inc_name in page._macroInclude_pagelist:
4.82 + continue
4.83 +
4.84 + # Obtain a separate formatter for the included page.
4.85 +
4.86 + inc_fmt = macro.formatter.__class__(request, is_included=True)
4.87 + inc_fmt._base_depth = macro.formatter._base_depth
4.88 +
4.89 + # Obtain the included page.
4.90 +
4.91 + inc_page = Page(request, inc_name, formatter=inc_fmt)
4.92 + if not inc_page.exists():
4.93 + continue
4.94 + inc_page._macroInclude_pagelist = page._macroInclude_pagelist
4.95 +
4.96 + if not hasattr(request, "_Include_backto"):
4.97 + request._Include_backto = pagename
4.98 +
4.99 + # Output a container for the included page.
4.100 +
4.101 + append(fmt.div(1, id=inc_name, css_class="included-comment"))
4.102 +
4.103 + # Add a label indicating a comment.
4.104 +
4.105 + match = ownerfn(inc_page.get_raw_body())
4.106 + if match:
4.107 + user = User(request, auth_username=match.group(1))
4.108 + if user.exists():
4.109 + append(fmt.div(1, css_class="included-comment-owner"))
4.110 + append(fmt.text(user.aliasname or user.name))
4.111 + append(fmt.div(0))
4.112 +
4.113 + # Set or increment include marker.
4.114 +
4.115 + page._macroInclude_pagelist[inc_name] = \
4.116 + page._macroInclude_pagelist.get(inc_name, 0) + 1
4.117 +
4.118 + # Output the included page.
4.119 +
4.120 + strfile = StringIO()
4.121 + request.redirect(strfile)
4.122 + try:
4.123 + inc_page.send_page(content_only=True,
4.124 + omit_footnotes=True,
4.125 + count_hit=False)
4.126 + append(strfile.getvalue())
4.127 + finally:
4.128 + request.redirect()
4.129 +
4.130 + # Decrement or remove include marker.
4.131 +
4.132 + if page._macroInclude_pagelist[inc_name] > 1:
4.133 + page._macroInclude_pagelist[inc_name] = \
4.134 + page._macroInclude_pagelist[inc_name] - 1
4.135 + else:
4.136 + del page._macroInclude_pagelist[inc_name]
4.137 +
4.138 + # Close the container for the included page.
4.139 +
4.140 + append(fmt.div(0))
4.141
4.142 return u"".join(output)
4.143