Renaming a page can leave a lot of broken links behind. It would be nice if the RenamePage action would, after renaming a page, create a new page with the old name containing a #redirect processing instruction so that people following old links to the page are sent to its new location.

Solution

for 1.7 (and may be 1.8):

   1 --- /usr/lib/python2.5/site-packages/MoinMoin/action/RenamePage.py      2008-06-30 00:13:22 +0400
   2 +++ /var/www/wiki/uneex/data/plugin/action/RenamePage.py        2009-11-28 17:07:48 +0300
   3 @@ -30,6 +30,15 @@
   4          subpagenames = request.rootpage.getPageList(user='', exists=1, filter=filterfn)
   5          self.subpages = [pagename for pagename in subpagenames if self.request.user.may.delete(pagename)]
   6  
   7 +        form = self.request.form
   8 +        self.redirect = 0
   9 +        if 'rename_redirect' in form:
  10 +            try:
  11 +                self.redirect = int(form['rename_redirect'][0])
  12 +            except:
  13 +                pass
  14 +
  15 +
  16      def is_allowed(self):
  17          may = self.request.user.may
  18          return may.write(self.pagename) and may.delete(self.pagename)
  19 @@ -49,9 +58,7 @@
  20          newpagename = self.request.normalizePagename(newpagename)
  21          comment = form.get('comment', [u''])[0]
  22          comment = wikiutil.clean_input(comment)
  23 -
  24 -        self.page = PageEditor(self.request, self.pagename)
  25 -        success, msgs = self.page.renamePage(newpagename, comment)
  26 +        rename_redirect = self.redirect
  27  
  28          rename_subpages = 0
  29          if 'rename_subpages' in form:
  30 @@ -60,6 +67,17 @@
  31              except:
  32                  pass
  33  
  34 +
  35 +        self.page = PageEditor(self.request, self.pagename)
  36 +        success, msgs = self.page.renamePage(newpagename, comment)
  37 +
  38 +        if not success:
  39 +            return success, msgs
  40 +
  41 +        if rename_redirect:
  42 +            self.page = PageEditor(self.request, self.pagename)
  43 +            self.page.saveText('#redirect %s' % newpagename, 0)
  44 +
  45          if rename_subpages and self.subpages:
  46              for name in self.subpages:
  47                  self.page = PageEditor(self.request, name)
  48 @@ -67,6 +85,11 @@
  49                  success_i, msg = self.page.renamePage(new_subpagename, comment)
  50                  msgs = "%s %s" % (msgs, msg)
  51  
  52 +                if rename_redirect and success_i:
  53 +                    self.page = PageEditor(self.request, name)
  54 +                    self.page.saveText('#redirect %s' % new_subpagename, 0)
  55 +
  56 +
  57          self.newpagename = newpagename # keep there for finish
  58          return success, msgs
  59  
  60 @@ -91,7 +114,9 @@
  61                  'newname_label': _("New name"),
  62                  'comment_label': _("Optional reason for the renaming"),
  63                  'buttons_html': buttons_html,
  64 -                'querytext': _('Really rename this page?')
  65 +                'querytext': _('Really rename this page?'),
  66 +                'redirect': self.redirect,
  67 +                'redirect_label': _('Create redirect for renamed pages?'),
  68                  }
  69  
  70              return '''
  71 @@ -107,6 +132,11 @@
  72          <class="label"><subpage> %(subpage)s</subpage>
  73      </dd>
  74      </tr>
  75 +    <tr>
  76 +    <dd>
  77 +        %(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s>
  78 +    </dd>
  79 +    </tr>
  80  </table>
  81  <table>
  82      <tr>
  83 @@ -136,9 +166,19 @@
  84                  'newname_label': _("New name"),
  85                  'comment_label': _("Optional reason for the renaming"),
  86                  'buttons_html': buttons_html,
  87 +                'redirect': self.redirect,
  88 +                'redirect_label': _('Create redirect for renamed page?'),
  89                  }
  90              return '''
  91  <table>
  92 +    </tr>
  93 +    <tr>
  94 +    <dd>
  95 +        %(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s>
  96 +    </dd>
  97 +    </tr>
  98 +</table>
  99 +<table>
 100      <tr>
 101          <td class="label"><label>%(newname_label)s</label></td>
 102          <td class="content">

patch for 1.9 hg:

   1 # HG changeset patch
   2 # User Eugene Syromyatnikov <evgsyr@gmail.com>
   3 # Date 1259423676 -10800
   4 # Node ID b9a8cfae00acd2b142c23f8abbc9fb8a06116aef
   5 # Parent  5aef81c6ba8d2e6d560001a3f535aaa26e815edd
   6 Rename page action: added redirect checkbox, fixed bug with renaming subpages to inaccesible names during renaming to page empty name
   7 
   8 diff -r 5aef81c6ba8d -r b9a8cfae00ac MoinMoin/action/RenamePage.py
   9 --- a/MoinMoin/action/RenamePage.py Mon Nov 16 13:31:48 2009 +0300
  10 +++ b/MoinMoin/action/RenamePage.py Sat Nov 28 18:54:36 2009 +0300
  11 @@ -29,6 +29,7 @@
  12          filterfn = re.compile(ur"^%s/.*$" % re.escape(pagename), re.U).match
  13          subpagenames = request.rootpage.getPageList(user='', exists=1, filter=filterfn)
  14          self.subpages = [pagename for pagename in subpagenames if self.request.user.may.delete(pagename)]
  15 +        self.redirect = int(self.request.form.get('rename_redirect', '0'))
  16  
  17      def is_allowed(self):
  18          may = self.request.user.may
  19 @@ -49,22 +50,32 @@
  20          newpagename = wikiutil.normalize_pagename(newpagename, self.cfg)
  21          comment = form.get('comment', u'')
  22          comment = wikiutil.clean_input(comment)
  23 +        rename_redirect = self.redirect
  24 +        rename_subpages = int(self.request.form.get('rename_subpages', '0'))
  25  
  26          self.page = PageEditor(self.request, self.pagename)
  27          success, msgs = self.page.renamePage(newpagename, comment)
  28  
  29 -        rename_subpages = 0
  30 -        try:
  31 -            rename_subpages = int(form['rename_subpages'])
  32 -        except:
  33 -            pass
  34 +        if not success:
  35 +            return success, msgs
  36 +
  37 +        if rename_redirect:
  38 +            self.page = PageEditor(self.request, self.pagename)
  39 +            self.page.saveText('#redirect %s' % newpagename, 0)
  40  
  41          if rename_subpages and self.subpages:
  42 +            msgs = []
  43              for name in self.subpages:
  44                  self.page = PageEditor(self.request, name)
  45                  new_subpagename = name.replace(self.pagename, newpagename, 1)
  46                  success_i, msg = self.page.renamePage(new_subpagename, comment)
  47 -                msgs = "%s %s" % (msgs, msg)
  48 +                msgs.append(msg)
  49 +
  50 +                if rename_redirect and success_i:
  51 +                    self.page = PageEditor(self.request, name)
  52 +                    self.page.saveText('#redirect %s' % new_subpagename, 0)
  53 +            msgs = ' '.join([msg for msg in msgs if msg != None])
  54 +
  55  
  56          self.newpagename = newpagename # keep there for finish
  57          return success, msgs
  58 @@ -88,7 +99,9 @@
  59                  'newname_label': _("New name"),
  60                  'comment_label': _("Optional reason for the renaming"),
  61                  'buttons_html': buttons_html,
  62 -                'querytext': _('Really rename this page?')
  63 +                'querytext': _('Really rename this page?'),
  64 +                'redirect': self.redirect,
  65 +                'redirect_label': _('Create redirect for renamed pages?'),
  66                  }
  67  
  68              return '''
  69 @@ -104,6 +117,11 @@
  70          <class="label"><subpage> %(subpage)s</subpage>
  71      </dd>
  72      </tr>
  73 +    <tr>
  74 +    <dd>
  75 +        %(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s>
  76 +    </dd>
  77 +    </tr>
  78  </table>
  79  <table>
  80      <tr>
  81 @@ -133,10 +151,19 @@
  82                  'newname_label': _("New name"),
  83                  'comment_label': _("Optional reason for the renaming"),
  84                  'buttons_html': buttons_html,
  85 +                'redirect': self.redirect,
  86 +                'redirect_label': _('Create redirect for renamed page?'),
  87                  }
  88              return '''
  89  <table>
  90      <tr>
  91 +    <dd>
  92 +        %(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s>
  93 +    </dd>
  94 +    </tr>
  95 +</table>
  96 +<table>
  97 +    <tr>
  98          <td class="label"><label>%(newname_label)s</label></td>
  99          <td class="content">
 100              <input type="text" name="newpagename" value="%(pagename)s" size="80">


/!\ Edit conflict - other version:


version of patch with config option:

   1 diff -r c800980890aa MoinMoin/action/RenamePage.py
   2 --- a/MoinMoin/action/RenamePage.py     Fri Jan 15 17:35:20 2010 +0300
   3 +++ b/MoinMoin/action/RenamePage.py     Fri Jan 15 19:20:24 2010 +0300
   4 @@ -29,6 +29,8 @@
   5          filterfn = re.compile(ur"^%s/.*$" % re.escape(pagename), re.U).match
   6          subpagenames = request.rootpage.getPageList(user='', exists=1, filter=filterfn)
   7          self.subpages = [pagename for pagename in subpagenames if self.request.user.may.delete(pagename)]
   8 +        self.redirect = int(self.request.form.get('rename_redirect', '0'))
   9 +        self.allow_redirect = request.cfg.allow_auto_redirect_creation_on_renaming
  10  
  11      def is_allowed(self):
  12          may = self.request.user.may
  13 @@ -49,6 +51,8 @@
  14          newpagename = wikiutil.normalize_pagename(newpagename, self.cfg)
  15          comment = form.get('comment', u'')
  16          comment = wikiutil.clean_input(comment)
  17 +        rename_redirect = self.redirect
  18 +        rename_subpages = int(self.request.form.get('rename_subpages', '0'))
  19  
  20          self.page = PageEditor(self.request, self.pagename)
  21          success, msgs = self.page.renamePage(newpagename, comment)
  22 @@ -56,18 +60,23 @@
  23          if not success:
  24              return success, msgs
  25  
  26 -        rename_subpages = 0
  27 -        try:
  28 -            rename_subpages = int(form['rename_subpages'])
  29 -        except:
  30 -            pass
  31 +        msgs = [msgs]
  32 +
  33 +        if self.allow_redirect and rename_redirect:
  34 +            self.page = PageEditor(self.request, self.pagename)
  35 +            self.page.saveText('#redirect %s' % newpagename, 0)
  36  
  37          if rename_subpages and self.subpages:
  38              for name in self.subpages:
  39                  self.page = PageEditor(self.request, name)
  40                  new_subpagename = name.replace(self.pagename, newpagename, 1)
  41                  success_i, msg = self.page.renamePage(new_subpagename, comment)
  42 -                msgs = "%s %s" % (msgs, msg)
  43 +                msgs.append(msg)
  44 +
  45 +                if self.allow_redirect and rename_redirect and success_i:
  46 +                    self.page = PageEditor(self.request, name)
  47 +                    self.page.saveText('#redirect %s' % new_subpagename, 0)
  48 +            msgs = ' '.join([msg for msg in msgs if msg != None])
  49  
  50          self.newpagename = newpagename # keep there for finish
  51          return success, msgs
  52 @@ -82,6 +91,14 @@
  53      def get_form_html(self, buttons_html):
  54          _ = self._
  55          if self.subpages:
  56 +            if self.allow_redirect:
  57 +                redirect_html = '<tr><dd>%(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s></dd></tr>' % {
  58 +                    'redirect': self.redirect,
  59 +                    'redirect_label': _('Create redirect for renamed page(s)?'),
  60 +                }
  61 +            else:
  62 +                redirect_html = ''
  63 +
  64              subpages = ' '.join(self.subpages)
  65              d = {
  66                  'subpage': subpages,
  67 @@ -91,7 +108,8 @@
  68                  'newname_label': _("New name"),
  69                  'comment_label': _("Optional reason for the renaming"),
  70                  'buttons_html': buttons_html,
  71 -                'querytext': _('Really rename this page?')
  72 +                'querytext': _('Really rename this page?'),
  73 +                'redirect_html': redirect_html,
  74                  }
  75  
  76              return '''
  77 @@ -107,6 +125,7 @@
  78          <class="label"><subpage> %(subpage)s</subpage>
  79      </dd>
  80      </tr>
  81 +    %(redirect_html)s
  82  </table>
  83  <table>
  84      <tr>
  85 @@ -131,13 +150,23 @@
  86  ''' % d
  87  
  88          else:
  89 +            if self.allow_redirect:
  90 +                redirect_html = '<table><tr><dd>%(redirect_label)s<input type="checkbox" name="rename_redirect" value="1" %(redirect)s></dd></tr></table>' % {
  91 +                    'redirect': self.redirect,
  92 +                    'redirect_label': _('Create redirect for renamed page?'),
  93 +                }
  94 +            else:
  95 +                redirect_html = ''
  96 +
  97              d = {
  98                  'pagename': wikiutil.escape(self.pagename, True),
  99                  'newname_label': _("New name"),
 100                  'comment_label': _("Optional reason for the renaming"),
 101                  'buttons_html': buttons_html,
 102 +                'redirect_html': redirect_html,
 103                  }
 104              return '''
 105 +%(redirect_html)s
 106  <table>
 107      <tr>
 108          <td class="label"><label>%(newname_label)s</label></td>
 109 diff -r c800980890aa MoinMoin/config/multiconfig.py
 110 --- a/MoinMoin/config/multiconfig.py    Fri Jan 15 17:35:20 2010 +0300
 111 +++ b/MoinMoin/config/multiconfig.py    Fri Jan 15 19:20:24 2010 +0300
 112 @@ -1047,6 +1047,8 @@
 113       "if True, do a reverse DNS lookup on page SAVE. If your DNS is broken, set this to False to speed up SAVE."),
 114      ('log_timing', False,
 115       "if True, add timing infos to the log output to analyse load conditions"),
 116 +    ('allow_auto_redirect_creation_on_renaming', False,
 117 +     "if True, option of creating redirect pages on place of renamed will be proposed on page renaming."),
 118  
 119      # some dangerous mimetypes (we don't use "content-disposition: inline" for them when a user
 120      # downloads such attachments, because the browser might execute e.g. Javascript contained

These patches also fix MoinMoinBugs/RenamePageDestroysSubPageNaming.

Discussion

Sometimes I rename pages to e.g. DeleteThisPage + name because it is an easy way to remove also by a script all its attachments. And i can create immediatly afterwards a new page with the same old name. At that time I don't want inplace redirects.

If one renames by xmlrpc you have the old situation. So implementing this at the action level may not be the best place.

The redirect page line may cause acl problems. Because if the renamed page has had an acl line and the placeholder does not. And if the new page which does have the redirect line on it and is not potected against editing one could easily replace the redirect by some important text. And by this the placeholder concept is broken.

I would prefer a different solution. Not sure if that can work better: Currently we save on the page which was renamed its old name. At least with xapian it should be possible to solve it differently too. xapian could index the old name of the page at rename time. And if a page does not exists one can get shown the creation dialog and the renamed name together. If one selects the renamed page and he can edit the page it would be nice to have an automated s/old/new of the link name then.

Status

Added in http://hg.moinmo.in/moin/1.9/rev/354356b125b4


CategoryFeatureImplemented

MoinMoin: FeatureRequests/LeaveRedirectInPlaceWhenRenamingPages (last edited 2010-04-04 22:49:14 by ThomasWaldmann)