diff roundup/cgi/templating.py @ 2649:1df7d4a41da4

Buncha stuff (sorry about the large checkin): - Permissions may now be defined on a per-property basis - added "Create" Permission. Replaces the "Web"- and "Email Registration" Permissions. - added option to turn off registration confirmation via email ("instant_registration" in config) Migrated the user edit/view permission to use check code. Fixed a buncha stuff in the default templates. Needs a thorough review though.
author Richard Jones <richard@users.sourceforge.net>
date Wed, 28 Jul 2004 02:29:46 +0000
parents b01eca163779
children 17bab083c8a0
line wrap: on
line diff
--- a/roundup/cgi/templating.py	Tue Jul 27 11:36:01 2004 +0000
+++ b/roundup/cgi/templating.py	Wed Jul 28 02:29:46 2004 +0000
@@ -262,17 +262,10 @@
     }
     # add in the item if there is one
     if client.nodeid:
-        if classname == 'user':
-            c['context'] = HTMLUser(client, classname, client.nodeid,
-                anonymous=1)
-        else:
-            c['context'] = HTMLItem(client, classname, client.nodeid,
-                anonymous=1)
+        c['context'] = HTMLItem(client, classname, client.nodeid,
+            anonymous=1)
     elif client.db.classes.has_key(classname):
-        if classname == 'user':
-            c['context'] = HTMLUserClass(client, classname, anonymous=1)
-        else:
-            c['context'] = HTMLClass(client, classname, anonymous=1)
+        c['context'] = HTMLClass(client, classname, anonymous=1)
     return c
 
 class RoundupPageTemplate(PageTemplate.PageTemplate):
@@ -328,15 +321,9 @@
         if m:
             cl = m.group('cl')
             self._client.db.getclass(cl)
-            if cl == 'user':
-                klass = HTMLUser
-            else:
-                klass = HTMLItem
-            return klass(self._client, cl, m.group('id'))
+            return HTMLItem(self._client, cl, m.group('id'))
         else:
             self._client.db.getclass(item)
-            if item == 'user':
-                return HTMLUserClass(self._client, item)
             return HTMLClass(self._client, item)
 
     def __getattr__(self, attr):
@@ -350,10 +337,7 @@
         l.sort()
         m = []
         for item in l:
-            if item == 'user':
-                m.append(HTMLUserClass(self._client, item))
-            else:
-                m.append(HTMLClass(self._client, item))
+            m.append(HTMLClass(self._client, item))
         return m
 
 def lookupIds(db, prop, ids, fail_ok=0, num_re=re.compile('^-?\d+$')):
@@ -386,42 +370,6 @@
             l.append(entry)
     return l
 
-class HTMLPermissions:
-    ''' Helpers that provide answers to commonly asked Permission questions.
-    '''
-    def is_edit_ok(self):
-        ''' Is the user allowed to Edit the current class?
-        '''
-        return self._db.security.hasPermission('Edit', self._client.userid,
-            self._classname)
-
-    def is_view_ok(self):
-        ''' Is the user allowed to View the current class?
-        '''
-        return self._db.security.hasPermission('View', self._client.userid,
-            self._classname)
-
-    def is_only_view_ok(self):
-        ''' Is the user only allowed to View (ie. not Edit) the current class?
-        '''
-        return self.is_view_ok() and not self.is_edit_ok()
-
-    def view_check(self):
-        ''' Raise the Unauthorised exception if the user's not permitted to
-            view this class.
-        '''
-        if not self.is_view_ok():
-            raise Unauthorised("view", self._classname,
-                translator=self._client.translator)
-
-    def edit_check(self):
-        ''' Raise the Unauthorised exception if the user's not permitted to
-            edit this class.
-        '''
-        if not self.is_edit_ok():
-            raise Unauthorised("edit", self._classname,
-                translator=self._client.translator)
-
 def input_html4(**attrs):
     """Generate an 'input' (html4) element with given attributes"""
     return '<input %s>'%' '.join(['%s="%s"'%item for item in attrs.items()])
@@ -453,6 +401,32 @@
 
     _ = gettext
 
+class HTMLPermissions:
+
+    def view_check(self):
+        ''' Raise the Unauthorised exception if the user's not permitted to
+            view this class.
+        '''
+        if not self.is_view_ok():
+            raise Unauthorised("view", self._classname,
+                translator=self._client.translator)
+
+    def create_check(self):
+        ''' Raise the Unauthorised exception if the user's not permitted to
+            create items of this class.
+        '''
+        if not self.is_create_ok():
+            raise Unauthorised("create", self._classname,
+                translator=self._client.translator)
+
+    def edit_check(self):
+        ''' Raise the Unauthorised exception if the user's not permitted to
+            edit items of this class.
+        '''
+        if not self.is_edit_ok():
+            raise Unauthorised("edit", self._classname,
+                translator=self._client.translator)
+
 class HTMLClass(HTMLInputMixin, HTMLPermissions):
     ''' Accesses through a class (either through *class* or *db.<classname>*)
     '''
