1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/actions/PostComment.py Sun Nov 03 14:43:31 2013 +0100
1.3 @@ -0,0 +1,128 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - PostComment action
1.7 +
1.8 + @copyright: 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from MoinMoin.action import ActionBase
1.13 +from MoinMoin.PageEditor import PageEditor
1.14 +from MoinMoin.security import Permissions
1.15 +from MoinMoin.wikiutil import escape
1.16 +from MoinSupport import getPagesForSearch, getPagesFromResults, ActionSupport
1.17 +
1.18 +Dependencies = ['pages']
1.19 +
1.20 +class SpecialPermissions(Permissions):
1.21 +
1.22 + "Permit saving of ACL-enabled comment pages."
1.23 +
1.24 + def __init__(self, user, pagename):
1.25 + Permissions.__init__(self, user)
1.26 + self.pagename = pagename
1.27 +
1.28 + def admin(self, pagename):
1.29 + return pagename == self.pagename
1.30 +
1.31 +class PostComment(ActionBase, ActionSupport):
1.32 +
1.33 + "Post a comment to the wiki."
1.34 +
1.35 + def get_form_html(self, buttons_html):
1.36 +
1.37 + "Return the action's form incorporating the 'buttons_html'."
1.38 +
1.39 + _ = self._
1.40 + request = self.request
1.41 + form = self.get_form()
1.42 +
1.43 + comment = form.get("comment", [""])[0]
1.44 +
1.45 + d = {
1.46 + "comment_label" : escape(comment and _("Please review your comment.") or _("Write a comment in the box.")),
1.47 + "comment_default" : escape(comment),
1.48 + "buttons_html" : buttons_html,
1.49 + }
1.50 +
1.51 + return u"""\
1.52 +<p>%(comment_label)s</p>
1.53 +<textarea name="comment" cols="60" rows="10">%(comment_default)s</textarea>
1.54 +<p>%(buttons_html)s</p>
1.55 +""" % d
1.56 +
1.57 + def do_action(self):
1.58 +
1.59 + "Attempt to post a comment."
1.60 +
1.61 + _ = self._
1.62 + request = self.request
1.63 + form = self.get_form()
1.64 +
1.65 + comment = form.get("comment", [""])[0]
1.66 +
1.67 + if not comment.strip():
1.68 + return 0, _("A comment should have some content.")
1.69 +
1.70 + if not request.user.valid or not request.user.may.write(self.pagename):
1.71 + return 0, _("You are not allowed to comment on this page.")
1.72 +
1.73 + # Determine the last comment.
1.74 +
1.75 + comments = get_comment_numbers(self.pagename, request)
1.76 + last_comment_pagename = comments and comments[-1] or -1
1.77 +
1.78 + # Write the new page.
1.79 +
1.80 + comment_pagename = "%s/%04d" % (self.pagename, last_comment_pagename + 1)
1.81 + new_page = PageEditor(request, comment_pagename)
1.82 + username = request.user.name
1.83 +
1.84 + try:
1.85 + # To add a page with an ACL, a special policy is required.
1.86 +
1.87 + may = request.user.may
1.88 + request.user.may = SpecialPermissions(request.user, comment_pagename)
1.89 +
1.90 + # Save the page, labelling it with the actual username.
1.91 +
1.92 + try:
1.93 + new_page.saveText(comment_template % (username, username, comment), 0)
1.94 +
1.95 + # Restore the superusers.
1.96 +
1.97 + finally:
1.98 + request.user.may = may
1.99 +
1.100 + return 1, _("Comment added.")
1.101 + except new_page.SaveError, exc:
1.102 + return 0, unicode(exc)
1.103 +
1.104 +comment_template = """\
1.105 +#acl %s:read,write,delete,revert All:read
1.106 +#pragma comment-owner %s
1.107 +%s"""
1.108 +
1.109 +def get_comment_numbers(pagename, request):
1.110 +
1.111 + """
1.112 + Return a list of comment numbers associated with the given 'pagename', using
1.113 + the 'request' provided.
1.114 + """
1.115 +
1.116 + pagenames = []
1.117 +
1.118 + for page in getPagesForSearch("title:regex:^%s/" % pagename, request):
1.119 + basename, number = page.page_name.rsplit("/", 1)
1.120 + if basename == pagename and number.isdigit():
1.121 + pagenames.append(int(number))
1.122 +
1.123 + pagenames.sort()
1.124 + return pagenames
1.125 +
1.126 +# Action invocation function.
1.127 +
1.128 +def execute(pagename, request):
1.129 + PostComment(pagename, request).render()
1.130 +
1.131 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/macros/IncludeComments.py Sun Nov 03 14:43:31 2013 +0100
2.3 @@ -0,0 +1,157 @@
2.4 +# -*- coding: iso-8859-1 -*-
2.5 +"""
2.6 + MoinMoin - IncludeComments Macro
2.7 +
2.8 + @copyright: 2013 by Paul Boddie <paul@boddie.org.uk>
2.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
2.10 +
2.11 + Code from the Include macro:
2.12 +
2.13 + @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
2.14 + 2000-2001 Richard Jones <richard@bizarsoftware.com.au>
2.15 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
2.16 +"""
2.17 +
2.18 +from MoinMoin.Page import Page
2.19 +from MoinMoin.macro import Include
2.20 +from MoinMoin.user import User
2.21 +from MoinMoin.wikiutil import escape
2.22 +import re
2.23 +import codecs
2.24 +
2.25 +try:
2.26 + from cStringIO import StringIO
2.27 +except ImportError:
2.28 + from StringIO import StringIO
2.29 +
2.30 +Dependencies = ['pages']
2.31 +
2.32 +# Macro functions.
2.33 +
2.34 +def execute(macro, text):
2.35 + request = macro.request
2.36 + fmt = request.formatter
2.37 + page = request.page
2.38 + pagename = page.page_name
2.39 + _ = request.getText
2.40 +
2.41 + output = []
2.42 + append = output.append
2.43 +
2.44 + # Add a heading.
2.45 +
2.46 + append(fmt.heading(on=1, depth=1))
2.47 + append(fmt.text(_("Comments")))
2.48 + append(fmt.heading(on=0, depth=1))
2.49 +
2.50 + # Provide a form for adding new comments.
2.51 +
2.52 + if request.user.valid and request.user.may.write(pagename):
2.53 +
2.54 + d = {
2.55 + "show_form" : escape(_("Add a comment to this page.")),
2.56 + "comment_label" : escape(_("Write a comment in the box.")),
2.57 + "comment_default" : "",
2.58 + "submit" : escape(_("Submit this comment")),
2.59 + }
2.60 +
2.61 + append("""\
2.62 +<div id="includecomments-anchor">
2.63 +<a href="#includecomments-anchor">%(show_form)s</a>
2.64 +<form action="?action=PostComment" method="post" class="includecomments-form">
2.65 +<p>%(comment_label)s</p>
2.66 +<textarea name="comment" cols="60" rows="10">%(comment_default)s</textarea>
2.67 +<p><input name="submit" type="submit" value="%(submit)s" /></p>
2.68 +</form>
2.69 +</div>
2.70 +""" % d)
2.71 +
2.72 + # NOTE: Much of the code below originates from the Include macro, but it
2.73 + # NOTE: excludes various options of that macro and adds comment-related
2.74 + # NOTE: output.
2.75 +
2.76 + # Add included comments.
2.77 +
2.78 + filterfn = re.compile(ur"^%s/" % re.escape(pagename), re.U).match
2.79 + pages = request.rootpage.getPageList(filter=filterfn)
2.80 + pages.sort()
2.81 +
2.82 + ownerfn = re.compile("^#pragma comment-owner (.*?)$", re.MULTILINE | re.UNICODE).search
2.83 +
2.84 + # Track included pages.
2.85 +
2.86 + if not hasattr(page, '_macroInclude_pagelist'):
2.87 + page._macroInclude_pagelist = {}
2.88 +
2.89 + # Visit each comment page.
2.90 +
2.91 + for inc_name in pages:
2.92 +
2.93 + # Skip unreadable or already included pages.
2.94 +
2.95 + if not request.user.may.read(inc_name):
2.96 + continue
2.97 + if inc_name in page._macroInclude_pagelist:
2.98 + continue
2.99 +
2.100 + # Obtain a separate formatter for the included page.
2.101 +
2.102 + inc_fmt = macro.formatter.__class__(request, is_included=True)
2.103 + inc_fmt._base_depth = macro.formatter._base_depth
2.104 +
2.105 + # Obtain the included page.
2.106 +
2.107 + inc_page = Page(request, inc_name, formatter=inc_fmt)
2.108 + if not inc_page.exists():
2.109 + continue
2.110 + inc_page._macroInclude_pagelist = page._macroInclude_pagelist
2.111 +
2.112 + if not hasattr(request, "_Include_backto"):
2.113 + request._Include_backto = pagename
2.114 +
2.115 + # Output a container for the included page.
2.116 +
2.117 + append(fmt.div(1, id=inc_name, css_class="included-comment"))
2.118 +
2.119 + # Add a label indicating a comment.
2.120 +
2.121 + match = ownerfn(inc_page.get_raw_body())
2.122 + if match:
2.123 + user = User(request, auth_username=match.group(1))
2.124 + if user.exists():
2.125 + append(fmt.div(1, css_class="included-comment-owner"))
2.126 + append(fmt.text(user.aliasname or user.name))
2.127 + append(fmt.div(0))
2.128 +
2.129 + # Set or increment include marker.
2.130 +
2.131 + page._macroInclude_pagelist[inc_name] = \
2.132 + page._macroInclude_pagelist.get(inc_name, 0) + 1
2.133 +
2.134 + # Output the included page.
2.135 +
2.136 + strfile = codecs.getwriter("utf-8")(StringIO())
2.137 + request.redirect(strfile)
2.138 + try:
2.139 + inc_page.send_page(content_only=True,
2.140 + omit_footnotes=True,
2.141 + count_hit=False)
2.142 + append(unicode(strfile.getvalue(), "utf-8"))
2.143 + finally:
2.144 + request.redirect()
2.145 +
2.146 + # Decrement or remove include marker.
2.147 +
2.148 + if page._macroInclude_pagelist[inc_name] > 1:
2.149 + page._macroInclude_pagelist[inc_name] = \
2.150 + page._macroInclude_pagelist[inc_name] - 1
2.151 + else:
2.152 + del page._macroInclude_pagelist[inc_name]
2.153 +
2.154 + # Close the container for the included page.
2.155 +
2.156 + append(fmt.div(0))
2.157 +
2.158 + return u"".join(output)
2.159 +
2.160 +# vim: tabstop=4 expandtab shiftwidth=4