[Checkins] SVN: five.customerize/trunk/src/five/customerize/ Add permission registration/checking

Alec Mitchell apm13 at columbia.edu
Sun Oct 29 18:59:49 EST 2006


Log message for revision 70976:
  Add permission registration/checking
  

Changed:
  U   five.customerize/trunk/src/five/customerize/browser.py
  U   five.customerize/trunk/src/five/customerize/customerize.txt
  A   five.customerize/trunk/src/five/customerize/testviewtemplate.pt
  U   five.customerize/trunk/src/five/customerize/zpt.py

-=-
Modified: five.customerize/trunk/src/five/customerize/browser.py
===================================================================
--- five.customerize/trunk/src/five/customerize/browser.py	2006-10-29 20:14:44 UTC (rev 70975)
+++ five.customerize/trunk/src/five/customerize/browser.py	2006-10-29 23:59:49 UTC (rev 70976)
@@ -81,6 +81,7 @@
                 'zptfile': mangleAbsoluteFilename(reg.factory.index.filename),
                 'zcmlfile': mangleAbsoluteFilename(reg.info.file)
                 }
+
     def viewClassFromViewName(self, viewname):
         view = zope.component.getMultiAdapter((self.context, self.request),
                                               name=viewname)
@@ -89,12 +90,11 @@
         # (generally object or BrowserView) we return the full class
         # and hope that it can be pickled
         klass = view.__class__
-        bases =klass.__bases__
-        if len(bases) == 1:
+        base =klass.__bases__[0]
+        if base is BrowserView or base is object:
             return klass
-        return bases[0]
+        return base
 
-
     def templateFromViewName(self, viewname):
         view = zope.component.getMultiAdapter((self.context, self.request),
                                               name=viewname)
@@ -104,6 +104,14 @@
         template = self.templateFromViewName(viewname)
         return open(template.filename, 'rb').read() #XXX: bad zope
 
+    def permissionFromViewName(self, viewname):
+        view = zope.component.getMultiAdapter((self.context, self.request),
+                                              name=viewname)
+        permissions = view.__class__.__ac_permissions__
+        for permission, methods in permissions:
+            if methods[0] in ('', '__call__'):
+                return permission
+
     def doCustomizeTemplate(self, viewname):
         # find the nearest site
         site = findSite(self.context, IObjectManagerSite)
@@ -118,7 +126,9 @@
 
         template_file = self.templateCodeFromViewName(viewname)
         viewclass = self.viewClassFromViewName(viewname)
-        viewzpt = TTWTemplate(zpt_id, template_file, view=viewclass)
+        permission = self.permissionFromViewName(viewname)
+        viewzpt = TTWTemplate(zpt_id, template_file, view=viewclass,
+                              permission=permission)
         site._setObject(zpt_id, viewzpt) #XXXthere could be a naming conflict
         components = site.getSiteManager()
 

Modified: five.customerize/trunk/src/five/customerize/customerize.txt
===================================================================
--- five.customerize/trunk/src/five/customerize/customerize.txt	2006-10-29 20:14:44 UTC (rev 70975)
+++ five.customerize/trunk/src/five/customerize/customerize.txt	2006-10-29 23:59:49 UTC (rev 70976)
@@ -29,8 +29,13 @@
   >>> zcml.load_config('configure.zcml', Products.Five)
   >>> zcml.load_config('configure.zcml', five.customerize)
 
+Make this test a usable module
+
+  >>> from zope.testing.module import setUp, tearDown
+  >>> setUp(test, name='five.customerize.testcustomerize')
+
 XXX: we are using root as the app name
-  >>> root = app
+  >>> root = self.folder
 
 
 1. Turning an ObjectManager into a site
@@ -156,10 +161,21 @@
   >>> from zope.app.component.hooks import setSite
   >>> setSite(site)
 
-Now look it up and compare its output:
+The newly registered adapter has an explicit security check that
+matches the original (in this case 'Manage Five local sites'),
+so the adapter lookup will fail unless logged in:
 
   >>> view = zope.component.getMultiAdapter((item, request),
   ...                                       name=u"customizezpt.html")
+  Traceback (most recent call last):
+  ...
+  Unauthorized: The current user does not have the required "Manage Five local sites" permission
+
+Now look it up as manager and compare its output:
+
+  >>> self.setRoles(['Manager',])
+  >>> view = zope.component.getMultiAdapter((item, request),
+  ...                                       name=u"customizezpt.html")
   >>> view = view.__of__(item)
   >>> print view() #doctest: +ELLIPSIS
   context:   <SimpleContent at item>
@@ -171,11 +187,7 @@
   nothing:   
   <BLANKLINE>
 
-  >>> view.__class__.__bases__
-  XXX
-
-
-5. Deleting view templates
+6. Deleting view templates
 --------------------------
 
 Once in a while we would like to get rid of the customized view.  The
@@ -196,7 +208,63 @@
     <code tal:content="request/form/viewname">viewname</code>:</p>
   ...
 
+5. Views with custom classes
+----------------------------
 
+Sometimes view classes have custom base classes which we need to be
+available to the customized local view.  We create one of these views
+(using all the normal browser:page insanity) and then customize it:
+
+  >>> from Products.Five.browser import BrowserView
+  >>> class TestView(BrowserView):
+  ...     """A view class"""
+  ...     __name__ = 'mystaticview.html'
+  ...     def foo_method(self):
+  ...         return 'baz'
+  >>> from Products.Five.browser.metaconfigure import makeClassForTemplate
+  >>> from Products.Five.security import getSecurityInfo, protectClass
+  >>> from Globals import InitializeClass
+  >>> cdict = getSecurityInfo(TestView)
+  >>> cdict['__name__'] = 'simpleview.html'
+  >>> viewclass = makeClassForTemplate('testviewtemplate.pt', globals=globals(),
+  ... bases=(TestView,), cdict=cdict, name='simpleview.html')
+  >>> protectClass(viewclass, 'zope.Public')
+  >>> InitializeClass(viewclass)
+  >>> from zope.component import provideAdapter
+  >>> from zope.interface import Interface
+  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+  >>> provideAdapter(viewclass, (Interface, IDefaultBrowserLayer),
+  ...                    Interface, name='simpleview.html')
+
+Now we retrieve the view and make sure it does what it should:
+
+  >>> view = zope.component.getMultiAdapter((item, request),
+  ...                                       name=u"simpleview.html")
+  >>> print view()
+  <html>
+  ...
+  A simple view template with a class
+  baz
+  ...
+
+And we customize it:
+
+  >>> customizeview = zope.component.getMultiAdapter((item, request),
+  ...                                       name=u"customizezpt.html")
+  >>> zpt = customizeview.doCustomizeTemplate(u'simpleview.html')
+  >>> template = getattr(site, 'testviewtemplate.pt')
+  >>> template.pt_edit('''\
+  ... A customized view
+  ... <span tal:replace="view/foo_method" />''', content_type=None)
+
+And render it again:
+
+  >>> view = zope.component.getMultiAdapter((item, request),
+  ...                                       name=u"simpleview.html")
+  >>> print view()
+  A customized view
+  baz
+
 Clean up:
 ---------
 

Added: five.customerize/trunk/src/five/customerize/testviewtemplate.pt
===================================================================
--- five.customerize/trunk/src/five/customerize/testviewtemplate.pt	2006-10-29 20:14:44 UTC (rev 70975)
+++ five.customerize/trunk/src/five/customerize/testviewtemplate.pt	2006-10-29 23:59:49 UTC (rev 70976)
@@ -0,0 +1,10 @@
+<html metal:use-macro="context/@@standard_macros/view"
+      i18n:domain="zope">
+  <body>
+  <div metal:fill-slot="body">
+
+    A simple view template with a class
+    <span tal:replace="view/foo_method"/>
+  </div>
+  </body>
+</html>
\ No newline at end of file

Modified: five.customerize/trunk/src/five/customerize/zpt.py
===================================================================
--- five.customerize/trunk/src/five/customerize/zpt.py	2006-10-29 20:14:44 UTC (rev 70975)
+++ five.customerize/trunk/src/five/customerize/zpt.py	2006-10-29 23:59:49 UTC (rev 70976)
@@ -1,4 +1,7 @@
 import zope.component
+from AccessControl import getSecurityManager
+from AccessControl import Unauthorized
+
 from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
 from zope.app.container.interfaces import IObjectRemovedEvent
 
@@ -6,13 +9,19 @@
     """A template class used to generate Zope 3 views TTW"""
 
     def __init__(self, id, text=None, content_type=None, encoding='utf-8',
-                 strict=False, view=None):
-        
+                 strict=False, view=None, permission=None):
         self.view = view
+        self.permission = permission
         super(TTWTemplate, self).__init__(id, text, content_type, encoding,
                                           strict)
 
     def __call__(self, context, request):
+        sm = getSecurityManager()
+        if self.permission:
+            allowed = sm.checkPermission(self.permission, context)
+            if not allowed:
+                raise Unauthorized, 'The current user does not have the '\
+                      'required "%s" permission'%self.permission
         return TTWTemplateRenderer(context, request, self, self.view)
 
 
@@ -26,17 +35,21 @@
     def __call__(self, *args, **kwargs):
         """Add the zope user to the security context, as done in
         PageTemplateFile"""
-        view = self.view
-        if view is not None:
-            class TTWView(view):
-                __allow_access_to_unprotected_subobjects__ = 1
-            view = TTWView(self.context, self.request)
+        view = self._getView()
         bound_names = {'view': view,
                        'request': self.request,
                        'context': self.context}
         template = self.template.__of__(self.context)
         return template._exec(bound_names, args, kwargs)
 
+    def _getView(self):
+        view = self.view
+        if view is not None:
+            class TTWView(view):
+                __allow_access_to_unprotected_subobjects__ = 1
+            view = TTWView(self.context, self.request)
+        return view
+
     def __of__(self, obj):
         return self
 
@@ -48,4 +61,3 @@
             break
     components.unregisterAdapter(reg.factory, reg.required, reg.provided,
                                  reg.name)
-



More information about the Checkins mailing list