[Checkins] SVN: grok/trunk/ Merge the jw-refer-to-permission-class branch

Jan-Wijbrand Kolman janwijbrand at gmail.com
Fri May 2 05:57:37 EDT 2008


Log message for revision 86068:
  Merge the jw-refer-to-permission-class branch

Changed:
  U   grok/trunk/CHANGES.txt
  U   grok/trunk/src/grok/__init__.py
  U   grok/trunk/src/grok/components.py
  U   grok/trunk/src/grok/directive.py
  U   grok/trunk/src/grok/ftests/rest/rest.py
  U   grok/trunk/src/grok/ftests/security/require.py
  U   grok/trunk/src/grok/ftests/security/roles.py
  U   grok/trunk/src/grok/ftests/security/xmlrpc.py
  U   grok/trunk/src/grok/ftests/viewlet/viewlet_security.py
  U   grok/trunk/src/grok/interfaces.py
  U   grok/trunk/src/grok/tests/security/missing_permission_json3.py
  U   grok/trunk/src/grok/tests/security/missing_permission_xmlrpc3.py
  U   grok/trunk/src/grok/tests/security/multiple_require.py
  U   grok/trunk/src/grok/tests/security/multiple_require_json.py
  U   grok/trunk/src/grok/tests/security/multiple_require_xmlrpc.py
  A   grok/trunk/src/grok/tests/security/not_a_permissionclass.py
  U   grok/trunk/src/grok/tests/security/view_decorator.py

-=-
Modified: grok/trunk/CHANGES.txt
===================================================================
--- grok/trunk/CHANGES.txt	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/CHANGES.txt	2008-05-02 09:57:37 UTC (rev 86068)
@@ -7,16 +7,21 @@
 Feature changes
 ---------------
 
+* grok.require() can refer to subclasses of grok.Permission directly, instead
+  of their id. This, for one, avoids making typos in permission ids. Permission
+  components *do* still need the grok.name() directive for defining the
+  permission's id.
+
 * The basic component base classes (``Adapter``, ``MultiAdapter``,
   ``GlobalUtility``), their grokkers, as well as many of the basic
   directives have been factored out to a reusable
   ``grokcore.component`` package.
 
 * Added an optional parameter 'data' to the method 'url()' that accepts
-  a dictionary that is then converted to a query string. See 
-   
+  a dictionary that is then converted to a query string. See
+
   http://grok.zope.org/documentation/how-to/generate-urls-with-the-url-function-in-views/view
-  
+
 * Added an ``OrderedContainer`` component.
 
 * Introduced the new `sphinx`-based documentation engine. See

Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/__init__.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -38,7 +38,7 @@
 from grok.components import Site, LocalUtility, Annotation
 from grok.components import Application, Form, AddForm, EditForm, DisplayForm
 from grok.components import Indexes
-from grok.components import Permission, Role
+from grok.components import Permission, Role, Public
 from grok.components import Skin, IGrokLayer
 from grok.components import RESTProtocol, IRESTLayer
 from grok.interfaces import IRESTSkinType

Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/components.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -192,7 +192,7 @@
 
 
     def url(self, obj=None, name=None, data=None):
-        """Return string for the URL based on the obj and name. The data 
+        """Return string for the URL based on the obj and name. The data
         argument is used to form a CGI query string.
         """
         if isinstance(obj, basestring):
@@ -209,7 +209,7 @@
         elif name is not None and obj is None:
             # create URL to view on context
             obj = self.context
-            
+
         if data is None:
             data = {}
         else:
@@ -635,6 +635,8 @@
 class Permission(Permission):
     pass
 
+Public = 'zope.Public'
+
 class Role(Role):
     pass
 

Modified: grok/trunk/src/grok/directive.py
===================================================================
--- grok/trunk/src/grok/directive.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/directive.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -30,6 +30,7 @@
                                ClassOrModuleDirectiveContext)
 from martian import util
 from grokcore.component.directive import MultiValueOnceDirective
+from grok import components
 
 class LocalUtilityDirective(MultipleTimesDirective):
     def check_arguments(self, factory, provides=None, name=u'',
@@ -55,9 +56,20 @@
         self.name_in_container = name_in_container
 
 
-class RequireDirective(BaseTextDirective, SingleValue, MultipleTimesDirective):
+class RequireDirective(SingleValue, MultipleTimesDirective):
 
+    def check_arguments(self, value):
+        if util.check_subclass(value, components.Permission):
+            return
+        if util.not_unicode_or_ascii(value):
+            raise GrokImportError(
+                "You can only pass unicode, ASCII, or a subclass "
+                "of grok.Permission %s." % self.name)
+
     def store(self, frame, value):
+        if util.check_subclass(value, components.Permission):
+            value = getattr(value, '__grok_name__')
+
         super(RequireDirective, self).store(frame, value)
         values = frame.f_locals.get(self.local_name, [])
 
@@ -71,6 +83,7 @@
             return func
         return decorator
 
+
 # Define grok directives
 template = SingleTextDirective('grok.template', ClassDirectiveContext())
 templatedir = SingleTextDirective('grok.templatedir', ModuleDirectiveContext())

Modified: grok/trunk/src/grok/ftests/rest/rest.py
===================================================================
--- grok/trunk/src/grok/ftests/rest/rest.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/ftests/rest/rest.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -7,7 +7,7 @@
   >>> root = getRootFolder()
   >>> root['app'] = MyApp()
   >>> root['app']['alpha'] = MyContent()
-  
+
 Issue a GET request::
 
   >>> response = http_call('GET', 'http://localhost/++rest++a/app')
@@ -100,7 +100,7 @@
   Traceback (most recent call last):
     ...
   GrokMethodNotAllowed: <grok.ftests.rest.rest.MyApp object at ...
-  
+
 We have added support for GET for the ``alpha`` subobject only, in
 the default rest layer::
 
@@ -133,10 +133,10 @@
   Content-Length: 18
   <BLANKLINE>
   Method Not Allowed
-  
+
   >>> print http('POST /++rest++c/app HTTP/1.1')
   HTTP/1. 405 Method Not Allowed
-  Allow: 
+  Allow:
   Content-Length: 18
   Content-Type: text/plain
   <BLANKLINE>
@@ -233,7 +233,7 @@
   <BLANKLINE>
 
  We shouldn't be allowed to PUT either::
- 
+
   >>> print http('PUT /app/beta HTTP/1.1')
   HTTP/1. 404 Not Found
   Content-Length: 0
@@ -264,7 +264,7 @@
   >>> response = http_call('PUT', 'http://localhost/++rest++g/app/two')
   >>> print response.getBody()
   PUT directly registered
-  
+
 We expect POST and DELETE to be the same on both. For the directly
 registered object (two) it should fall back to the interface as there
 is none more specifically declared::
@@ -301,7 +301,7 @@
 
 class MyContent(grok.Model):
     pass
-    
+
 class LayerA(grok.IRESTLayer):
     pass
 
@@ -340,11 +340,11 @@
 
 class G(grok.RESTProtocol):
     grok.layer(LayerInterface)
-    
+
 class ARest(grok.REST):
     grok.layer(LayerA)
     grok.context(MyApp)
-    
+
     def GET(self):
         return "GET"
 
@@ -360,7 +360,7 @@
 class BRest(grok.REST):
     grok.layer(LayerB)
     grok.context(MyApp)
-    
+
     def GET(self):
         return "GET"
 
@@ -373,15 +373,15 @@
 
 class DRest(grok.REST):
     grok.context(MyContent)
-    
+
     def GET(self):
         return "GET2"
 
 class SecurityRest(grok.REST):
     grok.context(MyContent)
     grok.layer(LayerSecurity)
-    
-    @grok.require('zope.Public')
+
+    @grok.require(grok.Public)
     def GET(self):
         return "GET3"
 
@@ -396,7 +396,7 @@
     @grok.require('zope.ManageContent')
     def DELETE(self):
         return "DELETE3"
-    
+
 class BodyTest(grok.REST):
     grok.context(MyContent)
     grok.layer(LayerContent)
@@ -416,7 +416,7 @@
 class InterfaceRest(grok.REST):
     grok.context(IFoo)
     grok.layer(LayerInterface)
-    
+
     def GET(self):
         return "GET interface registered"
 
@@ -432,7 +432,7 @@
 class NoInterfaceRest(grok.REST):
     grok.context(MyNoInterfaceContent)
     grok.layer(LayerInterface)
-    
+
     def GET(self):
         return "GET directly registered"
 

Modified: grok/trunk/src/grok/ftests/security/require.py
===================================================================
--- grok/trunk/src/grok/ftests/security/require.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/ftests/security/require.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -34,17 +34,15 @@
     grok.name('cave.ViewPainting')
 
 class Painting(grok.View):
-
     grok.context(zope.interface.Interface)
-    grok.require('cave.ViewPainting')
+    grok.require(ViewPainting)
 
     def render(self):
         return 'What a beautiful painting.'
 
 class PublicNudity(grok.View):
-
     grok.context(zope.interface.Interface)
-    grok.require('zope.Public')
+    grok.require(grok.Public)
 
     def render(self):
         return 'Everybody can see this.'

Modified: grok/trunk/src/grok/ftests/security/roles.py
===================================================================
--- grok/trunk/src/grok/ftests/security/roles.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/ftests/security/roles.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -46,16 +46,16 @@
 import grok
 import zope.interface
 
-class View(grok.Permission):
+class ViewPermission(grok.Permission):
     grok.name('paint.ViewPainting')
 
-class Edit(grok.Permission):
+class EditPermission(grok.Permission):
     grok.name('paint.EditPainting')
 
-class Erase(grok.Permission):
+class ErasePermission(grok.Permission):
     grok.name('paint.ErasePainting')
 
-class Approve(grok.Permission):
+class ApprovePermission(grok.Permission):
     grok.name('paint.ApprovePainting')
 
 class PaintingOwner(grok.Role):
@@ -67,7 +67,7 @@
 class CavePainting(grok.View):
 
     grok.context(zope.interface.Interface)
-    grok.require('paint.ViewPainting')
+    grok.require(ViewPermission)
 
     def render(self):
         return 'What a beautiful painting.'
@@ -75,7 +75,7 @@
 class EditCavePainting(grok.View):
 
     grok.context(zope.interface.Interface)
-    grok.require('paint.EditPainting')
+    grok.require(EditPermission)
 
     def render(self):
         return 'Let\'s make it even prettier.'
@@ -83,7 +83,7 @@
 class EraseCavePainting(grok.View):
 
     grok.context(zope.interface.Interface)
-    grok.require('paint.ErasePainting')
+    grok.require(ErasePermission)
 
     def render(self):
         return 'Oops, mistake, let\'s erase it.'
@@ -91,7 +91,7 @@
 class ApproveCavePainting(grok.View):
 
     grok.context(zope.interface.Interface)
-    grok.require('paint.ApprovePainting')
+    grok.require(ApprovePermission)
 
     def render(self):
         return 'Painting owners cannot approve their paintings.'

Modified: grok/trunk/src/grok/ftests/security/xmlrpc.py
===================================================================
--- grok/trunk/src/grok/ftests/security/xmlrpc.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/ftests/security/xmlrpc.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -15,7 +15,7 @@
 
 With manager privileges, the protected method is accessible, however:
 
-  >>> print mgr_server.dance()  
+  >>> print mgr_server.dance()
   Manfred doesn't like to dance.
 
 The same applies when a default permission is defined for all XML-RPC
@@ -58,6 +58,6 @@
     def eat(self):
         return 'MMM, MANFRED TASTE GOOD!'
 
-    @grok.require('zope.Public')
+    @grok.require(grok.Public)
     def rest(self):
         return 'ME GROK TIRED!'

Modified: grok/trunk/src/grok/ftests/viewlet/viewlet_security.py
===================================================================
--- grok/trunk/src/grok/ftests/viewlet/viewlet_security.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/ftests/viewlet/viewlet_security.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -149,7 +149,7 @@
 class GoldBone(grok.Viewlet):
     grok.context(Interface)
     grok.viewletmanager(Pot)
-    grok.require('bone.gold')
+    grok.require(Gold)
 
     def render(self):
         return 'Gold Bone'

Modified: grok/trunk/src/grok/interfaces.py
===================================================================
--- grok/trunk/src/grok/interfaces.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/interfaces.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -50,6 +50,9 @@
     Skin = interface.Attribute("Base class for skin.")
     ViewletManager = interface.Attribute("Base class for viewletmanager.")
     Viewlet = interface.Attribute("Base class for viewlet.")
+    Permission = interface.Attribute("Base class for permissions.")
+    Role = interface.Attribute("Base class for roles.")
+    Public = interface.Attribute("Marker for explicitly not requiring a permission.")
 
 
 class IGrokErrors(interface.Interface):
@@ -308,8 +311,8 @@
 
         If both object and name arguments are supplied, construct
         URL to obj/name.
-        
-        Optionally pass a 'data' keyword argument which gets added to the URL 
+
+        Optionally pass a 'data' keyword argument which gets added to the URL
         as a cgi query string.
         """
 

Modified: grok/trunk/src/grok/tests/security/missing_permission_json3.py
===================================================================
--- grok/trunk/src/grok/tests/security/missing_permission_json3.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/missing_permission_json3.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -20,8 +20,8 @@
     grok.context(zope.interface.Interface)
 
     grok.require('doesnt.exist')
-    
-    @grok.require('json.exists')
+
+    @grok.require(Permission)
     def foo(self):
         pass
 

Modified: grok/trunk/src/grok/tests/security/missing_permission_xmlrpc3.py
===================================================================
--- grok/trunk/src/grok/tests/security/missing_permission_xmlrpc3.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/missing_permission_xmlrpc3.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -21,6 +21,6 @@
     grok.context(zope.interface.Interface)
     grok.require('doesnt.exist')
 
-    @grok.require('foo')
+    @grok.require(Foo)
     def foo(self):
         pass

Modified: grok/trunk/src/grok/tests/security/multiple_require.py
===================================================================
--- grok/trunk/src/grok/tests/security/multiple_require.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/multiple_require.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -18,8 +18,8 @@
 
 class MultipleView(grok.View):
     grok.context(zope.interface.Interface)
-    grok.require('permission.1')
-    grok.require('permission.2')
+    grok.require(One)
+    grok.require(Two)
 
     def render(self):
         pass

