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