Commit 09e6eff9 authored by Romain Courteaud's avatar Romain Courteaud

Add ZipFolder product

Simplify import of JS components
parent 20fa8240
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
#
# taken from utilities/load_site.py
#
import string
from sgmllib import SGMLParser
def join_attrs(attrs):
attr_list = []
for attrname, value in attrs:
attr_list.append('%s="%s"' % (attrname, string.strip(value)))
if attr_list:
s = " " + string.join(attr_list, " ")
else:
s = ""
return s
class HeadParser(SGMLParser):
def __init__(self):
SGMLParser.__init__(self)
self.seen_starthead = 0
self.seen_endhead = 0
self.seen_startbody = 0
self.head = ""
self.title = ""
self.accumulator = ""
def handle_data(self, data):
if data:
self.accumulator = self.accumulator + data
def handle_comment(self, data):
if data:
self.handle_data("<!--%s-->" % data)
def handle_charref(self, ref):
self.handle_data("&#%s;" % ref)
def handle_entityref(self, ref):
self.handle_data("&%s;" % ref)
def start_head(self, attrs):
if not self.seen_starthead:
self.seen_starthead = 1
self.head = ""
self.title = ""
self.accumulator = ""
def end_head(self):
if not self.seen_endhead:
self.seen_endhead = 1
self.head = self.head + self.accumulator
self.accumulator = ""
def start_title(self, attrs):
self.head = self.head + self.accumulator
self.accumulator = ""
def end_title(self):
self.title = self.accumulator
self.accumulator = ""
def start_body(self, attrs):
if not self.seen_startbody:
self.seen_startbody = 1
self.accumulator = ""
def end_body(self): pass # Do not put </BODY> and </HTML>
def end_html(self): pass # into output stream
# Pass other tags unmodified
def unknown_starttag(self, tag, attrs):
self.accumulator = self.accumulator + "<%s%s>" % (string.upper(tag), join_attrs(attrs))
def unknown_endtag(self, tag):
self.accumulator = self.accumulator + "</%s>" % string.upper(tag)
MANIFEST
README.txt
refresh.txt
version.txt
HeadParser.py
ZipFolder.py
ZipFolder_icon.png
ZipImporter.py
__init__.py
zipfile152.py
zipfolderAdd.dtml
zipfolderUpload.dtml
help/ZipFolder_Add.stx
help/ZipFolder_Upload.stx
locales/de/zipfolderAdd.dtml
locales/de/zipfolderUpload.dtml
ZipFolder is a folder,
plus:
- manage_upload(Form) to upload a zip file
The zip file's content will be used to
create Document/File/Folder/Image objects inside the
folder
- manage_addZipFolder accepts an optional zip file,
to upload a zip file directly
minus:
- doesn't create index_html or acl_users in constructor
Some problems still exist:
- zipfile.py doesn't handle all zipfile formats yet
- zipfile.py of Python 2.0 is broken
- zipfile.py for Python < 2.0 does not exist
If you are using Python 1.52, or experiencing problems
unpacking zip files with Python 2.0, copy zipfile152.py
in this package to zipfile.py.
This is a modified version of the Python zipfile.py (release 1.11
or later):
- it requires zlib to run on python 1.52
- it contains a fix for a file header problem (fixed in Python 2.1)
- doesn't seem to work with zope-win32 (binary distribution)
from OFS import Folder,Image
from Globals import HTMLFile, MessageDialog
from AccessControl import getSecurityManager, Permissions
import os
import re
import string
import tempfile
import types
import StringIO
import zipfile
import ZipImporter
# check zip file names for:
filenamepattern=re.compile(r'[A-Za-z0-9][\w\_\-\.]*$')
MINZIPFILESIZE=22
manage_addZipFolderForm=HTMLFile('zipfolderAdd', globals())
def manage_addZipFolder(self, id, title='',
file=None,
subfolders=0,
REQUEST=None):
"""Add a new ZipFolder object with id *id*, uploading file.
"""
id=str(id)
id, title = Image.cookId(id, '', file)
ob=ZipFolder()
ob.id=id
self._setObject(id, ob)
ob=self._getOb(id)
checkPermission=getSecurityManager().checkPermission
if file is not None:
if not checkPermission('Add Documents, Images, and Files', ob):
raise 'Unauthorized', (
'You are not authorized to add DTML Documents.'
)
return ob.manage_upload(file,subfolders,REQUEST=REQUEST)
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
class ZipFolder(Folder.Folder, ZipImporter.ZipImporter):
"""Ein Ordner mit einer Erweiterung, um seinen Inhalt
und seine Attribute in Form einer ZIP-Datei hochladen
zu konnen."""
meta_type="ZipFolder"
__ac_permissions__=(
(Permissions.view_management_screens,
('manage_uploadForm',)),
('Change ZipFolders',
('manage_upload','manage_uploadForm')))
manage_options=(Folder.Folder.manage_options+
({ "label": "Upload",
"action": "manage_uploadForm"},)
)
manage_uploadForm=HTMLFile('zipfolderUpload', globals())
def manage_upload(self,file='',subfolders=0,replace=0,REQUEST=None, RESPONSE=None):
"""Accept a file and load it up"""
if isinstance(file,types.StringType):
if REQUEST: return MessageDialog(
title ='Success!',
message='But no ZIP file.',
action ='manage_main')
return # anyway
# check file sizes
file.seek(0,2)
fsize=file.tell()
file.seek(0,0)
if fsize == 0:
if RESPONSE:
RESPONSE.redirect('manage_main')
return # anyway
if replace:
if subfolders:
self._remove_objects(metatypes=('DTML Document','Image',
'File','Folder'))
else:
self._remove_objects(metatypes=('DTML Document','Image',
'File'))
self._v_skipped=[]
self._v_subfolders=subfolders
self.import_zipfile(file)
if REQUEST:
if len(self._v_skipped)>0:
return MessageDialog(
title ='Success!',
message=('ZIP file uploaded successfully, '+
'some files/folders ignored:<br>'+
string.join(self._v_skipped,'<br>')),
action ='manage_main')
else:
return MessageDialog(
title ='Success!',
message='ZIP file uploaded successfully',
action ='manage_main')
if len(self._v_skipped) > 0:
return self._v_skipped
return None
def _remove_objects(self,metatypes):
"""Removes old objects from the folder"""
removelist=self.objectIds(metatypes)
self.manage_delObjects(ids=removelist)
def add_file(self,path,basename,sf):
if not filenamepattern.match(basename):
return # skip ugly files
suffix=os.path.splitext(basename)[1]
folder=self
if self._v_subfolders:
folder=self._get_subfolder(path)
if folder:
if string.lower(suffix) in ['.htm', '.html']:
# this is ugly
sfx=StringIO.StringIO(self._edit_html(sf.getvalue()))
sf.close()
folder.manage_addDTMLDocument(id=basename, title='', file=sfx)
elif string.lower(suffix) in ['.gif', '.jpg', '.jpeg', '.png']:
folder.manage_addImage(id=basename, title='', file=sf)
elif len(suffix)==0 and basename[-5:] == "_html":
folder.manage_addDTMLDocument(id=basename, title='', file=sf)
else:
self._add_other_file(folder,path,basename,sf)
def _get_subfolder(self,path):
dirlist = []
rest = ""
while path != rest:
rest=path
(path,dir)=os.path.split(path)
if dir != "":
dirlist.append(dir)
dirlist.reverse()
folder=self
path=""
for dir in dirlist:
if self.check_filename(path,dir):
if dir in folder.objectIds():
if not folder[dir].isPrincipiaFolderish:
raise RuntimeError,("Object '%s' already exists "+
"and is no folder: Cannot "+
"create or use folder") % dir
else:
folder.manage_addFolder(id=dir)
folder=folder[dir]
else:
return None # no folder, no files in there...
if path:
path=path + "/" + dir
else:
path=dir
return folder
def _edit_html(self, data):
# a hook for filters to edit the imported html files
return data
def _add_other_file(self,folder,path,basename,sf):
# Hook for other known file types, default: add file objects
folder.manage_addFile(id=basename, title='', file=sf)
def check_filename(self,pathname,basename):
# return 0 to skip file, raise an exception to annoy...
match=filenamepattern.match(basename) != None;
if not match and basename != '':
self._v_skipped.append(os.path.join(pathname,basename))
return match
import os
import string
import tempfile
import types
import StringIO
import zipfile
MINZIPFILESIZE=22
class ZipImporter:
"""A mix-in class to add zipfile-import-support to folders"""
def import_zipfile(self,file):
# minimum/maximum size check
file.seek(0,2)
fsize=file.tell()
file.seek(0,0)
if fsize > self.max_zipfile_size():
raise RuntimeError,'ZIP file is too big'
if fsize < MINZIPFILESIZE:
raise RuntimeError,'ZIP file is too small'
zf=zipfile.ZipFile(file,'r')
try:
self.check_zip(zf)
for name in zf.namelist():
self._add_file_from_zip(zf,name)
finally:
zf.close()
def _add_file_from_zip(self,zipfile,name):
basename=os.path.basename(name)
pathname=os.path.dirname(name)
if not self.check_filename(pathname,basename):
return # skip ugly files
sf=StringIO.StringIO(zipfile.read(name))
self.add_file(pathname,basename,sf)
sf.close()
#
#
# To be overwritten:
def max_zipfile_size(self):
"""return maximum size for zip files. Default 4MB"""
return 4*1024*1024;
def check_zip(self,zipfile):
# a hook to check zipfile before import loop
# maybe: Look for a special file in the zip...
pass
def check_filename(self,pathname,basename):
# return 0 to skip file, raise an exception to annoy...
return 1;
def add_file(self,pathname,basename,file):
#add file to whatever...
#is called with path,basename and file handle
# overwrite this!
pass
from ZipFolder import *
from OFS import Folder
__doc__="""ZipFolder initialization module"""
__version__= '0.2'
def initialize(context):
"""Initialize the PaketFolder product"""
context.registerClass(
ZipFolder,
constructors = (manage_addZipFolderForm,
manage_addZipFolder
),
icon='ZipFolder_icon.png'
)
context.registerHelp()
ZipFolder - Add: Add a ZipFolder.
Description
This view allows you to create a new ZipFolder.
ZipFolder can be updated at once using zip archive files.
Controls
'Id' -- The id of the Folder.
'Upload' -- Select an optional zip file for upload.
'Create subfolders' -- Create folders to hold objects, if the zip file contains folders
'Add' -- Creates a new Folder.
ZipFolder - Upload: Upload a new zip file.
Description
This view allows you to upload another zip file.
The contents of the zipfile will optionally replace all existing
Documents, images, files and folders in the folder.
Controls
'Upload' -- Select an optional zip file for upload.
'Update' -- Add uploaded zip's contents to folder. To replace, check the "Replace folder contents" option.
'Create subfolders' -- Create folders to hold objects, if the zip file contains folders
'Replace folder contents' -- Remove all old objects before adding any new objects from the uploaded zip file
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='ZipFolder hinzufgen',
help_product='ZipFolder',
help_topic='ZipFolder_Add.stx'
)">
<P class="form-help">
Ein Zip-Ordner enthlt, wie ein normaler Ordner, Objekte.
Ein Zip-Ordner kann jedoch mit Objekten bestckt werden, indem
eine einzige Zip-Datei mit allen Inhalten auf den Server bertragen wird.
</P>
<P>
Mit dem angezeigten Formular knnen Sie einen Zip-Ordner anlegen.
Mit der Upload-Mglichkeit knnen Sie direkt Inhalte in den Ordner
bringen.
</P>
<FORM ACTION="manage_addZipFolder" METHOD="POST" enctype="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<STRONG>Id</STRONG>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="40">
</TD>
</TR>
<dtml-if "_.SecurityCheckPermission('Add Documents, Images, and Files',this())">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
Die Datei
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="FILE" NAME="file" SIZE="20">
</TD>
</TR>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="subfolders:int" value="1" checked="1"
id="cbsubFolders">
<label for="cbsubFolders">ggf. Unter-Ordner anlegen</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
</dtml-if>
<TR>
<TD></TD>
<TD>
<BR><INPUT TYPE="SUBMIT" VALUE=" ZIP-Ordner einfgen ">
</TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-if manage_tabs><dtml-var "manage_tabs">
<dtml-else>
<dtml-var "manage_form_title(this(), _,
form_title='Neue ZIP-Datei hochladen',
help_product='ZipFolder',
help_topic='ZipFolder_Upload.stx'
)">
</dtml-if>
<P class="form-help">
Mit diesem Formular knnen Sie eine neue ZIP-Datei hochladen. Beachten Sie
bitte, das vor dem Hochladen alle bestehenden Dokumente, Bilder und Dateien aus
dem Ordner gelscht werden.
</P>
<FORM ACTION="manage_upload" METHOD="POST" enctype="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
Die ZIP-Datei
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="FILE" NAME="file" SIZE="20">
</TD>
</TR>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="subfolders:int" value="1" checked="1"
id="cbsubFolders">
<label for="cbsubFolders">ggf. Unter-Ordner anlegen</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="replace:int" value="1"
id="cbreplace">
<label for="cbreplace">Alle alten Inhalte des Ordners lschen</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
<TR>
<TD></TD>
<TD>
<BR><INPUT TYPE="SUBMIT" VALUE=" ZIP-Datei bertragen ">
</TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
ZipFolder is a refreshable product.
This diff is collapsed.
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add ZipFolder',
help_product='ZipFolder',
help_topic='ZipFolder_Add.stx'
)">
<P class="form-help">
A Folder contains other objects. Use Folders to organize your
web objects in to logical groups. ZIPFolders enable you to
upload their content in one single zip file package.
</P>
<P class="form-help">
The form below allows you to create
a ZIPFolder. The Upload option enables you to upload a zip file
containing the folder's content.</P>
<FORM ACTION="manage_addZipFolder" METHOD="POST" enctype="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<STRONG>Id</STRONG>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="40">
</TD>
</TR>
<dtml-if "_.SecurityCheckPermission('Add Documents, Images, and Files',this())">
<TR>
<TD ALIGN="LEFT" VALIGN="CENTER">
Upload
<TD ALIGN="LEFT" VALIGN="CENTER">
<INPUT TYPE="FILE" NAME="file" SIZE="20">
</TD>
</TR>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="subfolders:int" value="1" checked="1"
id="cbsubFolders">
<label for="cbsubFolders">Create subfolders if necessary</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
<dtml-else>
<TR><i>You are not allowed to add documents, images or files. You may, however,
create an empty ZIPFolder.</i></TR>
</dtml-if>
<TR>
<TD></TD>
<TD>
<BR><INPUT TYPE="SUBMIT" VALUE=" Add ">
</TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-if manage_tabs><dtml-var "manage_tabs">
<dtml-else>
<dtml-var "manage_form_title(this(), _,
form_title='Manage workflow',
help_product='ZipFolder',
help_topic='ZipFolder_Upload.stx'
)">
</dtml-if>
<P class="form-help">
The form below allows you to upload a ZIP file containg the folder's
contents. All documents already in the folder will be removed before adding the
contents of the zip file.
</P>
<FORM ACTION="manage_upload" METHOD="POST" enctype="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="CENTER">
<B>Upload</B>
<TD ALIGN="LEFT" VALIGN="CENTER">
<INPUT TYPE="FILE" NAME="file" SIZE="20">
</TD>
</TR>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="subfolders:int" value="1" checked="1"
id="cbsubFolders">
<label for="cbsubFolders">Create subfolders</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-text">
<input type="checkbox" name="replace:int" value="1"
id="cbreplace">
<label for="cbreplace">Replace folder contents (delete everything old)</label>
</div>
</td>
</tr>
<TR><TD COLSPAN="2"><BR></TD></TR>
<TR>
<TD></TD>
<TD>
<BR><INPUT TYPE="SUBMIT" VALUE=" Update ">
</TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment