changeset 8155:e9af08743759 permission-performance

Add check_factory For Permission objects where we're given a filter function but no check function, manufacture a check function.
author Ralf Schlatterbeck <rsc@runtux.com>
date Mon, 11 Nov 2024 14:32:25 +0100
parents 67a0fc4f9934
children 3f720edd9594
files roundup/security.py test/db_test_base.py
diffstat 2 files changed, 38 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/roundup/security.py	Mon Nov 11 11:25:55 2024 +0100
+++ b/roundup/security.py	Mon Nov 11 14:32:25 2024 +0100
@@ -89,6 +89,13 @@
 
         if check is None:
             self.check_version = 0
+            if filter is not None:
+                if klass is None:
+                    s = "Definition of a filter function" \
+                        " needs a check function if no klass is given"
+                    raise ValueError(s)
+                self.check = self.check_factory(klass, filter)
+                self.check_version = 1
         else:
             args = findargspec.findargspec(check)
             # args[2] is the keywords argument. Leave it as a subscript and
@@ -102,6 +109,18 @@
                 # function definition is function(db, userid, itemid, **other)
                 self.check_version = 2
 
+    def check_factory(self, klass, filter_function):
+        """ When a Permission defines a filter function but no check
+            function, we manufacture a check function here
+        """
+        def check(db, userid, itemid):
+            cls = db.getclass(klass)
+            args = filter_function(db, userid, cls)
+            for a in args:
+                if cls.filter([itemid], **a):
+                    return True
+        return check
+
     def test(self, db, permission, classname, property, userid, itemid):
         ''' Test permissions 5 args:
             permission - string like Edit, Register etc. Required, no wildcard.
--- a/test/db_test_base.py	Mon Nov 11 11:25:55 2024 +0100
+++ b/test/db_test_base.py	Mon Nov 11 14:32:25 2024 +0100
@@ -3049,6 +3049,25 @@
         # User may see own and public queries
         self.assertEqual(r, ['5', '6', '4', '3', '2', '1'])
 
+    def testFilteringWithManufacturedCheckFunction(self):
+        # We define a permission with a filter function but no check
+        # function. The check function is manufactured automatically.
+        # Then we test the manufactured *check* function only by turning
+        # off the filter function.
+        view_query = self.setupQuery()
+
+        def filter(db, userid, klass):
+            return [dict(filterspec = dict(private_for=['-1', userid]))]
+        perm = self.db.security.addPermission
+        p = perm(name='View', klass='query', filter=filter)
+        self.db.security.addPermissionToRole("User", p)
+        # Turn filtering off
+        self.db.config.RDBMS_DEBUG_FILTER = True
+        filt = self.db.query.filter_with_permissions
+        r = filt(None, {}, sort=[('+', 'name')])
+        # User may see own and public queries
+        self.assertEqual(r, ['5', '6', '4', '3', '2', '1'])
+
 # XXX add sorting tests for other types
 
     # nuke and re-create db for restore

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