root/tracforgeplugin/branches/bewst/0.11-clearsilver/tracforge/admin/perm.py

Revision 2410, 6.5 kB (checked in by bewst, 2 years ago)

TracForgePlugin:

Make computation of the contents of the assign-to popup in a
restrict_owner setup much more efficient.

Line 
1 from trac.core import *
2 from trac.config import Option
3 from trac.perm import IPermissionGroupProvider, PermissionSystem, DefaultPermissionStore
4 from trac.env import Environment
5
6 from model import Project
7 from config import EnvironmentOption
8 from tracforge.userlist import UserManager
9
10 import inspect
11
12 class TracForgePermissionModule(DefaultPermissionStore):
13     """Enhanced permission module to allow for central management."""
14
15     master_env = EnvironmentOption('tracforge', 'master_path',
16                                    doc='Path to master Trac')
17                          
18     def get_user_permissions(self, username):
19         subjects = set([username])
20         for provider in self.group_providers:
21             subjects |= set(provider.get_permission_groups(username))
22
23         actions = []
24         db = self.env.get_db_cnx()
25         cursor = db.cursor()
26         cursor.execute("SELECT username,action FROM permission")
27         rows = cursor.fetchall()
28         master_db = self.master_env.get_db_cnx()
29         master_cursor = master_db.cursor()
30         master_cursor.execute("SELECT username,action FROM tracforge_permission")
31         rows += master_cursor.fetchall()
32         while True:
33             num_users = len(subjects)
34             num_actions = len(actions)
35             for user, action in rows:
36                 if user in subjects:
37                     if not action.islower() and action not in actions:
38                         actions.append(action)
39                     if action.islower() and action not in subjects:
40                         # action is actually the name of the permission group
41                         # here
42                         subjects.add(action)
43             if num_users == len(subjects) and num_actions == len(actions):
44                 break
45         return [action for action in actions if not action.islower()]
46
47     def get_users_with_permissions(self, permissions):
48        
49         # This is really inefficient when there are many users.  The best way to
50         # do this would be to find all roles to which these permissions had been
51         # directly granted, then expand each role to get the users it contained.
52         # However, I don't think we currently have that interface in Trac.
53         result = set()
54        
55         def intersects(s1,s2):
56             if len(s1) < len(s2):
57                 for x in s1:
58                     if x in s2: return True
59             else:
60                 for x in s2:
61                     if x in s1: return True
62             return False
63
64         perms = set(permissions)
65
66         all_users = UserManager(self.master_env).get_all_users()
67        
68         for u in all_users:
69             if intersects(set(self.get_user_permissions(u)), perms):
70                 result.add(u)
71
72         result = list(result)
73         result.sort()
74         return result
75                
76     def get_all_permissions(self):
77         """Return all permissions for all users.
78
79         The permissions are returned as a list of (subject, action)
80         formatted tuples."""
81         db = self.env.get_db_cnx()
82         cursor = db.cursor()
83         cursor.execute("SELECT username,action FROM permission")
84         rows = cursor.fetchall()
85         req = self._extract_req()
86         if req is not None and not req.path_info.startswith('/admin/general/perm'):
87             master_db = self.master_env.get_db_cnx()
88             master_cursor = master_db.cursor()
89             master_cursor.execute("SELECT username,action FROM tracforge_permission")
90             rows += master_cursor.fetchall()
91         return [(row[0], row[1]) for row in rows]
92
93     def _extract_req(self):
94         """Truly evil magic to scan for a variable called req in the stack."""
95         for record in inspect.stack():
96             locals = record[0].f_locals
97             if 'req' in locals:
98                 return locals['req']
99         return None
100
101 class DefaultPermissionGroupProvider(object):
102     """A component that provides the groups defined by users
103
104     (by assigning lowercase action names).  This should really be handled by
105     trac.perm.DefaultPermissionGroupProvider.  See
106     http://trac.edgewall.org/ticket/5648 for details.  This code was shamelessly
107     copied from trac.perm.DefaultPermissionStore
108     """
109     implements(IPermissionGroupProvider)
110    
111     def __init__(self, env):
112         self.env = env
113    
114     def get_permission_groups(self, username):
115         subjects = set([username])
116         actions = set([])
117         db = self.env.get_db_cnx()
118         cursor = db.cursor()
119         cursor.execute("SELECT username,action FROM permission")
120         rows = cursor.fetchall()
121         while True:
122             num_users = len(subjects)
123             num_actions = len(actions)
124             for user, action in rows:
125                 if user in subjects:
126                     if action.isupper() and action not in actions:
127                         actions.add(action)
128                     if not action.isupper() and action not in subjects:
129                         # action is actually the name of the permission group
130                         # here
131                         subjects.add(action)
132             if num_users == len(subjects) and num_actions == len(actions):
133                 break
134            
135         return [s for s in subjects if s != username]
136
137
138    
139 class TracForgeGroupsModule(Component):
140     """A component to provide virtual groups based on the membership system."""
141    
142     master_env = EnvironmentOption('tracforge', 'master_path',
143                                    doc='Path to master Trac')
144
145     implements(IPermissionGroupProvider)
146
147     # IPermissionGroupProvider methods
148     def get_permission_groups(self, username):
149         group_extn_point = PermissionSystem(self.master_env).store.group_providers
150         group_providers = [x for x in group_extn_point if x.__class__.__name__ != self.__class__.__name__] # Filter out this one (recursion block)
151
152         master_groups = []
153         for prov in group_providers:
154             master_groups += list(prov.get_permission_groups(username))
155
156         self.log.debug('TracForgeGroupModule: Detected master groups (%s) for %s'%(', '.join([str(x) for x in master_groups]), username))
157
158         proj = Project.by_env_path(self.master_env, self.env.path)
159         access = set()
160         subjects = [username] + master_groups
161         for subj in subjects:
162             if subj in proj:
163                 access.add(proj.members[subj])
164                  
165         if 'admin' in access:
166             return ['admin', 'member']
167         elif 'member' in access:
168             return ['member']
169         elif 'staff' in access:
170             return ['staff']
171         else:
172             return []   
173        
Note: See TracBrowser for help on using the browser.