changeset 1858:970140d46ae1

merged main
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Thu, 08 Mar 2007 14:32:22 +0100
parents 659070e5e4d3 (current diff) 763fb3eba3b3 (diff)
children 327b23c27532
files MoinMoin/Page.py
diffstat 7 files changed, 261 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/Page.py	Thu Mar 08 14:31:48 2007 +0100
+++ b/MoinMoin/Page.py	Thu Mar 08 14:32:22 2007 +0100
@@ -1728,7 +1728,7 @@
         request.clock.stop('getPageList')
         return pages
 
-    def getPageDict(self, user=None, exists=1, filter=None):
+    def getPageDict(self, user=None, exists=1, filter=None, include_underlay=True):
         """ Return a dictionary of filtered page objects readable by user
 
         Invoke getPageList then create a dict from the page list. See
@@ -1741,7 +1741,7 @@
         @return: user readable pages
         """
         pages = {}
-        for name in self.getPageList(user=user, exists=exists, filter=filter):
+        for name in self.getPageList(user=user, exists=exists, filter=filter, include_underlay=include_underlay):
             pages[name] = Page(self.request, name)
         return pages
 
--- a/MoinMoin/PageEditor.py	Thu Mar 08 14:31:48 2007 +0100
+++ b/MoinMoin/PageEditor.py	Thu Mar 08 14:32:22 2007 +0100
@@ -487,6 +487,68 @@
         page = backto and Page(request, backto) or self
         page.send_page(msg=_('Edit was cancelled.'))
 
+    def copyPage(self, newpagename, comment=None):
+        """
+        Copy the current version of the page (keeping the backups, logs and attachments).
+        
+        @param comment: Comment given by user
+        @rtype: unicode
+        @return: success flag, error message
+        """
+        request = self.request
+        _ = self._
+
+        if not newpagename:
+            return False, _("You can't copy to an empty pagename.")
+
+        newpage = PageEditor(request, newpagename)
+
+        pageexists_error = _("""'''A page with the name {{{'%s'}}} already exists.'''
+Try a different name.""") % (newpagename,)
+
+        # Check whether a page with the new name already exists
+        if newpage.exists(includeDeleted=1):
+            return False, pageexists_error
+
+        # Get old page text
+        savetext = self.get_raw_body()
+
+        oldpath = self.getPagePath(check_create=0)
+        newpath = newpage.getPagePath(check_create=0)
+
+        # Copy page
+        # NOTE: might fail if another process created newpagename just
+        try:
+            filesys.copytree(oldpath, newpath)
+            self.error = None
+            if not comment:
+                comment = u"## page was copied from %s" % self.page_name
+            if request.user.may.write(newpagename):
+                # If current user has write access
+                # Save page text with a comment about the old name
+                savetext = u"## page was copied from %s\n%s" % (self.page_name, savetext)
+                newpage.saveText(savetext, 0, comment=comment, index=0, extra=self.page_name, action='SAVE')
+            else:
+                # if user is  not able to write to the page itselfs we set a log entry only
+                from MoinMoin import packages
+                rev = newpage.current_rev()
+                packages.edit_logfile_append(self, newpagename, newpath, rev, 'SAVENEW', logname='edit-log',
+                                       comment=comment, author=u"CopyPage action")
+
+            if request.cfg.xapian_search:
+                from MoinMoin.search.Xapian import Index
+                index = Index(request)
+                if index.exists():
+                    index.update_page(newpagename)
+            return True, None
+        except OSError, err:
+            # Try to understand what happened. Maybe its better to check
+            # the error code, but I just reused the available code above...
+            if newpage.exists(includeDeleted=1):
+                return False, pageexists_error
+            else:
+                return False, _('Could not copy page because of file system error: %s.') % unicode(err)
+
     def renamePage(self, newpagename, comment=None):
         """
         Rename the current version of the page (making a backup before deletion
@@ -498,6 +560,12 @@
         """
         request = self.request
         _ = self._
+
+        if not (request.user.may.delete(self.page_name)
+                and request.user.may.write(newpagename)):
+            msg = _('You are not allowed to rename this page!')
+            raise self.AccessDenied, msg
+
         if not newpagename:
             return False, _("You can't rename to an empty pagename.")
 
@@ -583,7 +651,8 @@
                 _('Page "%s" was successfully deleted!') % (self.page_name,))
 
         except self.SaveError, message:
-            # XXX Error handling
+            # XXX do not only catch base class SaveError here, but
+            # also the derived classes, so we can give better err msgs
             success = False
             msg = "SaveError has occured in PageEditor.deletePage. We need locking there."
 
@@ -622,7 +691,7 @@
         else:
             querystr = {}
         pagelink = request.getQualifiedURL(self.url(request, querystr, relative=False))
- 
+
         mailBody = _("Dear Wiki user,\n\n"
             'You have subscribed to a wiki page or wiki category on "%(sitename)s" for change notification.\n\n'
             "The following page has been changed by %(editor)s:\n"
@@ -852,7 +921,8 @@
 
         return pragmas
 
-    def copypage(self):
+    def copy_underlay_page(self):
+        # renamed from copypage to avoid conflicts with copyPage
         """
         Copy a page from underlay directory to page directory
         """
@@ -883,7 +953,7 @@
         #is_deprecated = self._get_pragmas(text).has_key("deprecated")
         was_deprecated = self._get_pragmas(self.get_raw_body()).has_key("deprecated")
 
-        self.copypage()
+        self.copy_underlay_page()
 
         # remember conflict state
         self.setConflict(wikiutil.containsConflictMarker(text))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/action/CopyPage.py	Thu Mar 08 14:32:22 2007 +0100
@@ -0,0 +1,170 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - CopyPage action
+
+    This action allows you to copy a page.
+
+    @copyright: 2007 ReimarBauer
+    @license: GNU GPL, see COPYING for details.
+"""
+import re
+from MoinMoin import wikiutil
+from MoinMoin.Page import Page
+from MoinMoin.PageEditor import PageEditor
+from MoinMoin.action import ActionBase
+
+class CopyPage(ActionBase):
+    """ Copy page action
+
+    Note: the action name is the class name
+    """
+    def __init__(self, pagename, request):
+        ActionBase.__init__(self, pagename, request)
+        self.use_ticket = True
+        _ = self._
+        self.form_trigger = 'copy'
+        self.form_trigger_label = _('Copy Page')
+        filterfn = re.compile(pagename).match
+        pages = request.rootpage.getPageList(user='', exists=1, filter=filterfn)
+        self.subpages = []
+        self.users_subpages = []
+        subpage = pagename + '/'
+        for name in pages:
+            if name.startswith(subpage):
+                self.subpages.append(name)
+                if self.request.user.may.read(name):
+                    self.users_subpages.append(name)
+
+    def is_allowed(self):
+        may = self.request.user.may
+        return may.read(self.pagename)
+
+    def check_condition(self):
+        _ = self._
+        if not self.page.exists():
+            return _('This page is already deleted or was never created!')
+        else:
+            return None
+
+    def do_action(self):
+        """ copy this page to "pagename" """
+        _ = self._
+        form = self.form
+        newpagename = form.get('newpagename', [u''])[0]
+        newpagename = self.request.normalizePagename(newpagename)
+        comment = form.get('comment', [u''])[0]
+        comment = wikiutil.clean_comment(comment)
+
+        self.page = PageEditor(self.request, self.pagename)
+        success, msg = self.page.copyPage(newpagename, comment)
+
+        copy_subpages = 0
+        if form.has_key('copy_subpages'):
+            try:
+                copy_subpages = int(form['copy_subpages'][0])
+            except:
+                pass
+
+        if copy_subpages and self.subpages or (not self.users_subpages and self.subpages):
+            for name in self.subpages:
+                self.page = PageEditor(self.request, name)
+                new_subpagename = name.replace(self.pagename, newpagename, 1)
+                success_i, msg = self.page.copyPage(new_subpagename, comment)
+
+        self.newpagename = newpagename # keep there for finish
+        return success, msg
+
+    def do_action_finish(self, success):
+        if success:
+            url = Page(self.request, self.newpagename).url(self.request, relative=False)
+            self.request.http_redirect(url)
+            self.request.finish()
+        else:
+            self.render_msg(self.make_form())
+
+    def get_form_html(self, buttons_html):
+        _ = self._
+        if self.users_subpages:
+            subpages = ' '.join(self.users_subpages)
+
+            d = {
+                'subpage': subpages,
+                'subpages_checked':('', 'checked')[self.request.form.get('subpages_checked', ['0'])[0] == '1'],
+                'subpage_label': _('Copy all /subpages too?'),
+                'pagename': wikiutil.escape(self.pagename),
+                'newname_label': _("New name"),
+                'comment_label': _("Optional reason for the copying"),
+                'buttons_html': buttons_html,
+                'querytext': _('Really copy this page?')
+                }
+
+            return '''
+<strong>%(querytext)s</strong>
+<br>
+<br>
+<table>
+    <tr>
+    <dd>
+        %(subpage_label)s<input type="checkbox" name="copy_subpages" value="1" %(subpages_checked)s> 
+    </dd>
+    <dd>
+        <class="label"><subpage> %(subpage)s</subpage>
+    </dd>   
+    </tr>
+</table>       
+<table>
+    <tr>
+        <td class="label"><label>%(newname_label)s</label></td>
+        <td class="content">
+            <input type="text" name="newpagename" value="%(pagename)s">
+        </td>
+    </tr>
+    <tr>
+        <td class="label"><label>%(comment_label)s</label></td>
+        <td class="content">
+            <input type="text" name="comment" maxlength="200">
+        </td>
+    </tr>
+    <tr>
+        <td></td>
+        <td class="buttons">
+            %(buttons_html)s
+        </td>
+    </tr>
+</table>
+''' % d
+
+        else:
+            d = {
+                'pagename': wikiutil.escape(self.pagename),
+                'newname_label': _("New name"),
+                'comment_label': _("Optional reason for the copying"),
+                'buttons_html': buttons_html,
+                }
+            return '''
+<table>
+    <tr>
+        <td class="label"><label>%(newname_label)s</label></td>
+        <td class="content">
+            <input type="text" name="newpagename" value="%(pagename)s">
+        </td>
+    </tr>
+    <tr>
+        <td class="label"><label>%(comment_label)s</label></td>
+        <td class="content">
+            <input type="text" name="comment" maxlength="200">
+        </td>
+    </tr>
+    <tr>
+        <td></td>
+        <td class="buttons">
+            %(buttons_html)s
+        </td>
+    </tr>
+</table>
+''' % d
+
+def execute(pagename, request):
+    """ Glue code for actions """
+    CopyPage(pagename, request).render()
+
--- a/MoinMoin/action/sitemap.py	Thu Mar 08 14:31:48 2007 +0100
+++ b/MoinMoin/action/sitemap.py	Thu Mar 08 14:32:22 2007 +0100
@@ -70,7 +70,7 @@
     request.write("""<?xml version="1.0" encoding="UTF-8"?>\r\n""")
 
     result = []
-    result.append("""<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">\n""")
+    result.append("""<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n""")
 
     # we include the / url as an important and often changed URL
     result.append(make_url_xml({
@@ -82,7 +82,11 @@
     }))
 
     # Get page dict readable by current user
-    pages = request.rootpage.getPageDict()
+    try:
+        underlay = int(form.get('underlay', [1])[0])
+    except ValueError:
+        underlay = 1
+    pages = request.rootpage.getPageDict(include_underlay=underlay)
     pagelist = pages.keys()
     pagelist.sort()
     for name in pagelist:
--- a/MoinMoin/server/STANDALONE.py	Thu Mar 08 14:31:48 2007 +0100
+++ b/MoinMoin/server/STANDALONE.py	Thu Mar 08 14:32:22 2007 +0100
@@ -273,8 +273,9 @@
     staticExpire = 365 * 24 * 3600 # 1 year expiry for static files
 
     def __init__(self, request, client_address, server):
-        self.server_version = "MoinMoin %s %s" % (version.revision,
-                                                  server.__class__.__name__)
+        self.server_version = "MoinMoin %s %s %s" % (version.release,
+                                                     version.revision,
+                                                     server.__class__.__name__)
         self.expires = 0
         SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request,
             client_address, server)
--- a/MoinMoin/theme/__init__.py	Thu Mar 08 14:31:48 2007 +0100
+++ b/MoinMoin/theme/__init__.py	Thu Mar 08 14:32:22 2007 +0100
@@ -314,7 +314,7 @@
         request = self.request
         fmt = request.formatter
         title = None
-        
+
         # Handle [pagename title] or [url title] formats
         if text.startswith('[') and text.endswith(']'):
             text = text[1:-1].strip()
@@ -363,7 +363,7 @@
             page = wikiutil.getLocalizedPage(request, pagename)
         else:
             page = Page(request, pagename)
-            
+
         if not title:
             title = page.split_title()
             title = self.shortenPagename(title)
@@ -900,6 +900,7 @@
             'LocalSiteMap',
             '__separator__',
             'RenamePage',
+            'CopyPage',
             'DeletePage',
             '__separator__',
             'MyPages',
@@ -921,6 +922,7 @@
             'refresh': _('Delete Cache', formatted=False),
             'SpellCheck': _('Check Spelling', formatted=False), # rename action!
             'RenamePage': _('Rename Page', formatted=False),
+            'CopyPage': _('Copy Page', formatted=False),
             'DeletePage': _('Delete Page', formatted=False),
             'LikePages': _('Like Pages', formatted=False),
             'LocalSiteMap': _('Local Site Map', formatted=False),
--- a/docs/CHANGES	Thu Mar 08 14:31:48 2007 +0100
+++ b/docs/CHANGES	Thu Mar 08 14:32:22 2007 +0100
@@ -334,6 +334,8 @@
       patch.
     * autofilters for databrowser widget. Thanks to Johannes Berg for the patch.
     * action DeletePage and RenamePage could now be used for subpages of a page too
+    * Added Action CopyPage so you can use now an existing page or page hierarchy as template for a new page, see FeatureRequests/CloneOrCopyPages
+      TODO: we need a copy icon in RC
 
   Bugfixes:
     * on action "info" page, "revert" link will not be displayed for empty page