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 from MoinSupport import Form, ActionSupport, get_form, escattr, groupHasMember 22 import re 23 24 __version__ = "0.2" 25 26 space_pattern = re.compile("(\s+)") 27 group_member_pattern = re.compile(ur'^ \* +(?:\[\[)?(?P<member>.+?)(?:\]\])? *$', re.MULTILINE | re.UNICODE) 28 29 def have_user_specific_queue(request): 30 return getattr(request.cfg, "queued_changes_per_user", False) 31 32 def get_user_specific_queue(request): 33 return have_user_specific_queue(request) and \ 34 request.user.valid and ("%s/" % request.user.name) or \ 35 "" 36 37 def get_queued_changes_page(request): 38 return getattr(request.cfg, "queued_changes_page", "ApprovalQueue") 39 40 def get_approved_editors_group(request): 41 return getattr(request.cfg, "approved_editors_group", "ApprovedGroup") 42 43 def get_page_reviewers_group(request): 44 return getattr(request.cfg, "reviewers_group", "PageReviewersGroup") 45 46 def is_reviewer(request): 47 return request.user.valid and ( 48 groupHasMember(request, get_page_reviewers_group(request), request.user.name) or \ 49 request.user.isSuperUser()) 50 51 def is_approved(request): 52 return request.user.valid and ( 53 user_is_approved(request, request.user.name) or \ 54 request.user.isSuperUser()) 55 56 def user_is_approved(request, username): 57 return groupHasMember(request, get_approved_editors_group(request), username) 58 59 def is_queued_changes_page(request, pagename): 60 61 "Return whether 'pagename' is a queued changes page by testing its name." 62 63 parts = pagename.split("/") 64 return len(parts) > 1 and parts[-1] == get_queued_changes_page(request) 65 66 def get_target_page_name(page): 67 68 "Return the target page name for the given queued changes 'page'." 69 70 directive = "unapproved-user-queue" 71 body, directives = remove_directives(page.get_raw_body(), [directive]) 72 extra_parts = directives.has_key(directive) and 2 or 1 73 return "/".join(page.page_name.split("/")[:-extra_parts]) 74 75 def get_user(request, username): 76 77 "Return the user having the given 'username'." 78 79 uid = user.getUserId(request, username) 80 81 # If the user does not exist, just return None. 82 83 if not uid: 84 return None 85 86 # Otherwise, return the privileged user. 87 88 return user.User(request, uid) 89 90 def get_parent_revision_directive(request, pagename): 91 92 """ 93 Using the 'request', return a parent page revision directive for the page 94 having the given 'pagename'. 95 """ 96 97 page = Page(request, pagename) 98 return "#parent-revision %s" % page.current_rev() 99 100 def get_access_control_directive(request): 101 102 """ 103 Using the 'request', return an ACL directive for use in a page body in order 104 to prevent anyone other than reviewers from seeing it in the queue. 105 """ 106 107 return "#acl %s:read,write,delete,revert,admin All:" % ( 108 get_page_reviewers_group(request)) 109 110 def get_user_directive(request): 111 112 """ 113 Using the 'request', return a user directive for use in a page body in order 114 to record who saved the changes originally. 115 """ 116 117 if request.user.valid: 118 return "#unapproved-user %s" % request.user.name 119 else: 120 return "" 121 122 def get_user_queue_directive(request): 123 124 """ 125 Using the 'request', return a user directive for use in a page body in order 126 to record who saved the changes originally. 127 """ 128 129 if request.user.valid and have_user_specific_queue(request): 130 return "#unapproved-user-queue" 131 else: 132 return "" 133 134 def add_directives(body, directives): 135 136 "Add to the page 'body' the given 'directives'." 137 138 return "\n".join([directive for directive in directives if directive] + [body]) 139 140 def remove_directives(body, names): 141 142 """ 143 Return a new page body, copying the page 'body' provided but removing the 144 first of each directive having one of the given 'names', along with a 145 dictionary mapping directive names to values. 146 """ 147 148 new_body = [] 149 header = 1 150 found = {} 151 152 for line in body.split("\n"): 153 if header: 154 155 # Detect the end of the header. 156 157 if not line.startswith("#"): 158 header = 0 159 160 # Process the comment or directive. 161 162 else: 163 parts = space_pattern.split(line[1:]) 164 165 # Identify any directive. 166 167 directive = parts[0] 168 169 # Obtain the value of the first instance of any directive, 170 # stripping any initial space. 171 172 if directive in names and not found.has_key(directive): 173 found[directive] = "".join(parts[2:]) 174 continue 175 176 new_body.append(line) 177 178 return "\n".join(new_body), found 179 180 def add_to_group_page(request, username, groupname): 181 182 """ 183 Using the 'request', add 'username' to 'groupname', changing the group page. 184 This is not the same as adding a member to the group, but it will have the 185 same effect when the group is rescanned. 186 """ 187 188 _ = request.getText 189 190 page = PageEditor(request, groupname) 191 body = page.get_raw_body() 192 match = None 193 194 # Find the last matching span. 195 196 for match in group_member_pattern.finditer(body): 197 start, end = match.span() 198 199 # Add a group member to the body. 200 201 entry = ("\n * %s" % username) 202 203 if match: 204 body = body[:end] + entry + body[end:] 205 else: 206 body += entry 207 208 page.saveText(body, 0, comment=_("Added %s to the approved editors group.") % username) 209 210 # vim: tabstop=4 expandtab shiftwidth=4