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