[Checkins] SVN: z3c.amf/ flash/amf in zope2. Initial import
Jean-Fran�ois Roche
jfroche at jfroche.be
Mon Nov 17 18:14:33 EST 2008
Log message for revision 93063:
flash/amf in zope2. Initial import
Changed:
A z3c.amf/
A z3c.amf/branches/
A z3c.amf/tags/
A z3c.amf/trunk/
A z3c.amf/trunk/.installed.cfg
A z3c.amf/trunk/bootstrap.py
A z3c.amf/trunk/buildout.cfg
A z3c.amf/trunk/docs/
A z3c.amf/trunk/docs/HISTORY.txt
A z3c.amf/trunk/setup.cfg
A z3c.amf/trunk/setup.py
A z3c.amf/trunk/z3c/
A z3c.amf/trunk/z3c/__init__.py
A z3c.amf/trunk/z3c/amf/
A z3c.amf/trunk/z3c/amf/HTTPRequest.py
A z3c.amf/trunk/z3c/amf/README.txt
A z3c.amf/trunk/z3c/amf/__init__.py
A z3c.amf/trunk/z3c/amf/amfgateway.py
A z3c.amf/trunk/z3c/amf/browser/
A z3c.amf/trunk/z3c/amf/browser/__init__.py
A z3c.amf/trunk/z3c/amf/browser/configure.zcml
A z3c.amf/trunk/z3c/amf/browser/crossdomain.xml
A z3c.amf/trunk/z3c/amf/configure.zcml
A z3c.amf/trunk/z3c/amf/ftesting.zcml
A z3c.amf/trunk/z3c/amf/ftests.py
A z3c.amf/trunk/z3c/amf/interfaces.py
A z3c.amf/trunk/z3c/amf/meta.zcml
A z3c.amf/trunk/z3c/amf/metaconfigure.py
A z3c.amf/trunk/z3c/amf/metadirectives.py
A z3c.amf/trunk/z3c/amf/patch.py
A z3c.amf/trunk/z3c/amf/permissions.py
A z3c.amf/trunk/z3c/amf/tests/
A z3c.amf/trunk/z3c/amf/tests/__init__.py
A z3c.amf/trunk/z3c/amf/tests/amf.zcml
A z3c.amf/trunk/z3c/amf/tests/amf_error.zcml
A z3c.amf/trunk/z3c/amf/tests/test_directives.py
-=-
Added: z3c.amf/trunk/.installed.cfg
===================================================================
--- z3c.amf/trunk/.installed.cfg (rev 0)
+++ z3c.amf/trunk/.installed.cfg 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,65 @@
+[buildout]
+installed_develop_eggs = /svn/z3c.amf/develop-eggs/z3c.amf.egg-link
+parts = zope2 instance test
+
+[zope2]
+__buildout_installed__ = /svn/z3c.amf/parts/zope2
+__buildout_signature__ = plone.recipe.zope2install-2.5-py2.4.egg setuptools-0.6c9-py2.4.egg zc.buildout-1.1.1-py2.4.egg
+executable = /svn/z3c.amf/bin/python2.4
+fake-zope-eggs = true
+location = /svn/z3c.amf/parts/zope2
+recipe = plone.recipe.zope2install
+skip-fake-eggs = zope.testing
+url = http://www.zope.org/Products/Zope/2.10.6/Zope-2.10.6-final.tgz
+
+[instance]
+__buildout_installed__ = /svn/z3c.amf/parts/instance
+__buildout_signature__ = plone.recipe.zope2instance-2.6-py2.4.egg zc.recipe.egg-1.1.0-py2.4.egg setuptools-0.6c9-py2.4.egg zc.buildout-1.1.1-py2.4.egg zc.buildout-1.1.1-py2.4.egg
+_b = /svn/z3c.amf/bin
+_d = /svn/z3c.amf/develop-eggs
+_e = /svn/z3c.amf/eggs
+bin-directory = /svn/z3c.amf/bin
+debug-mode = on
+develop-eggs-directory = /svn/z3c.amf/develop-eggs
+eggs = %(__buildout_space_n__)s%(__buildout_space_n__)szope.testing
+ z3c.amf
+eggs-directory = /svn/z3c.amf/eggs
+executable = /svn/z3c.amf/bin/python2.4
+location = /svn/z3c.amf/parts/instance
+recipe = plone.recipe.zope2instance
+scripts =
+user = admin:admin
+verbose-security = on
+zcml = %(__buildout_space_n__)sz3c.amf-meta
+ z3c.amf
+zope2-location = /svn/z3c.amf/parts/zope2
+
+[test]
+__buildout_installed__ = /svn/z3c.amf/parts/test
+ /svn/z3c.amf/bin/test
+__buildout_signature__ = zc.recipe.testrunner-1.1.0-py2.4.egg zc.recipe.egg-1.1.0-py2.4.egg setuptools-0.6c9-py2.4.egg zope.testing-3.7.1-py2.4.egg zc.buildout-1.1.1-py2.4.egg zc.buildout-1.1.1-py2.4.egg zope.interface-/ZDECtRPNxDRwonKEero+A==
+_b = /svn/z3c.amf/bin
+_d = /svn/z3c.amf/develop-eggs
+_e = /svn/z3c.amf/eggs
+bin-directory = /svn/z3c.amf/bin
+defaults = ['--tests-pattern', '^f?tests$', '-c', '--module=z3c.amf']
+develop-eggs-directory = /svn/z3c.amf/develop-eggs
+eggs = z3c.amf
+eggs-directory = /svn/z3c.amf/eggs
+executable = /svn/z3c.amf/bin/python2.4
+extra-paths = /svn/z3c.amf/parts/zope2/lib/python
+location = /svn/z3c.amf/parts/test
+recipe = zc.recipe.testrunner
+script = /svn/z3c.amf/bin/test
+
+[buildout]
+installed_develop_eggs = /svn/z3c.amf/develop-eggs/z3c.amf.egg-link
+
+[buildout]
+parts = instance test zope2
+
+[buildout]
+parts = test zope2 instance
+
+[buildout]
+parts = zope2 instance test
Added: z3c.amf/trunk/bootstrap.py
===================================================================
--- z3c.amf/trunk/bootstrap.py (rev 0)
+++ z3c.amf/trunk/bootstrap.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: z3c.amf/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/buildout.cfg
===================================================================
--- z3c.amf/trunk/buildout.cfg (rev 0)
+++ z3c.amf/trunk/buildout.cfg 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,40 @@
+[buildout]
+parts =
+ instance
+ test
+
+find-links =
+
+develop =
+ .
+
+eggs =
+
+unzip = true
+
+[zope2]
+recipe = plone.recipe.zope2install
+url = http://www.zope.org/Products/Zope/2.10.6/Zope-2.10.6-final.tgz
+fake-zope-eggs = true
+skip-fake-eggs = zope.testing
+
+[instance]
+recipe = plone.recipe.zope2instance
+zope2-location = ${zope2:location}
+user = admin:admin
+verbose-security = on
+debug-mode = on
+eggs =
+ ${buildout:eggs}
+ zope.testing
+ z3c.amf
+
+zcml =
+ z3c.amf-meta
+ z3c.amf
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.amf
+defaults = ['--tests-pattern', '^f?tests$', '-c', '--module=z3c.amf']
+extra-paths = ${zope2:location}/lib/python
Added: z3c.amf/trunk/docs/HISTORY.txt
===================================================================
--- z3c.amf/trunk/docs/HISTORY.txt (rev 0)
+++ z3c.amf/trunk/docs/HISTORY.txt 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,8 @@
+Changelog
+=========
+
+0.1 - (2008-11-17)
+------------------
+
+* Initial release
+
Property changes on: z3c.amf/trunk/docs/HISTORY.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.amf/trunk/setup.cfg
===================================================================
--- z3c.amf/trunk/setup.cfg (rev 0)
+++ z3c.amf/trunk/setup.cfg 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
Added: z3c.amf/trunk/setup.py
===================================================================
--- z3c.amf/trunk/setup.py (rev 0)
+++ z3c.amf/trunk/setup.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,41 @@
+from setuptools import setup, find_packages
+import os
+
+version = '0.1'
+
+setup(name='z3c.amf',
+ version=version,
+ description="Zope support for Flash messages (AMF)",
+ long_description=open(os.path.join("z3c", "amf",
+ "README.txt")).read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ classifiers=[
+ "Environment :: Web Environment",
+ "Framework :: Zope2",
+ "Framework :: Zope3",
+ "License :: OSI Approved :: Zope Public License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Topic :: Internet :: WWW/HTTP :: Site Management",
+ "Programming Language :: Python",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+ keywords='Zope2 Zope AMF Flash Flex',
+ author='Jean-Francois Roche',
+ author_email='jfroche at affinitic.be',
+ url='http://svn.zope.org/z3c.amf',
+ license='ZPL 2.1',
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['z3c'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ 'pyamf',
+ 'Products.CMFCore',
+ 'Products.PluggableAuthService'
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Property changes on: z3c.amf/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/__init__.py
===================================================================
--- z3c.amf/trunk/z3c/__init__.py (rev 0)
+++ z3c.amf/trunk/z3c/__init__.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Property changes on: z3c.amf/trunk/z3c/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/HTTPRequest.py
===================================================================
--- z3c.amf/trunk/z3c/amf/HTTPRequest.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/HTTPRequest.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,718 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+$Id$
+"""
+
+import re
+from cgi import FieldStorage, escape
+from ZPublisher.HTTPRequest import *
+from ZPublisher.Converters import get_converter
+from copy import deepcopy
+from ZPublisher.TaintedString import TaintedString
+from zope.interface import directlyProvides
+from z3c.amf.interfaces import IAMFRequest
+
+xmlrpc=None # Placeholder for module that we'll import if we have to.
+amfgateway=None
+
+def processInputs(
+ self,
+ # "static" variables that we want to be local for speed
+ SEQUENCE=1,
+ DEFAULT=2,
+ RECORD=4,
+ RECORDS=8,
+ REC=12, # RECORD|RECORDS
+ EMPTY=16,
+ CONVERTED=32,
+ hasattr=hasattr,
+ getattr=getattr,
+ setattr=setattr,
+ search_type=re.compile('(:[a-zA-Z][-a-zA-Z0-9_]+|\\.[xy])$').search,
+ ):
+ """Process request inputs
+
+ We need to delay input parsing so that it is done under
+ publisher control for error handling purposes.
+ """
+ response=self.response
+ environ=self.environ
+ method=environ.get('REQUEST_METHOD','GET')
+
+ if method != 'GET': fp=self.stdin
+ else: fp=None
+
+ form=self.form
+ other=self.other
+ taintedform=self.taintedform
+ meth=None
+ fs=FieldStorage(fp=fp,environ=environ,keep_blank_values=1)
+ if not hasattr(fs,'list') or fs.list is None:
+ # Hm, maybe it's an XML-RPC
+ if (fs.headers.has_key('content-type') and
+ 'text/xml' in fs.headers['content-type'] and
+ method == 'POST'):
+ # Ye haaa, XML-RPC!
+ global xmlrpc
+ if xmlrpc is None: from ZPublisher import xmlrpc
+ meth, self.args = xmlrpc.parse_input(fs.value)
+ response=xmlrpc.response(response)
+ other['RESPONSE']=self.response=response
+ self.maybe_webdav_client = 0
+ elif (fs.headers.has_key('content-type') and
+ 'application/x-amf' in fs.headers['content-type']):
+ global amfgateway
+ directlyProvides(self, IAMFRequest)
+ if amfgateway is None: import amfgateway
+ aparser = amfgateway.AMFParser(fs.value)
+ aparser.parse()
+ meth = aparser.method
+ self.args = aparser.args
+ response = amfgateway.AMFResponse(response)
+ response._amfVersion = aparser.amfVersion
+ response._clientType = aparser.clientType
+ response._method = meth
+ response._name = aparser.name
+ auth = aparser.auth
+ if auth:
+ import base64
+ response._auth = 1
+ authString = "%s:%s" % (auth.get('userid'),
+ auth.get('password'))
+ self._auth = "Basic %s" % base64.encodestring(authString)
+ self._auth = self._auth.replace('\n','')
+ other['RESPONSE'] = self.response = response
+ other['REQUEST_METHOD'] = method
+ self.maybe_webdav_client = 0
+
+ else:
+ self._file=fs.file
+ else:
+ fslist=fs.list
+ tuple_items={}
+ lt=type([])
+ CGI_name=isCGI_NAME
+ defaults={}
+ tainteddefaults={}
+ converter=None
+
+ for item in fslist:
+
+ isFileUpload = 0
+ key=item.name
+ if (hasattr(item,'file') and hasattr(item,'filename')
+ and hasattr(item,'headers')):
+ if (item.file and
+ (item.filename is not None
+ # RFC 1867 says that all fields get a content-type.
+ # or 'content-type' in map(lower, item.headers.keys())
+ )):
+ item=FileUpload(item)
+ isFileUpload = 1
+ else:
+ item=item.value
+
+ flags=0
+ character_encoding = ''
+ # Variables for potentially unsafe values.
+ tainted = None
+ converter_type = None
+
+ # Loop through the different types and set
+ # the appropriate flags
+
+ # We'll search from the back to the front.
+ # We'll do the search in two steps. First, we'll
+ # do a string search, and then we'll check it with
+ # a re search.
+
+
+ l=key.rfind(':')
+ if l >= 0:
+ mo = search_type(key,l)
+ if mo: l=mo.start(0)
+ else: l=-1
+
+ while l >= 0:
+ type_name=key[l+1:]
+ key=key[:l]
+ c=get_converter(type_name, None)
+
+ if c is not None:
+ converter=c
+ converter_type = type_name
+ flags=flags|CONVERTED
+ elif type_name == 'list':
+ flags=flags|SEQUENCE
+ elif type_name == 'tuple':
+ tuple_items[key]=1
+ flags=flags|SEQUENCE
+ elif (type_name == 'method' or type_name == 'action'):
+ if l: meth=key
+ else: meth=item
+ elif (type_name == 'default_method' or type_name == \
+ 'default_action'):
+ if not meth:
+ if l: meth=key
+ else: meth=item
+ elif type_name == 'default':
+ flags=flags|DEFAULT
+ elif type_name == 'record':
+ flags=flags|RECORD
+ elif type_name == 'records':
+ flags=flags|RECORDS
+ elif type_name == 'ignore_empty':
+ if not item: flags=flags|EMPTY
+ elif has_codec(type_name):
+ character_encoding = type_name
+
+ l=key.rfind(':')
+ if l < 0: break
+ mo=search_type(key,l)
+ if mo: l = mo.start(0)
+ else: l = -1
+
+
+
+ # Filter out special names from form:
+ if CGI_name(key) or key[:5]=='HTTP_': continue
+
+ # If the key is tainted, mark it so as well.
+ tainted_key = key
+ if '<' in key:
+ tainted_key = TaintedString(key)
+
+ if flags:
+
+ # skip over empty fields
+ if flags&EMPTY: continue
+
+ #Split the key and its attribute
+ if flags&REC:
+ key=key.split(".")
+ key, attr=".".join(key[:-1]), key[-1]
+
+ # Update the tainted_key if necessary
+ tainted_key = key
+ if '<' in key:
+ tainted_key = TaintedString(key)
+
+ # Attributes cannot hold a <.
+ if '<' in attr:
+ raise ValueError(
+ "%s is not a valid record attribute name" %
+ escape(attr))
+
+ # defer conversion
+ if flags&CONVERTED:
+ try:
+ if character_encoding:
+ # We have a string with a specified character encoding.
+ # This gets passed to the converter either as unicode, if it can
+ # handle it, or crunched back down to latin-1 if it can not.
+ item = unicode(item,character_encoding)
+ if hasattr(converter,'convert_unicode'):
+ item = converter.convert_unicode(item)
+ else:
+ item = converter(item.encode(default_encoding))
+ else:
+ item=converter(item)
+
+ # Flag potentially unsafe values
+ if converter_type in ('string', 'required', 'text',
+ 'ustring', 'utext'):
+ if not isFileUpload and '<' in item:
+ tainted = TaintedString(item)
+ elif converter_type in ('tokens', 'lines',
+ 'utokens', 'ulines'):
+ is_tainted = 0
+ tainted = item[:]
+ for i in range(len(tainted)):
+ if '<' in tainted[i]:
+ is_tainted = 1
+ tainted[i] = TaintedString(tainted[i])
+ if not is_tainted:
+ tainted = None
+
+ except:
+ if (not item and not (flags&DEFAULT) and
+ defaults.has_key(key)):
+ item = defaults[key]
+ if flags&RECORD:
+ item=getattr(item,attr)
+ if flags&RECORDS:
+ item = getattr(item[-1], attr)
+ if tainteddefaults.has_key(tainted_key):
+ tainted = tainteddefaults[tainted_key]
+ if flags&RECORD:
+ tainted = getattr(tainted, attr)
+ if flags&RECORDS:
+ tainted = getattr(tainted[-1], attr)
+ else:
+ raise
+
+ elif not isFileUpload and '<' in item:
+ # Flag potentially unsafe values
+ tainted = TaintedString(item)
+
+ # If the key is tainted, we need to store stuff in the
+ # tainted dict as well, even if the value is safe.
+ if '<' in tainted_key and tainted is None:
+ tainted = item
+
+ #Determine which dictionary to use
+ if flags&DEFAULT:
+ mapping_object = defaults
+ tainted_mapping = tainteddefaults
+ else:
+ mapping_object = form
+ tainted_mapping = taintedform
+
+ #Insert in dictionary
+ if mapping_object.has_key(key):
+ if flags&RECORDS:
+ #Get the list and the last record
+ #in the list. reclist is mutable.
+ reclist = mapping_object[key]
+ x = reclist[-1]
+
+ if tainted:
+ # Store a tainted copy as well
+ if not tainted_mapping.has_key(tainted_key):
+ tainted_mapping[tainted_key] = deepcopy(
+ reclist)
+ treclist = tainted_mapping[tainted_key]
+ lastrecord = treclist[-1]
+
+ if not hasattr(lastrecord, attr):
+ if flags&SEQUENCE: tainted = [tainted]
+ setattr(lastrecord, attr, tainted)
+ else:
+ if flags&SEQUENCE:
+ getattr(lastrecord,
+ attr).append(tainted)
+ else:
+ newrec = record()
+ setattr(newrec, attr, tainted)
+ treclist.append(newrec)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # If we already put a tainted value into this
+ # recordset, we need to make sure the whole
+ # recordset is built.
+ treclist = tainted_mapping[tainted_key]
+ lastrecord = treclist[-1]
+ copyitem = item
+
+ if not hasattr(lastrecord, attr):
+ if flags&SEQUENCE: copyitem = [copyitem]
+ setattr(lastrecord, attr, copyitem)
+ else:
+ if flags&SEQUENCE:
+ getattr(lastrecord,
+ attr).append(copyitem)
+ else:
+ newrec = record()
+ setattr(newrec, attr, copyitem)
+ treclist.append(newrec)
+
+ if not hasattr(x,attr):
+ #If the attribute does not
+ #exist, setit
+ if flags&SEQUENCE: item=[item]
+ setattr(x,attr,item)
+ else:
+ if flags&SEQUENCE:
+ # If the attribute is a
+ # sequence, append the item
+ # to the existing attribute
+ y = getattr(x, attr)
+ y.append(item)
+ setattr(x, attr, y)
+ else:
+ # Create a new record and add
+ # it to the list
+ n=record()
+ setattr(n,attr,item)
+ mapping_object[key].append(n)
+ elif flags&RECORD:
+ b=mapping_object[key]
+ if flags&SEQUENCE:
+ item=[item]
+ if not hasattr(b,attr):
+ # if it does not have the
+ # attribute, set it
+ setattr(b,attr,item)
+ else:
+ # it has the attribute so
+ # append the item to it
+ setattr(b,attr,getattr(b,attr)+item)
+ else:
+ # it is not a sequence so
+ # set the attribute
+ setattr(b,attr,item)
+
+ # Store a tainted copy as well if necessary
+ if tainted:
+ if not tainted_mapping.has_key(tainted_key):
+ tainted_mapping[tainted_key] = deepcopy(
+ mapping_object[key])
+ b = tainted_mapping[tainted_key]
+ if flags&SEQUENCE:
+ seq = getattr(b, attr, [])
+ seq.append(tainted)
+ setattr(b, attr, seq)
+ else:
+ setattr(b, attr, tainted)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # If we already put a tainted value into this
+ # record, we need to make sure the whole record
+ # is built.
+ b = tainted_mapping[tainted_key]
+ if flags&SEQUENCE:
+ seq = getattr(b, attr, [])
+ seq.append(item)
+ setattr(b, attr, seq)
+ else:
+ setattr(b, attr, item)
+
+ else:
+ # it is not a record or list of records
+ found=mapping_object[key]
+
+ if tainted:
+ # Store a tainted version if necessary
+ if not tainted_mapping.has_key(tainted_key):
+ copied = deepcopy(found)
+ if isinstance(copied, lt):
+ tainted_mapping[tainted_key] = copied
+ else:
+ tainted_mapping[tainted_key] = [copied]
+ tainted_mapping[tainted_key].append(tainted)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # We may already have encountered a tainted
+ # value for this key, and the tainted_mapping
+ # needs to hold all the values.
+ tfound = tainted_mapping[tainted_key]
+ if isinstance(tfound, lt):
+ tainted_mapping[tainted_key].append(item)
+ else:
+ tainted_mapping[tainted_key] = [tfound,
+ item]
+
+ if type(found) is lt:
+ found.append(item)
+ else:
+ found=[found,item]
+ mapping_object[key]=found
+ else:
+ # The dictionary does not have the key
+ if flags&RECORDS:
+ # Create a new record, set its attribute
+ # and put it in the dictionary as a list
+ a = record()
+ if flags&SEQUENCE: item=[item]
+ setattr(a,attr,item)
+ mapping_object[key]=[a]
+
+ if tainted:
+ # Store a tainted copy if necessary
+ a = record()
+ if flags&SEQUENCE: tainted = [tainted]
+ setattr(a, attr, tainted)
+ tainted_mapping[tainted_key] = [a]
+
+ elif flags&RECORD:
+ # Create a new record, set its attribute
+ # and put it in the dictionary
+ if flags&SEQUENCE: item=[item]
+ r = mapping_object[key]=record()
+ setattr(r,attr,item)
+
+ if tainted:
+ # Store a tainted copy if necessary
+ if flags&SEQUENCE: tainted = [tainted]
+ r = tainted_mapping[tainted_key] = record()
+ setattr(r, attr, tainted)
+ else:
+ # it is not a record or list of records
+ if flags&SEQUENCE: item=[item]
+ mapping_object[key]=item
+
+ if tainted:
+ # Store a tainted copy if necessary
+ if flags&SEQUENCE: tainted = [tainted]
+ tainted_mapping[tainted_key] = tainted
+
+ else:
+ # This branch is for case when no type was specified.
+ mapping_object = form
+
+ if not isFileUpload and '<' in item:
+ tainted = TaintedString(item)
+ elif '<' in key:
+ tainted = item
+
+ #Insert in dictionary
+ if mapping_object.has_key(key):
+ # it is not a record or list of records
+ found=mapping_object[key]
+
+ if tainted:
+ # Store a tainted version if necessary
+ if not taintedform.has_key(tainted_key):
+ copied = deepcopy(found)
+ if isinstance(copied, lt):
+ taintedform[tainted_key] = copied
+ else:
+ taintedform[tainted_key] = [copied]
+ elif not isinstance(taintedform[tainted_key], lt):
+ taintedform[tainted_key] = [
+ taintedform[tainted_key]]
+ taintedform[tainted_key].append(tainted)
+
+ elif taintedform.has_key(tainted_key):
+ # We may already have encountered a tainted value
+ # for this key, and the taintedform needs to hold
+ # all the values.
+ tfound = taintedform[tainted_key]
+ if isinstance(tfound, lt):
+ taintedform[tainted_key].append(item)
+ else:
+ taintedform[tainted_key] = [tfound, item]
+
+ if type(found) is lt:
+ found.append(item)
+ else:
+ found=[found,item]
+ mapping_object[key]=found
+ else:
+ mapping_object[key]=item
+ if tainted:
+ taintedform[tainted_key] = tainted
+
+ #insert defaults into form dictionary
+ if defaults:
+ for key, value in defaults.items():
+ tainted_key = key
+ if '<' in key: tainted_key = TaintedString(key)
+
+ if not form.has_key(key):
+ # if the form does not have the key,
+ # set the default
+ form[key]=value
+
+ if tainteddefaults.has_key(tainted_key):
+ taintedform[tainted_key] = \
+ tainteddefaults[tainted_key]
+ else:
+ #The form has the key
+ tdefault = tainteddefaults.get(tainted_key, value)
+ if isinstance(value, record):
+ # if the key is mapped to a record, get the
+ # record
+ r = form[key]
+
+ # First deal with tainted defaults.
+ if taintedform.has_key(tainted_key):
+ tainted = taintedform[tainted_key]
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(tainted, k):
+ setattr(tainted, k, v)
+
+ elif tainteddefaults.has_key(tainted_key):
+ # Find out if any of the tainted default
+ # attributes needs to be copied over.
+ missesdefault = 0
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(r, k):
+ missesdefault = 1
+ break
+ if missesdefault:
+ tainted = deepcopy(r)
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(tainted, k):
+ setattr(tainted, k, v)
+ taintedform[tainted_key] = tainted
+
+ for k, v in value.__dict__.items():
+ # loop through the attributes and value
+ # in the default dictionary
+ if not hasattr(r, k):
+ # if the form dictionary doesn't have
+ # the attribute, set it to the default
+ setattr(r,k,v)
+ form[key] = r
+
+ elif isinstance(value, lt):
+ # the default value is a list
+ l = form[key]
+ if not isinstance(l, lt):
+ l = [l]
+
+ # First deal with tainted copies
+ if taintedform.has_key(tainted_key):
+ tainted = taintedform[tainted_key]
+ if not isinstance(tainted, lt):
+ tainted = [tainted]
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ for k, v in defitem.__dict__.items():
+ for origitem in tainted:
+ if not hasattr(origitem, k):
+ setattr(origitem, k, v)
+ else:
+ if not defitem in tainted:
+ tainted.append(defitem)
+ taintedform[tainted_key] = tainted
+
+ elif tainteddefaults.has_key(tainted_key):
+ missesdefault = 0
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ try:
+ for k, v in \
+ defitem.__dict__.items():
+ for origitem in l:
+ if not hasattr(origitem, k):
+ missesdefault = 1
+ raise NestedLoopExit
+ except NestedLoopExit:
+ break
+ else:
+ if not defitem in l:
+ missesdefault = 1
+ break
+ if missesdefault:
+ tainted = deepcopy(l)
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ for k, v in defitem.__dict__.items():
+ for origitem in tainted:
+ if not hasattr(origitem, k):
+ setattr(origitem, k, v)
+ else:
+ if not defitem in tainted:
+ tainted.append(defitem)
+ taintedform[tainted_key] = tainted
+
+ for x in value:
+ # for each x in the list
+ if isinstance(x, record):
+ # if the x is a record
+ for k, v in x.__dict__.items():
+
+ # loop through each
+ # attribute and value in
+ # the record
+
+ for y in l:
+
+ # loop through each
+ # record in the form
+ # list if it doesn't
+ # have the attributes
+ # in the default
+ # dictionary, set them
+
+ if not hasattr(y, k):
+ setattr(y, k, v)
+ else:
+ # x is not a record
+ if not x in l:
+ l.append(x)
+ form[key] = l
+ else:
+ # The form has the key, the key is not mapped
+ # to a record or sequence so do nothing
+ pass
+
+ # Convert to tuples
+ if tuple_items:
+ for key in tuple_items.keys():
+ # Split the key and get the attr
+ k=key.split( ".")
+ k,attr='.'.join(k[:-1]), k[-1]
+ a = attr
+ new = ''
+ # remove any type_names in the attr
+ while not a=='':
+ a=a.split( ":")
+ a,new=':'.join(a[:-1]), a[-1]
+ attr = new
+ if form.has_key(k):
+ # If the form has the split key get its value
+ tainted_split_key = k
+ if '<' in k: tainted_split_key = TaintedString(k)
+ item =form[k]
+ if isinstance(item, record):
+ # if the value is mapped to a record, check if it
+ # has the attribute, if it has it, convert it to
+ # a tuple and set it
+ if hasattr(item,attr):
+ value=tuple(getattr(item,attr))
+ setattr(item,attr,value)
+ else:
+ # It is mapped to a list of records
+ for x in item:
+ # loop through the records
+ if hasattr(x, attr):
+ # If the record has the attribute
+ # convert it to a tuple and set it
+ value=tuple(getattr(x,attr))
+ setattr(x,attr,value)
+
+ # Do the same for the tainted counterpart
+ if taintedform.has_key(tainted_split_key):
+ tainted = taintedform[tainted_split_key]
+ if isinstance(item, record):
+ seq = tuple(getattr(tainted, attr))
+ setattr(tainted, attr, seq)
+ else:
+ for trec in tainted:
+ if hasattr(trec, attr):
+ seq = getattr(trec, attr)
+ seq = tuple(seq)
+ setattr(trec, attr, seq)
+ else:
+ # the form does not have the split key
+ tainted_key = key
+ if '<' in key: tainted_key = TaintedString(key)
+ if form.has_key(key):
+ # if it has the original key, get the item
+ # convert it to a tuple
+ item=form[key]
+ item=tuple(form[key])
+ form[key]=item
+
+ if taintedform.has_key(tainted_key):
+ tainted = tuple(taintedform[tainted_key])
+ taintedform[tainted_key] = tainted
+
+ if meth:
+ if environ.has_key('PATH_INFO'):
+ path=environ['PATH_INFO']
+ while path[-1:]=='/': path=path[:-1]
+ else: path=''
+ other['PATH_INFO']=path="%s/%s" % (path,meth)
+ self._hacked_path=1
+
+HTTPRequest.processInputs = processInputs
+import logging
+logger = logging.getLogger('Zope')
+logger.info("z3c.amf: modified ZPublisher.HTTPRequest.processInputs")
+
Property changes on: z3c.amf/trunk/z3c/amf/HTTPRequest.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/README.txt
===================================================================
--- z3c.amf/trunk/z3c/amf/README.txt (rev 0)
+++ z3c.amf/trunk/z3c/amf/README.txt 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,246 @@
+AMF/Flash Support in Zope 2
+===========================
+
+Introduction
+------------
+
+This package allows you to query Zope 2 from a flash using Flex with
+Actionscript 2 or Actionscript 3 throught AMF0 or AMF3.
+
+We are just providing here the Zope layer. The lower layer has been done
+using the PyAMF package (see http://pyamf.org).
+
+Let's write a simple AMF view that echoes various types of input:
+
+ >>> from Products.Five import BrowserView
+ >>> from datetime import datetime
+ >>> import elementtree.ElementTree as etree
+ >>> class EchoView(BrowserView):
+ ...
+ ... def echoString(self, value):
+ ... return "%s" % value
+ ...
+ ... def echoProtectedString(self, value):
+ ... return "%s" % value
+ ...
+ ... def echoList(self, value):
+ ... return list(value)
+ ...
+ ... def echoDict(self, value):
+ ... return dict(value)
+ ...
+ ... def echoVoid(self, value):
+ ... pass
+ ...
+ ... def echoTuple(self, value):
+ ... return tuple(value)
+ ...
+ ... def echoDate(self):
+ ... return datetime(2008, 11, 17, 11, 11)
+ ...
+ ... def echoXML(self, value):
+ ... root = etree.Element("html")
+ ... body = etree.SubElement(root, 'body')
+ ... body.text = value
+ ... return root
+
+Now we'll register it as a Flash view. For now we'll just register the
+view for folder objects and call it on the default folder of the user:
+
+ >>> from zope.configuration import xmlconfig
+ >>> ignored = xmlconfig.string("""
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/zope"
+ ... xmlns:browser="http://namespaces.zope.org/browser"
+ ... xmlns:flash="http://namespaces.zope.org/flash"
+ ... >
+ ...
+ ... <include package="z3c.amf" file="meta.zcml" />
+ ... <include package="Products.Five" file="meta.zcml" />
+ ... <include package="z3c.amf" />
+ ...
+ ... <flash:view
+ ... for="OFS.interfaces.IFolder"
+ ... methods="echoString echoList echoDict echoVoid echoTuple
+ ... echoDate echoXML"
+ ... class="z3c.amf.README.EchoView"
+ ... permission="zope.Public"
+ ... />
+ ...
+ ... <flash:view
+ ... for="OFS.interfaces.IFolder"
+ ... methods="echoProtectedString"
+ ... class="z3c.amf.README.EchoView"
+ ... permission="zope2.FlashAccess"
+ ... />
+ ...
+ ... </configure>
+ ... """)
+
+We create some helper functions.
+For Requests:
+
+ >>> def createAMFRequest(target, body, username=None, password=None):
+ ... envelope = remoting.Envelope(pyamf.AMF0, pyamf.ClientTypes.Flash9)
+ ... if username is not None and password is not None:
+ ... envelope.headers['Credentials'] = dict(userid=unicode(username),
+ ... password=unicode(password))
+ ... request = remoting.Request(target, [body], envelope)
+ ... envelope[u'/1'] = request
+ ... amfRequest = remoting.encode(envelope)
+ ... amfRequest.seek(0)
+ ... return amfRequest.read()
+
+For Responses:
+
+ >>> import pyamf
+ >>> from pyamf import remoting
+ >>> def printAMFResponse(response):
+ ... context = pyamf.amf0.Context
+ ... requests = remoting.decode(response.body, context())
+ ... for name, value in requests.items():
+ ... print (name, value, type(value.body))
+
+Basic Types
+-----------
+
+String
+
+ >>> amfRequest = createAMFRequest(target='echoString', body='Hello World!')
+ >>> amfRequest
+ '\x00\x03\x00\x00\x00\x01\x00\nechoString\x00\x02/1\x00\x00\x00\x00\n\x00\x00\x00\x01\x02\x00\x0cHello World!'
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>Hello World!</Response>, <type 'unicode'>)
+
+List
+
+ >>> amfRequest = createAMFRequest(target='echoList', body=[u'Hé', u'Ho'])
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>[u'H\xc3\xa9', u'Ho']</Response>,
+ <type 'list'>)
+
+Dictionary
+
+ >>> amfRequest = createAMFRequest(target='echoDict',
+ ... body={'fruit': 'orange'})
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>{u'fruit': u'orange'}</Response>,
+ <class 'pyamf.ASObject'>)
+
+Without return
+
+ >>> amfRequest = createAMFRequest(target='echoVoid', body='Hello World!')
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>None</Response>, <type 'NoneType'>)
+
+Tuple
+
+ >>> amfRequest = createAMFRequest(target='echoTuple', body=['foo', 'bar'])
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>[u'foo', u'bar']</Response>,
+ <type 'list'>)
+
+Datetime
+
+ >>> amfRequest = createAMFRequest(target='echoDate', body=None)
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>2008-11-17 11:11:00</Response>,
+ <type 'datetime.datetime'>)
+
+XML
+
+ >>> amfRequest = createAMFRequest(target='echoXML', body='It works!')
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult><Element html at ...></Response>,
+ <type 'instance'>)
+
+Errors
+------
+
+
+ >>> amfRequest = createAMFRequest(target='echoUnknown', body=['foo', 'bar'])
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onStatus><ErrorFault level=error code=NotFound type=Resource not found...
+ ...
+
+
+User authentication
+-------------------
+
+Try to access our protected view without providing login/pass in flash:
+
+ >>> amfRequest = createAMFRequest(target='echoProtectedString',
+ ... body='It works!')
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onStatus><ErrorFault level=error code=zExceptions.unauthorized.Unauthorized type=Not authorized></Response>,
+ <class 'pyamf.remoting.ErrorFault'>)
+
+
+Now try to access with login/pass:
+
+ >>> from Testing.ZopeTestCase import user_name, user_password
+ >>> amfRequest = createAMFRequest(target='echoProtectedString',
+ ... body="Hello World!", username=user_name,
+ ... password=user_password)
+ >>> response = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 200
+ ... Content-Type: application/x-amf
+ ...
+ ... %s""" % amfRequest)
+ >>> printAMFResponse(response)
+ (u'/1', <Response status=/onResult>Hello World!</Response>, <type 'unicode'>)
Property changes on: z3c.amf/trunk/z3c/amf/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.amf/trunk/z3c/amf/__init__.py
===================================================================
--- z3c.amf/trunk/z3c/amf/__init__.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/__init__.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,3 @@
+import HTTPRequest
+import patch
+from permissions import *
Property changes on: z3c.amf/trunk/z3c/amf/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/amfgateway.py
===================================================================
--- z3c.amf/trunk/z3c/amf/amfgateway.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/amfgateway.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,131 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+$Id$
+"""
+
+import logging
+import sys
+import traceback
+import types
+
+from z3c.amf.interfaces import IAMFResponse
+from zExceptions import Unauthorized, NotFound
+from zope.interface import implements
+
+import pyamf
+from pyamf import remoting
+from pyamf.remoting import amf0
+
+
+class AMFParser(object):
+ """
+ Parse the request
+ """
+
+ def __init__(self, data):
+ context = pyamf.get_context(pyamf.AMF0)
+ self.requests = remoting.decode(data, context)
+ self.auth = None
+
+ def parse(self):
+ name, request = self.requests.items()[0]
+ if self.requests.headers:
+ self.auth = self.requests.headers.get(u'Credentials')
+ self.method = request.target
+ params = request.body
+ if params[0] is None:
+ self.args = tuple()
+ else:
+ self.args = tuple(params)
+ self.amfVersion = self.requests.amfVersion
+ self.clientType = self.requests.clientType
+ self.name = name
+
+
+def parse_input(data):
+ parser = AMFParser(data)
+ return parser.parse()
+
+
+class AMFResponse:
+ """Customized Response that handles AMF-specific details.
+
+ We override setBody to marhsall Python objects into AMF. We
+ also override exception to convert errors to AMF faults.
+ """
+ implements(IAMFResponse)
+ _contentType = remoting.CONTENT_TYPE
+
+ # Because we can't predict what kind of thing we're customizing,
+ # we have to use delegation, rather than inheritence to do the
+ # customization.
+
+ def __init__(self, real):
+ self.__dict__['_real']=real
+
+ def __getattr__(self, name):
+ return getattr(self._real, name)
+
+ def __setattr__(self, name, v):
+ return setattr(self._real, name, v)
+
+ def __delattr__(self, name):
+ return delattr(self._real, name)
+
+ def setBody(self, body, title='', is_error=0, bogus_str_search=None):
+ responseBody = remoting.Envelope(self._amfVersion,
+ self._clientType)
+ context = pyamf.get_context(pyamf.AMF0)
+ proc = amf0.RequestProcessor(self)
+ if isinstance(body, remoting.BaseFault):
+ amfResponse = remoting.Response(body,
+ status=remoting.STATUS_ERROR)
+ else:
+ amfResponse = remoting.Response(body)
+ responseBody[self._name] = amfResponse
+ body = remoting.encode(responseBody, context)
+ body.seek(0)
+ self._real.setBody(body.read())
+ self._setHeader()
+ return self
+
+ def exception(self, fatal=0, info=None,
+ absuri_match=None, tag_search=None):
+ if isinstance(info, tuple) and len(info)==3:
+ t, v, tb = info
+ else:
+ t, v, tb = sys.exc_info()
+
+ content = "".join(traceback.format_tb(tb))
+ logger = logging.getLogger('Zope')
+ logger.info('AMF Exception: %s' % content)
+ f=None
+ self._real.setStatus(200)
+ if t == 'Unauthorized' or t == Unauthorized or (
+ isinstance(t, types.ClassType) and issubclass(t, Unauthorized)):
+ # 401
+ f = remoting.ErrorFault(code=str(t), type='Not authorized')
+ elif isinstance(v, NotFound): # 404
+ f = remoting.ErrorFault(code='NotFound',
+ type='Resource not found',
+ description=str(v))
+ elif not isinstance(v, pyamf.BaseError): # 500
+ f = remoting.ErrorFault(code=str(t), type=str(v), description=content)
+ self.setBody(f)
+ return tb
+
+ def _setHeader(self):
+ self.setHeader('content-length', len(self._real.body))
+ self._real.setHeader('content-type', self._contentType)
Property changes on: z3c.amf/trunk/z3c/amf/amfgateway.py
___________________________________________________________________
Added: svn:keywords
+ Id
Property changes on: z3c.amf/trunk/z3c/amf/browser/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/browser/configure.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/browser/configure.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/browser/configure.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,12 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="z3c.amf">
+
+ <browser:page
+ for="*"
+ name="crossdomain.xml"
+ permission="zope.Public"
+ template="crossdomain.xml"/>
+
+</configure>
+
Added: z3c.amf/trunk/z3c/amf/browser/crossdomain.xml
===================================================================
--- z3c.amf/trunk/z3c/amf/browser/crossdomain.xml (rev 0)
+++ z3c.amf/trunk/z3c/amf/browser/crossdomain.xml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,5 @@
+<!DOCTYPE cross-domain-policy
+ SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
+<cross-domain-policy>
+ <allow-access-from domain="*" />
+</cross-domain-policy>
Added: z3c.amf/trunk/z3c/amf/configure.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/configure.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/configure.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,10 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="z3c.amf">
+
+ <permission
+ id="zope2.FlashAccess"
+ title="Flash Access"/>
+
+</configure>
+
Added: z3c.amf/trunk/z3c/amf/ftesting.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/ftesting.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/ftesting.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,9 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="z3c.amf">
+
+ <include package="Products.Five"/>
+ <include package="z3c.amf" file="meta.zcml" />
+
+
+</configure>
+
Added: z3c.amf/trunk/z3c/amf/ftests.py
===================================================================
--- z3c.amf/trunk/z3c/amf/ftests.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/ftests.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Functional tests for AMF.
+
+$Id$
+"""
+
+import sys
+import os
+import zope.interface
+from zope.testing import doctest
+from zope.app.folder.folder import IFolder
+from zope.app.testing.functional import ZCMLLayer
+from zope.app.testing import ztapi
+from z3c.amf.interfaces import IAMFRequest
+
+
+# Evil hack to make pickling work with classes defined in doc tests
+
+
+class NoCopyDict(dict):
+
+ def copy(self):
+ return self
+
+
+class FakeModule:
+
+ def __init__(self, dict):
+ self.__dict = dict
+
+ def __getattr__(self, name):
+ try:
+ return self.__dict[name]
+ except KeyError:
+ raise AttributeError(name)
+
+
+globs = NoCopyDict()
+name = 'z3c.amf.README'
+
+
+def setUp(test):
+ globs['__name__'] = name
+ sys.modules[name] = FakeModule(globs)
+
+
+def tearDown(test):
+ # clean up the views we registered:
+
+ # we use the fact that registering None unregisters whatever is
+ # registered. We can't use an unregistration call because that
+ # requires the object that was registered and we don't have that handy.
+ # (OK, we could get it if we want. Maybe later.)
+
+ ztapi.provideView(IFolder,
+ IAMFRequest,
+ zope.interface,
+ 'contents',
+ None,
+ )
+ ztapi.provideView(IFolder,
+ IAMFRequest,
+ zope.interface,
+ 'contents',
+ None,
+ )
+
+ globs.clear()
+ del sys.modules[name]
+
+
+dir = os.path.abspath(os.path.dirname(__file__))
+filename = os.path.join(dir, 'ftesting.zcml')
+
+z3c_amf_functional_layer = ZCMLLayer(filename,
+ __name__,
+ 'z3c.amf_functional_layer')
+
+
+def test_suite():
+ from Testing.ZopeTestCase import FunctionalDocFileSuite
+ ftest = FunctionalDocFileSuite(
+ 'README.txt',
+ optionflags=doctest.ELLIPSIS|
+ doctest.REPORT_NDIFF|
+ doctest.REPORT_ONLY_FIRST_FAILURE|
+ doctest.NORMALIZE_WHITESPACE,
+ setUp=setUp, tearDown=tearDown, globs=globs)
+ ftest.layer = z3c_amf_functional_layer
+ return ftest
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='test_suite')
Property changes on: z3c.amf/trunk/z3c/amf/ftests.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/interfaces.py
===================================================================
--- z3c.amf/trunk/z3c/amf/interfaces.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/interfaces.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+"""
+z3c.amf
+
+Licensed under the <+ LICENSE +> license, see LICENCE.txt for more details.
+Copyright by Affinitic sprl
+
+$Id$
+"""
+from zope.interface import Interface
+
+
+class IAMFResponse(Interface):
+ """
+ Marker interface
+ """
+
+
+class IAMFRequest(Interface):
+ """
+ Marker interface
+ """
Property changes on: z3c.amf/trunk/z3c/amf/interfaces.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/meta.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/meta.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/meta.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,12 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta"
+ i18n_domain="z3c.amf">
+
+ <meta:directive
+ namespace="http://namespaces.zope.org/flash"
+ name="view"
+ schema=".metadirectives.IViewDirective"
+ handler=".metaconfigure.view" />
+
+</configure>
+
Added: z3c.amf/trunk/z3c/amf/metaconfigure.py
===================================================================
--- z3c.amf/trunk/z3c/amf/metaconfigure.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/metaconfigure.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,137 @@
+"""
+AMF configuration code
+
+$Id$
+"""
+
+from zope.interface import Interface
+from zope.security.checker import CheckerPublic
+from zope.component.interface import provideInterface
+from Products.Five.security import protectClass, protectName
+from zope.app.publisher.browser.viewmeta import _handle_for
+
+# XXX handler is non-public. Should call directives instead
+from zope.app.component.metaconfigure import handler
+
+from inspect import ismethod
+from z3c.amf.interfaces import IAMFRequest
+from Globals import InitializeClass as initializeClass
+from Products.Five.security import getSecurityInfo
+from Products.Five.metaclass import makeClass
+
+from Products.Five.browser import BrowserView
+from Products.Five.browser.metaconfigure import ViewMixinForAttributes
+from Products.Five.security import CheckerPrivateId
+
+
+def view(_context, for_=None, interface=None, methods=None,
+ class_=None, permission=None, name=None):
+
+ interface = interface or []
+ methods = methods or []
+
+ # If there were special permission settings provided, then use them
+ if permission == 'zope.Public':
+ permission = CheckerPublic
+
+ require = {}
+ for attr_name in methods:
+ require[attr_name] = permission
+
+ if interface:
+ for iface in interface:
+ for field_name in iface:
+ require[field_name] = permission
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', for_))
+
+ cdict = getSecurityInfo(class_)
+
+ if name:
+ cdict['__name__'] = name
+ new_class = makeClass(class_.__name__,
+ (class_, BrowserView), cdict)
+
+ _handle_for(_context, for_)
+ # Register the new view.
+ _context.action(
+ discriminator = ('view', (for_, ), name, IAMFRequest),
+ callable = handler,
+ args = ('registerAdapter',
+ new_class, (for_, IAMFRequest),
+ Interface, name,
+ _context.info)
+ )
+ _context.action(
+ discriminator = ('five:protectClass', new_class),
+ callable = protectClass,
+ args = (new_class, permission))
+
+ for name in require:
+ _context.action(
+ discriminator = ('five:protectName', new_class, name),
+ callable = protectName,
+ args = (new_class, name, permission))
+
+ #else its private:
+ allowed = require
+ private_attrs = [name for name in dir(new_class)
+ if (not name.startswith('_')) and
+ (name not in allowed) and
+ ismethod(getattr(new_class, name))]
+ for attr in private_attrs:
+ _context.action(
+ discriminator = ('five:protectName', new_class, attr),
+ callable = protectName,
+ args = (new_class, attr, CheckerPrivateId))
+
+ else:
+ for name in require:
+ cdict.update({'__page_attribute__': name,
+ '__name__': name})
+ new_class = makeClass(class_.__name__,
+ (class_, ViewMixinForAttributes),
+ cdict)
+
+ func = getattr(new_class, name)
+ if not func.__doc__:
+ # cannot test for MethodType/UnboundMethod here
+ # because of ExtensionClass
+ if hasattr(func, 'im_func'):
+ # you can only set a docstring on functions, not
+ # on method objects
+ func = func.im_func
+ func.__doc__ = "Stub docstring to make ZPublisher work"
+
+ _context.action(
+ discriminator = ('view', (for_, ), name, IAMFRequest),
+ callable = handler,
+ args = ('registerAdapter',
+ new_class,
+ (for_, IAMFRequest), Interface, name,
+ _context.info))
+
+ _context.action(
+ discriminator = ('five:protectClass', new_class),
+ callable = protectClass,
+ args = (new_class, permission))
+
+ _context.action(
+ discriminator = ('five:protectName', new_class, name),
+ callable = protectName,
+ args = (new_class, name, permission))
+
+ _context.action(
+ discriminator = ('five:initialize:class', new_class),
+ callable = initializeClass,
+ args = (new_class, )
+ )
+
+ # Register the used interfaces with the interface service
+ if for_ is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', for_))
Property changes on: z3c.amf/trunk/z3c/amf/metaconfigure.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/metadirectives.py
===================================================================
--- z3c.amf/trunk/z3c/amf/metadirectives.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/metadirectives.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,70 @@
+"""
+AMF ZCML Namespace Schemas
+
+$Id$
+"""
+import zope.configuration.fields
+from zope.security.zcml import Permission
+from zope.interface import Interface
+from zope.schema import TextLine
+
+
+class IViewDirective(Interface):
+ """View Directive for AMF methods."""
+
+ for_ = zope.configuration.fields.GlobalObject(
+ title=u"Published Object Type",
+ description=u"""The types of objects to be published via AMF
+
+ This can be expressed with either a class or an interface
+ """,
+ required=True)
+
+ interface = zope.configuration.fields.Tokens(
+ title=u"Interface to be published.",
+ required=False,
+ value_type=zope.configuration.fields.GlobalInterface())
+
+ methods = zope.configuration.fields.Tokens(
+ title=u"Methods (or attributes) to be published",
+ required=False,
+ value_type=zope.configuration.fields.PythonIdentifier())
+
+ class_ = zope.configuration.fields.GlobalObject(
+ title=u"Class",
+ description=u"A class that provides attributes used by the view.",
+ required=False)
+
+ permission = Permission(
+ title=u"Permission",
+ description=u"""The permission needed to use the view.
+
+ If this option is used and a name is given for the view, then
+ the names defined by the given methods or interfaces will be
+ under the given permission.
+
+ If a name is not given for the view, then, this option is
+ required and the the given permission is required to call the
+ individual views defined by the given interface and methods.
+
+ (See the name attribute.)
+
+ If no permission is given, then permissions should be declared
+ for the view using other means, such as the class directive.
+ """,
+ required=False, )
+
+ name = TextLine(
+ title=u"The name of the view.",
+ description=u"""
+ If a name is given, then rpc methods are accessed by
+ traversing the name and then accessing the methods. In this
+ case, the class should implement
+ zope.pubisher.interfaces.IPublishTraverse.
+
+ If no name is provided, then the names given by the attributes
+ and interfaces are published directly as callable views.
+
+ """,
+ required=False,
+ )
Property changes on: z3c.amf/trunk/z3c/amf/metadirectives.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/patch.py
===================================================================
--- z3c.amf/trunk/z3c/amf/patch.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/patch.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,203 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+import sys
+from zExceptions import Redirect
+from ZPublisher.mapply import mapply
+from ZPublisher.Publish import (call_object, missing_name, dont_publish_class,
+ get_module_info, Retry)
+from zope.publisher.browser import setDefaultSkin
+from zope.security.management import newInteraction, endInteraction
+from z3c.amf.interfaces import IAMFRequest
+from z3c.amf.amfgateway import AMFResponse
+import pyamf
+
+
+def publish(request, module_name, after_list, debug=0,
+ call_object=call_object,
+ missing_name=missing_name,
+ dont_publish_class=dont_publish_class,
+ mapply=mapply,
+ ):
+
+ (bobo_before, bobo_after, object, realm, debug_mode, err_hook,
+ validated_hook, transactions_manager)= get_module_info(module_name)
+
+ parents=None
+ response=None
+
+ try:
+ # TODO pass request here once BaseRequest implements IParticipation
+ newInteraction()
+
+ request.processInputs()
+
+ request_get=request.get
+ response=request.response
+
+ # First check for "cancel" redirect:
+ if request_get('SUBMIT', '').strip().lower()=='cancel':
+ cancel=request_get('CANCEL_ACTION', '')
+ if cancel:
+ raise Redirect(cancel)
+
+ after_list[0]=bobo_after
+ if debug_mode:
+ response.debug_mode=debug_mode
+ if realm and not request.get('REMOTE_USER', None):
+ response.realm=realm
+
+ if bobo_before is not None:
+ bobo_before()
+
+ # Get the path list.
+ # According to RFC1738 a trailing space in the path is valid.
+ path=request_get('PATH_INFO')
+
+ request['PARENTS']=parents=[object]
+
+ if transactions_manager:
+ transactions_manager.begin()
+
+ object=request.traverse(path, validated_hook=validated_hook)
+
+ if transactions_manager:
+ transactions_manager.recordMetaData(object, request)
+
+ result=mapply(object, request.args, request,
+ call_object, 1,
+ missing_name,
+ dont_publish_class,
+ request, bind=1)
+
+ if result is not response:
+ response.setBody(result)
+
+ if transactions_manager:
+ transactions_manager.commit()
+ endInteraction()
+
+ return response
+ except:
+ # DM: provide nicer error message for FTP
+ sm = None
+ if response is not None:
+ sm = getattr(response, "setMessage", None)
+ if sm is not None:
+ from asyncore import compact_traceback
+ cl, val= sys.exc_info()[:2]
+ sm('%s: %s %s' % (
+ getattr(cl, '__name__', cl), val,
+ debug_mode and compact_traceback()[-1] or ''))
+ if IAMFRequest.providedBy(request):
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+ if response is None:
+ response = AMFResponse(request.response)
+ response._amfVersion = pyamf.AMF0
+ response._clientType = pyamf.AMF0
+ response._name = '/1'
+ response.exception()
+ return response
+ if err_hook is not None:
+ if parents:
+ parents=parents[0]
+ try:
+ try:
+ return err_hook(parents, request,
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ )
+ except Retry:
+ if not request.supports_retry():
+ return err_hook(parents, request,
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ )
+ finally:
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+
+ # Only reachable if Retry is raised and request supports retry.
+ newrequest=request.retry()
+ request.close() # Free resources held by the request.
+ # Set the default layer/skin on the newly generated request
+ setDefaultSkin(newrequest)
+ try:
+ return publish(newrequest, module_name, after_list, debug)
+ finally:
+ newrequest.close()
+
+ else:
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+ raise
+
+import ZPublisher.Publish
+ZPublisher.Publish.publish = publish
+
+from Products.PluggableAuthService.plugins.CookieAuthHelper import CookieAuthHelper
+from urllib import quote
+
+
+def unauthorized(self):
+ req = self.REQUEST
+ resp = req['RESPONSE']
+
+ # If we set the auth cookie before, delete it now.
+ if self.cookie_name in resp.cookies:
+ del resp.cookies[self.cookie_name]
+
+ # Redirect if desired.
+ url = self.getLoginURL()
+ if IAMFRequest.providedBy(req):
+ #no need to redirect if it's an amf request
+ return 0
+
+ if url is not None:
+ came_from = req.get('came_from', None)
+
+ if came_from is None:
+ came_from = req.get('URL', '')
+ query = req.get('QUERY_STRING')
+ if query:
+ if not query.startswith('?'):
+ query = '?' + query
+ came_from = came_from + query
+ else:
+ # If came_from contains a value it means the user
+ # must be coming through here a second time
+ # Reasons could be typos when providing credentials
+ # or a redirect loop (see below)
+ req_url = req.get('URL', '')
+
+ if req_url and req_url == url:
+ # Oops... The login_form cannot be reached by the user -
+ # it might be protected itself due to misconfiguration -
+ # the only sane thing to do is to give up because we are
+ # in an endless redirect loop.
+ return 0
+
+ url = url + '?came_from=%s' % quote(came_from)
+ resp.redirect(url, lock=1)
+ return 1
+
+ # Could not challenge.
+ return 0
+
+CookieAuthHelper.unauthorized = unauthorized
Property changes on: z3c.amf/trunk/z3c/amf/patch.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/permissions.py
===================================================================
--- z3c.amf/trunk/z3c/amf/permissions.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/permissions.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+$Id$
+"""
+from AccessControl import ModuleSecurityInfo
+from Products.CMFCore.permissions import setDefaultRoles
+
+security = ModuleSecurityInfo('z3c.amf.permissions')
+security.declarePublic('Flash Access')
+AMFAccess = 'Flash Access'
+setDefaultRoles(AMFAccess, ('Authenticated', ))
Property changes on: z3c.amf/trunk/z3c/amf/permissions.py
___________________________________________________________________
Added: svn:keywords
+ Id
Property changes on: z3c.amf/trunk/z3c/amf/tests/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.amf/trunk/z3c/amf/tests/amf.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/tests/amf.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/tests/amf.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,53 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:flash="http://namespaces.zope.org/flash"
+ i18n_domain="zope">
+
+ <include package="z3c.amf" file="meta.zcml"/>
+ <include package="zope.app.security" file="meta.zcml"/>
+ <flash:view
+ name="test"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ />
+
+ <flash:view
+ name="test2"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ interface="zope.app.component.tests.views.IV"
+ />
+
+ <flash:view
+ name="test3"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action" />
+
+ <flash:view
+ name="test4"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action"
+ interface="zope.app.component.tests.views.IV" />
+
+ <flash:view
+ name="test5"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action index"
+ interface="zope.app.component.tests.views.IV" />
+
+ <flash:view
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ interface="zope.app.component.tests.views.IV"
+ methods="action"
+ permission="zope.Public"
+ />
+
+</configure>
Added: z3c.amf/trunk/z3c/amf/tests/amf_error.zcml
===================================================================
--- z3c.amf/trunk/z3c/amf/tests/amf_error.zcml (rev 0)
+++ z3c.amf/trunk/z3c/amf/tests/amf_error.zcml 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,14 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:flash="http://namespaces.zope.org/flash"
+ i18n_domain="zope">
+
+ <include package="z3c.amf" file="meta.zcml"/>
+ <include package="zope.app.security" file="meta.zcml"/>
+
+ <flash:view
+ name="test"
+ factory="zope.component.tests.views.V1"
+ for="zope.component.tests.views.IC"
+ methods="action index" />
+
+</configure>
Added: z3c.amf/trunk/z3c/amf/tests/test_directives.py
===================================================================
--- z3c.amf/trunk/z3c/amf/tests/test_directives.py (rev 0)
+++ z3c.amf/trunk/z3c/amf/tests/test_directives.py 2008-11-17 23:14:33 UTC (rev 93063)
@@ -0,0 +1,83 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Test 'amf' ZCML Namespace directives.
+
+$Id$
+"""
+
+from zope.configuration import xmlconfig
+from zope.configuration.exceptions import ConfigurationError
+from zope.app.component.tests.views import IC
+from zope.component import getMultiAdapter, queryMultiAdapter
+from zope.app.testing.placelesssetup import PlacelessSetup
+from z3c.amf.interfaces import IAMFRequest
+from zope.interface import alsoProvides
+from zope.interface import implements
+import unittest
+import z3c.amf.tests
+from zope.publisher.browser import TestRequest
+
+request = TestRequest()
+alsoProvides(request, IAMFRequest)
+
+
+class Ob(object):
+
+ implements(IC)
+
+ob = Ob()
+
+
+class DirectivesTest(PlacelessSetup, unittest.TestCase):
+
+ def testView(self):
+ self.assertEqual(
+ queryMultiAdapter((ob, request), name='test'), None)
+ xmlconfig.file("amf.zcml", z3c.amf.tests)
+ self.assertEqual(
+ str(queryMultiAdapter((ob, request), name='test').__class__),
+ "<class 'Products.Five.metaclass.V1'>")
+
+ def testInterfaceAndAttributeProtectedView(self):
+ xmlconfig.file("amf.zcml", z3c.amf.tests)
+ v = getMultiAdapter((ob, request), name='test4')
+ self.assertEqual(v.index(), 'V1 here')
+ self.assertEqual(v.action(), 'done')
+
+ def testDuplicatedInterfaceAndAttributeProtectedView(self):
+ xmlconfig.file("amf.zcml", z3c.amf.tests)
+ v = getMultiAdapter((ob, request), name='test5')
+ self.assertEqual(v.index(), 'V1 here')
+ self.assertEqual(v.action(), 'done')
+
+ def testIncompleteProtectedViewNoPermission(self):
+ self.assertRaises(ConfigurationError, xmlconfig.file,
+ "amf_error.zcml", z3c.amf.tests)
+
+ def test_no_name(self):
+ xmlconfig.file("amf.zcml", z3c.amf.tests)
+ v = getMultiAdapter((ob, request), name='index')
+ self.assertEqual(v(), 'V1 here')
+ v = getMultiAdapter((ob, request), name='action')
+ self.assertEqual(v(), 'done')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(DirectivesTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: z3c.amf/trunk/z3c/amf/tests/test_directives.py
___________________________________________________________________
Added: svn:keywords
+ Id
More information about the Checkins
mailing list