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.
  • [get | view] (2018-03-15 00:01:02, 10.4 KB) [[attachment:GlobalPageRename.png]]
  • [get | view] (2018-03-14 23:52:11, 11.5 KB) [[attachment:GlobalPageRename.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.