[Zope3-checkins] CVS: Zope3/src/zope/app/contentdirective - __init__.py:1.2 contentdirective.py:1.2 meta.zcml:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:13:51 -0500
Update of /cvs-repository/Zope3/src/zope/app/contentdirective
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/app/contentdirective
Added Files:
__init__.py contentdirective.py meta.zcml
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/app/contentdirective/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/contentdirective/__init__.py Wed Dec 25 09:12:49 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/app/contentdirective/contentdirective.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/contentdirective/contentdirective.py Wed Dec 25 09:12:49 2002
@@ -0,0 +1,206 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+""" Register class directive.
+
+$Id$
+"""
+from types import ModuleType
+from zope.interface.implements import implements
+from zope.interfaces.configuration import INonEmptyDirective
+from zope.interfaces.configuration import ISubdirectiveHandler
+from zope.component import getService
+from zope.configuration.exceptions import ConfigurationError
+from zope.configuration.action import Action
+from zope.app.component.classfactory import ClassFactory
+from zope.app.security.protectclass \
+ import protectLikeUnto, protectName, checkPermission, protectSetAttribute
+from zope.app.security.registries.permissionregistry import permissionRegistry
+from zope.security.proxy import ProxyFactory
+from zope.security.checker import NamesChecker
+from zope.schema.interfaces import IField
+
+PublicPermission = 'zope.Public'
+
+class ProtectionDeclarationException(Exception):
+ """Security-protection-specific exceptions."""
+ pass
+
+def handler(serviceName, methodName, *args, **kwargs):
+ method=getattr(getService(None, serviceName), methodName)
+ method(*args, **kwargs)
+
+def assertPermission(permission=None, *args, **kw):
+ """Check if permission is defined"""
+ if permission is not None:
+ permissionRegistry.ensurePermissionDefined(permission)
+
+class ContentDirective:
+
+ __class_implements__ = INonEmptyDirective
+ __implements__ = ISubdirectiveHandler
+
+ def __init__(self, _context, class_):
+ self.__id = class_
+ self.__class = _context.resolve(class_)
+ if isinstance(self.__class, ModuleType):
+ raise ConfigurationError('Content class attribute must be a class')
+ # not used yet
+ #self.__name = class_
+ #self.__normalized_name = _context.getNormalizedName(class_)
+ self.__context = _context
+
+ def implements(self, _context, interface):
+ resolved_interface = _context.resolve(interface)
+ return [
+ Action(
+ discriminator = ('ContentDirective', self.__class, object()),
+ callable = implements,
+ # the last argument is check=1, which causes implements
+ # to verify that the class does implement the interface
+ args = (self.__class, resolved_interface, 1),
+ ),
+ Action(
+ discriminator = None,
+ callable = handler,
+ args = ('Interfaces', 'provideInterface',
+ resolved_interface.__module__+
+ '.'+
+ resolved_interface.__name__,
+ resolved_interface)
+ )
+ ]
+
+ def require(self, _context,
+ permission=None, attributes=None, interface=None,
+ like_class=None, set_attributes=None, set_schema=None):
+ """Require a the permission to access a specific aspect"""
+
+ if like_class:
+ r = self.__mimic(_context, like_class)
+ else:
+ r = []
+
+ if not (interface or attributes or set_attributes or set_schema):
+ if r:
+ return r
+ raise ConfigurationError("Nothing required")
+
+ if not permission:
+ raise ConfigurationError("No permission specified")
+
+
+ if interface:
+ self.__protectByInterface(interface, permission, r)
+ if attributes:
+ self.__protectNames(attributes, permission, r)
+ if set_attributes:
+ self.__protectSetAttributes(set_attributes, permission, r)
+ if set_schema:
+ self.__protectSetSchema(set_schema, permission, r)
+
+
+ return r
+
+ def __mimic(self, _context, class_):
+ """Base security requirements on those of the given class"""
+ class_to_mimic = _context.resolve(class_)
+ return [
+ Action(discriminator=('mimic', self.__class, object()),
+ callable=protectLikeUnto,
+ args=(self.__class, class_to_mimic),
+ )
+ ]
+
+ def allow(self, _context, attributes=None, interface=None):
+ """Like require, but with permission_id zope.Public"""
+ return self.require(_context, PublicPermission, attributes, interface)
+
+
+
+ def __protectByInterface(self, interface, permission_id, r):
+ "Set a permission on names in an interface."
+ interface = self.__context.resolve(interface)
+ for n, d in interface.namesAndDescriptions(1):
+ self.__protectName(n, permission_id, r)
+
+ def __protectName(self, name, permission_id, r):
+ "Set a permission on a particular name."
+ r.append((
+ ('protectName', self.__class, name),
+ protectName, (self.__class, name, permission_id)))
+
+ def __protectNames(self, names, permission_id, r):
+ "Set a permission on a bunch of names."
+ for name in names.split():
+ self.__protectName(name.strip(), permission_id, r)
+
+ def __protectSetAttributes(self, names, permission_id, r):
+ "Set a permission on a bunch of names."
+ for name in names.split():
+ r.append((
+ ('protectSetAttribute', self.__class, name),
+ protectSetAttribute, (self.__class, name, permission_id)))
+
+ def __protectSetSchema(self, schema, permission_id, r):
+ "Set a permission on a bunch of names."
+ schema = self.__context.resolve(schema)
+ for name in schema:
+ field = schema[name]
+ if IField.isImplementedBy(field):
+ r.append((
+ ('protectSetAttribute', self.__class, name),
+ protectSetAttribute, (self.__class, name, permission_id)))
+
+
+ def __call__(self):
+ "Handle empty/simple declaration."
+ return ()
+
+
+ def factory(self, _context,
+ permission=None, title="", id=None, description=''):
+ """Register a zmi factory for this class"""
+
+ id = id or self.__id
+
+ # note factories are all in one pile, services and content,
+ # so addable names must also act as if they were all in the
+ # same namespace, despite the service/content division
+ return [
+ Action(
+ discriminator = ('FactoryFromClass', id),
+ callable = provideClass,
+ args = (id, self.__class,
+ permission, title, description)
+ )
+ ]
+
+def provideClass(id, _class, permission=None,
+ title='', description=''):
+ """Provide simple class setup
+
+ - create a component
+
+ - set component permission
+ """
+
+ assertPermission(permission)
+ factory = ClassFactory(_class)
+ if permission and (permission != 'zope.Public'):
+ # XXX should getInterfaces be public, as below?
+ factory = ProxyFactory(factory,
+ NamesChecker(('getInterfaces',),
+ __call__=permission))
+
+ getService(None, 'Factories').provideFactory(id, factory)
=== Zope3/src/zope/app/contentdirective/meta.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:51 2002
+++ Zope3/src/zope/app/contentdirective/meta.zcml Wed Dec 25 09:12:49 2002
@@ -0,0 +1,91 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+<!-- zope.app.contentdirective -->
+<directives namespace="http://namespaces.zope.org/zope">
+
+ <directive
+ name="content"
+ handler="zope.app.contentdirective.contentdirective.ContentDirective"
+ description="Make a component available as a content object type"
+ >
+ <attribute
+ name="class"
+ required="yes"
+ description="resolvable name of a class" />
+
+ <subdirective
+ name="implements"
+ description="Declare that the class given by the content
+ directive's class attribute implements a given interface"
+ >
+ <attribute
+ name="interface"
+ required="yes"
+ description="resolvable name of an Interface" />
+ </subdirective>
+
+ <subdirective
+ name="require"
+ description="Indicate that the a specified list of names or the
+ names in a given Interface require a given permission for
+ access."
+ >
+ <attribute
+ name="permission"
+ required="yes"
+ description="a permission id" />
+ <attribute
+ name="attributes"
+ description="space-separated list of attribute names" />
+ <attribute
+ name="interface"
+ description="the resolvable name of an interface" />
+ <attribute
+ name="like_class"
+ description="a class on which the security requirements
+ for this class will be based" />
+ </subdirective>
+
+ <subdirective
+ name="allow"
+ description="Declare a part of the class to be publicly
+ viewable (that is, requires the zope.Public
+ permission). Only one of the following two
+ attributes may be used."
+ >
+ <attribute
+ name="attributes"
+ description="space-separated list of attribute names" />
+ <attribute
+ name="interface"
+ description="the resolvable name of an interface" />
+ </subdirective>
+ <subdirective
+ name="factory"
+ description="Specify the factory used to create this
+ content object"
+ >
+ <attribute
+ name="permission"
+ description="permission id required to use this factory.
+ Although optional, this attribute should normally
+ be specified." />
+ <attribute
+ name="id"
+ description="the identifier for this factory in the
+ ZMI factory identification scheme. If not given, defaults
+ to the literal string given as the content directive's
+ 'class' attribute." />
+ <attribute
+ name="title"
+ description="text suitable for use in the 'add content' menu of
+ a management interface" />
+ <attribute
+ name="description"
+ description="longer narrative description of what this
+ factory does" />
+ </subdirective>
+ </directive>
+</directives>
+
+</zopeConfigure>