Back to index

moin  1.9.0~rc2
PackagePages.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - PackagePages action
00004 
00005     This action allows you to package pages.
00006 
00007     TODO: use ActionBase class
00008 
00009     @copyright: 2005 MoinMoin:AlexanderSchremmer
00010                 2007-2009 MoinMoin:ReimarBauer
00011     @license: GNU GPL, see COPYING for details.
00012 """
00013 import cStringIO
00014 import os
00015 import zipfile
00016 from datetime import datetime
00017 
00018 from MoinMoin import wikiutil, config, user
00019 from MoinMoin.Page import Page
00020 from MoinMoin.action.AttachFile import _addLogEntry
00021 from MoinMoin.packages import MOIN_PACKAGE_FILE, packLine, unpackLine
00022 from MoinMoin.action import AttachFile
00023 from MoinMoin.action.AttachFile import _get_files
00024 from MoinMoin.search import searchPages
00025 
00026 class ActionError(Exception):
00027     pass
00028 
00029 class PackagePages:
00030     def __init__(self, pagename, request):
00031         self.request = request
00032         self.pagename = pagename
00033         self.page = Page(request, pagename)
00034 
00035     def allowed(self):
00036         """ Check if user is allowed to do this. """
00037         return not self.__class__.__name__ in self.request.cfg.actions_excluded
00038 
00039     def render(self):
00040         """ Render action
00041 
00042         This action returns a wiki page with optional message, or
00043         redirects to new page.
00044         """
00045         _ = self.request.getText
00046 
00047         if 'cancel' in self.request.values:
00048             # User canceled
00049             return self.page.send_page()
00050 
00051         try:
00052             if not self.allowed():
00053                 self.request.theme.add_msg(_('You are not allowed to edit this page.'), "error")
00054                 raise ActionError
00055             elif not self.page.exists():
00056                 self.request.theme.add_msg(_('This page is already deleted or was never created!'))
00057                 raise ActionError
00058 
00059             self.package()
00060         except ActionError, e:
00061             return self.page.send_page()
00062 
00063     def package(self):
00064         """ Calls collectpackage() with the arguments specified. """
00065         _ = self.request.getText
00066 
00067         # Get new name from form and normalize.
00068         pagelist = self.request.values.get('pagelist', u'')
00069         packagename = self.request.values.get('packagename', u'')
00070         include_attachments = self.request.values.get('include_attachments', False)
00071 
00072         if not self.request.values.get('submit'):
00073             self.request.theme.add_msg(self.makeform(), "dialog")
00074             raise ActionError
00075 
00076         target = wikiutil.taintfilename(packagename)
00077 
00078         if not target:
00079             self.request.theme.add_msg(self.makeform(_('Invalid filename "%s"!') % wikiutil.escape(packagename)), "error")
00080             raise ActionError
00081 
00082         request = self.request
00083         filelike = cStringIO.StringIO()
00084         package = self.collectpackage(unpackLine(pagelist, ","), filelike, target, include_attachments)
00085         request.content_type = 'application/zip'
00086         request.content_length = filelike.tell()
00087         request.headers.add('Content-Disposition', 'inline; filename="%s"' % target)
00088         request.write(filelike.getvalue())
00089         filelike.close()
00090 
00091     def makeform(self, error=""):
00092         """ Display a package page form
00093 
00094         The form might contain an error that happened when package file was not given.
00095         """
00096         from MoinMoin.widget.dialog import Dialog
00097         _ = self.request.getText
00098 
00099         if error:
00100             error = u'<p class="error">%s</p>\n' % error
00101 
00102         d = {
00103             'url': self.request.href(self.pagename),
00104             'error': error,
00105             'action': self.__class__.__name__,
00106             'pagename': wikiutil.escape(self.pagename, True),
00107             'include_attachments_label': _('Include all attachments?'),
00108             'package': _('Package pages'),
00109             'cancel': _('Cancel'),
00110             'newname_label': _("Package name"),
00111             'list_label': _("List of page names - separated by a comma"),
00112         }
00113         form = '''
00114 %(error)s
00115 <form method="post" action="%(url)s">
00116 <input type="hidden" name="action" value="%(action)s">
00117 <table>
00118     <tr>
00119         <td class="label"><label>%(newname_label)s</label></td>
00120         <td class="content">
00121             <input type="text" name="packagename" value="package.zip" size="80">
00122         </td>
00123     </tr>
00124     <tr>
00125         <td class="label"><label>%(list_label)s</label></td>
00126         <td class="content">
00127             <input type="text" name="pagelist" size="80" maxlength="200" value="%(pagename)s">
00128         </td>
00129     </tr>
00130     <tr>
00131         <td class="label">
00132         %(include_attachments_label)s<input type="checkbox" name="include_attachments" value="0" %(include_attachments_label)s>
00133     </td>
00134     </tr>
00135     <tr>
00136         <td></td>
00137         <td class="buttons">
00138             <input type="submit" name="submit" value="%(package)s">
00139             <input type="submit" name="cancel" value="%(cancel)s">
00140         </td>
00141     </tr>
00142 </table>
00143 </form>''' % d
00144 
00145         return Dialog(self.request, content=form)
00146 
00147     def searchpackage(self, request, searchkey):
00148         """ Search MoinMoin for the string specified and return a list of
00149         matching pages, provided they are not system pages and not
00150         present in the underlay.
00151 
00152         @param request: current request
00153         @param searchkey: string to search for
00154         @rtype: list
00155         @return: list of pages matching searchkey
00156         """
00157 
00158         pagelist = searchPages(request, searchkey)
00159 
00160         titles = []
00161         for title in pagelist.hits:
00162             if not wikiutil.isSystemPage(request, title.page_name) or not title.page.getPageStatus()[0]:
00163                 titles.append(title.page_name)
00164         return titles
00165 
00166     def collectpackage(self, pagelist, fileobject, pkgname="", include_attachments=False):
00167         """ Expects a list of pages as an argument, and fileobject to be an open
00168         file object, which a zipfile will get written to.
00169 
00170         @param pagelist: pages to package
00171         @param fileobject: open file object to write to
00172         @param pkgname: optional file name, to prevent self packaging
00173         @rtype: string or None
00174         @return: error message, if one happened
00175         @rtype: boolean
00176         @param include_attachments: True if you want attachments collected
00177         """
00178         _ = self.request.getText
00179         COMPRESSION_LEVEL = zipfile.ZIP_DEFLATED
00180 
00181         pages = []
00182         for pagename in pagelist:
00183             pagename = wikiutil.normalize_pagename(pagename, self.request.cfg)
00184             if pagename:
00185                 page = Page(self.request, pagename)
00186                 if page.exists() and self.request.user.may.read(pagename):
00187                     pages.append(page)
00188         if not pages:
00189             return (_('No pages like "%s"!') % wikiutil.escape(pagelist))
00190 
00191         # Set zipfile output
00192         zf = zipfile.ZipFile(fileobject, "w", COMPRESSION_LEVEL)
00193 
00194         cnt = 0
00195         userid = user.getUserIdentification(self.request)
00196         script = [packLine(['MoinMoinPackage', '1']), ]
00197 
00198         for page in pages:
00199             cnt += 1
00200             files = _get_files(self.request, page.page_name)
00201             script.append(packLine(["AddRevision", str(cnt), page.page_name, userid, "Created by the PackagePages action."]))
00202 
00203             timestamp = wikiutil.version2timestamp(page.mtime_usecs())
00204             zi = zipfile.ZipInfo(filename=str(cnt), date_time=datetime.fromtimestamp(timestamp).timetuple()[:6])
00205             zi.compress_type = COMPRESSION_LEVEL
00206             zf.writestr(zi, page.get_raw_body().encode("utf-8"))
00207             if include_attachments:
00208                 for attname in files:
00209                     if attname != pkgname:
00210                         cnt += 1
00211                         zipname = "%d_attachment" % cnt
00212                         script.append(packLine(["AddAttachment", zipname, attname, page.page_name, userid, "Created by the PackagePages action."]))
00213                         filename = AttachFile.getFilename(self.request, page.page_name, attname)
00214                         zf.write(filename, zipname)
00215         script += [packLine(['Print', 'Thank you for using PackagePages!'])]
00216 
00217         zf.writestr(MOIN_PACKAGE_FILE, u"\n".join(script).encode("utf-8"))
00218         zf.close()
00219 
00220 def execute(pagename, request):
00221     """ Glue code for actions """
00222     PackagePages(pagename, request).render()
00223