1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - ApproveChanges library 4 5 This library relies on the existence of a user (by default 6 "ApprovalQueueUser") who has sufficient privileges to write pages with ACLs 7 to an approval queue (ACL permissions "write,admin"). 8 9 If users other than the superuser are to be able to edit pages freely, they 10 must be present in a group (by default "ApprovedGroup"), and if they are to 11 be allowed to review changes, they must be present in a different group (by 12 default "PageReviewersGroup"). 13 14 @copyright: 2011 by Paul Boddie <paul@boddie.org.uk> 15 @license: GNU GPL (v2 or later), see COPYING.txt for details. 16 """ 17 18 from MoinMoin import user 19 import re 20 21 acl_pattern = re.compile(ur"^#acl .*$", re.UNICODE | re.MULTILINE) 22 23 __version__ = "0.1" 24 25 def get_queued_changes_page(request): 26 return getattr(request.cfg, "queued_changes_page", "ApprovalQueue") 27 28 def get_approved_editors_group(request): 29 return getattr(request.cfg, "approved_editors_group", "ApprovedGroup") 30 31 def get_page_reviewers_group(request): 32 return getattr(request.cfg, "reviewers_group", "PageReviewersGroup") 33 34 def get_queued_changes_user(request): 35 return getattr(request.cfg, "queued_changes_user", "ApprovalQueueUser") 36 37 def get_secret_key(request): 38 return request.cfg.secrets["wikiutil/tickets"] 39 40 def is_reviewer(request): 41 return request.user.valid and ( 42 request.dicts.has_member(get_approved_editors_group(request), request.user.name) or \ 43 request.user.isSuperUser()) 44 45 def is_approved(request): 46 return request.user.valid and ( 47 request.dicts.has_member(get_approved_editors_group(request), request.user.name) or \ 48 request.user.isSuperUser()) 49 50 def is_queued_changes_user(request): 51 return request.user.valid and request.user.name == get_queued_changes_user(request) 52 53 def is_queued_changes_page(request, pagename): 54 55 "Return whether 'pagename' is a queued changes page by testing its name." 56 57 parts = pagename.split("/") 58 return len(parts) > 1 and parts[-1] == get_queued_changes_page(request) 59 60 def get_target_page_name(pagename): 61 62 "Return the target page name for the given queued changes 'pagename'." 63 64 return "/".join(pagename.split("/")[:-1]) 65 66 def get_user_for_saving(request): 67 68 "Return a user that can save pages with ACLs." 69 70 username = get_queued_changes_user(request) 71 uid = user.getUserId(request, username) 72 73 # If the user does not exist, just return the existing user. 74 75 if not uid: 76 return request.user 77 78 # Otherwise, return the privileged user. 79 80 return user.User(request, uid) 81 82 def add_access_control(request, body): 83 84 """ 85 Using the 'request', add an ACL to the page 'body' in order to prevent 86 anyone other than reviewers from seeing it in the queue. 87 """ 88 89 # Find existing ACLs. 90 91 match = acl_pattern.search(body) 92 if match: 93 start, end = match.span() 94 95 # Comment out existing ACLs. 96 97 parts = [] 98 parts.append(body[:start]) 99 parts.append("#") 100 parts.append(body[start:]) 101 else: 102 parts = [body] 103 104 # Add the ACL. 105 106 parts.insert(0, "#acl %s:read,write,delete,revert,admin All:\n" % 107 get_page_reviewers_group(request)) 108 return "".join(parts) 109 110 def remove_access_control(request, body): 111 112 "Using the 'request', remove any added ACL to the page 'body'." 113 114 lines = body.split("\n") 115 116 try: 117 directive = lines[0].split()[0] 118 if directive == "#acl": 119 return "\n".join(lines[1:]) 120 except ValueError: 121 pass 122 123 return body 124 125 # Utility classes and associated functions. 126 # NOTE: These are a subset of EventAggregatorSupport. 127 128 class Form: 129 130 """ 131 A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x 132 environment. 133 """ 134 135 def __init__(self, form): 136 self.form = form 137 138 def get(self, name, default=None): 139 values = self.form.getlist(name) 140 if not values: 141 return default 142 else: 143 return values 144 145 def __getitem__(self, name): 146 return self.form.getlist(name) 147 148 class ActionSupport: 149 150 """ 151 Work around disruptive MoinMoin changes in 1.9, and also provide useful 152 convenience methods. 153 """ 154 155 def get_form(self): 156 return get_form(self.request) 157 158 def get_form(request): 159 160 "Work around disruptive MoinMoin changes in 1.9." 161 162 if hasattr(request, "values"): 163 return Form(request.values) 164 else: 165 return request.form 166 167 # vim: tabstop=4 expandtab shiftwidth=4