Attachment 'GlobalPageRename.py'
Download 1 # -*- coding: utf-8 -*-
2 """
3 MoinMoin - GlobalPageRename action
4
5 This action allows you to rename multiple pages in one go.
6 It offers a preview feature that lets you review what would be renamed
7 before doing the actual renaming.
8
9 Adapted to moin-1.9.8 and extended by David Linke.
10 Based on version 1.0 of "RenameMultiplePages.py" downloaded
11 from http://www.egenix.com/library/moinmoin/
12
13 Written by Marc-Andre Lemburg <mal@egenix.com>,
14 Based on the RenamePage action by Jürgen Hermann <jh@web.de>
15
16 @copyright: 2015-2018, David Linke, MoinMoin:DavidLinke, https://github.com/dalito
17 @copyright: 2008, eGenix.com Software, Skills and Services GmbH <info@egenix.com>
18 @license: GNU GPL 2.0, see COPYING for details.
19 """
20
21 import re
22
23 from MoinMoin import wikiutil
24 from MoinMoin.PageEditor import PageEditor
25 from MoinMoin.Page import Page
26 from MoinMoin.action import ActionBase
27 from MoinMoin import log
28
29 __version__ = '2.0'
30
31 # Should only the superuser be allowed to use this action ?
32 SUPERUSER_ONLY = False
33
34 logging = log.getLogger(__name__)
35
36
37 class GlobalPageRename(ActionBase):
38 """Rename multiple pages action
39
40 Note: the action name is the class name
41 """
42 def __init__(self, pagename, request):
43 ActionBase.__init__(self, pagename, request)
44 self.page = PageEditor(self.request, pagename)
45 self.orig_pagename = pagename
46 self.feedback = u''
47 self.newpagename = None
48 self.no_refused_access = 0
49
50 def is_allowed(self, pagename=None):
51 """Check if user is allowed to access page"""
52 if pagename is None:
53 pagename = self.pagename
54 may = self.request.user.may
55 return may.write(pagename) and may.delete(pagename)
56
57 def render(self):
58 """Render action
59
60 This action returns a wiki page with optional message, or
61 redirect to one of the new pages.
62 """
63 _ = self.request.getText
64 form = self.request.form
65
66 if 'cancel' in form:
67 # User cancelled
68 return self.page.send_page()
69
70 # Validate user rights and page state. If we get error here, we
71 # return an error message, without the rename form.
72 error = None
73 if self.is_excluded():
74 error = _('Action %(actionname)s is excluded in this wiki!') % {
75 'actionname': self.actionname}
76 elif SUPERUSER_ONLY and not self.request.user.isSuperUser():
77 error = _(u'Only superusers are allowed to use this action.')
78 elif not self.page.exists():
79 error = _(u'This page is already deleted or was never created!')
80 if error:
81 # Send page with an error message
82 self.request.theme.add_msg(msg=error)
83 return self.page.send_page()
84
85 if not form.get('pagename') or not form.get('newpagename'):
86 self.request.theme.add_msg(_(u'Please fill in both a search text '
87 'and a replacement text!'), 'info')
88
89 # Rename the pages.
90 elif ('rename' in form or 'preview' in form) and 'ticket' in form:
91 # Do the renaming
92 self.rename()
93
94 # Switch to new page if current page was renamed.
95 if self.newpagename:
96 self.request.theme.add_msg(_('<B>Current page renamed.</B> '
97 ' Moved to new page.'), 'info')
98 self.page = Page(self.request, self.newpagename)
99
100 # Show the form (with error or feedback information)
101 self.request.theme.add_msg(self.makeform(), 'info')
102 return self.page.send_page()
103
104 def rename(self):
105 """Rename pagename and return the new page"""
106 _ = self.request.getText
107 form = self.request.form
108 formatter = self.request.formatter
109 self.feedback = u''
110 self.no_refused_access = 0
111
112 # Require a valid ticket. Make outside attacks harder by
113 # requiring two full HTTP transactions
114 if not wikiutil.checkTicket(self.request, form['ticket']):
115 self.error = _(u'Please use the interactive user interface '
116 'to rename pages!')
117 return
118
119 # Get new name from form and normalize.
120 comment = form.get('comment', [u''])
121 comment = wikiutil.clean_input(comment)
122
123 pagename = form.get('pagename')
124 newpagename = form.get('newpagename')
125
126 # test if regular expression is OK
127 try:
128 re.compile(pagename)
129 except Exception as err:
130 self.error = _(u'Error in page name pattern: %s' % err)
131 return
132
133 # Get list of all pages and find the ones to rename
134 pages = self.request.rootpage.getPageList(user='', exists='')
135 pages_to_rename = [p for p in pages if re.search(pagename, p)]
136
137 self.feedback += formatter.rule()
138 self.feedback += formatter.paragraph(1)
139 self.feedback += _('Found %i matching pagename(s).' %
140 len(pages_to_rename))
141 self.feedback += formatter.paragraph(0)
142
143 if not pages_to_rename:
144 return
145
146 self.feedback += formatter.rule()
147 self.feedback += formatter.paragraph(1)
148 if 'preview' in self.request.form:
149 self.feedback += _('Would do the following renaming:')
150 else:
151 self.feedback += _('Renaming pages...')
152 self.feedback += formatter.paragraph(0)
153
154 # Rename all matching pages one by one
155 self.feedback += formatter.bullet_list(1)
156
157 for oldpage in pages_to_rename:
158 # Create & normalize new page name
159 try:
160 newpage = re.sub(pagename, newpagename, oldpage)
161 except Exception as err:
162 self.error = _(u'Error in new name pattern: %s' % err)
163 return
164 newpage = wikiutil.normalize_pagename(newpage, self.cfg)
165 # Rename page
166 if oldpage != newpage:
167 self.rename_page(oldpage, newpage, comment)
168
169 if self.no_refused_access:
170 self.feedback += formatter.listitem(1)
171 self.feedback += formatter.smiley('<!>')
172 self.feedback += _(u' %i pages skipped because of access '
173 'restrictions.' % self.no_refused_access)
174 self.feedback += formatter.listitem(0)
175 self.feedback += formatter.bullet_list(0)
176
177 def rename_page(self, pagename, newpagename, comment):
178 """Rename page with pagename to newpage and add comment to editlog
179 """
180 _ = self.request.getText
181 formatter = self.request.formatter
182
183 # Check permissions. Don't reveal the page name, just count.
184 if not self.is_allowed(pagename):
185 self.no_refused_access += 1
186 return
187
188 # Name might be empty after normalization.
189 if not newpagename:
190 self.feedback += formatter.listitem(1)
191 self.feedback += formatter.smiley('<!>')
192 self.feedback += _(u' Cannot rename page "%s" to an empty '
193 'pagename!' % pagename)
194 self.feedback += formatter.listitem(0)
195 return
196
197 page = PageEditor(self.request, pagename)
198 newpage = PageEditor(self.request, newpagename)
199
200 # preview
201 if 'preview' in self.request.form:
202 self.feedback += formatter.listitem(1)
203 if newpage.exists(includeDeleted=True):
204 self.feedback += formatter.smiley('<!>')
205 self.feedback += ' "%s" --> "%s" ' % (pagename, newpagename)
206 self.feedback += formatter.strong(1)
207 self.feedback += _('Target already exists.')
208 self.feedback += formatter.strong(0)
209 else:
210 self.feedback += '"%s" --> "%s"' % (pagename, newpagename)
211 self.feedback += formatter.listitem(0)
212 return
213
214 # Check whether a page with the new name already exists
215 if newpage.exists(includeDeleted=True):
216 return self.page_exists_error(newpagename)
217
218 if newpage.exists(includeDeleted=True):
219 self.feedback += formatter.listitem(1)
220 self.feedback += formatter.smiley('<!>')
221 self.feedback += _('A page <B>%s</B> already exists.' %
222 wikiutil.escape(newpagename))
223 self.feedback += formatter.listitem(0)
224
225 # Rename page
226 success, msgs = page.renamePage(newpagename, comment)
227 if msgs:
228 self.feedback += msgs
229
230 if success and self.orig_pagename == pagename:
231 self.newpagename = newpagename
232
233 self.feedback += formatter.listitem(1)
234 self.feedback += formatter.smiley('(./)')
235 self.feedback += '%s --> %s' % (pagename, newpagename)
236 self.feedback += formatter.listitem(0)
237
238 def makeform(self):
239 """ Display a rename page form
240
241 The form also provides error feedback in case there was an
242 error during the replace.
243 """
244 from MoinMoin.widget.dialog import Dialog
245 _ = self.request.getText
246
247 error = ''
248 if self.error:
249 error = u'<p class="error">%s</p>\n' % self.error
250
251 namespace = {
252 'error': error,
253 'feedback': self.feedback,
254 'action': self.__class__.__name__,
255 'ticket': wikiutil.createTicket(self.request),
256 'pagename': self.request.form.get('pagename', self.pagename),
257 'newpagename': self.request.form.get('newpagename', self.pagename),
258 'comment': self.request.form.get('comment', ''),
259 'rename': _(u'Rename Pages'),
260 'preview': _(u'Preview'),
261 'cancel': _(u'Cancel'),
262 'pagename_label': _(u"Page name pattern"),
263 'newname_label': _(u"New name pattern"),
264 'comment_label': _(u"Optional reason for the renaming"),
265 'note': _(u"Note: Page name pattern may use regular expression "
266 "syntax (Python re-module syntax). Groups can be "
267 "referenced in the new name pattern using \\1, \\2, "
268 "etc."),
269 }
270 form = """
271 %(error)s
272 <form method="post" action="">
273 <input type="hidden" name="action" value="%(action)s">
274 <input type="hidden" name="ticket" value="%(ticket)s">
275 <table>
276 <tr>
277 <td class="label"><label>%(pagename_label)s</label></td>
278 <td class="content">
279 <input type="text" name="pagename" size="60" value="%(pagename)s">
280 </td>
281 </tr>
282 <tr>
283 <td class="label"><label>%(newname_label)s</label></td>
284 <td class="content">
285 <input type="text" name="newpagename" size="60" value="%(newpagename)s">
286 </td>
287 </tr>
288 <tr>
289 <td class="label"><label>%(comment_label)s</label></td>
290 <td class="content">
291 <input type="text" name="comment" size="60" maxlength="80" value="%(comment)s">
292 </td>
293 </tr>
294 <tr>
295 <td></td>
296 <td class="buttons">
297 <input type="submit" name="preview" value="%(preview)s">
298 <input type="submit" name="rename" value="%(rename)s">
299 <input type="submit" name="cancel" value="%(cancel)s">
300 </td>
301 </tr>
302 </table>
303 <p style="font-weight: normal">%(note)s</p>
304 <p>%(feedback)s</p>
305 </form>
306 """ % namespace
307
308 return Dialog(self.request, content=form)
309
310 def page_exists_error(self, pagename):
311 _ = self.request.getText
312 self.error += _(u"A page with the name %s already exists. "
313 "Skipped. <br>") % (pagename,)
314
315
316 def execute(pagename, request):
317 """Glue code for actions"""
318 GlobalPageRename(pagename, request).render()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.