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.Page import Page 20 from MoinMoin.wikiutil import escape 21 import re 22 23 __version__ = "0.1" 24 25 space_pattern = re.compile("(\s+)") 26 27 def get_queued_changes_page(request): 28 return getattr(request.cfg, "queued_changes_page", "ApprovalQueue") 29 30 def get_approved_editors_group(request): 31 return getattr(request.cfg, "approved_editors_group", "ApprovedGroup") 32 33 def get_page_reviewers_group(request): 34 return getattr(request.cfg, "reviewers_group", "PageReviewersGroup") 35 36 def get_queued_changes_user(request): 37 return getattr(request.cfg, "queued_changes_user", "ApprovalQueueUser") 38 39 def get_secret_key(request): 40 return request.cfg.secrets["wikiutil/tickets"] 41 42 def is_reviewer(request): 43 return request.user.valid and ( 44 request.dicts.has_member(get_approved_editors_group(request), request.user.name) or \ 45 request.user.isSuperUser()) 46 47 def is_approved(request): 48 return request.user.valid and ( 49 request.dicts.has_member(get_approved_editors_group(request), request.user.name) or \ 50 request.user.isSuperUser()) 51 52 def is_queued_changes_user(request): 53 return request.user.valid and request.user.name == get_queued_changes_user(request) 54 55 def is_queued_changes_page(request, pagename): 56 57 "Return whether 'pagename' is a queued changes page by testing its name." 58 59 parts = pagename.split("/") 60 return len(parts) > 1 and parts[-1] == get_queued_changes_page(request) 61 62 def get_target_page_name(pagename): 63 64 "Return the target page name for the given queued changes 'pagename'." 65 66 return "/".join(pagename.split("/")[:-1]) 67 68 def get_user_for_saving(request): 69 70 "Return a user that can save pages with ACLs." 71 72 username = get_queued_changes_user(request) 73 uid = user.getUserId(request, username) 74 75 # If the user does not exist, just return the existing user. 76 77 if not uid: 78 return request.user 79 80 # Otherwise, return the privileged user. 81 82 return user.User(request, uid) 83 84 def get_parent_revision_directive(request, pagename): 85 86 """ 87 Using the 'request', return a parent page revision directive for the page 88 having the given 'pagename'. 89 """ 90 91 page = Page(request, pagename) 92 return "#parent-revision %s" % page.current_rev() 93 94 def get_access_control_directive(request): 95 96 """ 97 Using the 'request', return an ACL directive for use in a page body in order 98 to prevent anyone other than reviewers from seeing it in the queue. 99 """ 100 101 return "#acl %s:read,write,delete,revert,admin All:" % ( 102 get_page_reviewers_group(request)) 103 104 def add_directives(body, directives): 105 106 "Add to the page 'body' the given 'directives'." 107 108 return "\n".join(directives + [body]) 109 110 def remove_directives(body, names): 111 112 """ 113 Return a new page body, copying the page 'body' provided but removing the 114 first of each directive having one of the given 'names', along with a 115 dictionary mapping directive names to values. 116 """ 117 118 new_body = [] 119 header = 1 120 found = {} 121 122 for line in body.split("\n"): 123 if header: 124 125 # Detect the end of the header. 126 127 if not line.startswith("#"): 128 header = 0 129 130 # Process the comment or directive. 131 132 else: 133 parts = space_pattern.split(line[1:]) 134 135 # Identify any directive. 136 137 directive = parts[0] 138 139 # Obtain the value of the first instance of any directive, 140 # stripping any initial space. 141 142 if directive in names and not found.has_key(directive): 143 found[directive] = "".join(parts[2:]) 144 continue 145 146 new_body.append(line) 147 148 return "\n".join(new_body), found 149 150 # Utility classes and associated functions. 151 # NOTE: These are a subset of EventAggregatorSupport. 152 153 class Form: 154 155 """ 156 A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x 157 environment. 158 """ 159 160 def __init__(self, form): 161 self.form = form 162 163 def get(self, name, default=None): 164 values = self.form.getlist(name) 165 if not values: 166 return default 167 else: 168 return values 169 170 def __getitem__(self, name): 171 return self.form.getlist(name) 172 173 class ActionSupport: 174 175 """ 176 Work around disruptive MoinMoin changes in 1.9, and also provide useful 177 convenience methods. 178 """ 179 180 def get_form(self): 181 return get_form(self.request) 182 183 def get_form(request): 184 185 "Work around disruptive MoinMoin changes in 1.9." 186 187 if hasattr(request, "values"): 188 return Form(request.values) 189 else: 190 return request.form 191 192 def escattr(s): 193 return escape(s, 1) 194 195 # vim: tabstop=4 expandtab shiftwidth=4