@@ -469,6 +443,25 @@
 
         HTMLInputMixin.__init__(self)
 
+    def is_edit_ok(self):
+        ''' Is the user allowed to Create the current class?
+        '''
+        return self._db.security.hasPermission('Create', self._client.userid,
+            self._classname)
+
+    def is_view_ok(self):
+        ''' Is the user allowed to View the current class?
+        '''
+        if self._db.security.hasPermission('View', self._client.userid,
+                self._classname):
+            return 1
+        return self.is_create_ok()
+
+    def is_only_view_ok(self):
+        ''' Is the user only allowed to View (ie. not Create) the current class?
+        '''
+        return self.is_view_ok() and not self.is_create_ok()
+
     def __repr__(self):
         return '<HTMLClass(0x%x) %s>'%(id(self), self.classname)
 
@@ -534,12 +527,7 @@
         if not isinstance(itemid, type(1)) and not num_re.match(itemid):
             itemid = self._klass.lookup(itemid)
 
-        if self.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-
-        return klass(self._client, self.classname, itemid)
+        return HTMLItem(self._client, self.classname, itemid)
 
     def properties(self, sort=1):
         ''' Return HTMLProperty for all of this class' properties.
@@ -561,17 +549,12 @@
     def list(self, sort_on=None):
         ''' List all items in this class.
         '''
-        if self.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-
         # get the list and sort it nicely
         l = self._klass.list()
         sortfunc = make_sort_function(self._db, self.classname, sort_on)
         l.sort(sortfunc)
 
-        l = [klass(self._client, self.classname, x) for x in l]
+        l = [HTMLItem(self._client, self.classname, x) for x in l]
         return l
 
     def csv(self):
@@ -615,11 +598,7 @@
             filterspec = request.filterspec
             sort = request.sort
             group = request.group
-        if self.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-        l = [klass(self._client, self.classname, x)
+        l = [HTMLItem(self._client, self.classname, x)
              for x in self._klass.filter(None, filterspec, sort, group)]
         return l
 
@@ -683,7 +662,7 @@
         }
         return pt.render(self._client, self.classname, req, **args)
 
-class HTMLItem(HTMLInputMixin, HTMLPermissions):
+class _HTMLItem(HTMLInputMixin, HTMLPermissions):
     ''' Accesses through an *item*
     '''
     def __init__(self, client, classname, nodeid, anonymous=0):
@@ -699,6 +678,25 @@
 
         HTMLInputMixin.__init__(self)
 
+    def is_edit_ok(self):
+        ''' Is the user allowed to Edit the current class?
+        '''
+        return self._db.security.hasPermission('Edit', self._client.userid,
+            self._classname, itemid=self._nodeid)
+
+    def is_view_ok(self):
+        ''' Is the user allowed to View the current class?
+        '''
+        if self._db.security.hasPermission('View', self._client.userid,
+                self._classname, itemid=self._nodeid):
+            return 1
+        return self.is_edit_ok()
+
+    def is_only_view_ok(self):
+        ''' Is the user only allowed to View (ie. not Edit) the current class?
+        '''
+        return self.is_view_ok() and not self.is_edit_ok()
+
     def __repr__(self):
         return '<HTMLItem(0x%x) %s %s>'%(id(self), self._classname,
             self._nodeid)
@@ -1010,66 +1008,26 @@
         url = '%s%s/%s'%(self._classname, self._nodeid, name)
         return urllib.quote(url)
 
-
-class HTMLUserPermission:
-
-    def is_edit_ok(self):
-        ''' Is the user allowed to Edit the current class?
-            Also check whether this is the current user's info.
-        '''
-        return self._user_perm_check('Edit')
-
-    def is_view_ok(self):
-        ''' Is the user allowed to View the current class?
-            Also check whether this is the current user's info.
-        '''
-        return self._user_perm_check('View')
-
-    def _user_perm_check(self, type):
-        # some users may view / edit all users
-        s = self._db.security
-        userid = self._client.userid
-        if s.hasPermission(type, userid, self._classname):
-            return 1
-
-        # users may view their own info
-        is_anonymous = self._db.user.get(userid, 'username') == 'anonymous'
-        if getattr(self, '_nodeid', None) == userid and not is_anonymous:
-            return 1
-
-        # may anonymous users register? (so, they need to be anonymous,
-        # need the Web Rego permission, and not trying to view an item)
-        rego = s.hasPermission('Web Registration', userid, self._classname)
-        rego = rego and self._client.template == 'register'
-        if is_anonymous and rego and getattr(self, '_nodeid', None) is None:
-            return 1
-
-        # nope, no access here
-        return 0
-
-class HTMLUserClass(HTMLUserPermission, HTMLClass):
-    pass
-
-class HTMLUser(HTMLUserPermission, HTMLItem):
-    ''' Accesses through the *user* (a special case of item)
+class _HTMLUser(_HTMLItem):
+    '''Add ability to check for permissions on users.
     '''
-    def __init__(self, client, classname, nodeid, anonymous=0):
-        HTMLItem.__init__(self, client, 'user', nodeid, anonymous)
-        self._default_classname = client.classname
-
-        # used for security checks
-        self._security = client.db.security
-
     _marker = []
     def hasPermission(self, permission, classname=_marker):
-        ''' Determine if the user has the Permission.
+        '''Determine if the user has the Permission.
 
-            The class being tested defaults to the template's class, but may
-            be overidden for this test by suppling an alternate classname.
+        The class being tested defaults to the template's class, but may
+        be overidden for this test by suppling an alternate classname.
         '''
         if classname is self._marker:
-            classname = self._default_classname
-        return self._security.hasPermission(permission, self._nodeid, classname)
+            classname = self._client.classname
+        return self._client.db.security.hasPermission(permission,
+            self._nodeid, classname)
+
+def HTMLItem(client, classname, nodeid, anonymous=0):
+    if classname == 'user':
+        return _HTMLUser(client, classname, nodeid, anonymous)
+    else:
+        return _HTMLItem(client, classname, nodeid, anonymous)
 
 class HTMLProperty(HTMLInputMixin, HTMLPermissions):
     ''' String, Number, Date, Interval HTMLProperty
@@ -1116,24 +1074,23 @@
         return self._value is not None
 
     def is_edit_ok(self):
-        ''' Is the user allowed to Edit the current class?
+        '''Should the user be allowed to use an edit form field for this
+        property. Check "Create" for new items, or "Edit" for existing
+        ones.
         '''
-        thing = HTMLDatabase(self._client)[self._classname]
         if self._nodeid:
-            # this is a special-case for the User class where permission's
-            # on a per-item basis :(
-            thing = thing.getItem(self._nodeid)
-        return thing.is_edit_ok()
+            return self._db.security.hasPermission('Edit', self._client.userid,
+                self._classname, self._name, self._nodeid)
+        return self._db.security.hasPermission('Create', self._client.userid,
+            self._classname, self._name)
 
     def is_view_ok(self):
         ''' Is the user allowed to View the current class?
         '''
-        thing = HTMLDatabase(self._client)[self._classname]
-        if self._nodeid:
-            # this is a special-case for the User class where permission's
-            # on a per-item basis :(
-            thing = thing.getItem(self._nodeid)
-        return thing.is_view_ok()
+        if self._db.security.hasPermission('View', self._client.userid,
+                self._classname, self._name, self._nodeid):
+            return 1
+        return self.is_edit_ok()
 
 class StringHTMLProperty(HTMLProperty):
     hyper_re = re.compile(r'((?P<url>\w{3,6}://\S+)|'
@@ -1551,11 +1508,7 @@
        #print 'Link.getattr', (self, attr, self._value)
         if not self._value:
             raise AttributeError, "Can't access missing value"
-        if self._prop.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-        i = klass(self._client, self._prop.classname, self._value)
+        i = HTMLItem(self._client, self._prop.classname, self._value)
         return getattr(i, attr)
 
     def plain(self, escape=0):
@@ -1688,11 +1641,7 @@
         '''
        #print 'Multi.getitem', (self, num)
         value = self._value[num]
-        if self._prop.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-        return klass(self._client, self._prop.classname, value)
+        return HTMLItem(self._client, self._prop.classname, value)
 
     def __contains__(self, value):
         ''' Support the "in" operator. We have to make sure the passed-in
@@ -1709,11 +1658,8 @@
         '''
         l = self._value[:]
         l.reverse()
-        if self._prop.classname == 'user':
-            klass = HTMLUser
-        else:
-            klass = HTMLItem
-        return [klass(self._client, self._prop.classname, value) for value in l]
+        return [HTMLItem(self._client, self._prop.classname, value)
+            for value in l]
 
     def plain(self, escape=0):
         ''' Render a "plain" representation of the property
@@ -1865,7 +1811,7 @@
     - "form" the CGI form as a cgi.FieldStorage
     - "env" the CGI environment variables
     - "base" the base URL for this instance
-    - "user" a HTMLUser instance for this user
+    - "user" a HTMLItem instance for this user
     - "classname" the current classname (possibly None)
     - "template" the current template (suffix, also possibly None)
 
@@ -1888,7 +1834,7 @@
         self.form = client.form
         self.env = client.env
         self.base = client.base
-        self.user = HTMLUser(client, 'user', client.userid)
+        self.user = HTMLItem(client, 'user', client.userid)
 
         # store the current class name and action
         self.classname = client.classname
@@ -2220,10 +2166,7 @@
         item = self._sequence[index + self.first]
         if self.classname:
             # map the item ids to instances
-            if self.classname == 'user':
-                item = HTMLUser(self.client, self.classname, item)
-            else:
-                item = HTMLItem(self.client, self.classname, item)
+            item = HTMLItem(self.client, self.classname, item)
         self.current_item = item
         return item
 

Roundup Issue Tracker: http://roundup-tracker.org/