Modified: grok/trunk/src/grok/tests/security/multiple_require_json.py
===================================================================
--- grok/trunk/src/grok/tests/security/multiple_require_json.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/multiple_require_json.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -18,8 +18,8 @@
 
 class MultipleJSON(grok.JSON):
     grok.context(zope.interface.Interface)
-    grok.require('permission.1')
-    grok.require('permission.2')
+    grok.require(One)
+    grok.require(Two)
 
     def render(self):
         pass

Modified: grok/trunk/src/grok/tests/security/multiple_require_xmlrpc.py
===================================================================
--- grok/trunk/src/grok/tests/security/multiple_require_xmlrpc.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/multiple_require_xmlrpc.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -17,8 +17,8 @@
 
 class MultipleXMLRPC(grok.XMLRPC):
     grok.context(zope.interface.Interface)
-    grok.require('permission.1')
-    grok.require('permission.2')
+    grok.require(One)
+    grok.require(Two)
 
     def render(self):
         pass

Copied: grok/trunk/src/grok/tests/security/not_a_permissionclass.py (from rev 86056, grok/branches/jw-refer-to-permission-class/src/grok/tests/security/not_a_permissionclass.py)
===================================================================
--- grok/trunk/src/grok/tests/security/not_a_permissionclass.py	                        (rev 0)
+++ grok/trunk/src/grok/tests/security/not_a_permissionclass.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -0,0 +1,23 @@
+"""
+When refering to a class in the grok.require() directive, this class needs
+to implement the zope.security.interfaces.IPermission interface::
+
+  >>> from zope.interface import Interface
+  >>> class NotAProperPermission(object):
+  ...   pass
+  >>>
+  >>> class NoPermission(grok.View):
+  ...     grok.context(zope.interface.Interface)
+  ...     grok.require(NotAProperPermission)
+  ...
+  ...     def render(self):
+  ...         pass
+  Traceback (most recent call last):
+  ...
+  GrokImportError: You can only pass unicode, ASCII, or a subclass of
+  grok.Permission grok.require.
+
+"""
+
+import grok
+import zope.interface

Modified: grok/trunk/src/grok/tests/security/view_decorator.py
===================================================================
--- grok/trunk/src/grok/tests/security/view_decorator.py	2008-05-02 09:54:50 UTC (rev 86067)
+++ grok/trunk/src/grok/tests/security/view_decorator.py	2008-05-02 09:57:37 UTC (rev 86068)
@@ -17,6 +17,6 @@
 class BogusView(grok.View):
     grok.context(zope.interface.Interface)
 
-    @grok.require('bogus.perm')
+    @grok.require(Bogus)
     def render(self):
         pass



More information about the Checkins mailing list