1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/ApproveChangesSupport.py Sun Oct 09 21:17:09 2011 +0200
1.3 @@ -0,0 +1,92 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - ApproveChanges library
1.7 +
1.8 + @copyright: 2011 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 +import re
1.13 +
1.14 +__version__ = "0.1"
1.15 +
1.16 +def get_queued_changes_area(request):
1.17 + return getattr(request.cfg, "queued_changes_area", "ApprovalQueue")
1.18 +
1.19 +def get_approved_editors_group(request):
1.20 + return getattr(request.cfg, "approved_editors_group", "ApprovedGroup")
1.21 +
1.22 +def match_queue_pages(pagename, queued_changes_area):
1.23 +
1.24 + "Return a filter function which matches subpages of 'pagename'."
1.25 +
1.26 + return re.compile(ur"^%s/%s/.*$" % (re.escape(pagename), re.escape(queued_changes_area)), re.UNICODE).match
1.27 +
1.28 +def get_queue_pages(request, pagename, queued_changes_area):
1.29 +
1.30 + """
1.31 + Return the queued pages given the 'request', 'pagename' and subpage folder
1.32 + specified by 'queued_changes_area'.
1.33 + """
1.34 +
1.35 + return request.rootpage.getPageList(exists=1, filter=match_queue_pages(pagename, queued_changes_area))
1.36 +
1.37 +def is_queued_page(pagename, queued_changes_area):
1.38 +
1.39 + """
1.40 + Return whether 'pagename' is a queued page by testing for the presence of
1.41 + the 'queued_changes_area' component in its page path.
1.42 + """
1.43 +
1.44 + parts = pagename.split("/")
1.45 + return len(parts) > 2 and parts[-2] == queued_changes_area
1.46 +
1.47 +def get_target_page_name(pagename):
1.48 +
1.49 + "Return the target page name for the given queued 'pagename'."
1.50 +
1.51 + return "/".join(pagename.split("/")[:-2])
1.52 +
1.53 +# Utility classes and associated functions.
1.54 +# NOTE: These are a subset of EventAggregatorSupport.
1.55 +
1.56 +class Form:
1.57 +
1.58 + """
1.59 + A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x
1.60 + environment.
1.61 + """
1.62 +
1.63 + def __init__(self, form):
1.64 + self.form = form
1.65 +
1.66 + def get(self, name, default=None):
1.67 + values = self.form.getlist(name)
1.68 + if not values:
1.69 + return default
1.70 + else:
1.71 + return values
1.72 +
1.73 + def __getitem__(self, name):
1.74 + return self.form.getlist(name)
1.75 +
1.76 +class ActionSupport:
1.77 +
1.78 + """
1.79 + Work around disruptive MoinMoin changes in 1.9, and also provide useful
1.80 + convenience methods.
1.81 + """
1.82 +
1.83 + def get_form(self):
1.84 + return get_form(self.request)
1.85 +
1.86 +def get_form(request):
1.87 +
1.88 + "Work around disruptive MoinMoin changes in 1.9."
1.89 +
1.90 + if hasattr(request, "values"):
1.91 + return Form(request.values)
1.92 + else:
1.93 + return request.form
1.94 +
1.95 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/actions/ApproveChanges.py Sun Oct 09 20:37:21 2011 +0200
2.2 +++ b/actions/ApproveChanges.py Sun Oct 09 21:17:09 2011 +0200
2.3 @@ -15,6 +15,8 @@
2.4
2.5 from MoinMoin.action import ActionBase
2.6 from MoinMoin.PageEditor import PageEditor
2.7 +from MoinMoin.wikiutil import escape
2.8 +from ApproveChangesSupport import *
2.9
2.10 # Action class and supporting functions.
2.11
2.12 @@ -32,9 +34,35 @@
2.13 _ = self._
2.14 request = self.request
2.15 fmt = request.formatter
2.16 - prompt = _("Approve the displayed page version?")
2.17 - return fmt.paragraph(1) + fmt.text(prompt) + fmt.paragraph(0) + \
2.18 - fmt.paragraph(1) + fmt.rawHTML(buttons_html) + fmt.paragraph(0)
2.19 +
2.20 + d = {
2.21 + "buttons_html" : buttons_html,
2.22 + "prompt" : escape(_("Approve the displayed page version?")),
2.23 + "purge_label" : escape(_("Purge all other queued versions"))
2.24 + }
2.25 +
2.26 + # Prepare the output HTML.
2.27 +
2.28 + html = '''
2.29 +<table>
2.30 + <tr>
2.31 + <td colspan="2">%(prompt)s</td>
2.32 + </tr>
2.33 + <tr>
2.34 + <td class="label"><label>%(purge_label)s</label></td>
2.35 + <td>
2.36 + <input name="purge" type="checkbox" value="yes" />
2.37 + </td>
2.38 + </tr>
2.39 + <tr>
2.40 + <td></td>
2.41 + <td class="buttons">
2.42 + %(buttons_html)s
2.43 + </td>
2.44 + </tr>
2.45 +</table>''' % d
2.46 +
2.47 + return html
2.48
2.49 def do_action(self):
2.50
2.51 @@ -45,6 +73,7 @@
2.52
2.53 # Make sure that only suitably privileged users can perform this action.
2.54
2.55 + queued_changes_area = get_queued_changes_area(request)
2.56 reviewers_group = getattr(request.cfg, "reviewers_group", "PageReviewersGroup")
2.57
2.58 if not request.user.valid or (
2.59 @@ -54,10 +83,12 @@
2.60 return 0, _("Only page reviewers can perform this action.")
2.61
2.62 # Edit the target page, using this page's content.
2.63 - # The current page should have a name of the form...
2.64 - # ".../TargetPage/ApprovalQueue/n"
2.65 + # The current page must be a queued page version.
2.66
2.67 - target_page_name = "/".join(self.pagename.split("/")[:-2])
2.68 + if not is_queued_page(self.pagename, queued_changes_area):
2.69 + return 0, _("This page is not queued for approval.")
2.70 +
2.71 + target_page_name = get_target_page_name(self.pagename)
2.72 target_page = PageEditor(request, target_page_name)
2.73
2.74 # Save the target page.
2.75 @@ -72,6 +103,15 @@
2.76 current_page = PageEditor(request, self.pagename)
2.77 current_page.deletePage(_("Changes to page approved."))
2.78
2.79 + # Delete the rest of the queue if requested.
2.80 +
2.81 + form = get_form(request)
2.82 +
2.83 + if form.get("purge"):
2.84 + for name in get_queue_pages(request, target_page_name, queued_changes_area):
2.85 + queue_page = PageEditor(request, name)
2.86 + queue_page.deletePage(_("Changes to page rejected."))
2.87 +
2.88 # Redirect to the target page.
2.89
2.90 request.http_redirect(target_page.url(request))
3.1 --- a/events/queue_for_review.py Sun Oct 09 20:37:21 2011 +0200
3.2 +++ b/events/queue_for_review.py Sun Oct 09 21:17:09 2011 +0200
3.3 @@ -11,28 +11,21 @@
3.4
3.5 from MoinMoin.PageEditor import PageEditor
3.6 from MoinMoin.events import PagePreSaveEvent, Abort
3.7 -import re
3.8 -
3.9 -def match_queue_pages(pagename, queued_changes_area):
3.10 -
3.11 - "Return a filter function which matches subpages of 'pagename'."
3.12 -
3.13 - return re.compile(ur"^%s/%s/.*$" % (re.escape(pagename), re.escape(queued_changes_area)), re.UNICODE).match
3.14 +from ApproveChangesSupport import *
3.15
3.16 def handle_presave(event):
3.17 request = event.request
3.18 _ = request.getText
3.19
3.20 - approved_editors_group = getattr(request.cfg, "approved_editors_group", "ApprovedGroup")
3.21 - queued_changes_area = getattr(request.cfg, "queued_changes_area", "ApprovalQueue")
3.22 + approved_editors_group = get_approved_editors_group(request)
3.23 + queued_changes_area = get_queued_changes_area(request)
3.24
3.25 pagename = event.page_editor.page_name
3.26 - parts = pagename.split("/")
3.27
3.28 # Saving into queues has to be permitted or the mechanism will keep trying
3.29 # to save into a queue of the specified page.
3.30
3.31 - if len(parts) > 2 and parts[-2] == queued_changes_area:
3.32 + if is_queued_page(pagename, queued_changes_area):
3.33 return None
3.34
3.35 # For normal pages, the user has to be approved. Otherwise, the page will be
3.36 @@ -47,7 +40,7 @@
3.37
3.38 queue_number = -1
3.39
3.40 - for name in request.rootpage.getPageList(exists=1, filter=match_queue_pages(pagename, queued_changes_area)):
3.41 + for name in get_queue_pages(request, pagename, queued_changes_area):
3.42 number = name.split("/")[-1]
3.43 if number.isdigit():
3.44 queue_number = max(queue_number, int(number))
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/setup.py Sun Oct 09 21:17:09 2011 +0200
4.3 @@ -0,0 +1,13 @@
4.4 +#! /usr/bin/env python
4.5 +
4.6 +from distutils.core import setup
4.7 +
4.8 +setup(
4.9 + name = "ApproveChanges",
4.10 + description = "Queue changes to Wiki pages for subsequent approval",
4.11 + author = "Paul Boddie",
4.12 + author_email = "paul@boddie.org.uk",
4.13 + url = "http://moinmo.in/ActionMarket/ApproveChanges",
4.14 + version = "0.1",
4.15 + py_modules = ["ApproveChangesSupport"]
4.16 + )