Commit 4adafd42 authored by Julien Muchembled's avatar Julien Muchembled

PortalTransforms: merge upstream revision 10366 (17/01/09)

Conflicts:
	Products/PortalTransforms/Extensions/Install.py
	Products/PortalTransforms/HISTORY.txt
	Products/PortalTransforms/Transform.py
	Products/PortalTransforms/TransformEngine.py
	Products/PortalTransforms/chain.py
	Products/PortalTransforms/configure.zcml
	Products/PortalTransforms/data.py
	Products/PortalTransforms/interfaces.py
	Products/PortalTransforms/libtransforms/commandtransform.py
	Products/PortalTransforms/libtransforms/piltransform.py
	Products/PortalTransforms/libtransforms/retransform.py
	Products/PortalTransforms/tests/test_engine.py
	Products/PortalTransforms/tests/test_transforms.py
	Products/PortalTransforms/transforms/broken.py
	Products/PortalTransforms/transforms/html_body.py
	Products/PortalTransforms/transforms/identity.py
	Products/PortalTransforms/transforms/image_to_html.py
	Products/PortalTransforms/transforms/lynx_dump.py
	Products/PortalTransforms/transforms/markdown_to_html.py
	Products/PortalTransforms/transforms/pdf_to_html.py
	Products/PortalTransforms/transforms/pdf_to_text.py
	Products/PortalTransforms/transforms/python.py
	Products/PortalTransforms/transforms/rest.py
	Products/PortalTransforms/transforms/rtf_to_html.py
	Products/PortalTransforms/transforms/rtf_to_xml.py
	Products/PortalTransforms/transforms/safe_html.py
	Products/PortalTransforms/transforms/st.py
	Products/PortalTransforms/transforms/text_pre_to_html.py
	Products/PortalTransforms/transforms/text_to_html.py
	Products/PortalTransforms/transforms/textile_to_html.py
	Products/PortalTransforms/transforms/word_to_html.py
	Products/PortalTransforms/unsafe_transforms/command.py
	Products/PortalTransforms/unsafe_transforms/xml.py
	Products/PortalTransforms/utils.py
	Products/PortalTransforms/version.txt

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@41725 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 50392b74
DONT USE ChangeLog USE HISTORY.txt instead.
2004-07-24 Christian Heimes <heimes@faho.rwth-aachen.de>
* Changed version to stick to Archetypes version.
2004-05-25 Christian Heimes <heimes@faho.rwth-aachen.de>
* Seperate MimetypesRegistry to a new product
2004-04-20 Christian Heimes <heimes@faho.rwth-aachen.de>
* transforms/rest.py: rest transform is now using the zope implementation if
available
2004-04-07 Christian Heimes <heimes@faho.rwth-aachen.de>
* transforms/text_pre_to_html.py: new transform for preformatted plain text
* transforms/text_to_html.py: changed <br/> to <br />
2004-03-17 Christian Heimes <heimes@faho.rwth-aachen.de>
* transforms/pdf_to_text.py: return text utf-8 encoded
2004-02-04 Sylvain Thénault <syt@logilab.fr>
* transforms/office_com.py: fix wrong import
2003-12-03 Sidnei da Silva <sidnei@awkly.org>
* mime_types/magic.py (guessMime): Don't try to be so magic :)
2003-11-18 Andreas Jung <andreas@andreas-jung.com)
* commandtransform.py: fixed sick cleanDir() implementation
2003-11-17 Andreas Jung <andreas@andreas-jung.com)
* added rtf_to_html.py converter
* added rtf to as mimetypes to mime_types/__init__.py
* added rtf_to_xml.py converter
* added pdf_to_text.py converter
* removed dependency from CMFDefault.utils for misc converters
(integrated code into libtransforms/utils.py)
2003-11-14 Sidnei da Silva <sidnei@plone.org>
* MimeTypesRegistry.py (MimeTypesRegistry.classify): If no results
this far, use magic.py module, written by Jason Petrone, and
updated by Gabriel Wicke with the data from gnome-vfs-mime-magic.
2003-11-07 Sylvain Thénault <syt@logilab.fr>
* use the same license as Archetypes (BSD like instead of GPL)
* www/tr_widgets.zpt: fix bug in the list widget (space before the
parameter's name, making it unrecognized)
* zope/Transform.py: fix set parameters to correctly remap
transform if editable inputs or output. (fix #837244)
* TransformEngine.py: better error messages, a few lines wrapping
* zope/__init__.py: use pt_globals instead of globals for variable
handling the product globals, making it reloadable
* Extensions/Install.py: use pt_globals
* www/listMimeTypes.zpt: use mt/normalized as id instead of mt/name
2003-11-05 Sylvain Thénault <syt@logilab.fr>
* unsafe_tranforms/command.py: added dummy output mime type to avoid
error when added via the ZMI (fix #837252)
2003-10-30 Sylvain Thénault <syt@logilab.fr>
* fixed addMimeType, editMimeType and tr_widget templates (fix #832958)
2003-10-03 Sidnei da Silva <sidnei@dreamcatcher.homeunix.org>
* utils.py (TransformException.getToolByName): Modified
getToolByName to have a fallback mimetypes_registry, so we can
simplify BaseUnit.
2003-09-23 Sylvain Thénault <syt@logilab.fr>
* MimesTypesRegistry.py: make unicode error handling configurable
* zope/MimesTypesTool.py: add a property for unicode error handling
* zope/Transform.py: make tests working
2003-08-19 Sylvain Thénault <syt@logilab.fr>
* transforms/rest.py: override "traceback" setting to avoid
sys.exit !
* transforms/text_to_html.py: use html_quote
2003-08-12 Sylvain Thénault <syt@logilab.fr>
* TransformEngine.py: set "encoding" in datastream metadata if
tranform provides a "output_encoding" attribute. Fix access to
"id" instead of "name()"
* zope/Transform.py: add some code to handle output encoding...
2003-08-08 Sylvain Thénault <syt@logilab.fr>
* MimeTypesRegistry.py: use suffix map has the standard mime types
module, hopefully correct behaviour of classify
* unsafe_transforms/build_transforms.py: fix inputs and output
mime type of ps_to_text transform
2003-08-07 Sylvain Thenault <sylvain.thenault@logilab.fr>
* encoding.py: new module which aims to detect encoding of text
files
* MimeTypesRegistry.py: use the encoding module in iadapter
2003-08-06 Sylvain Thenault <sylvain.thenault@logilab.fr>
* MimeTypesRegistry.py (classify): return
'application/octet-stream' instead of None
* transforms/text_to_html.py: replace '\n' with <br/> instead of
<pre> wrapping
* unsafe_transforms/build_transforms.py: create a ps_to_text
transform if ps2ascii is available
* tests/test_transforms.py: handle name of transforms to test on
command line
* transforms/__init__.py: do not print traceback on missing binary
exception
2003-08-01 Sylvain Thenault <sylvain.thenault@logilab.fr>
* transforms/text_to_html.py: new transform to wrap plain text in
<pre> for html
* transforms/test_transforms.py: add test for text_to_html
2003-07-28 Sylvain Thenault <sylvain.thenault@logilab.fr>
* zope/TransformsChain.py: fixes to make it works within Zope.
* www/editTransformsChain.zpt: add inputs / output information.
2003-07-28 Sylvain Thenault <sylvain.thenault@logilab.fr>
* transforms/rest.py: remove class="document"
* tests/test_transforms.py: added missing output for the identity
transform's test, fix initialize method.
2003-07-21 Sylvain Thenault <sylvain.thenault@logilab.fr>
* transforms/identity.py: added identity transform (used for instance
to convert text/x-rest to text/plain).
* tests/test_transforms.py: added test for the identity transform.
2003-07-11 Sylvain Thenault <sylvain.thenault@logilab.fr>
* unsafe_transforms/xml.py: just make it working.
* unsafe_transforms/command.py: add missing "name" argument to the
constructor. Use popen3 instead of popen4.
* unsafe_transforms/build_transforms.py: create an xml_to_html
transform if an xslt processor is available (however this transform
is not configured for any doctypes / dtds). Create tidy_html
transform if the tidy command is available.
* tests/test_transforms.py: add test cases for the xml and
html_tidy transform.
* transform.py: added transform_customize hook.
* docs/user_manual.rst: explain difference between python distro
and zope product. Added notice about archetypes integration.
* docs/dev_manual.rst: minor fixes.
003-07-10 Sylvain Thenault <sylvain.thenault@logilab.fr>
* refactoring to permit use of this package outside zope :)
Zope mode is triggered when "import Zope" doesn't fail
* fix bug in word_to_html / office_wvware transform
* add a generic test for transforms. It's much more easier now to
add a test for a transform :)
* add licensing information
* interfaces.py: complete / cleanup interfaces
* bin/tranform: add command line tool
* unsafe_transforms/command.py: bug fix
* addTransformsChain.zpt: fix typo
* fix #768927
2003-07-09 Sylvain Thenault <sylvain.thenault@logilab.fr>
* code cleaning:
- moved Transform and TransformsChain in their own files
- removed no more used bindingmixin and sourceAdapter
- merged transform and chain classes together
- generic cache and misc utilities in the new utils.py.
* ready for 1.0 alpha1 :)
2003-07-05 Sylvain Thenault <sylvain.thenault@logilab.fr>
* make the PortalTransforms product from the original transform
package and the mimetypes / transforms tools originaly defined in
Archetypes.
* drop the ability to use it as a standalone python package, since
there was too much duplicated code to make it works.
* some works on tests to make them succeed :)
* MimeTypesTool.py (MimeTypesTool.lookup): return an empty list
instead of None when no matching mime types is found.
2003-05-14 Sidnei da Silva <sidnei@x3ng.com>
* interface.py: Trying to normalize the way interfaces are
imported in different versions of Zope.
2003-04-21 Sidnei da Silva <sidnei@x3ng.com>
* __init__.py: Fixed lots of things here and there to make it work
with the new BaseUnit in Archetypes.
2003-04-20 Sidnei da Silva <sidnei@x3ng.com>
* tests/output/rest3.out: Fixed subtitle and added a test.
2003-04-19 Sidnei da Silva <sidnei@x3ng.com>
* tests/test_rest.py (BaseReSTFileTest.testSame): Added tests
based on input/output dirs to make it easy to add new tests for reST.
* transforms/rest.py (rest.convert): Rendering of
reST was broken. It was not rendering references the right way,
and it didnt seem like it was doing the right thing with
titles. Updated to use docutils.core.publish_string.
* tests/test_all.py (test_suite): Added lynx_dump to transform
html -> text. With tests.
2003-04-18 Sidnei da Silva <sidnei@x3ng.com>
* tests/test_all.py (test_suite): Removed dependencies from
CMFCore on testsuite.
* __init__.py: Made it work without being inside Products. We
eventually need to make a distutils setup, and then this can be
removed. If someone knows a better way to do this, please do.
lynx
pdftohtml
python-docutils
This diff is collapsed.
Copyright (c) 2002-2003, Benjamin Saller <bcsaller@ideasuite.com>, and
the respective authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Archetypes nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS 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 THE COPYRIGHT
OWNER OR 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.
include ChangeLog
include README
include TODO
include version.txt
include bin/transform
include bin/transform.bat
recursive-include docs *.txt
recursive-include docs *.rst
recursive-include docs *.html
recursive-include tests/input *
recursive-include tests/output *
NAME=PortalTransforms
MAJOR_VERSION=1.0
MINOR_VERSION=4
RELEASE_TAG=
PACKAGE_NAME=${NAME}-${MAJOR_VERSION}.${MINOR_VERSION}${RELEASE_TAG}
PYTHON="/usr/bin/python"
TMPDIR=~/tmp
CURDIR=~/src/archetypes/head/PortalTransforms
BASE_DIR=${CURDIR}/..
SOFTWARE_HOME=~/src/zope/2_7/lib/python
INSTANCE_HOME=~/src/instance/shellex
PACKAGES=PortalTransforms
RM=rm -f
RMRF=rm -rf
FIND=find
XARGS=xargs
CD=cd
LN=ln -sfn
CP=cp
TAR=tar
MKDIR=mkdir -p
.PHONY : clean test reindent reindent_clean sdist
.PHONY : default
# default: The default step (invoked when make is called without a target)
default: clean test
clean :
find . \( -name '*~' -o -name '*.py[co]' -o -name '*.bak' \) -exec rm {} \; -print
reindent :
~/src/reindent.py -r -v .
test :
export INSTANCE_HOME=${INSTANCE_HOME}; export SOFTWARE_HOME=${SOFTWARE_HOME}; \
cd ${CURDIR}/tests && ${PYTHON} runalltests.py
# sdist: Create a source distribution file (implies clean).
#
sdist: reindent clean sdist_tgz
# sdist_tgz: Create a tgz archive file as a source distribution.
#
sdist_tgz:
echo -n "${MAJOR_VERSION}.${MINOR_VERSION}${RELEASE_TAG}" >\
${CURDIR}/version.txt
${MKDIR} ${TMPDIR}/${PACKAGE_NAME}
${CD} ${TMPDIR}/${PACKAGE_NAME} && \
for package in ${PACKAGES}; do ${LN} ${BASE_DIR}/$$package .; done && \
${CD} ${TMPDIR} && ${TAR} czfh ${BASE_DIR}/${PACKAGE_NAME}.tgz ${PACKAGE_NAME} \
--exclude=${PACKAGE_NAME}.tgz\
--exclude=CVS \
--exclude=.cvsignore \
--exclude=makefile \
--exclude=Makefile \
--exclude=*.pyc \
--exclude=TAGS \
--exclude=*~ \
--exclude=.#*
${RMRF} ${TMPDIR}/${PACKAGE_NAME}
Portal Transforms
=================
This Zope product provides two new tools for the CMF in order to make MIME
types based transformations on the portal contents, and so an easy to way to
plugin some new transformations for previously unsupported content types. The
provided tools are :
* portal_transform (the transform tool) : handle transformation of data from a
mime type to another
A bunch of ready to use transformations are also provided. Look at the
documentation for more information.
Notice this package can also be used as a standalone Python package. If
you've downloaded the Python distribution, you can't make it a Zope
product since Zope files have been removed from this distribution.
This product is an off-spring of the Archetypes project.
Installation
------------
WARNING : The two installation methods may conflict, choose the one adapted to
your need.
Zope
````
* Put this package in your Zope's Products directory and restart Zope
* either use the QuickInstaller to add this product to your CMF site or add an
external method to the root of your CMF site with the following information :
:module: PortalTransforms.Install
:method: install
and click the test tab to run it.
Python
``````
* Extract the tarball
* Run "python setup.py install". See "python setup.py install --help" for
installation options.
* That's it, you should have the library and the *transform* command line tool
installed.
Documentation
-------------
See the *docs* directory in this package.
Mailing-list
------------
Discussion about this products occurs to the archetypes mailing list :
http://sourceforge.net/mail/?group_id=75272
or on the #plone channel of irc.freenode.net.
Authors
-------
Benjamin Saller <bcsaller@yahoo.com>
Sidnei da Silva <sidnei@x3ng.com>
Sylvain Thénault <sylvain.thenault@logilab.fr>
wv
xsltproc
tidy
unrtf
ppthtml
xlhtml
gs-common
TODO list for the Portal Transforms product
-------------------------------------------
* enhance unsafe_transforms/build_transforms to provide a bunch of
transformations using command/xml with various configuration
* iencoding_classifier ?
* make more transforms :)
...@@ -2,25 +2,22 @@ ...@@ -2,25 +2,22 @@
from zLOG import ERROR from zLOG import ERROR
from UserDict import UserDict from UserDict import UserDict
from zope.interface import implements
from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from App.class_init import default__class_init__ as InitializeClass from App.class_init import default__class_init__ as InitializeClass
from Persistence import PersistentMapping from Persistence import PersistentMapping
try: from persistent.list import PersistentList
from ZODB.PersistentList import PersistentList
except ImportError:
from persistent.list import PersistentList
from OFS.SimpleItem import SimpleItem from OFS.SimpleItem import SimpleItem
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCore.permissions import ManagePortal from Products.CMFCore.permissions import ManagePortal
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.utils import TransformException, log, _www from Products.PortalTransforms.utils import TransformException, log, _www
from Products.PortalTransforms.transforms.broken import BrokenTransform from Products.PortalTransforms.transforms.broken import BrokenTransform
from zope.interface import implements
__revision__ = '$Id: Transform.py 6255 2006-04-11 15:29:29Z hannosch $'
def import_from_name(module_name): def import_from_name(module_name):
""" import and return a module by its name """ """ import and return a module by its name """
...@@ -69,10 +66,9 @@ class Transform(SimpleItem): ...@@ -69,10 +66,9 @@ class Transform(SimpleItem):
additional configuration information additional configuration information
""" """
implements(itransform) implements(ITransform)
meta_type = 'Transform' meta_type = 'Transform'
meta_types = all_meta_types = () meta_types = all_meta_types = ()
manage_options = ( manage_options = (
...@@ -120,8 +116,8 @@ class Transform(SimpleItem): ...@@ -120,8 +116,8 @@ class Transform(SimpleItem):
# check this is a valid transform # check this is a valid transform
if not hasattr(transform, '__class__'): if not hasattr(transform, '__class__'):
raise TransformException('Invalid transform : transform is not a class') raise TransformException('Invalid transform : transform is not a class')
if not itransform.providedBy(transform): if not ITransform.providedBy(transform):
raise TransformException('Invalid transform : itransform is not implemented by %s' % transform.__class__) raise TransformException('Invalid transform : ITransform is not implemented by %s' % transform.__class__)
if not hasattr(transform, 'inputs'): if not hasattr(transform, 'inputs'):
raise TransformException('Invalid transform : missing required "inputs" attribute') raise TransformException('Invalid transform : missing required "inputs" attribute')
if not hasattr(transform, 'output'): if not hasattr(transform, 'output'):
...@@ -146,7 +142,14 @@ class Transform(SimpleItem): ...@@ -146,7 +142,14 @@ class Transform(SimpleItem):
return transform return transform
def _load_transform(self): def _load_transform(self):
try:
m = import_from_name(self.module) m = import_from_name(self.module)
except ImportError, err:
transform = BrokenTransform(self.id, self.module, err)
msg = "Cannot register transform %s (ImportError), using BrokenTransform: Error\n %s" % (self.id, err)
self.title = 'BROKEN'
log(msg, severity=ERROR)
return transform
if not hasattr(m, 'register'): if not hasattr(m, 'register'):
msg = 'Invalid transform module %s: no register function defined' % self.module msg = 'Invalid transform module %s: no register function defined' % self.module
raise TransformException(msg) raise TransformException(msg)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from AccessControl.Role import RoleManager from logging import DEBUG
from zope.interface import implements
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import Implicit
from Acquisition import aq_parent
from Acquisition import aq_base from Acquisition import aq_base
from Persistence import Persistent
from App.class_init import default__class_init__ as InitializeClass from App.class_init import default__class_init__ as InitializeClass
from Persistence import PersistentMapping from Persistence import PersistentMapping
try: try:
...@@ -12,20 +11,24 @@ try: ...@@ -12,20 +11,24 @@ try:
except ImportError: except ImportError:
from persistent.list import PersistentList from persistent.list import PersistentList
from OFS.Folder import Folder from OFS.Folder import Folder
from OFS.SimpleItem import Item
from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.CMFCore.ActionProviderBase import ActionProviderBase from Products.CMFCore.ActionProviderBase import ActionProviderBase
from Products.CMFCore.permissions import ManagePortal, View from Products.CMFCore.permissions import ManagePortal, View
try:
from Products.CMFCore.utils import registerToolInterface
except ImportError: # BACK: Zope 2.8
registerToolInterface = lambda tool_id, tool_interface: None
from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import UniqueObject
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.PortalTransforms.libtransforms.utils import MissingBinary from Products.PortalTransforms.libtransforms.utils import MissingBinary
from Products.PortalTransforms import transforms from Products.PortalTransforms import transforms
from Products.PortalTransforms.interfaces import iengine from Products.PortalTransforms.interfaces import IDataStream
from Products.PortalTransforms.interfaces import idatastream from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import IEngine
from Products.PortalTransforms.interfaces import IPortalTransformsTool
from Products.PortalTransforms.data import datastream from Products.PortalTransforms.data import datastream
from Products.PortalTransforms.chain import TransformsChain from Products.PortalTransforms.chain import TransformsChain
from Products.PortalTransforms.chain import chain from Products.PortalTransforms.chain import chain
...@@ -33,12 +36,8 @@ from Products.PortalTransforms.cache import Cache ...@@ -33,12 +36,8 @@ from Products.PortalTransforms.cache import Cache
from Products.PortalTransforms.Transform import Transform from Products.PortalTransforms.Transform import Transform
from Products.PortalTransforms.utils import log from Products.PortalTransforms.utils import log
from Products.PortalTransforms.utils import TransformException from Products.PortalTransforms.utils import TransformException
from Products.PortalTransforms.utils import BadRequest
from Products.PortalTransforms.utils import _www from Products.PortalTransforms.utils import _www
from zope.interface import implements
__revision__ = '$Id: TransformEngine.py 6255 2006-04-11 15:29:29Z hannosch $'
from zLOG import WARNING from zLOG import WARNING
...@@ -48,7 +47,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -48,7 +47,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
meta_type = id.title().replace('_', ' ') meta_type = id.title().replace('_', ' ')
isPrincipiaFolderish = 1 # Show up in the ZMI isPrincipiaFolderish = 1 # Show up in the ZMI
implements(iengine) implements(IPortalTransformsTool, IEngine)
meta_types = all_meta_types = ( meta_types = all_meta_types = (
{ 'name' : 'Transform', { 'name' : 'Transform',
...@@ -99,7 +98,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -99,7 +98,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
* orig is an encoded string * orig is an encoded string
* data an optional idatastream object. If None a new datastream will be * data an optional IDataStream object. If None a new datastream will be
created and returned created and returned
* optional object argument is the object on which is bound the data. * optional object argument is the object on which is bound the data.
...@@ -108,7 +107,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -108,7 +107,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
* additional arguments (kwargs) will be passed to the transformations. * additional arguments (kwargs) will be passed to the transformations.
Some usual arguments are : filename, mimetype, encoding Some usual arguments are : filename, mimetype, encoding
return an object implementing idatastream or None if no path has been return an object implementing IDataStream or None if no path has been
found. found.
""" """
target_mimetype = str(target_mimetype) target_mimetype = str(target_mimetype)
...@@ -185,15 +184,13 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -185,15 +184,13 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
transform = path[0] transform = path[0]
result = transform.convert(orig, data, context=context, usedby=usedby, **kwargs) result = transform.convert(orig, data, context=context, usedby=usedby, **kwargs)
assert(idatastream.providedBy(result),
'result doesn\'t is not an idatastream')
self._setMetaData(result, transform) self._setMetaData(result, transform)
# set cache if possible # set cache if possible
if object is not None and result.isCacheable(): if object is not None and result.isCacheable():
cache.setCache(str(target_mimetype), result) cache.setCache(str(target_mimetype), result)
# return idatastream object # return IDataStream object
return result return result
def getRequirementListByMimetype(self, origin_mimetype, target_mimetype): def getRequirementListByMimetype(self, origin_mimetype, target_mimetype):
...@@ -279,7 +276,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -279,7 +276,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
def _unwrap(self, data): def _unwrap(self, data):
"""unwrap data from an icache""" """unwrap data from an icache"""
if idatastream.providedBy(data): if IDataStream.providedBy(data):
data = data.getData() data = data.getData()
return data return data
...@@ -382,6 +379,12 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -382,6 +379,12 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
outputs = self._mtmap.get(orig) outputs = self._mtmap.get(orig)
if outputs is None: if outputs is None:
return result return result
registry = getToolByName(self, 'mimetypes_registry')
mto = registry.lookup(target)
# target mimetype aliases
target_aliases = mto[0].mimetypes
path.append(None) path.append(None)
for o_mt, transforms in outputs.items(): for o_mt, transforms in outputs.items():
for transform in transforms: for transform in transforms:
...@@ -394,7 +397,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -394,7 +397,7 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
# avoid infinite loop... # avoid infinite loop...
continue continue
path[-1] = transform path[-1] = transform
if o_mt == target: if o_mt in target_aliases:
if not requirements: if not requirements:
result.append(path[:]) result.append(path[:])
else: else:
...@@ -507,8 +510,8 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -507,8 +510,8 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
# register non zope transform # register non zope transform
module = str(transform.__module__) module = str(transform.__module__)
transform = Transform(transform.name(), module, transform) transform = Transform(transform.name(), module, transform)
if not itransform.providedBy(transform): if not ITransform.providedBy(transform):
raise TransformException('%s does not implement itransform' % transform) raise TransformException('%s does not implement ITransform' % transform)
name = transform.name() name = transform.name()
__traceback_info__ = (name, transform) __traceback_info__ = (name, transform)
if name not in self.objectIds(): if name not in self.objectIds():
...@@ -548,3 +551,4 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder): ...@@ -548,3 +551,4 @@ class TransformTool(UniqueObject, ActionProviderBase, Folder):
return available_types return available_types
InitializeClass(TransformTool) InitializeClass(TransformTool)
registerToolInterface('portal_transforms', IPortalTransformsTool)
import os.path
__version__ = open(os.path.join(__path__[0], 'version.txt')).read().strip()
from Products.PortalTransforms.utils import skins_dir
from Products.PortalTransforms.TransformEngine import TransformTool from Products.PortalTransforms.TransformEngine import TransformTool
GLOBALS = globals()
PKG_NAME = 'PortalTransforms' PKG_NAME = 'PortalTransforms'
tools = ( tools = (
...@@ -26,9 +21,6 @@ from Products.MimetypesRegistry import MimeTypeItem ...@@ -26,9 +21,6 @@ from Products.MimetypesRegistry import MimeTypeItem
sys.modules['Products.PortalTransforms.zope.MimeTypeItem'] = MimeTypeItem sys.modules['Products.PortalTransforms.zope.MimeTypeItem'] = MimeTypeItem
def initialize(context): def initialize(context):
from Products.CMFCore.DirectoryView import registerDirectory
#registerDirectory(skins_dir, GLOBALS)
from Products.CMFCore import utils from Products.CMFCore import utils
utils.ToolInit("%s Tool" % PKG_NAME, utils.ToolInit("%s Tool" % PKG_NAME,
tools=tools, tools=tools,
......
from Products import PortalTransforms as PRODUCT
import os.path
version=PRODUCT.__version__
modname=PRODUCT.__name__
# (major, minor, patchlevel, release info) where release info is:
# -99 for alpha, -49 for beta, -19 for rc and 0 for final
# increment the release info number by one e.g. -98 for alpha2
major, minor, bugfix = version.split('.')[:3]
bugfix, release = bugfix.split('-')[:2]
relinfo=-99 #alpha
if 'beta' in release:
relinfo=-49
if 'rc' in release:
relinfo=-19
if 'final' in release:
relinfo=0
numversion = (int(major), int(minor), int(bugfix), relinfo)
license = 'BSD like'
license_text = open(os.path.join(PRODUCT.__path__[0], 'LICENSE.txt')).read()
copyright = '''Copyright (c) 2003 LOGILAB S.A. (Paris, FRANCE)'''
author = "Archetypes developement team"
author_email = "archetypes-devel@lists.sourceforge.net"
short_desc = "MIME types based transformations for the CMF"
long_desc = """This package provides two new CMF tools in order to
make MIME types based transformations on the portal contents and so an
easy to way to plugin some new transformations for previously
unsupported content types. You will find more info in the package's
README and docs directory.
.
It's part of the Archetypes project, but the only requirement to use it
is to have a CMF based site. If you are using Archetypes, this package
replaces the transform package.
.
Notice this package can also be used as a standalone Python package. If
you've downloaded the Python distribution, you can't make it a Zope
product since Zope files have been removed from this distribution.
"""
web = "http://plone.org/products/archetypes"
ftp = ""
mailing_list = "archetypes-devel@lists.sourceforge.net"
debian_name = "zope-cmftransforms"
debian_maintainer = "Sylvain Thenault"
debian_maintainer_email = "sylvain.thenault@logilab.fr"
debian_handler = "zope"
<configure
xmlns="http://namespaces.zope.org/five"
>
<bridge
zope2=".interfaces.idatastream"
package=".z3.interfaces"
name="IDataStream"
/>
<bridge
zope2=".interfaces.itransform"
package=".z3.interfaces"
name="ITransform"
/>
<bridge
zope2=".interfaces.ichain"
package=".z3.interfaces"
name="IChain"
/>
<bridge
zope2=".interfaces.iengine"
package=".z3.interfaces"
name="IEngine"
/>
</configure>
from zope.interface import implements
from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Persistence import Persistent from Persistence import Persistent
from App.class_init import default__class_init__ as InitializeClass from App.class_init import default__class_init__ as InitializeClass
...@@ -9,17 +11,17 @@ from AccessControl import ClassSecurityInfo ...@@ -9,17 +11,17 @@ from AccessControl import ClassSecurityInfo
from Products.CMFCore.permissions import ManagePortal, ManageProperties from Products.CMFCore.permissions import ManagePortal, ManageProperties
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.PortalTransforms.utils import TransformException, _www from Products.PortalTransforms.utils import _www
from Products.PortalTransforms.interfaces import ichain
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import IChain
from zope.interface import implements from Products.PortalTransforms.interfaces import ITransform
from UserList import UserList from UserList import UserList
class chain(UserList): class chain(UserList):
"""A chain of transforms used to transform data""" """A chain of transforms used to transform data"""
implements(ichain, itransform) implements(IChain, ITransform)
def __init__(self, name='',*args): def __init__(self, name='',*args):
UserList.__init__(self, *args) UserList.__init__(self, *args)
......
from Products.PortalTransforms.interfaces import idatastream
from zope.interface import implements from zope.interface import implements
from Products.PortalTransforms.interfaces import IDataStream
class datastream: class datastream:
"""A transformation datastream packet""" """A transformation datastream packet"""
implements(idatastream)
__slots__ = ('name', '_data', '_metadata') __slots__ = ('name', '_data', '_metadata')
implements(IDataStream)
def __init__(self, name): def __init__(self, name):
self.__name__ = name self.__name__ = name
self._data = '' self._data = ''
...@@ -61,8 +65,3 @@ class datastream: ...@@ -61,8 +65,3 @@ class datastream:
"""Set cacheable flag to yes or no """Set cacheable flag to yes or no
""" """
self._cacheable = bool(value) self._cacheable = bool(value)
#data = property('getData', 'setData', None, """idata.data""")
#metadata = property('getMetadata', 'setMetadata', None,
#"""idata.metadata""")
===================================
Portal Transforms'Developper manual
===================================
:Author: Sylvain Thenault
:Contact: syt@logilab.fr
:Date: $Date: 2005-08-19 23:43:41 +0200 (Fre, 19 Aug 2005) $
:Version: $Revision: 1.5 $
:Web site: http://sourceforge.net/projects/archetypes
.. contents::
Tools interfaces
----------------
The MIME types registry
```````````````````````
class isourceAdapter(Interface):
def __call__(data, \**kwargs):
"""convert data to unicode, may take optional kwargs to aid in conversion"""
class imimetypes_registry(isourceAdapter):
def classify(data, mimetype=None, filename=None):
"""return a content type for this data or None
None should rarely be returned as application/octet can be
used to represent most types.
"""
def lookup(mimetypestring):
"""Lookup for imimetypes object matching mimetypestring.
mimetypestring may have an empty minor part or containing a wildcard (*).
mimetypestring may be an imimetype object (in this case it will be
returned unchanged, else it should be a RFC-2046 name.
Return a list of mimetypes objects associated with the RFC-2046 name.
Return an empty list if no one is known.
"""
def lookupExtension(filename):
""" return the mimetypes object associated with the file's extension
or None if it is not known.
filename maybe a file name like 'content.txt' or an extension like 'rest'
"""
def mimetypes():
"""return all defined mime types, each one implements at least imimetype
"""
def list_mimetypes():
"""return all defined mime types, as string"""
The tranformation tool
``````````````````````
class iengine(Interface):
def registerTransform(transform):
"""register a transform
transform must implements itransform
"""
def unregisterTransform(name):
""" unregister a transform
name is the name of a registered transform
"""
def convertTo(mimetype, orig, idata=None, \**kwargs):
"""Convert orig to a given mimetype
return an object implementing idatastream or None if not path has been
found
"""
def convert(name, orig, idata=None, \**kwargs):
"""run a tranform of a given name on data
name is the name of a registered transform
return an object implementing idatastream
"""
def __call__(name, orig, idata=None, \**kwargs):
"""run a transform returning the raw data product
name is the name of a registered transform
return an object implementing idatastream
"""
Writing a new transformation
----------------------------
Writing a new transform should be an easy task. You only have to follow a
simple interface to do it, but knowing some advanced features and provided
utilities may help to do it quicker...
Related interfaces
``````````````````
class itransform(Interface):
"""A transformation plugin -- tranform data somehow must be threadsafe and stateless"""
inputs = Attribute("""list of imimetypes (or registered rfc-2046
names) this transform accepts as inputs""")
output = Attribute("output imimetype as instance or rfc-2046 name"")
def name(self):
"""return the name of the transform instance"""
def convert(data, idata, \**kwargs):
"""convert the data, store the result in idata and return that"""
class idatastream(Interface):
"""data stream, is the result of a transform"""
def setData(self, value):
"""set the main data produced by a transform, i.e. usually a string"""
def getData():
"""provide access to the transformed data object, i.e. usually a string.
This data may references subobjects.
"""
def setSubObjects(self, objects):
"""set a dict-like object containing subobjects.
keys should be object's identifier (e.g. usually a filename) and
values object's content.
"""
def getSubObjects(self):
"""return a dict-like object with any optional subobjects associated
with the data"""
def getMetadata():
"""return a dict-like object with any optional metadata from
the transform"""
Important note about encoding
`````````````````````````````
A transform receive data as an encoded string. A priori, no assumption can be
made about the used encoding. Data returned by a transform must use the same
encoding as received data, unless the transform provides a *output_encoding*
attribute indicating the output encoding (for instance this may be usefull for
XSLT based transforms).
Configurable transformation
```````````````````````````
You can make your transformation configurable through the ZMI by setting a
*config* dictionnary on your transform instance or class. Keys are parameter's
name and values parameter's value. Another dictionnary *config_metadata*
describes each parameter. In this mapping, keys are also parameter's name but
values are a tree-uple : (<parameter's type>, <parameter's label>, <parameter's
description>).
Possible types for parameters are :
:int: field is an integer
:string: field is a string
:list: field is a list
:dict: field is a dictionnary
You can look at the **command** and **xml** transforms for an example of
configurable transform.
Images / sub-objects management
````````````````````````````````
A transformation may produce some sub-objects, for instance when you convert a
PDF document to HTML. That's the purpose of the setObjects method of
the idatastream interface.
Some utilities
``````````````
Transform utilities may be found in the libtransforms subpackage. You'll find
there the following modules :
*commandtransform*
provides a base class for external command based transforms.
*retransform*
provides a base class for regular expression based transforms.
*html4zope*
provides a docutils HTML writer for Zope.
*utils*
provides some utilities functions.
Write a test your transform !
`````````````````````````````
Every transform should have its test... And it's easy to write a test for your
transform ! Imagine you have made a transform named "colabeer" which transforms
cola into beer (I let you find MIME type for these content types ;). Basically,
your test file should be :
from test_transforms import make_tests
tests =('Products.MyTransforms.colabeer', "drink.cola", "drink.beer", None, 0)
def test_suite():
return TestSuite([makeSuite(test) for test in make_tests()])
if __name__=='__main__':
main(defaultTest='test_suite')
In this example :
- "Products.MyTransforms.colabeer" is the module defining your transform (you
can also give directly the transform instance).
- "drink.cola" is the name of the file containing data to give to your transform
as input.
- "drink.beer" is the file containing expected transform result (what the getData
method of idatastream will return).
- Additional arguments (*None* and *0*) are respectivly an optional normalizing
function to apply to both the transform result and the output file content, and
the number of subobjects that the transform is expected to produce.
This example supposes your test is in the *tests* directory of PortalTransforms
and your input and output files respectively in *tests/input* and
*tests/output*.
\ No newline at end of file
REST2HTML=html.py --compact-lists --date --generator
all: user_manual.html dev_manual.html
user_manual.html: user_manual.rst
$(REST2HTML) user_manual.rst user_manual.html
dev_manual.html: dev_manual.rst
$(REST2HTML) dev_manual.rst dev_manual.html
clean:
rm *.html
===================================
How to setup PyUNO for zope
===================================
:Author: Junyong Pan <panjy at zopechina.com>, Anton Stonor <stonor@giraffen.dk>
:Date: $Date: 2003-08-12 02:50:50 -0800 (Tue, 12 Aug 2003) $
:Version: $Revision: 1.5 $
(to be refined)
Portal Transforms allows you to convert Word documents to HTML. A cool
feature
if you want to preview Word documents at your web site or use Word as a web
authoring tool.
To do the actual transform, Portal Transforms rely on a third party
application
to do the heavy lifting. If you have not installed such an application,
Portal
Transforms will not perfom Word to HTML transforms.
One of the options is Open Office. It is not the easiest application to
set up
to work with Portal Transforms, but it works on both Windows and Unix
and delivers
fairly good HTML.
Problems
====================
- PyUNO is cool, but PyUNO now ship with its own python intepreter, which is not compatible with zope's
- PyUNO is not threadsafe now.
SETTING UP OPEN OFFICE ON WINDOWS
=======================================
WARNING: You can setup pyuno, but you can't use it concurrently. see 'Install oood'
1) Install Open Office 2.0
Just run the standard installer.
Pyuno in this version ship with python 2.3, which is compatible with Zope 2.7
2) Set the environment PATH
Add the Open Office program dir to the Windows PATH, e.g.
C:\Program Files\OpenOffice.org 1.9.82\program
See this article on how to set the Windows PATH:
http://vlaurie.com/computers2/Articles/environment.htm
You can also look at the python.bat (located in your Open Office program
dir)
for inspiration.
3) Set the PYTHONPATH
You need to add these directories to the PYTHONPATH:
a) The Open Office program dir (e.g. C:\Program Files\OpenOffice.org
1.9.82\program)
b) The Open Office python lib dir (e.g. C:\Program Files\OpenOffice.org
1.9.82\program\python-core-2.3.4\lib)
From the Windows system shell, just run e.g.:
set PYTHONPATH= C:\Program Files\OpenOffice.org 1.9.82\program
set PYTHONPATH= C:\Program Files\OpenOffice.org
1.9.82\program\python-core-2.3.4\lib
You can also look at the python.bat (located in your Open Office program
dir) for inspiration.
4) Start Open Office as UNO-server
Run soffice "-accept=socket,host=localhost,port=2002;urp;"
5) Now it should work
For Debian Linux Users
=========================
see: http://bibus-biblio.sourceforge.net/html/en/LinuxInstall.html
1. install version 1.1, which doesn't contain pyuno::
apt-get install openoffice
2. install a version of pyuno which enable ucs4 unicode
- you can download at http://sourceforge.net/projects/bibus-biblio/
- copy to /usr/lib/openoffice/program
3. set up environment variables
OPENOFFICE_PATH="/usr/lib/openoffice/program"
export PYTHONPATH="$OPENOFFICE_PATH"
export LD_LIBRARY_PATH="$OPENOFFICE_PATH"
Install oood
===================
Note, this product is for linux only
http://udk.openoffice.org/python/oood/
UNDERSTANDING OPEN OFFICE AND UNO
=============================================
Open Office allows programmers to remotely control it. Portal Transforms
takes
advantage of this opportunity by scripting Open Office from Python. It
is possible
through PyUNO that exposes the Open Office API in Python.
Now, you can't download and install PyUNO as a module for your the Python
interpreter that is running your Zope server. PyUNO only comes bundled
with Open
Office and the Python that is distributed with Open Office. To make
PyUNO work
from within your standard Python you must expand the PYTHONPATH as done
above so
Python also will look inside Open Office for modules. If it works you
should be
able to start up a Python shell and do
>>>import uno
In some cases you can be unlucky and the Python used for Zope is not in
sync with
the Python that is distributed with Open Office. That is solved by
rebuilding
Python -- a task that is beyond the scope of this guide.
=============================
Portal Transforms'User manual
=============================
:Author: Sylvain Thénault
:Contact: syt@logilab.fr
:Date: $Date: 2005-08-19 23:43:41 +0200 (Fre, 19 Aug 2005) $
:Version: $Revision: 1.7 $
:Web site: http://sourceforge.net/projects/archetypes
.. contents::
What does this package provide ?
================================
This package is both a python library for MIME type based content
transformation, including a command line tool, (what i call the python package)
and a Zope product providing two new tools for the CMF (what i call the Zope
product). A python only distribution will be available, where all the Zope
specific files won't be included.
Python side
===========
The *transform* command line tool
`````````````````````````````````
command line tool for MIME type based transformation
USAGE: transform [OPTIONS] input_file output_file
OPTIONS:
-h / --help
display this help message and exit.
-o / --output <output mime type>
output MIME type. (conflict with --transform)
-t / --transform <transform id>
id of the transform to apply. (conflict with --output)
EXAMPLE:
$ transform -o text/html dev_manual.rst dev_manual.html
Customization hook
``````````````````
You can customize the transformation engine by providing a module
"transform_customize" somewhere in your Python path. The module must provide a
*initialize* method which will take the engine as only argument. This method
will have the reponsability to initialize the engine with desired
transformations. When it's not found, the *initialize* method from the
*transforms* subpackage will be used.
Zope side
=========
The MIME types registry
```````````````````````
This tool registered known MIME types. The information associated with a MIME
type are :
* a title
* a list rfc-2046 types
* a list of files extensions
* a binary flag
* an icon path
You can see regitered types by going to the *mimetypes_registry* object at the
root of your CMF site, using the ZMI. There you can modify existent information
or add / delete types. This product cames with a default set of MIME types icons
located in portal_skins/mimetypes_icons.
The tranformation tool
``````````````````````
It's a MIME type based transformation engine. It's has been designed to
transform portal content from a given MIME type to another. You can add / delete
transformations by going to the *portal_transforms* object at the root of your
CMF site, using the ZMI. Some transformations are configurable, but not all. A
transform is a Python object implementing a special interface. See the
developper documentation if you're interested in writing a new
transformation.
Archetypes integration
``````````````````````
Archetypes will use this product for automatic transformation if you have
configurated it to use the new base unit (set USE_NEW_BASEUNIT to 1 in the
Archetypes config.py). If you're using the old base unit (still default in 1.0),
the transform tool won't be used (at least by the Archetypes library).
Default transformations
=======================
The default transformations are described here. They are separated in two groups,
safe and unsafe. Safe transforms are located in the *transforms* directory of this
product. Unsafe transforms are located in the *unsafe_transforms* directory and
are not registered by default. Moreover, there is no __init__.py file in this
directory so it requires a manual intervention to make them addable to the
transforms tool. Usually unsafe transforms are so called since they allow
configuration of a path to a binary executable on the server, which may be
indesirable for Zope service providers.
Safe transforms
```````````````
*st*
transforms Structured Text to HTML. Not configurable.
*rest*
transforms Re Structured Text to HTML. You need docutils to use this
transformation. Not configurable.
*word_to_html*
transforms M$ Word file to HTML, using either COM (on windows), wvWare or
PyUNO (from OpenOffice.org). Not configurable.
*pdf_to_html*
transforms Adobe PDF to HTML. This transforms requires the "pdftohtml"
program. Not Configurable.
*lynx_dump*
transforms HTML to plain text. This transforms requires the "lynx"
program. Not Configurable.
*python*
transforms Python source code to colorized HTML. You can configure used
colors.
*text_to_html*
transforms plain text file to HTML by replacing new lines with
<br/>. You can configure allowable inputs for this transform.
*rest_to_text*
This is an example use of the *identity* transform, which does
basically nothing :). It's used here to transform ReST files
(text/x-rst) to text/plain. You can configure allowable inputs and
outuput on this transform.
Unsafe transforms
`````````````````
*command*
this is a fully configurable transform based on external commands. For
instance, you can obtain the same transformation as the previous
*lynx_dump*:
1. add a new transform named "lynx_dump" with
"Products.PortalTransforms.unsafe_transforms.command" as module
(this supposes that you've added a __init__.py file to the
unsafe_transforms directory to make them importable).
2. go to the configure tab of this transform and set the following
parameters :
:binary_path: '/usr/bin/lynx'
:command_line: '-dump %s'
:input: 'text/html'
:output: 'text/plain'
*xml*
this transform has been designed to handle XML file on a doctype / DTD
basis. All the real transformation work is done by a xslt processor. This
transform only associate XSLT to doctypes or DTD, and use give the correct
transformation to the processor when some content has to be
transformed.
FIXME: add an example on how to setup docbook transform.
Advanced features
=================
Transformation chains
`````````````````````
A transformation chain is an ordered suite of transformations. A chain
itselve is a transformation. You can build a transformations chain
using the ZMI.
Transformation policy
`````````````````````
You can set a simple transformation policies for the transforms
tool. A policy say that when you try to convert content to a given
MIME type, you have to include a given transformation. For instance,
imagine you have a *html_tidy* tranformation which tidy HTML page, you
can say that the transformation path to text/html should include the
*html_tidy* transform.
Caches
``````
For efficiency, transformation's result are cached. You can set the
life time of a cached result using the ZMI. This is a time exprimed in
seconds.
<configure
xmlns="http://namespaces.zope.org/five"
>
<implements
class=".chain.chain"
interface=".z3.interfaces.IChain"
/>
<implements
class=".chain.chain"
interface=".z3.interfaces.ITransform"
/>
<implements
class=".data.datastream"
interface=".z3.interfaces.IDataStream"
/>
<implements
class=".Transform.Transform"
interface=".z3.interfaces.ITransform"
/>
<implements
class=".TransformEngine.TransformTool"
interface=".z3.interfaces.IEngine"
/>
<implements
class=".libtransforms.commandtransform.commandtransform"
interface=".z3.interfaces.ITransform"
/>
<implements
class=".libtransforms.commandtransform.popentransform"
interface=".z3.interfaces.ITransform"
/>
<implements
class=".libtransforms.retransform.retransform"
interface=".z3.interfaces.ITransform"
/>
<!-- TODO: more -->
</configure>
from zope.interface import Interface, Attribute from zope.interface import Interface
class idatastream(Interface): class IPortalTransformsTool(Interface):
"""Marker interface for the portal_transforms tool."""
class IDataStream(Interface):
"""data stream, is the result of a transform""" """data stream, is the result of a transform"""
def setData(value): def setData(value):
...@@ -37,20 +40,10 @@ class idatastream(Interface): ...@@ -37,20 +40,10 @@ class idatastream(Interface):
"""Set cacheable flag to yes or no """Set cacheable flag to yes or no
""" """
class itransform(Interface): class ITransform(Interface):
"""A transformation plugin -- tranform data somehow """A transformation plugin -- tranform data somehow
must be threadsafe and stateless""" must be threadsafe and stateless"""
# inputs = Attribute("""list of imimetypes (or registered rfc-2046
# names) this transform accepts as inputs.""")
# output = Attribute("""output imimetype as instance or rfc-2046
# name""")
# output_encoding = Attribute("""output encoding of this transform.
# If not specified, the transform should output the same encoding as received data
# """)
def name(self): def name(self):
"""return the name of the transform instance""" """return the name of the transform instance"""
...@@ -67,18 +60,18 @@ class itransform(Interface): ...@@ -67,18 +60,18 @@ class itransform(Interface):
""" """
class ichain(itransform): class IChain(ITransform):
def registerTransform(transform, condition=None): def registerTransform(transform, condition=None):
"""Append a transform to the chain""" """Append a transform to the chain"""
class iengine(Interface): class IEngine(Interface):
def registerTransform(transform): def registerTransform(transform):
"""register a transform """register a transform
transform must implements itransform transform must implements ITransform
""" """
def unregisterTransform(name): def unregisterTransform(name):
...@@ -123,3 +116,8 @@ class iengine(Interface): ...@@ -123,3 +116,8 @@ class iengine(Interface):
see convert docstring for more info on additional arguments. see convert docstring for more info on additional arguments.
""" """
# BBB
idatastream = IDataStream
ichain = IChain
iengine = IEngine
itransform = ITransform
...@@ -5,15 +5,16 @@ import tempfile ...@@ -5,15 +5,16 @@ import tempfile
import re import re
import shutil import shutil
from os.path import join, basename from os.path import join, basename
from zope.interface import implements from zope.interface import implements
from Products.PortalTransforms.interfaces import itransform
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext, getShortPathName from Products.PortalTransforms.libtransforms.utils import bin_search, sansext, getShortPathName
from Products.PortalTransforms.interfaces import ITransform
class commandtransform: class commandtransform:
"""abstract class for external command based transform """abstract class for external command based transform
""" """
implements(itransform) implements(ITransform)
def __init__(self, name=None, binary=None, **kwargs): def __init__(self, name=None, binary=None, **kwargs):
if name is not None: if name is not None:
...@@ -59,7 +60,7 @@ class popentransform: ...@@ -59,7 +60,7 @@ class popentransform:
Command must read from stdin and write to stdout Command must read from stdin and write to stdout
""" """
implements(itransform) implements(ITransform)
binaryName = "" binaryName = ""
binaryArgs = "" binaryArgs = ""
...@@ -117,7 +118,7 @@ class subprocesstransform: ...@@ -117,7 +118,7 @@ class subprocesstransform:
Command must read from stdin and write to stdout Command must read from stdin and write to stdout
""" """
implements(itransform) implements(ITransform)
binaryName = "" binaryName = ""
binaryArgs = "" binaryArgs = ""
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
import subprocess import subprocess
from zope.interface import implements from zope.interface import implements
class ImageMagickTransforms: class ImageMagickTransforms:
implements(itransform) implements(ITransform)
__name__ = "imagemagick_transforms" __name__ = "imagemagick_transforms"
def __init__(self, name=None): def __init__(self, name=None):
if name is not None: if name is not None:
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from StringIO import StringIO from StringIO import StringIO
import PIL.Image import PIL.Image
from zope.interface import implements
class PILTransforms: class PILTransforms:
implements(itransform) implements(ITransform)
__name__ = "piltransforms" __name__ = "piltransforms"
def __init__(self, name=None): def __init__(self, name=None):
if name is not None: if name is not None:
......
from Products.PortalTransforms.interfaces import itransform
import re import re
from zope.interface import implements from zope.interface import implements
from Products.PortalTransforms.interfaces import ITransform
class retransform: class retransform:
"""abstract class for regex transforms (re.sub wrapper)""" """abstract class for regex transforms (re.sub wrapper)"""
implements(itransform)
implements(ITransform)
inputs = ('text/',) inputs = ('text/',)
......
...@@ -37,19 +37,15 @@ else: ...@@ -37,19 +37,15 @@ else:
def bin_search(binary): def bin_search(binary):
"""search the bin_search_path for a given binary returning its fullname or """search the bin_search_path for a given binary returning its fullname or
raises MissingBinary""" raises MissingBinary"""
result = None
mode = os.R_OK | os.X_OK mode = os.R_OK | os.X_OK
for path in bin_search_path: for path in bin_search_path:
for ext in ('', ) + extensions: for ext in ('', ) + extensions:
pathbin = os.path.join(path, binary) + ext pathbin = os.path.join(path, binary) + ext
if os.access(pathbin, mode) == 1: if os.access(pathbin, mode) == 1:
result = pathbin return pathbin
break
if not result:
raise MissingBinary('Unable to find binary "%s" in %s' % raise MissingBinary('Unable to find binary "%s" in %s' %
(binary, os.pathsep.join(bin_search_path))) (binary, os.pathsep.join(bin_search_path)))
else:
return result
def getShortPathName(binary): def getShortPathName(binary):
if WIN32: if WIN32:
...@@ -124,8 +120,10 @@ VALID_TAGS = { 'a' : 1 ...@@ -124,8 +120,10 @@ VALID_TAGS = { 'a' : 1
, 'pre' : 1 , 'pre' : 1
, 'span' : 1 , 'span' : 1
, 'strong' : 1 , 'strong' : 1
, 'strike' : 1
, 'table' : 1 , 'table' : 1
, 'tbody' : 1 , 'tbody' : 1
, 'thead' : 1
, 'td' : 1 , 'td' : 1
, 'th' : 1 , 'th' : 1
, 'title' : 1 , 'title' : 1
......
<?xml version="1.0"?>
<componentregistry>
<adapters/>
<utilities>
<utility
interface="Products.PortalTransforms.interfaces.IPortalTransformsTool"
object="portal_transforms"/>
</utilities>
</componentregistry>
<?xml version="1.0"?>
<import-steps>
<import-step id="portal-transforms-various" version="20070309-01"
handler="Products.PortalTransforms.setuphandlers.setupPortalTransforms"
title="PortalTransforms setup">
<dependency step="componentregistry"/>
PortalTransforms installation step.
</import-step>
</import-steps>
<?xml version="1.0"?>
<metadata>
<version>1.6</version>
</metadata>
<?xml version="1.0"?>
<tool-setup>
<required tool_id="portal_transforms"
class="Products.PortalTransforms.TransformEngine.TransformTool"/>
</tool-setup>
import os """
from Products.CMFCore.DirectoryView import addDirectoryViews PortalTransforms setup handlers.
from Products.CMFCore.DirectoryView import registerDirectory """
from Products.CMFCore.DirectoryView import createDirectoryView
from Products.CMFCore.DirectoryView import manage_listAvailableDirectories
from Products.CMFCore.utils import getToolByName
from Products.CMFCore.utils import minimalpath
from App.Common import package_home
from Acquisition import aq_base
from OFS.ObjectManager import BadRequestException
from Products.PortalTransforms import GLOBALS
from Products.PortalTransforms import skins_dir
from StringIO import StringIO from StringIO import StringIO
from Products.CMFCore.utils import getToolByName
def install(self):
out = StringIO()
qi=getToolByName(self, 'portal_quickinstaller')
qi.installProduct('MimetypesRegistry',)
id = 'portal_transforms'
if hasattr(aq_base(self), id):
pt = getattr(self, id)
if not getattr(aq_base(pt), '_new_style_pt', None) == 1:
print >>out, 'Removing old portal transforms tool'
self.manage_delObjects([id,])
if not hasattr(aq_base(self), id):
addTool = self.manage_addProduct['PortalTransforms'].manage_addTool
addTool('Portal Transforms')
print >>out, 'Installing portal transforms tool'
updateSafeHtml(self, out)
correctMapping(self, out)
# not required right now
# installSkin(self)
return out.getvalue()
def correctMapping(self, out):
pt = getToolByName(self, 'portal_transforms') def correctMapping(out, portal):
pt = getToolByName(portal, 'portal_transforms')
pt_ids = pt.objectIds() pt_ids = pt.objectIds()
for m_in, m_out_dict in pt._mtmap.items(): for m_in, m_out_dict in pt._mtmap.items():
...@@ -56,15 +23,14 @@ def correctMapping(self, out): ...@@ -56,15 +23,14 @@ def correctMapping(self, out):
else: else:
print >>out, "...ok" print >>out, "...ok"
def updateSafeHtml(self, out): def updateSafeHtml(out, portal):
print >>out, 'Update safe_html...' print >>out, 'Update safe_html...'
safe_html_id = 'safe_html' safe_html_id = 'safe_html'
safe_html_module = "Products.PortalTransforms.transforms.safe_html" safe_html_module = "Products.PortalTransforms.transforms.safe_html"
pt = getToolByName(self, 'portal_transforms') pt = getToolByName(portal, 'portal_transforms')
for id in pt.objectIds(): for id in pt.objectIds():
transform = getattr(pt, id) transform = getattr(pt, id)
if transform.id == safe_html_id and transform.module == safe_html_module: if transform.id == safe_html_id and transform.module == safe_html_module:
try: try:
disable_transform = transform.get_parameter_value('disable_transform') disable_transform = transform.get_parameter_value('disable_transform')
except KeyError: except KeyError:
...@@ -79,31 +45,22 @@ def updateSafeHtml(self, out): ...@@ -79,31 +45,22 @@ def updateSafeHtml(self, out):
print >>out, '...done' print >>out, '...done'
def installSkin(self):
skinstool=getToolByName(self, 'portal_skins')
fullProductSkinsPath = os.path.join(package_home(GLOBALS), skins_dir) def installPortalTransforms(portal):
productSkinsPath = minimalpath(fullProductSkinsPath) out = StringIO()
registered_directories = manage_listAvailableDirectories()
if productSkinsPath not in registered_directories: updateSafeHtml(out, portal)
registerDirectory(skins_dir, GLOBALS)
try: correctMapping(out, portal)
addDirectoryViews(skinstool, skins_dir, GLOBALS)
except BadRequestException, e: def setupPortalTransforms(context):
pass # directory view has already been added """
Setup PortalTransforms step.
"""
# Only run step if a flag file is present (e.g. not an extension profile)
if context.readDataFile('portal-transforms-various.txt') is None:
return
out = []
site = context.getSite()
installPortalTransforms(site)
files = os.listdir(fullProductSkinsPath)
for productSkinName in files:
if os.path.isdir(os.path.join(fullProductSkinsPath, productSkinName)) \
and productSkinName != 'CVS':
for skinName in skinstool.getSkinSelections():
path = skinstool.getSkinPath(skinName)
path = [i.strip() for i in path.split(',')]
try:
if productSkinName not in path:
path.insert(path.index('custom') +1, productSkinName)
except ValueError:
if productSkinName not in path:
path.append(productSkinName)
path = ','.join(path)
skinstool.addSkinSelection(skinName, path)
##############################################################################
#
# ZopeTestCase
#
# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
#
# This version of framework.py will use the SOFTWARE_HOME
# environment variable to locate Zope and the Testing package.
#
# If the tests are run in an INSTANCE_HOME installation of Zope,
# Products.__path__ and sys.path with be adjusted to include the
# instance's Products and lib/python directories respectively.
#
# If you explicitly set INSTANCE_HOME prior to running the tests,
# auto-detection is disabled and the specified path will be used
# instead.
#
# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
# will be adjusted to use it.
#
# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
# is assumed, and you can attach to a running ZEO server (via the
# instance's custom_zodb.py).
#
##############################################################################
#
# The following code should be at the top of every test module:
#
# import os, sys
# if __name__ == '__main__':
# execfile(os.path.join(sys.path[0], 'framework.py'))
#
# ...and the following at the bottom:
#
# if __name__ == '__main__':
# framework()
#
##############################################################################
__version__ = '0.2.3'
# Save start state
#
__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
if __SOFTWARE_HOME.endswith(os.sep):
__SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
if __INSTANCE_HOME.endswith(os.sep):
__INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
# Find and import the Testing package
#
if not sys.modules.has_key('Testing'):
p0 = sys.path[0]
if p0 and __name__ == '__main__':
os.chdir(p0)
p0 = ''
s = __SOFTWARE_HOME
p = d = s and s or os.getcwd()
while d:
if os.path.isdir(os.path.join(p, 'Testing')):
zope_home = os.path.dirname(os.path.dirname(p))
sys.path[:1] = [p0, p, zope_home]
break
p, d = s and ('','') or os.path.split(p)
else:
print 'Unable to locate Testing package.',
print 'You might need to set SOFTWARE_HOME.'
sys.exit(1)
import Testing, unittest
execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
# Include ZopeTestCase support
#
if 1: # Create a new scope
p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
if not os.path.isdir(p):
print 'Unable to locate ZopeTestCase package.',
print 'You might need to install ZopeTestCase.'
sys.exit(1)
ztc_common = 'ztc_common.py'
ztc_common_global = os.path.join(p, ztc_common)
f = 0
if os.path.exists(ztc_common_global):
execfile(ztc_common_global)
f = 1
if os.path.exists(ztc_common):
execfile(ztc_common)
f = 1
if not f:
print 'Unable to locate %s.' % ztc_common
sys.exit(1)
# Debug
#
print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
sys.stdout.flush()
<h2 class="title">Heading 1</h2> <h2 class="title">Heading 1</h2>
<p>Some text.</p> <p>Some text.</p>
<div class="section" id="heading-2"> <div class="section">
<h3><a name="heading-2">Heading 2</a></h3> <h3><a id="heading-2" name="heading-2">Heading 2</a></h3>
<p>Some text, bla ble bli blo blu. Yes, i know this is <a class="reference" href="http://www.example.com">Stupid</a>.</p> <p>Some text, bla ble bli blo blu. Yes, i know this is <a class="reference" href="http://www.example.com">Stupid</a>.</p>
</div> </div>
<h2 class="title">Title</h2> <h2 class="title">Title</h2>
<h3 class="subtitle">Subtitle</h3> <h3 class="subtitle">Subtitle</h3>
<p>This is a test document to make sure subtitle gets the right heading.</p> <p>This is a test document to make sure subtitle gets the right heading.</p>
<div class="section" id="now-the-real-heading"> <div class="section">
<h3><a name="now-the-real-heading">Now the real heading</a></h3> <h3><a id="now-the-real-heading" name="now-the-real-heading">Now the real heading</a></h3>
<p>The brown fox jumped over the lazy dog.</p> <p>The brown fox jumped over the lazy dog.</p>
<div class="section" id="with-a-subheading"> <div class="section">
<h4><a name="with-a-subheading">With a subheading</a></h4> <h4><a id="with-a-subheading" name="with-a-subheading">With a subheading</a></h4>
<p>Some text, bla ble bli blo blu. Yes, i know this is <a class="reference" href="http://www.example.com">Stupid</a>.</p> <p>Some text, bla ble bli blo blu. Yes, i know this is <a class="reference" href="http://www.example.com">Stupid</a>.</p>
</div> </div>
</div> </div>
...@@ -19,7 +19,7 @@ Copying Docutils ...@@ -19,7 +19,7 @@ Copying Docutils
Author: Author:
David Goodger David Goodger
Contact: Contact:
goodger&#64;users.sourceforge.net goodger@users.sourceforge.net
Date: Date:
2002-10-03 2002-10-03
Web site: http://docutils.sourceforge.net/ Web site: http://docutils.sourceforge.net/
......
#
# Runs all tests in the current directory
#
# Execute like:
# python runalltests.py
#
# Alternatively use the testrunner:
# python /path/to/Zope/utilities/testrunner.py -qa
#
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
import unittest
TestRunner = unittest.TextTestRunner
suite = unittest.TestSuite()
tests = os.listdir(os.curdir)
tests = [n[:-3] for n in tests if n.startswith('test') and n.endswith('.py')]
for test in tests:
m = __import__(test)
if hasattr(m, 'test_suite'):
suite.addTest(m.test_suite())
if __name__ == '__main__':
TestRunner().run(suite)
#!/bin/bash
#
# example test runner shell script
#
# full path to the python interpretor
export PYTHON="/usr/local/bin/python2.3"
# path to ZOPE_HOME/lib/python
export SOFTWARE_HOME="/opt/zope/releases/Zope-2_7-branch/lib/python"
# path to your instance. Don't set it if you aren't having instance
export INSTANCE_HOME="/opt/zope/instances/plone21/"
${PYTHON} runalltests.py
...@@ -2,6 +2,7 @@ import unittest ...@@ -2,6 +2,7 @@ import unittest
from zope.testing import doctestunit from zope.testing import doctestunit
modules = ( modules = (
'Products.PortalTransforms.transforms.safe_html',
'Products.PortalTransforms.transforms.rest', 'Products.PortalTransforms.transforms.rest',
) )
......
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
from Testing import ZopeTestCase from Testing import ZopeTestCase
from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
from zope.interface import implements
from Products.PortalTransforms.utils import TransformException from Products.PortalTransforms.utils import TransformException
from Products.PortalTransforms.interfaces import * from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.chain import chain from Products.PortalTransforms.chain import chain
import urllib import urllib
import time import time
import re import re
from zope.interface import implements
class BaseTransform: class BaseTransform:
def name(self): def name(self):
...@@ -20,7 +17,7 @@ class BaseTransform: ...@@ -20,7 +17,7 @@ class BaseTransform:
class HtmlToText(BaseTransform): class HtmlToText(BaseTransform):
implements(itransform) implements(ITransform)
inputs = ('text/html',) inputs = ('text/html',)
output = 'text/plain' output = 'text/plain'
...@@ -37,7 +34,7 @@ class HtmlToTextWithEncoding(HtmlToText): ...@@ -37,7 +34,7 @@ class HtmlToTextWithEncoding(HtmlToText):
output_encoding = 'ascii' output_encoding = 'ascii'
class FooToBar(BaseTransform): class FooToBar(BaseTransform):
implements(itransform) implements(ITransform)
inputs = ('text/*',) inputs = ('text/*',)
output = 'text/plain' output = 'text/plain'
...@@ -50,9 +47,28 @@ class FooToBar(BaseTransform): ...@@ -50,9 +47,28 @@ class FooToBar(BaseTransform):
data.setData(orig) data.setData(orig)
return data return data
class DummyHtmlFilter1(BaseTransform):
implements(ITransform)
__name__ = 'dummy_html_filter1'
inputs = ('text/html',)
output = 'text/html'
def convert(self, orig, data, **kwargs):
data.setData("<span class='dummy'>%s</span>" % orig)
return data
class DummyHtmlFilter2(BaseTransform):
implements(ITransform)
__name__ = 'dummy_html_filter2'
inputs = ('text/html',)
output = 'text/html'
def convert(self, orig, data, **kwargs):
data.setData("<div class='dummy'>%s</div>" % orig)
return data
class TransformNoIO(BaseTransform): class TransformNoIO(BaseTransform):
implements(itransform) implements(ITransform)
class BadTransformMissingImplements(BaseTransform): class BadTransformMissingImplements(BaseTransform):
#__implements__ = None #__implements__ = None
...@@ -60,27 +76,25 @@ class BadTransformMissingImplements(BaseTransform): ...@@ -60,27 +76,25 @@ class BadTransformMissingImplements(BaseTransform):
output = 'text/plain' output = 'text/plain'
class BadTransformBadMIMEType1(BaseTransform): class BadTransformBadMIMEType1(BaseTransform):
implements(itransform) implements(ITransform)
inputs = ('truc/muche',) inputs = ('truc/muche',)
output = 'text/plain' output = 'text/plain'
class BadTransformBadMIMEType2(BaseTransform): class BadTransformBadMIMEType2(BaseTransform):
implements(itransform) implements(ITransform)
inputs = ('text/plain',) inputs = ('text/plain',)
output = 'truc/muche' output = 'truc/muche'
class BadTransformNoInput(BaseTransform): class BadTransformNoInput(BaseTransform):
implements(itransform) implements(ITransform)
inputs = () inputs = ()
output = 'text/plain' output = 'text/plain'
class BadTransformWildcardOutput(BaseTransform): class BadTransformWildcardOutput(BaseTransform):
implements(itransform) implements(ITransform)
inputs = ('text/plain',) inputs = ('text/plain',)
output = 'text/*' output = 'text/*'
class TestEngine(ATSiteTestCase): class TestEngine(ATSiteTestCase):
def afterSetUp(self): def afterSetUp(self):
...@@ -159,6 +173,34 @@ class TestEngine(ATSiteTestCase): ...@@ -159,6 +173,34 @@ class TestEngine(ATSiteTestCase):
self.failUnlessEqual(cache.getData(), "bar") self.failUnlessEqual(cache.getData(), "bar")
self.failUnlessEqual(cache.name(), "hbar") self.failUnlessEqual(cache.name(), "hbar")
def testPolicy(self):
mt = 'text/x-html-safe'
data = '<script>this_is_unsafe();</script><p>this is safe</p>'
cache = self.engine.convertTo(mt, data, mimetype='text/html')
self.failUnlessEqual(cache.getData(), '<p>this is safe</p>')
self.engine.registerTransform(DummyHtmlFilter1())
self.engine.registerTransform(DummyHtmlFilter2())
required = ['dummy_html_filter1', 'dummy_html_filter2']
self.engine.manage_addPolicy(mt, required)
expected_policy = [('text/x-html-safe',
('dummy_html_filter1', 'dummy_html_filter2'))]
self.failUnlessEqual(self.engine.listPolicies(), expected_policy)
cache = self.engine.convertTo(mt, data, mimetype='text/html')
self.failUnlessEqual(cache.getData(), '<div class="dummy"><span class="dummy"><p>this is safe</p></span></div>')
self.failUnlessEqual(cache.getMetadata()['mimetype'], mt)
self.failUnlessEqual(cache.name(), mt)
path = self.engine._findPath('text/html', mt, required)
self.failUnlessEqual(str(path),
"[<Transform at dummy_html_filter1>, "
"<Transform at dummy_html_filter2>, "
"<Transform at safe_html>]")
def testSame(self): def testSame(self):
data = "This is a test" data = "This is a test"
mt = "text/plain" mt = "text/plain"
...@@ -187,6 +229,3 @@ def test_suite(): ...@@ -187,6 +229,3 @@ def test_suite():
suite = TestSuite() suite = TestSuite()
suite.addTest(makeSuite(TestEngine)) suite.addTest(makeSuite(TestEngine))
return suite return suite
if __name__ == '__main__':
framework()
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
from Testing import ZopeTestCase
from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
from utils import input_file_path from utils import input_file_path
...@@ -15,10 +10,17 @@ class TestGraph(ATSiteTestCase): ...@@ -15,10 +10,17 @@ class TestGraph(ATSiteTestCase):
self.engine = self.portal.portal_transforms self.engine = self.portal.portal_transforms
def testGraph(self): def testGraph(self):
### XXX Local file and expected output
data = open(FILE_PATH, 'r').read() data = open(FILE_PATH, 'r').read()
requirements = self.engine._policies.get('text/plain', [])
if requirements:
out = self.engine.convertTo('text/plain', data, filename=FILE_PATH) out = self.engine.convertTo('text/plain', data, filename=FILE_PATH)
assert(out.getData()) self.failUnless(out.getData())
def testIdentity(self):
orig = 'Some text'
converted = self.engine.convertTo(
'text/plain', 'Some text', mimetype='text/plain')
self.assertEquals(orig, str(converted))
def test_suite(): def test_suite():
...@@ -26,6 +28,3 @@ def test_suite(): ...@@ -26,6 +28,3 @@ def test_suite():
suite = TestSuite() suite = TestSuite()
suite.addTest(makeSuite(TestGraph)) suite.addTest(makeSuite(TestGraph))
return suite return suite
if __name__ == '__main__':
framework()
# -*- coding: utf-8 -*-
from Testing import ZopeTestCase
from Products.CMFCore.utils import getToolByName
from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
class TransformTestCase(ATSiteTestCase):
def afterSetUp(self):
ATSiteTestCase.afterSetUp(self)
self.transforms = self.portal.portal_transforms
class TestIntelligentTextToHtml(TransformTestCase):
def performTransform(self, orig, targetMimetype = 'text/html', mimetype='text/x-web-intelligent'):
return self.transforms.convertTo(targetMimetype, orig, context=self.portal, mimetype=mimetype).getData()
def testHyperlinks(self):
orig = "A test http://test.com"
new = self.performTransform(orig)
self.assertEqual(new, 'A test <a href="http://test.com" rel="nofollow">http://test.com</a>')
def testMailto(self):
orig = "A test test@test.com of mailto"
new = self.performTransform(orig)
self.assertEqual(new, 'A test <a href="&#0109;ailto&#0058;test&#0064;test.com">test&#0064;test.com</a> of mailto')
def testTextAndLinks(self):
orig = """A test
URL: http://test.com End
Mail: test@test.com End
URL: http://foo.com End"""
new = self.performTransform(orig)
self.assertEqual(new, 'A test<br />' \
'URL: <a href="http://test.com" rel="nofollow">http://test.com</a> End<br />' \
'Mail: <a href="&#0109;ailto&#0058;test&#0064;test.com">test&#0064;test.com</a> End<br />' \
'URL: <a href="http://foo.com" rel="nofollow">http://foo.com</a> End')
def testTextAndLinksAtEndOfLine(self):
orig = """A test
URL: http://test.com
Mail: test@test.com
URL: http://foo.com"""
new = self.performTransform(orig)
self.assertEqual(new, 'A test<br />' \
'URL: <a href="http://test.com" rel="nofollow">http://test.com</a><br />' \
'Mail: <a href="&#0109;ailto&#0058;test&#0064;test.com">test&#0064;test.com</a><br />' \
'URL: <a href="http://foo.com" rel="nofollow">http://foo.com</a>')
def testIndents(self):
orig = """A test
URL: http://test.com
Mail: test@test.com
URL: http://foo.com"""
new = self.performTransform(orig)
self.assertEqual(new, 'A test<br />' \
'&nbsp;&nbsp;URL: <a href="http://test.com" rel="nofollow">http://test.com</a><br />' \
'&nbsp;&nbsp;&nbsp;&nbsp;Mail: <a href="&#0109;ailto&#0058;test&#0064;test.com">test&#0064;test.com</a><br />' \
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;URL: <a href="http://foo.com" rel="nofollow">http://foo.com</a>')
def testEntities(self):
orig = "Some & funny < characters"
new = self.performTransform(orig)
self.assertEqual(new, "Some &amp; funny &lt; characters")
def testAccentuatedCharacters(self):
orig = "The French use é à ô ù à and ç"
new = self.performTransform(orig)
self.assertEqual(new, "The French use &eacute; &agrave; &ocirc; &ugrave; &agrave; and &ccedil;")
class TestHtmlToIntelligentText(TransformTestCase):
def performTransform(self, orig, targetMimetype = 'text/x-web-intelligent', mimetype='text/html'):
return self.transforms.convertTo(targetMimetype, orig, context=self.portal, mimetype=mimetype).getData()
def testStripTags(self):
orig = "Some <b>bold</b> text."
new = self.performTransform(orig)
self.assertEqual(new, "Some bold text.")
def testBreaks(self):
orig = "Some<br/>broken<BR/>text<br />"
new = self.performTransform(orig)
self.assertEqual(new, "Some\nbroken\ntext\n")
def testStartBlocks(self):
orig = "A block<dt>there</dt>"
new = self.performTransform(orig)
self.assertEqual(new, "A block\n\nthere")
def testEndBlocks(self):
orig = "<p>Paragraph</p>Other stuff"
new = self.performTransform(orig)
self.assertEqual(new, "Paragraph\n\nOther stuff")
def testIndentBlocks(self):
orig = "A<blockquote>Indented blockquote</blockquote>"
new = self.performTransform(orig)
self.assertEqual(new, "A\n\n Indented blockquote")
def testListBlocks(self):
orig = "A list<ul><li>Foo</li><li>Bar</li></ul>"
new = self.performTransform(orig)
self.assertEqual(new, "A list\n\n - Foo\n\n - Bar\n\n")
def testNbsp(self):
orig = "Some space &nbsp;&nbsp;here"
new = self.performTransform(orig)
self.assertEqual(new, "Some space here")
def testAngles(self):
orig = "Watch &lt;this&gt; and &lsaquo;that&rsaquo;"
new = self.performTransform(orig)
self.assertEqual(new, "Watch <this> and &#8249;that&#8250;")
def testBullets(self):
orig = "A &bull; bullet"
new = self.performTransform(orig)
self.assertEqual(new, "A &#8226; bullet")
def testAmpersands(self):
orig = "An &amp; ampersand"
new = self.performTransform(orig)
self.assertEqual(new, "An & ampersand")
def testEntities(self):
orig = "A &mdash; dash"
new = self.performTransform(orig)
self.assertEqual(new, "A &#8212; dash")
def testPre(self):
orig = "A <pre> pre\n section</pre>"
new = self.performTransform(orig)
self.assertEqual(new, "A \n\n pre\n section\n\n")
def testWhitespace(self):
orig = "A \n\t spaceful, <b> tag-filled</b>, <b> <i> snippet\n</b></i>"
new = self.performTransform(orig)
self.assertEqual(new, "A spaceful, tag-filled, snippet ")
def test_suite():
from unittest import TestSuite, makeSuite
suite = TestSuite()
suite.addTest(makeSuite(TestIntelligentTextToHtml))
suite.addTest(makeSuite(TestHtmlToIntelligentText))
return suite
from __future__ import nested_scopes import os
import logging
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
from Testing import ZopeTestCase from Testing import ZopeTestCase
from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
from utils import input_file_path, output_file_path, normalize_html,\ from utils import input_file_path, output_file_path, normalize_html,\
load, matching_inputs load, matching_inputs
from Products.PortalTransforms.data import datastream from Products.PortalTransforms.data import datastream
from Products.PortalTransforms.interfaces import IDataStream
from Products.PortalTransforms.interfaces import idatastream from Products.PortalTransforms.interfaces import idatastream
from Products.MimetypesRegistry.MimeTypesTool import MimeTypesTool from Products.MimetypesRegistry.MimeTypesTool import MimeTypesTool
from Products.PortalTransforms.TransformEngine import TransformTool from Products.PortalTransforms.TransformEngine import TransformTool
...@@ -23,10 +20,14 @@ from Products.PortalTransforms.transforms.image_to_tiff import image_to_tiff ...@@ -23,10 +20,14 @@ from Products.PortalTransforms.transforms.image_to_tiff import image_to_tiff
from Products.PortalTransforms.transforms.image_to_ppm import image_to_ppm from Products.PortalTransforms.transforms.image_to_ppm import image_to_ppm
from Products.PortalTransforms.transforms.image_to_pcx import image_to_pcx from Products.PortalTransforms.transforms.image_to_pcx import image_to_pcx
from Products.PortalTransforms.transforms.textile_to_html import HAS_TEXTILE
from Products.PortalTransforms.transforms.markdown_to_html import HAS_MARKDOWN
from os.path import exists from os.path import exists
import sys import sys
# we have to set locale because lynx output is locale sensitive ! # we have to set locale because lynx output is locale sensitive !
os.environ['LC_ALL'] = 'C' os.environ['LC_ALL'] = 'C'
logger = logging.getLogger('PortalTransforms')
class TransformTest(ATSiteTestCase): class TransformTest(ATSiteTestCase):
...@@ -40,7 +41,7 @@ class TransformTest(ATSiteTestCase): ...@@ -40,7 +41,7 @@ class TransformTest(ATSiteTestCase):
input.close() input.close()
data = datastream(self.transform.name()) data = datastream(self.transform.name())
res_data = self.transform.convert(orig, data, filename=filename) res_data = self.transform.convert(orig, data, filename=filename)
self.assert_(idatastream.providedBy(res_data)) self.assert_(IDataStream.providedBy(res_data))
got = res_data.getData() got = res_data.getData()
try: try:
output = open(output) output = open(output)
...@@ -63,13 +64,20 @@ class TransformTest(ATSiteTestCase): ...@@ -63,13 +64,20 @@ class TransformTest(ATSiteTestCase):
got, expected, self.transform.name(), self.input)) got, expected, self.transform.name(), self.input))
self.assertEquals(self.subobjects, len(res_data.getSubObjects()), self.assertEquals(self.subobjects, len(res_data.getSubObjects()),
'%s\n\n!=\n\n%s\n\nIN %s(%s)' % ( '%s\n\n!=\n\n%s\n\nIN %s(%s)' % (
self.subobjects, len(res_data.getSubObjects()), self.transform.name(), self.input)) self.subobjects, len(res_data.getSubObjects()),
self.transform.name(), self.input))
def testSame(self): def testSame(self):
try:
self.do_convert(filename=self.input) self.do_convert(filename=self.input)
except MissingBinary, e:
pass
def testSameNoFilename(self): def testSameNoFilename(self):
try:
self.do_convert() self.do_convert()
except MissingBinary, e:
pass
def __repr__(self): def __repr__(self):
return self.transform.name() return self.transform.name()
...@@ -179,9 +187,15 @@ TRANSFORMS_TESTINFO = ( ...@@ -179,9 +187,15 @@ TRANSFORMS_TESTINFO = (
('Products.PortalTransforms.transforms.image_to_pcx', ('Products.PortalTransforms.transforms.image_to_pcx',
"logo.png", "logo.pcx", None, 0 "logo.png", "logo.pcx", None, 0
), ),
)
if HAS_MARKDOWN:
TRANSFORMS_TESTINFO = TRANSFORMS_TESTINFO + (
('Products.PortalTransforms.transforms.markdown_to_html', ('Products.PortalTransforms.transforms.markdown_to_html',
"markdown.txt", "markdown.html", None, 0 "markdown.txt", "markdown.html", None, 0
), ),
)
if HAS_TEXTILE:
TRANSFORMS_TESTINFO = TRANSFORMS_TESTINFO + (
('Products.PortalTransforms.transforms.textile_to_html', ('Products.PortalTransforms.transforms.textile_to_html',
"input.textile", "textile.html", None, 0 "input.textile", "textile.html", None, 0
), ),
...@@ -246,6 +260,3 @@ def test_suite(): ...@@ -246,6 +260,3 @@ def test_suite():
for test in make_tests(): for test in make_tests():
suite.addTest(makeSuite(test)) suite.addTest(makeSuite(test))
return suite return suite
if __name__ == '__main__':
framework()
"""
"""
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
from Testing import ZopeTestCase
from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
class TestXSSFilter(ATSiteTestCase):
def afterSetUp(self):
ATSiteTestCase.afterSetUp(self)
self.engine = self.portal.portal_transforms
def doTest(self, data_in, data_out):
html = self.engine.convertTo('text/x-html-safe', data_in, mimetype="text/html")
self.assertEqual (data_out,html.getData())
def test_1(self):
data_in = """<html><body><img src="javascript:Alert('XSS');" /></body></html>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_2(self):
data_in = """<img src="javascript:Alert('XSS');" />"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_3(self):
data_in = """<html><body><IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;></body></html>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_4(self):
data_in = """<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_5(self):
data_in = """<img src="jav
asc
ript:Alert('XSS');" />"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_6(self):
data_in = """<img src="jav asc ript:Alert('XSS');"/>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_7(self):
data_in = """<a href=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>test med a-tag</a>"""
data_out = """<a>test med a-tag</a>"""
self.doTest(data_in, data_out)
def test_8(self):
data_in = """<div style="bacground:url(jav asc ript:Alert('XSS')">test</div>"""
data_out = """<div>test</div>"""
self.doTest(data_in, data_out)
def test_9(self):
data_in = """<div style="bacground:url(jav
asc
ript:
Alert('XSS')">test</div>"""
data_out = """<div>test</div>"""
self.doTest(data_in, data_out)
def test_10(self):
data_in = """<div style="bacground:url(&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;">test</div>"""
data_out = """<div>test</div>"""
self.doTest(data_in, data_out)
def test_11(self):
data_in = """<div style="bacground:url(v b sc ript:msgbox('XSS')">test</div>"""
data_out = """<div>test</div>"""
self.doTest(data_in, data_out)
def test_12(self):
data_in = """<img src="vbscript:msgbox('XSS')"/>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_13(self):
data_in = """<img src="vb
sc
ript:msgbox('XSS')"/>"""
data_out = """<img />"""
self.doTest(data_in, data_out)
def test_14(self):
data_in = """<a href="vbscript:Alert('XSS')">test</a>"""
data_out = """<a>test</a>"""
self.doTest(data_in, data_out)
def test_15(self):
data_in = """<div STYLE="width: expression(window.location='http://www.dr.dk';);">div</div>"""
data_out = """<div>div</div>"""
self.doTest(data_in, data_out)
def test_16(self):
data_in = """<div STYLE="width: ex pre ss io n(window.location='http://www.dr.dk';);">div</div>"""
data_out = """<div>div</div>"""
self.doTest(data_in, data_out)
def test_17(self):
data_in = """<div STYLE="width: ex
pre
ss
io
n(window.location='http://www.dr.dk';);">div</div>"""
data_out = """<div>div</div>"""
self.doTest(data_in, data_out)
def test_18(self):
data_in = """<div style="width: 14px;">div</div>"""
data_out = data_in
self.doTest(data_in, data_out)
def test_19(self):
data_in = """<a href="http://www.headnet.dk">headnet</a>"""
data_out = data_in
self.doTest(data_in, data_out)
def test_20(self):
data_in = """<img src="http://www.headnet.dk/log.jpg" />"""
data_out = data_in
self.doTest(data_in, data_out)
def test_21(self):
data_in = """<mustapha name="mustap" tlf="11 11 11 11" address="unknown">bla bla bla</mustapha>"""
data_out = """bla bla bla"""
self.doTest(data_in, data_out)
def test_22(self):
data_in = '<<frame></frame>script>alert("XSS");<<frame></frame>/script>'
data_out = '&lt;script&gt;alert("XSS");&lt;/script&gt;'
self.doTest(data_in, data_out)
def test_suite():
from unittest import TestSuite, makeSuite
suite = TestSuite()
suite.addTest(makeSuite(TestXSSFilter))
return suite
if __name__ == '__main__':
framework()
...@@ -43,6 +43,8 @@ modules = [ ...@@ -43,6 +43,8 @@ modules = [
'identity', # identity transform, no dependancies 'identity', # identity transform, no dependancies
'markdown_to_html', # markdown, depends on http://surfnet.dl.sourceforge.net/sourceforge/python-markdown/markdown-1-5.py 'markdown_to_html', # markdown, depends on http://surfnet.dl.sourceforge.net/sourceforge/python-markdown/markdown-1-5.py
'textile_to_html',# textile, depends on PyTextile http://dom.eav.free.fr/python/textile-mirror-2.0.10.tar.gz 'textile_to_html',# textile, depends on PyTextile http://dom.eav.free.fr/python/textile-mirror-2.0.10.tar.gz
'web_intelligent_plain_text_to_html',
'html_to_web_intelligent_plain_text',
] ]
g = globals() g = globals()
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.utils import log
from zope.interface import implements from zope.interface import implements
from Products.PortalTransforms.utils import log
WARNING=100 WARNING=100
class BrokenTransform: class BrokenTransform:
implements(itransform) implements(ITransform)
__name__ = "broken transform" __name__ = "broken transform"
inputs = ("BROKEN",) inputs = ("BROKEN",)
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from Products.CMFDefault.utils import bodyfinder
from zope.interface import implements from zope.interface import implements
from Products.CMFDefault.utils import bodyfinder
class HTMLBody: class HTMLBody:
"""Simple transform which extracts the content of the body tag""" """Simple transform which extracts the content of the body tag"""
implements(itransform) implements(ITransform)
__name__ = "html_body" __name__ = "html_body"
inputs = ('text/html',) inputs = ('text/html',)
......
from Products.PortalTransforms.libtransforms.retransform import retransform from Products.PortalTransforms.libtransforms.retransform import retransform
import htmlentitydefs
class html_to_text(retransform): class html_to_text(retransform):
inputs = ('text/html',) inputs = ('text/html',)
output = 'text/plain' output = 'text/plain'
def register(): def register():
# XXX convert entites with htmlentitydefs.name2codepoint ? def sub_func(matchobj):
full = matchobj.group()
ent = matchobj.group(1)
result = htmlentitydefs.name2codepoint.get(ent)
if result is None:
if ent.startswith('#'):
return unichr(int(ent[1:])).encode('utf-8')
else:
return full
else:
return unichr(result).encode('utf-8')
return html_to_text("html_to_text", return html_to_text("html_to_text",
('<script [^>]>.*</script>(?im)', ' '), ('<script [^>]>.*</script>(?im)', ' '),
('<style [^>]>.*</style>(?im)', ' '), ('<style [^>]>.*</style>(?im)', ' '),
...@@ -16,4 +29,5 @@ def register(): ...@@ -16,4 +29,5 @@ def register():
('(?im)</?(font|em|i|strong|b)(?=\W)[^>]*>', ''), ('(?im)</?(font|em|i|strong|b)(?=\W)[^>]*>', ''),
('<[^>]*>(?i)(?m)', ' '), ('<[^>]*>(?i)(?m)', ' '),
(r'&([a-zA-Z0-9#]*?);', sub_func),
) )
from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from plone.intelligenttext.transforms import convertHtmlToWebIntelligentPlainText
class HtmlToWebIntelligentPlainText:
"""Transform which replaces urls and email into hyperlinks"""
implements(ITransform)
__name__ = "html_to_web_intelligent_plain_text"
output = "text/x-web-intelligent"
def __init__(self, name=None, inputs=('text/html',), tab_width = 4):
self.config = { 'inputs' : inputs, 'tab_width' : 4}
self.config_metadata = {
'inputs' : ('list', 'Inputs', 'Input(s) MIME type. Change with care.'),
'tab_width' : ('string', 'Tab width', 'Number of spaces for a tab in the input')
}
if name:
self.__name__ = name
def name(self):
return self.__name__
def __getattr__(self, attr):
if attr in self.config:
return self.config[attr]
raise AttributeError(attr)
def convert(self, orig, data, **kwargs):
text = convertHtmlToWebIntelligentPlainText(orig)
data.setData(text)
return data
def register():
return HtmlToWebIntelligentPlainText()
...@@ -4,7 +4,7 @@ A simple identity transform ...@@ -4,7 +4,7 @@ A simple identity transform
__revision__ = '$Id: identity.py 4787 2005-08-19 21:43:41Z dreamcatcher $' __revision__ = '$Id: identity.py 4787 2005-08-19 21:43:41Z dreamcatcher $'
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements from zope.interface import implements
class IdentityTransform: class IdentityTransform:
...@@ -12,7 +12,7 @@ class IdentityTransform: ...@@ -12,7 +12,7 @@ class IdentityTransform:
return content unchanged. return content unchanged.
""" """
implements(itransform,) implements(ITransform)
__name__ = "rest_to_text" __name__ = "rest_to_text"
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements from zope.interface import implements
class image_to_html: class image_to_html:
implements(itransform) implements(ITransform)
__name__ = "image_to_html" __name__ = "image_to_html"
inputs = ('image/*', ) inputs = ('image/*', )
......
""" """
Uses lynx -dump Uses lynx -dump
""" """
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.libtransforms.commandtransform import popentransform from Products.PortalTransforms.libtransforms.commandtransform import popentransform
import os import os
from zope.interface import implements
class lynx_dump(popentransform): class lynx_dump(popentransform):
implements(itransform) implements(ITransform)
__name__ = "lynx_dump" __name__ = "lynx_dump"
inputs = ('text/html',) inputs = ('text/html',)
...@@ -22,7 +22,7 @@ class lynx_dump(popentransform): ...@@ -22,7 +22,7 @@ class lynx_dump(popentransform):
useStdin = True useStdin = True
class old_lynx_dump(commandtransform): class old_lynx_dump(commandtransform):
implements(itransform) implements(ITransform)
__name__ = "lynx_dump" __name__ = "lynx_dump"
inputs = ('text/html',) inputs = ('text/html',)
......
...@@ -4,24 +4,29 @@ Uses the http://www.freewisdom.org/projects/python-markdown/ module to do its ha ...@@ -4,24 +4,29 @@ Uses the http://www.freewisdom.org/projects/python-markdown/ module to do its ha
author: Tom Lazar <tom@tomster.org> at the archipelago sprint 2006 author: Tom Lazar <tom@tomster.org> at the archipelago sprint 2006
""" """
from Products.PortalTransforms.interfaces import itransform
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.CMFDefault.utils import bodyfinder
import os import os
from zope.interface import implements from zope.interface import implements
from Products.CMFDefault.utils import bodyfinder
from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.libtransforms.utils import bin_search
from Products.PortalTransforms.libtransforms.utils import sansext
from Products.PortalTransforms.utils import log
try: try:
import markdown as markdown_transformer import markdown as markdown_transformer
except ImportError: except ImportError:
HAS_MARKDOWN = False HAS_MARKDOWN = False
log('markdown_to_html: Could not import python-markdown.')
else: else:
HAS_MARKDOWN = True HAS_MARKDOWN = True
class markdown: class markdown:
implements(itransform) implements(ITransform)
__name__ = "markdown_to_html" __name__ = "markdown_to_html"
inputs = ("text/x-web-markdown",) inputs = ("text/x-web-markdown",)
......
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
Uses the http://sf.net/projects/pdftohtml bin to do its handy work Uses the http://sf.net/projects/pdftohtml bin to do its handy work
""" """
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.libtransforms.commandtransform import popentransform from Products.PortalTransforms.libtransforms.commandtransform import popentransform
from Products.CMFDefault.utils import bodyfinder from Products.CMFDefault.utils import bodyfinder
import os import os
from zope.interface import implements
class popen_pdf_to_html(popentransform): class popen_pdf_to_html(popentransform):
implements(itransform) implements(ITransform)
__version__ = '2004-07-02.01' __version__ = '2004-07-02.01'
...@@ -28,7 +28,7 @@ class popen_pdf_to_html(popentransform): ...@@ -28,7 +28,7 @@ class popen_pdf_to_html(popentransform):
return bodyfinder(couterr.read()) return bodyfinder(couterr.read())
class pdf_to_html(commandtransform): class pdf_to_html(commandtransform):
implements(itransform) implements(ITransform)
__name__ = "pdf_to_html" __name__ = "pdf_to_html"
inputs = ('application/pdf',) inputs = ('application/pdf',)
......
...@@ -3,16 +3,16 @@ ...@@ -3,16 +3,16 @@
Uses the xpdf (www.foolabs.com/xpdf) Uses the xpdf (www.foolabs.com/xpdf)
""" """
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.libtransforms.commandtransform import popentransform from Products.PortalTransforms.libtransforms.commandtransform import popentransform
from Products.PortalTransforms.libtransforms.commandtransform import subprocesstransform from Products.PortalTransforms.libtransforms.commandtransform import subprocesstransform
import os import os
from zope.interface import implements
class pdf_to_text(subprocesstransform): class pdf_to_text(subprocesstransform):
implements(itransform) implements(ITransform)
__name__ = "pdf_to_text" __name__ = "pdf_to_text"
inputs = ('application/pdf',) inputs = ('application/pdf',)
...@@ -26,7 +26,7 @@ class pdf_to_text(subprocesstransform): ...@@ -26,7 +26,7 @@ class pdf_to_text(subprocesstransform):
useStdin = True useStdin = True
class old_pdf_to_text(commandtransform): class old_pdf_to_text(commandtransform):
implements(itransform) implements(ITransform)
__name__ = "pdf_to_text" __name__ = "pdf_to_text"
inputs = ('application/pdf',) inputs = ('application/pdf',)
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.libtransforms.commandtransform \ from Products.PortalTransforms.libtransforms.commandtransform \
import popentransform import popentransform
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
...@@ -8,7 +8,7 @@ import tempfile ...@@ -8,7 +8,7 @@ import tempfile
from zope.interface import implements from zope.interface import implements
class png_to_text(popentransform): class png_to_text(popentransform):
implements(itransform) implements(ITransform)
__name__ = "png_to_text" __name__ = "png_to_text"
inputs = ('image/png',) inputs = ('image/png',)
......
...@@ -19,9 +19,9 @@ import string ...@@ -19,9 +19,9 @@ import string
import keyword, token, tokenize import keyword, token, tokenize
from cStringIO import StringIO from cStringIO import StringIO
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from DocumentTemplate.DT_Util import html_quote
from zope.interface import implements from zope.interface import implements
from DocumentTemplate.DT_Util import html_quote
## Python Source Parser ##################################################### ## Python Source Parser #####################################################
...@@ -110,7 +110,7 @@ class Parser: ...@@ -110,7 +110,7 @@ class Parser:
class PythonTransform: class PythonTransform:
"""Colorize Python source files """Colorize Python source files
""" """
implements(itransform) implements(ITransform)
__name__ = "python_to_html" __name__ = "python_to_html"
inputs = ("text/x-python",) inputs = ("text/x-python",)
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from reStructuredText import HTML from reStructuredText import HTML
import sys import sys
from zope.interface import implements
class rest: class rest:
r"""Converts from reST to HTML. r"""Converts from reST to HTML.
...@@ -20,22 +20,28 @@ class rest: ...@@ -20,22 +20,28 @@ class rest:
default: default:
>>> try: >>> try:
... transform.convert('.. raw:: html\n :file: <isonum.txt>', D()) ... out = transform.convert('.. raw:: html\n :file: <isonum.txt>', D())
... except NotImplementedError: ... except NotImplementedError:
... print 'Good' ... print 'Good'
... else: ... else:
... if "&quot;raw&quot; directive disabled." in out.value:
... print 'Good'
... else:
... print 'Failure' ... print 'Failure'
Good Good
>>> try: >>> try:
... transform.convert('.. include:: <isonum.txt>', D()) ... out = transform.convert('.. include:: <isonum.txt>', D())
... except NotImplementedError: ... except NotImplementedError:
... print 'Good' ... print 'Good'
... else: ... else:
... if "&quot;include&quot; directive disabled." in out.value:
... print 'Good'
... else:
... print 'Failure' ... print 'Failure'
Good Good
""" """
implements(itransform) implements(ITransform)
__name__ = "rest_to_html" __name__ = "rest_to_html"
inputs = ("text/x-rst", "text/restructured",) inputs = ("text/x-rst", "text/restructured",)
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
Uses the http://freshmeat.net/projects/rtfconverter/ bin to do its handy work Uses the http://freshmeat.net/projects/rtfconverter/ bin to do its handy work
""" """
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.CMFDefault.utils import bodyfinder from Products.CMFDefault.utils import bodyfinder
from zope.interface import implements
import os import os
class rtf_to_html(commandtransform): class rtf_to_html(commandtransform):
implements(itransform) implements(ITransform)
__name__ = "rtf_to_html" __name__ = "rtf_to_html"
inputs = ('application/rtf',) inputs = ('application/rtf',)
......
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
Uses the http://sf.net/projects/rtf2xml bin to do its handy work Uses the http://sf.net/projects/rtf2xml bin to do its handy work
""" """
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
import os import os
from zope.interface import implements
class rtf_to_xml(commandtransform): class rtf_to_xml(commandtransform):
implements(itransform) implements(ITransform)
__name__ = "rtf_to_xml" __name__ = "rtf_to_xml"
inputs = ('application/rtf',) inputs = ('application/rtf',)
......
...@@ -3,9 +3,9 @@ from zLOG import ERROR ...@@ -3,9 +3,9 @@ from zLOG import ERROR
from HTMLParser import HTMLParser, HTMLParseError from HTMLParser import HTMLParser, HTMLParseError
import re import re
from cgi import escape from cgi import escape
from zope.interface import implements
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.utils import log from Products.PortalTransforms.utils import log
from Products.CMFDefault.utils import IllegalHTML from Products.CMFDefault.utils import IllegalHTML
from Products.CMFDefault.utils import SimpleHTMLParser from Products.CMFDefault.utils import SimpleHTMLParser
...@@ -88,7 +88,8 @@ msg_pat = """ ...@@ -88,7 +88,8 @@ msg_pat = """
ALLOWED_HTTP_EQUIV_VALUE_LIST = ('content-type',) ALLOWED_HTTP_EQUIV_VALUE_LIST = ('content-type',)
def hasScript(s): def hasScript(s):
""" """Dig out evil Java/VB script inside an HTML attribute.
>>> hasScript('script:evil(1);') >>> hasScript('script:evil(1);')
True True
>>> hasScript('expression:evil(1);') >>> hasScript('expression:evil(1);')
...@@ -196,6 +197,7 @@ class StrippingParser(HTMLParser): ...@@ -196,6 +197,7 @@ class StrippingParser(HTMLParser):
self.result.append('<' + tag) self.result.append('<' + tag)
remove_script = getattr(self,'remove_javascript',True) remove_script = getattr(self,'remove_javascript',True)
for k, v in attrs: for k, v in attrs:
if remove_script and k.strip().lower().startswith('on'): if remove_script and k.strip().lower().startswith('on'):
if not self.raise_error: continue if not self.raise_error: continue
...@@ -275,7 +277,7 @@ class SafeHTML: ...@@ -275,7 +277,7 @@ class SafeHTML:
-> Flush Cache. -> Flush Cache.
""" """
implements(itransform) implements(ITransform)
__name__ = "safe_html" __name__ = "safe_html"
inputs = ('text/html',) inputs = ('text/html',)
......
from StructuredText.StructuredText import HTML from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.interfaces import itransform
from zope.interface import implements from zope.interface import implements
from zope.structuredtext import stx2html
DEFAULT_STX_LEVEL = 2 DEFAULT_STX_LEVEL = 2
STX_LEVEL = DEFAULT_STX_LEVEL STX_LEVEL = DEFAULT_STX_LEVEL
class st: class st:
implements(itransform) implements(ITransform)
__name__ = "st_to_html" __name__ = "st_to_html"
inputs = ("text/structured",) inputs = ("text/structured",)
...@@ -18,7 +18,7 @@ class st: ...@@ -18,7 +18,7 @@ class st:
def convert(self, orig, data, level=None, **kwargs): def convert(self, orig, data, level=None, **kwargs):
if level is None: if level is None:
level = STX_LEVEL level = STX_LEVEL
data.setData(HTML(orig, level=level, header=0)) data.setData(stx2html(orig, level=level, header=0))
return data return data
def register(): def register():
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from DocumentTemplate.DT_Util import html_quote
from zope.interface import implements from zope.interface import implements
from DocumentTemplate.DT_Util import html_quote
__revision__ = '$Id: text_pre_to_html.py 3658 2005-02-23 16:29:54Z tiran $' __revision__ = '$Id: text_pre_to_html.py 3658 2005-02-23 16:29:54Z tiran $'
class TextPreToHTML: class TextPreToHTML:
"""simple transform which wraps raw text into a <pre> tag""" """simple transform which wraps raw text into a <pre> tag"""
implements(itransform) implements(ITransform)
__name__ = "text-pre_to_html" __name__ = "text-pre_to_html"
inputs = ('text/plain-pre',) inputs = ('text/plain-pre',)
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from DocumentTemplate.DT_Util import html_quote
from zope.interface import implements from zope.interface import implements
from DocumentTemplate.DT_Util import html_quote
__revision__ = '$Id: text_to_html.py 4787 2005-08-19 21:43:41Z dreamcatcher $' __revision__ = '$Id: text_to_html.py 4787 2005-08-19 21:43:41Z dreamcatcher $'
class TextToHTML: class TextToHTML:
"""simple transform which wrap raw text in a verbatim environment""" """simple transform which wrap raw text in a verbatim environment"""
implements(itransform) implements(ITransform)
__name__ = "text_to_html" __name__ = "text_to_html"
output = "text/html" output = "text/html"
......
...@@ -4,24 +4,30 @@ Uses Roberto A. F. De Almeida's http://dealmeida.net/ module to do its handy wor ...@@ -4,24 +4,30 @@ Uses Roberto A. F. De Almeida's http://dealmeida.net/ module to do its handy wor
author: Tom Lazar <tom@tomster.org> at the archipelago sprint 2006 author: Tom Lazar <tom@tomster.org> at the archipelago sprint 2006
""" """
from Products.PortalTransforms.interfaces import itransform
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.CMFDefault.utils import bodyfinder
import os import os
from zope.interface import implements from zope.interface import implements
from Products.CMFDefault.utils import bodyfinder
from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.libtransforms.utils import bin_search
from Products.PortalTransforms.libtransforms.utils import sansext
from Products.PortalTransforms.utils import log
try: try:
import textile as textile_transformer import textile as textile_transformer
except ImportError: except ImportError:
HAS_TEXTILE = False HAS_TEXTILE = False
log('textile_to_html: Could not import textile.')
else: else:
HAS_TEXTILE = True HAS_TEXTILE = True
class textile: class textile:
implements(itransform) implements(ITransform)
__name__ = "textile_to_html" __name__ = "textile_to_html"
inputs = ("text/x-web-textile",) inputs = ("text/x-web-textile",)
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# #
############################################################################## ##############################################################################
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from Products.PortalTransforms.libtransforms.commandtransform import\ from Products.PortalTransforms.libtransforms.commandtransform import\
subprocesstransform subprocesstransform
from zope.interface import implements from zope.interface import implements
...@@ -35,7 +35,7 @@ from zope.interface import implements ...@@ -35,7 +35,7 @@ from zope.interface import implements
# Conversor using w3m to replace lynx at PortalTransforms... # Conversor using w3m to replace lynx at PortalTransforms...
class w3m_dump(subprocesstransform): class w3m_dump(subprocesstransform):
implements(itransform) implements(ITransform)
__name__ = "w3m_dump" __name__ = "w3m_dump"
inputs = ('text/html',) inputs = ('text/html',)
......
from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from plone.intelligenttext.transforms import convertWebIntelligentPlainTextToHtml
class WebIntelligentPlainTextToHtml:
"""Transform which replaces urls and email into hyperlinks"""
implements(ITransform)
__name__ = "web_intelligent_plain_text_to_html"
output = "text/html"
def __init__(self, name=None, inputs=('text/x-web-intelligent',), tab_width = 4):
self.config = { 'inputs' : inputs, 'tab_width' : 4}
self.config_metadata = {
'inputs' : ('list', 'Inputs', 'Input(s) MIME type. Change with care.'),
'tab_width' : ('string', 'Tab width', 'Number of spaces for a tab in the input')
}
if name:
self.__name__ = name
def name(self):
return self.__name__
def __getattr__(self, attr):
if attr in self.config:
return self.config[attr]
raise AttributeError(attr)
def convert(self, orig, data, **kwargs):
text = convertWebIntelligentPlainTextToHtml(orig, tab_width=self.tab_width)
data.setData(text)
return data
def register():
return WebIntelligentPlainTextToHtml()
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements from zope.interface import implements
EXTRACT_BODY = 1 EXTRACT_BODY = 1
...@@ -31,7 +31,7 @@ else: ...@@ -31,7 +31,7 @@ else:
import os.path import os.path
class word_to_html: class word_to_html:
implements(itransform) implements(ITransform)
__name__ = "word_to_html" __name__ = "word_to_html"
inputs = ('application/msword',) inputs = ('application/msword',)
......
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements from zope.interface import implements
from lxml import etree from lxml import etree
class xml_to_text: class xml_to_text:
implements(itransform) implements(ITransform)
__name__ = 'xml_to_text' __name__ = 'xml_to_text'
inputs = ('text/xml', 'application/xml') inputs = ('text/xml', 'application/xml')
......
...@@ -6,11 +6,11 @@ __revision__ = '$Id: command.py 4439 2005-06-15 16:32:36Z panjunyong $' ...@@ -6,11 +6,11 @@ __revision__ = '$Id: command.py 4439 2005-06-15 16:32:36Z panjunyong $'
import os.path import os.path
from os import popen3 from os import popen3
from Products.PortalTransforms.interfaces import itransform from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.utils import log from Products.PortalTransforms.utils import log
from zope.interface import implements
class ExternalCommandTransform(commandtransform): class ExternalCommandTransform(commandtransform):
""" Custom external command """ Custom external command
...@@ -21,7 +21,7 @@ class ExternalCommandTransform(commandtransform): ...@@ -21,7 +21,7 @@ class ExternalCommandTransform(commandtransform):
the command line parameters) and return output on stdout. the command line parameters) and return output on stdout.
Input and output mime types must be set correctly ! Input and output mime types must be set correctly !
""" """
implements(itransform,) implements(ITransform)
__name__ = "command_transform" __name__ = "command_transform"
......
...@@ -9,8 +9,8 @@ import re ...@@ -9,8 +9,8 @@ import re
from os import popen3, popen4, system from os import popen3, popen4, system
from cStringIO import StringIO from cStringIO import StringIO
from Products.PortalTransforms.interfaces import ITransform
from zope.interface import implements from zope.interface import implements
from Products.PortalTransforms.interfaces import itransform
from Products.PortalTransforms.libtransforms.utils import bin_search, sansext from Products.PortalTransforms.libtransforms.utils import bin_search, sansext
from Products.PortalTransforms.libtransforms.commandtransform import commandtransform from Products.PortalTransforms.libtransforms.commandtransform import commandtransform
from Products.PortalTransforms.utils import log from Products.PortalTransforms.utils import log
...@@ -24,7 +24,7 @@ class XsltTransform(commandtransform): ...@@ -24,7 +24,7 @@ class XsltTransform(commandtransform):
You can associate different document type to different transformations. You can associate different document type to different transformations.
""" """
implements(itransform,) implements(ITransform)
__name__ = "xml_to_html" __name__ = "xml_to_html"
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""some common utilities """some common utilities
""" """
from time import time
from types import UnicodeType, StringType
STRING_TYPES = (UnicodeType, StringType)
class TransformException(Exception): class TransformException(Exception):
pass pass
...@@ -22,20 +18,10 @@ def log(message, severity=INFO): ...@@ -22,20 +18,10 @@ def log(message, severity=INFO):
# directory where template for the ZMI are located # directory where template for the ZMI are located
import os.path import os.path
_www = os.path.join(os.path.dirname(__file__), 'www') _www = os.path.join(os.path.dirname(__file__), 'www')
skins_dir = os.path.join(os.path.dirname(__file__), 'skins')
from zExceptions import BadRequest
# directory where template for the ZMI are located
import os.path
_www = os.path.join(os.path.dirname(__file__), 'www')
skins_dir = None
def safeToInt(value): def safeToInt(value):
"""Convert value to integer or just return 0 if we can't""" """Convert value to integer or just return 0 if we can't"""
try: try:
return int(value) return int(value)
except ValueError: except (TypeError, ValueError):
return 0
except TypeError:
return 0 return 0
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