view MoinMoin/action/PackagePages.py @ 3040:8608b258f8e6

bug fix of MoinMoinBugs/MoveAttachmentNotWorkingWithModPython (thanks to Boleslaw Kulbabinski) (ported from 1.6)
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Tue, 05 Feb 2008 21:22:56 +0100
parents ba14d391c2ba
children 94941d9d30ee
line wrap: on
line source
# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - PackagePages action

    This action allows you to package pages.

    TODO: use ActionBase class

    @copyright: 2005 MoinMoin:AlexanderSchremmer
    @license: GNU GPL, see COPYING for details.
"""

import os
import zipfile
from datetime import datetime

from MoinMoin import wikiutil, config, user
from MoinMoin.Page import Page
from MoinMoin.action.AttachFile import _addLogEntry
from MoinMoin.packages import MOIN_PACKAGE_FILE, packLine, unpackLine
from MoinMoin.action import AttachFile
from MoinMoin.action.AttachFile import _get_files

class ActionError(Exception):
    pass

class PackagePages:
    def __init__(self, pagename, request):
        self.request = request
        self.pagename = pagename
        self.page = Page(request, pagename)

    def allowed(self):
        """ Check if user is allowed to do this. """
        may = self.request.user.may
        return (not self.__class__.__name__ in self.request.cfg.actions_excluded and
                may.write(self.pagename))

    def render(self):
        """ Render action

        This action returns a wiki page with optional message, or
        redirects to new page.
        """
        _ = self.request.getText
        form = self.request.form

        if 'cancel' in form:
            # User canceled
            return self.page.send_page()

        try:
            if not self.allowed():
                self.request.theme.add_msg(_('You are not allowed to edit this page.'), "error")
                raise ActionError
            elif not self.page.exists():
                self.request.theme.add_msg(_('This page is already deleted or was never created!', formatted=False))
                raise ActionError

            self.package()
        except ActionError, e:
            return self.page.send_page()

    def package(self):
        """ Packages pages. """
        _ = self.request.getText
        form = self.request.form
        COMPRESSION_LEVEL = zipfile.ZIP_DEFLATED

        # Get new name from form and normalize.
        pagelist = form.get('pagelist', [u''])[0]
        packagename = form.get('packagename', [u''])[0]

        if not form.get('submit', [None])[0]:
            self.request.theme.add_msg(self.makeform(), "dialog")
            raise ActionError

        pages = []
        for pagename in unpackLine(pagelist, ","):
            pagename = self.request.normalizePagename(pagename)
            if pagename:
                page = Page(self.request, pagename)
                if page.exists() and self.request.user.may.read(pagename):
                    pages.append(page)
        if not pages:
            self.request.theme.add_msg(self.makeform(_('No pages like "%s"!') % wikiutil.escape(pagelist)), "error")
            raise ActionError

        pagelist = ', '.join([getattr(page, "page_name") for page in pages])
        target = wikiutil.taintfilename(packagename)

        if not target:
            self.request.theme.add_msg(self.makeform(_('Invalid filename "%s"!') % wikiutil.escape(packagename)), "error")
            raise ActionError

        # get directory, and possibly create it
        attach_dir = Page(self.request, self.page.page_name).getPagePath("attachments", check_create=1)
        fpath = os.path.join(attach_dir, target).encode(config.charset)
        if os.path.exists(fpath):
            self.request.theme.add_msg(_("Attachment '%(target)s' (remote name '%(filename)s') already exists.") % {
                'target': wikiutil.escape(target), 'filename': wikiutil.escape(target)}, "error")
            raise ActionError

        zf = zipfile.ZipFile(fpath, "w", COMPRESSION_LEVEL)

        cnt = 0
        script = [packLine(['MoinMoinPackage', '1']),
                  ]

        for page in pages:
            cnt += 1
            files = _get_files(self.request, page.page_name)
            script.append(packLine(["AddRevision", str(cnt), page.page_name, user.getUserIdentification(self.request), "Created by the PackagePages action."]))

            timestamp = wikiutil.version2timestamp(page.mtime_usecs())
            zi = zipfile.ZipInfo(filename=str(cnt), date_time=datetime.fromtimestamp(timestamp).timetuple()[:6])
            zi.compress_type = COMPRESSION_LEVEL
            zf.writestr(zi, page.get_raw_body().encode("utf-8"))
            for attname in files:
                if attname != packagename:
                    cnt += 1
                    zipname = "%d_attachment" % cnt
                    script.append(packLine(["AddAttachment", zipname, attname, page.page_name, user.getUserIdentification(self.request), "Created by the PackagePages action."]))
                    filename = AttachFile.getFilename(self.request, page.page_name, attname)
                    zf.write(filename.encode("cp437"), zipname)
        script += [packLine(['Print', 'Thank you for using PackagePages!'])]

        zf.writestr(MOIN_PACKAGE_FILE, u"\n".join(script).encode("utf-8"))
        zf.close()

        _addLogEntry(self.request, 'ATTNEW', self.pagename, target)

        self.request.theme.add_msg(_("Created the package %s containing the pages %s.") % (wikiutil.escape(target), wikiutil.escape(pagelist)))
        raise ActionError

    def makeform(self, error=""):
        """ Display a rename page form

        The form might contain an error that happened when trying to rename.
        """
        from MoinMoin.widget.dialog import Dialog
        _ = self.request.getText

        error = u'<p class="error">%s</p>\n' % error

        d = {
            'baseurl': self.request.getScriptname(),
            'error': error,
            'action': self.__class__.__name__,
            'pagename': wikiutil.escape(self.pagename),
            'pagename_quoted': wikiutil.quoteWikinameURL(self.pagename),
            'package': _('Package pages'),
            'cancel': _('Cancel'),
            'newname_label': _("Package name"),
            'list_label': _("List of page names - separated by a comma"),
        }
        form = '''
%(error)s
<form method="post" action="%(baseurl)s/%(pagename_quoted)s">
<input type="hidden" name="action" value="%(action)s">
<table>
    <tr>
        <td class="label"><label>%(newname_label)s</label></td>
        <td class="content">
            <input type="text" name="packagename" value="package.zip" size="80">
        </td>
    </tr>
    <tr>
        <td class="label"><label>%(list_label)s</label></td>
        <td class="content">
            <input type="text" name="pagelist" size="80" maxlength="200" value=%(pagename)s>
        </td>
    </tr>
    <tr>
        <td></td>
        <td class="buttons">
            <input type="submit" name="submit" value="%(package)s">
            <input type="submit" name="cancel" value="%(cancel)s">
        </td>
    </tr>
</table>
</form>''' % d

        return Dialog(self.request, content=form)

def execute(pagename, request):
    """ Glue code for actions """
    PackagePages(pagename, request).render()