[Zope-Checkins] SVN: Zope/trunk/ - refactored ``browser:view`` and ``browser:page`` directives
Yvo Schubbe
cvs-admin at zope.org
Sat Jul 7 09:41:21 UTC 2012
Log message for revision 127279:
- refactored ``browser:view`` and ``browser:page`` directives
Changed:
U Zope/trunk/doc/CHANGES.rst
UU Zope/trunk/src/Products/Five/browser/metaconfigure.py
U Zope/trunk/src/Products/Five/browser/tests/pages.txt
U Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py
-=-
Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst 2012-07-06 22:50:25 UTC (rev 127278)
+++ Zope/trunk/doc/CHANGES.rst 2012-07-07 09:41:15 UTC (rev 127279)
@@ -40,6 +40,10 @@
Features Added
++++++++++++++
+- Five: Refactored ``browser:view`` and ``browser:page`` directives.
+ This makes their implementation more similar to that in ``zope.browserpage``
+ and adds allowed_interface support for the ``browser:view`` directive.
+
- Optimized the `OFS.Traversable.getPhysicalPath` method to avoid excessive
amounts of method calls.
Modified: Zope/trunk/src/Products/Five/browser/metaconfigure.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/metaconfigure.py 2012-07-06 22:50:25 UTC (rev 127278)
+++ Zope/trunk/src/Products/Five/browser/metaconfigure.py 2012-07-07 09:41:15 UTC (rev 127279)
@@ -33,9 +33,12 @@
from zope.security.zcml import Permission
import zope.browserpage.metaconfigure
-from zope.browserpage.metaconfigure import providesCallable
-from zope.browserpage.metaconfigure import _handle_menu
+from zope.browserpage.metaconfigure import _handle_allowed_attributes
+from zope.browserpage.metaconfigure import _handle_allowed_interface
from zope.browserpage.metaconfigure import _handle_for
+from zope.browserpage.metaconfigure import _handle_menu
+from zope.browserpage.metaconfigure import _handle_permission
+from zope.browserpage.metaconfigure import providesCallable
from zope.browserpage.metadirectives import IViewDirective
from AccessControl.class_init import InitializeClass
@@ -52,14 +55,48 @@
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.Five.metaclass import makeClass
+def _configure_z2security(_context, new_class, required):
+ _context.action(
+ discriminator=('five:protectClass', new_class),
+ callable=protectClass,
+ args=(new_class, required.pop(''))
+ )
+ for attr, permission in required.iteritems():
+ _context.action(
+ discriminator=('five:protectName', new_class, attr),
+ callable=protectName,
+ args=(new_class, attr, permission)
+ )
+ # Make everything else private
+ private_attrs = [name for name in dir(new_class)
+ if (not name.startswith('_')) and
+ (name not in required) 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, False)
+ )
+ # Protect the class
+ _context.action(
+ discriminator=('five:initialize:class', new_class),
+ callable=InitializeClass,
+ args=(new_class,)
+ )
+# page
+
def page(_context, name, permission, for_=Interface,
layer=IDefaultBrowserLayer, template=None, class_=None,
allowed_interface=None, allowed_attributes=None,
attribute='__call__', menu=None, title=None,
):
_handle_menu(_context, menu, title, [for_], name, permission, layer)
+ required = {}
+ permission = _handle_permission(_context, permission)
+
if not (class_ or template):
raise ConfigurationError("Must specify a class or template")
@@ -77,6 +114,7 @@
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
+ # TODO: new __name__ attribute must be tested
if class_:
if attribute != '__call__':
if not hasattr(class_, attribute):
@@ -122,14 +160,18 @@
# template
new_class = makeClassForTemplate(template, name=name)
- if allowed_attributes is None:
- allowed_attributes = []
- if allowed_interface is not None:
- for interface in allowed_interface:
- allowed_attributes.extend(interface.names(all=True))
+ for n in ('', attribute):
+ required[n] = permission
+ _handle_allowed_interface(_context, allowed_interface, permission,
+ required)
+ _handle_allowed_attributes(_context, allowed_attributes, permission,
+ required)
+
_handle_for(_context, for_)
+ _configure_z2security(_context, new_class, required)
+
_context.action(
discriminator = ('view', (for_, layer), name, IBrowserRequest),
callable = handler,
@@ -137,40 +179,7 @@
new_class, (for_, layer), Interface, name, _context.info),
)
- # Security
- _context.action(
- discriminator = ('five:protectClass', new_class),
- callable = protectClass,
- args = (new_class, permission)
- )
- if allowed_attributes:
- for attr in allowed_attributes:
- _context.action(
- discriminator = ('five:protectName', new_class, attr),
- callable = protectName,
- args = (new_class, attr, permission)
- )
- # Make everything else private
- allowed = [attribute] + (allowed_attributes or [])
- 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)
- )
- # Protect the class
- _context.action(
- discriminator = ('five:initialize:class', new_class),
- callable = InitializeClass,
- args = (new_class,)
- )
-
-
class pages(zope.browserpage.metaconfigure.pages):
def page(self, _context, name, attribute='__call__', template=None,
@@ -274,8 +283,17 @@
cdict['__name__'] = name
newclass = makeClass(cname, bases, cdict)
+ for n in ('',):
+ required[n] = permission
+
+ _handle_allowed_interface(_context, allowed_interface, permission,
+ required)
+ _handle_allowed_attributes(_context, allowed_attributes, permission,
+ required)
_handle_for(_context, for_)
+ _configure_z2security(_context, newclass, required)
+
if self.provides is not None:
_context.action(
discriminator = None,
@@ -291,42 +309,7 @@
_context.info),
)
- # Security
- _context.action(
- discriminator = ('five:protectClass', newclass),
- callable = protectClass,
- args = (newclass, permission)
- )
-
- if allowed_attributes:
- for attr in allowed_attributes:
- _context.action(
- discriminator = ('five:protectName', newclass, attr),
- callable = protectName,
- args = (newclass, attr, permission)
- )
-
- # Make everything else private
- allowed = allowed_attributes or []
- private_attrs = [name for name in dir(newclass)
- if (not name.startswith('_')) and
- (name not in allowed) and
- ismethod(getattr(newclass, name))]
- for attr in private_attrs:
- _context.action(
- discriminator = ('five:protectName', newclass, attr),
- callable = protectName,
- args = (newclass, attr, CheckerPrivateId, False)
- )
-
- # Protect the class
- _context.action(
- discriminator = ('five:initialize:class', newclass),
- callable = InitializeClass,
- args = (newclass,)
- )
-
_factory_map = {'image':{'prefix':'ImageResource',
'count':0,
'factory':ImageResourceFactory},
@@ -448,6 +431,14 @@
class ViewMixinForAttributes(BrowserView,
zope.browserpage.metaconfigure.simple):
+ # XXX: this alternative implementation would support permission checks for
+ # the attribute instead of the view
+ # def browserDefault(self, request):
+ # return self, (self.__page_attribute__,)
+ #
+ # def publishTraverse(self, request, name):
+ # return getattr(self, name)
+
# For some reason, the 'simple' baseclass doesn't implement this
# mandatory method (see https://bugs.launchpad.net/zope3/+bug/129296)
def browserDefault(self, request):
Property changes on: Zope/trunk/src/Products/Five/browser/metaconfigure.py
___________________________________________________________________
Deleted: svn:keywords
- Id
Modified: Zope/trunk/src/Products/Five/browser/tests/pages.txt
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/pages.txt 2012-07-06 22:50:25 UTC (rev 127278)
+++ Zope/trunk/src/Products/Five/browser/tests/pages.txt 2012-07-07 09:41:15 UTC (rev 127279)
@@ -205,11 +205,11 @@
>>> request = TestRequest()
>>> view = getMultiAdapter((self.folder.testoid, request), name=u'eagle.txt')
-It's protecting the object with the permission, and not the attribute,
-so we get ('',) instead of ('eagle',):
+With the current browserDefault implementation permissions are checked for the
+object, and not for the attribute, but it is more robust to protect both:
>>> view.__ac_permissions__
- (('View management screens', ('',)),)
+ (('View management screens', ('', 'eagle')),)
The view's __roles__ attribute can be evaluated correctly:
@@ -224,6 +224,21 @@
>>> aq_acquire(view, '__roles__')
('Manager',)
+ >>> aq_acquire(view, 'eagle__roles__')
+ ('Manager',)
+
+Other attributes are private:
+
+ >>> from AccessControl import ACCESS_PRIVATE
+ >>> aq_acquire(view, 'mouse__roles__') is ACCESS_PRIVATE
+ True
+
+In zope.browserpage this is just protected with the specified permission. Not
+sure if this has to be private in Zope 2:
+
+ >>> aq_acquire(view, 'publishTraverse__roles__') is ACCESS_PRIVATE
+ True
+
Check to see if view's context properly acquires its true
parent
Modified: Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py 2012-07-06 22:50:25 UTC (rev 127278)
+++ Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py 2012-07-07 09:41:15 UTC (rev 127279)
@@ -78,6 +78,12 @@
... xmlns:browser="http://namespaces.zope.org/browser">
... <browser:page
... for="*"
+ ... name="testpage"
+ ... permission="zope2.ViewManagementScreens"
+ ... class="AccessControl.tests.testZCML.Dummy1"
+ ... allowed_interface="AccessControl.tests.testZCML.IDummy" />
+ ... <browser:view
+ ... for="*"
... name="testview"
... permission="zope2.ViewManagementScreens"
... class="AccessControl.tests.testZCML.Dummy1"
@@ -106,7 +112,7 @@
>>> from zope.component import getMultiAdapter
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
- >>> view = getMultiAdapter((dummy1, request), name="testview")
+ >>> view = getMultiAdapter((dummy1, request), name="testpage")
As 'foo' is defined in IDummy, it should have the 'Manager' role.
@@ -124,6 +130,16 @@
>>> getRoles(view, 'superMethod', view.superMethod, ('Def',))
('Manager',)
+ Same tests work using the view directive:
+
+ >>> view = getMultiAdapter((dummy1, request), name="testview")
+ >>> getRoles(view, 'foo', view.foo, ('Def',))
+ ('Manager',)
+ >>> getRoles(view, 'wot', view.wot, ('Def',)) is ACCESS_PRIVATE
+ True
+ >>> getRoles(view, 'superMethod', view.superMethod, ('Def',))
+ ('Manager',)
+
>>> tearDown()
"""
More information about the Zope-Checkins
mailing list