Code

- admin permissions are special: the classname is None which means
[roundup.git] / roundup / security.py
index 3dfa8bd442c13ec068ca90589a10e55fc9f5b9fa..e46e291c36c6c65630439121db834cb3638a6bbf 100644 (file)
@@ -54,6 +54,28 @@ class Permission:
         # we have a winner
         return 1
 
+    def searchable(self, classname, property):
+        """ A Permission is searchable for the given permission if it
+            doesn't include a check method and otherwise matches the
+            given parameters.
+        """
+        if self.name not in ('View', 'Search'):
+            return 0
+
+        # are we checking the correct class
+        if self.klass is not None and self.klass != classname:
+            return 0
+
+        # what about property?
+        if not self._properties_dict[property]:
+            return 0
+
+        if self.check:
+            return 0
+
+        return 1
+
+
     def __repr__(self):
         return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name,
             self.klass, self.properties, self.check)
@@ -175,6 +197,60 @@ class Security:
                     return 1
         return 0
 
+    def roleHasSearchPermission(self, rolename, classname, property):
+        """ For each of the user's Roles, check the permissions.
+            Property can be a transitive property.
+        """
+        cn = classname
+        last = None
+        # Note: break from inner loop means "found"
+        #       break from outer loop means "not found"
+        for propname in property.split('.'):
+            if last:
+                try:
+                    cls = self.db.getclass(cn)
+                    lprop = cls.getprops()[last]
+                except KeyError:
+                    break
+                cn = lprop.classname
+            last = propname
+            for perm in self.role[rolename].permissions:
+                if perm.searchable(cn, propname):
+                    break
+            else:
+                break
+        else:
+            return 1
+        return 0
+
+    def hasSearchPermission(self, userid, classname, property):
+        '''Look through all the Roles, and hence Permissions, and
+           see if "permission" exists given the constraints of
+           classname and property.
+
+           A search permission is granted if we find a 'View' or
+           'Search' permission for the user which does *not* include
+           a check function. If such a permission is found, the user may
+           search for the given property in the given class.
+
+           Note that classname *and* property are mandatory arguments.
+
+           Contrary to hasPermission, the search will *not* match if
+           there are additional constraints (namely a search function)
+           on a Permission found.
+
+           Concerning property, the Permission matched must have
+           either no properties listed or the property must appear in
+           the list.
+        '''
+        for rolename in self.db.user.get_roles(userid):
+            if not rolename or not self.role.has_key(rolename):
+                continue
+            # for each of the user's Roles, check the permissions
+            if self.roleHasSearchPermission (rolename, classname, property):
+                return 1
+        return 0
+
     def addPermission(self, **propspec):
         ''' Create a new Permission with the properties defined in
             'propspec'. See the Permission class for the possible
@@ -208,4 +284,22 @@ class Security:
         role = self.role[rolename.lower()]
         role.permissions.append(permission)
 
+    # Convenience methods for removing non-allowed properties from a
+    # filterspec or sort/group list
+
+    def filterFilterspec(self, userid, classname, filterspec):
+        """ Return a filterspec that has all non-allowed properties removed.
+        """
+        return dict ([(k, v) for k, v in filterspec.iteritems()
+            if self.hasSearchPermission(userid,classname,k)])
+
+    def filterSortspec(self, userid, classname, sort):
+        """ Return a sort- or group-list that has all non-allowed properties
+            removed.
+        """
+        if isinstance(sort, tuple) and sort[0] in '+-':
+            sort = [sort]
+        return [(d, p) for d, p in sort
+            if self.hasSearchPermission(userid,classname,p)]
+
 # vim: set filetype=python sts=4 sw=4 et si :