ApproveChanges

ApproveChangesSupport.py

30:623d4bb10f11
2013-11-05 Paul Boddie Removed the ApprovalQueueUser, making use of a special security policy instead.
     1 # -*- coding: iso-8859-1 -*-     2 """     3     MoinMoin - ApproveChanges library     4      5     If users other than the superuser are to be able to edit pages freely, they     6     must be present in a group (by default "ApprovedGroup"), and if they are to     7     be allowed to review changes, they must be present in a different group (by     8     default "PageReviewersGroup").     9     10     @copyright: 2011, 2013 by Paul Boddie <paul@boddie.org.uk>    11                 2013 by Jakub Jedelsky <jedelsky@master.cz>    12                 2003-2007 MoinMoin:ThomasWaldmann,    13                 2003 by Gustavo Niemeyer    14     @license: GNU GPL (v2 or later), see COPYING.txt for details.    15 """    16     17 from MoinMoin import user    18 from MoinMoin.Page import Page    19 from MoinMoin.PageEditor import PageEditor    20 from MoinMoin.wikiutil import escape    21 import re    22     23 __version__ = "0.2"    24     25 space_pattern = re.compile("(\s+)")    26 group_member_pattern = re.compile(ur'^ \* +(?:\[\[)?(?P<member>.+?)(?:\]\])? *$', re.MULTILINE | re.UNICODE)    27     28 def have_user_specific_queue(request):    29     return getattr(request.cfg, "queued_changes_per_user", False)    30     31 def get_user_specific_queue(request):    32     return have_user_specific_queue(request) and \    33         request.user.valid and ("%s/" % request.user.name) or \    34         ""    35     36 def get_queued_changes_page(request):    37     return getattr(request.cfg, "queued_changes_page", "ApprovalQueue")    38     39 def get_approved_editors_group(request):    40     return getattr(request.cfg, "approved_editors_group", "ApprovedGroup")    41     42 def get_page_reviewers_group(request):    43     return getattr(request.cfg, "reviewers_group", "PageReviewersGroup")    44     45 def is_reviewer(request):    46     return request.user.valid and (    47         has_member(request, get_page_reviewers_group(request), request.user.name) or \    48         request.user.isSuperUser())    49     50 def is_approved(request):    51     return request.user.valid and (    52         user_is_approved(request, request.user.name) or \    53         request.user.isSuperUser())    54     55 def user_is_approved(request, username):    56     return has_member(request, get_approved_editors_group(request), username)    57     58 def is_queued_changes_page(request, pagename):    59     60     "Return whether 'pagename' is a queued changes page by testing its name."    61     62     parts = pagename.split("/")    63     return len(parts) > 1 and parts[-1] == get_queued_changes_page(request)    64     65 def get_target_page_name(page):    66     67     "Return the target page name for the given queued changes 'page'."    68     69     directive = "unapproved-user-queue"    70     body, directives = remove_directives(page.get_raw_body(), [directive])    71     extra_parts = directives.has_key(directive) and 2 or 1    72     return "/".join(page.page_name.split("/")[:-extra_parts])    73     74 def get_user(request, username):    75     76     "Return the user having the given 'username'."    77     78     uid = user.getUserId(request, username)    79     80     # If the user does not exist, just return None.    81     82     if not uid:    83         return None    84     85     # Otherwise, return the privileged user.    86     87     return user.User(request, uid)    88     89 def get_parent_revision_directive(request, pagename):    90     91     """    92     Using the 'request', return a parent page revision directive for the page    93     having the given 'pagename'.    94     """    95     96     page = Page(request, pagename)    97     return "#parent-revision %s" % page.current_rev()    98     99 def get_access_control_directive(request):   100    101     """   102     Using the 'request', return an ACL directive for use in a page body in order   103     to prevent anyone other than reviewers from seeing it in the queue.   104     """   105    106     return "#acl %s:read,write,delete,revert,admin All:" % (   107         get_page_reviewers_group(request))   108    109 def get_user_directive(request):   110    111     """   112     Using the 'request', return a user directive for use in a page body in order   113     to record who saved the changes originally.   114     """   115    116     if request.user.valid:   117         return "#unapproved-user %s" % request.user.name   118     else:   119         return ""   120    121 def get_user_queue_directive(request):   122    123     """   124     Using the 'request', return a user directive for use in a page body in order   125     to record who saved the changes originally.   126     """   127    128     if request.user.valid and have_user_specific_queue(request):   129         return "#unapproved-user-queue"   130     else:   131         return ""   132    133 def add_directives(body, directives):   134    135     "Add to the page 'body' the given 'directives'."   136    137     return "\n".join([directive for directive in directives if directive] + [body])   138    139 def remove_directives(body, names):   140    141     """   142     Return a new page body, copying the page 'body' provided but removing the   143     first of each directive having one of the given 'names', along with a   144     dictionary mapping directive names to values.   145     """   146    147     new_body = []   148     header = 1   149     found = {}   150    151     for line in body.split("\n"):   152         if header:   153    154             # Detect the end of the header.   155    156             if not line.startswith("#"):   157                 header = 0   158    159             # Process the comment or directive.   160    161             else:   162                 parts = space_pattern.split(line[1:])   163    164                 # Identify any directive.   165    166                 directive = parts[0]   167    168                 # Obtain the value of the first instance of any directive,   169                 # stripping any initial space.   170    171                 if directive in names and not found.has_key(directive):   172                     found[directive] = "".join(parts[2:])   173                     continue   174    175         new_body.append(line)   176    177     return "\n".join(new_body), found   178    179 def add_to_group_page(request, username, groupname):   180    181     """   182     Using the 'request', add 'username' to 'groupname', changing the group page.   183     This is not the same as adding a member to the group, but it will have the   184     same effect when the group is rescanned.   185     """   186    187     _ = request.getText   188    189     page = PageEditor(request, groupname)   190     body = page.get_raw_body()   191     match = None   192    193     # Find the last matching span.   194    195     for match in group_member_pattern.finditer(body):   196         start, end = match.span()   197    198     # Add a group member to the body.   199    200     entry = ("\n * %s" % username)   201    202     if match:   203         body = body[:end] + entry + body[end:]   204     else:   205         body += entry   206    207     page.saveText(body, 0, comment=_("Added %s to the approved editors group.") % username)   208    209 # Utility classes and associated functions.   210 # NOTE: These are now present in MoinSupport which should be used in future.   211    212 class Form:   213    214     """   215     A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x   216     environment.   217     """   218    219     def __init__(self, form):   220         self.form = form   221    222     def get(self, name, default=None):   223         values = self.form.getlist(name)   224         if not values:   225             return default   226         else:   227             return values   228    229     def __getitem__(self, name):   230         return self.form.getlist(name)   231    232 class ActionSupport:   233    234     """   235     Work around disruptive MoinMoin changes in 1.9, and also provide useful   236     convenience methods.   237     """   238    239     def get_form(self):   240         return get_form(self.request)   241    242 def get_form(request):   243    244     "Work around disruptive MoinMoin changes in 1.9."   245    246     if hasattr(request, "values"):   247         return Form(request.values)   248     else:   249         return request.form   250    251 def escattr(s):   252     return escape(s, 1)   253    254 # More Moin 1.9 compatibility functions.   255    256 def has_member(request, groupname, username):   257     if hasattr(request.dicts, "has_member"):   258         return request.dicts.has_member(groupname, username)   259     else:   260         return username in request.groups.get(groupname, [])   261    262 # vim: tabstop=4 expandtab shiftwidth=4