##// END OF EJS Templates
switch to defaultdict for counter implementation
marcink -
r3096:69b25f1b beta
parent child Browse files
Show More
@@ -1,707 +1,707 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import itertools
28 import itertools
29 import collections
29 import collections
30 import functools
30 import functools
31 from pylons import url
31 from pylons import url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.exc import DatabaseError
35 from sqlalchemy.orm import joinedload
35 from sqlalchemy.orm import joinedload
36
36
37 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
37 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
38 from rhodecode.lib.caching_query import FromCache
38 from rhodecode.lib.caching_query import FromCache
39 from rhodecode.model import BaseModel
39 from rhodecode.model import BaseModel
40 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
40 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
41 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
41 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
42 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
42 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
43 UserEmailMap
43 UserEmailMap
44 from rhodecode.lib.exceptions import DefaultUserException, \
44 from rhodecode.lib.exceptions import DefaultUserException, \
45 UserOwnsReposException
45 UserOwnsReposException
46
46
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
51
51
52
52
53 class UserModel(BaseModel):
53 class UserModel(BaseModel):
54 cls = User
54 cls = User
55
55
56 def get(self, user_id, cache=False):
56 def get(self, user_id, cache=False):
57 user = self.sa.query(User)
57 user = self.sa.query(User)
58 if cache:
58 if cache:
59 user = user.options(FromCache("sql_cache_short",
59 user = user.options(FromCache("sql_cache_short",
60 "get_user_%s" % user_id))
60 "get_user_%s" % user_id))
61 return user.get(user_id)
61 return user.get(user_id)
62
62
63 def get_user(self, user):
63 def get_user(self, user):
64 return self._get_user(user)
64 return self._get_user(user)
65
65
66 def get_by_username(self, username, cache=False, case_insensitive=False):
66 def get_by_username(self, username, cache=False, case_insensitive=False):
67
67
68 if case_insensitive:
68 if case_insensitive:
69 user = self.sa.query(User).filter(User.username.ilike(username))
69 user = self.sa.query(User).filter(User.username.ilike(username))
70 else:
70 else:
71 user = self.sa.query(User)\
71 user = self.sa.query(User)\
72 .filter(User.username == username)
72 .filter(User.username == username)
73 if cache:
73 if cache:
74 user = user.options(FromCache("sql_cache_short",
74 user = user.options(FromCache("sql_cache_short",
75 "get_user_%s" % username))
75 "get_user_%s" % username))
76 return user.scalar()
76 return user.scalar()
77
77
78 def get_by_email(self, email, cache=False, case_insensitive=False):
78 def get_by_email(self, email, cache=False, case_insensitive=False):
79 return User.get_by_email(email, case_insensitive, cache)
79 return User.get_by_email(email, case_insensitive, cache)
80
80
81 def get_by_api_key(self, api_key, cache=False):
81 def get_by_api_key(self, api_key, cache=False):
82 return User.get_by_api_key(api_key, cache)
82 return User.get_by_api_key(api_key, cache)
83
83
84 def create(self, form_data):
84 def create(self, form_data):
85 from rhodecode.lib.auth import get_crypt_password
85 from rhodecode.lib.auth import get_crypt_password
86 try:
86 try:
87 new_user = User()
87 new_user = User()
88 for k, v in form_data.items():
88 for k, v in form_data.items():
89 if k == 'password':
89 if k == 'password':
90 v = get_crypt_password(v)
90 v = get_crypt_password(v)
91 if k == 'firstname':
91 if k == 'firstname':
92 k = 'name'
92 k = 'name'
93 setattr(new_user, k, v)
93 setattr(new_user, k, v)
94
94
95 new_user.api_key = generate_api_key(form_data['username'])
95 new_user.api_key = generate_api_key(form_data['username'])
96 self.sa.add(new_user)
96 self.sa.add(new_user)
97 return new_user
97 return new_user
98 except:
98 except:
99 log.error(traceback.format_exc())
99 log.error(traceback.format_exc())
100 raise
100 raise
101
101
102 def create_or_update(self, username, password, email, firstname='',
102 def create_or_update(self, username, password, email, firstname='',
103 lastname='', active=True, admin=False, ldap_dn=None):
103 lastname='', active=True, admin=False, ldap_dn=None):
104 """
104 """
105 Creates a new instance if not found, or updates current one
105 Creates a new instance if not found, or updates current one
106
106
107 :param username:
107 :param username:
108 :param password:
108 :param password:
109 :param email:
109 :param email:
110 :param active:
110 :param active:
111 :param firstname:
111 :param firstname:
112 :param lastname:
112 :param lastname:
113 :param active:
113 :param active:
114 :param admin:
114 :param admin:
115 :param ldap_dn:
115 :param ldap_dn:
116 """
116 """
117
117
118 from rhodecode.lib.auth import get_crypt_password
118 from rhodecode.lib.auth import get_crypt_password
119
119
120 log.debug('Checking for %s account in RhodeCode database' % username)
120 log.debug('Checking for %s account in RhodeCode database' % username)
121 user = User.get_by_username(username, case_insensitive=True)
121 user = User.get_by_username(username, case_insensitive=True)
122 if user is None:
122 if user is None:
123 log.debug('creating new user %s' % username)
123 log.debug('creating new user %s' % username)
124 new_user = User()
124 new_user = User()
125 edit = False
125 edit = False
126 else:
126 else:
127 log.debug('updating user %s' % username)
127 log.debug('updating user %s' % username)
128 new_user = user
128 new_user = user
129 edit = True
129 edit = True
130
130
131 try:
131 try:
132 new_user.username = username
132 new_user.username = username
133 new_user.admin = admin
133 new_user.admin = admin
134 # set password only if creating an user or password is changed
134 # set password only if creating an user or password is changed
135 if edit is False or user.password != password:
135 if edit is False or user.password != password:
136 new_user.password = get_crypt_password(password)
136 new_user.password = get_crypt_password(password)
137 new_user.api_key = generate_api_key(username)
137 new_user.api_key = generate_api_key(username)
138 new_user.email = email
138 new_user.email = email
139 new_user.active = active
139 new_user.active = active
140 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
140 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
141 new_user.name = firstname
141 new_user.name = firstname
142 new_user.lastname = lastname
142 new_user.lastname = lastname
143 self.sa.add(new_user)
143 self.sa.add(new_user)
144 return new_user
144 return new_user
145 except (DatabaseError,):
145 except (DatabaseError,):
146 log.error(traceback.format_exc())
146 log.error(traceback.format_exc())
147 raise
147 raise
148
148
149 def create_for_container_auth(self, username, attrs):
149 def create_for_container_auth(self, username, attrs):
150 """
150 """
151 Creates the given user if it's not already in the database
151 Creates the given user if it's not already in the database
152
152
153 :param username:
153 :param username:
154 :param attrs:
154 :param attrs:
155 """
155 """
156 if self.get_by_username(username, case_insensitive=True) is None:
156 if self.get_by_username(username, case_insensitive=True) is None:
157
157
158 # autogenerate email for container account without one
158 # autogenerate email for container account without one
159 generate_email = lambda usr: '%s@container_auth.account' % usr
159 generate_email = lambda usr: '%s@container_auth.account' % usr
160
160
161 try:
161 try:
162 new_user = User()
162 new_user = User()
163 new_user.username = username
163 new_user.username = username
164 new_user.password = None
164 new_user.password = None
165 new_user.api_key = generate_api_key(username)
165 new_user.api_key = generate_api_key(username)
166 new_user.email = attrs['email']
166 new_user.email = attrs['email']
167 new_user.active = attrs.get('active', True)
167 new_user.active = attrs.get('active', True)
168 new_user.name = attrs['name'] or generate_email(username)
168 new_user.name = attrs['name'] or generate_email(username)
169 new_user.lastname = attrs['lastname']
169 new_user.lastname = attrs['lastname']
170
170
171 self.sa.add(new_user)
171 self.sa.add(new_user)
172 return new_user
172 return new_user
173 except (DatabaseError,):
173 except (DatabaseError,):
174 log.error(traceback.format_exc())
174 log.error(traceback.format_exc())
175 self.sa.rollback()
175 self.sa.rollback()
176 raise
176 raise
177 log.debug('User %s already exists. Skipping creation of account'
177 log.debug('User %s already exists. Skipping creation of account'
178 ' for container auth.', username)
178 ' for container auth.', username)
179 return None
179 return None
180
180
181 def create_ldap(self, username, password, user_dn, attrs):
181 def create_ldap(self, username, password, user_dn, attrs):
182 """
182 """
183 Checks if user is in database, if not creates this user marked
183 Checks if user is in database, if not creates this user marked
184 as ldap user
184 as ldap user
185
185
186 :param username:
186 :param username:
187 :param password:
187 :param password:
188 :param user_dn:
188 :param user_dn:
189 :param attrs:
189 :param attrs:
190 """
190 """
191 from rhodecode.lib.auth import get_crypt_password
191 from rhodecode.lib.auth import get_crypt_password
192 log.debug('Checking for such ldap account in RhodeCode database')
192 log.debug('Checking for such ldap account in RhodeCode database')
193 if self.get_by_username(username, case_insensitive=True) is None:
193 if self.get_by_username(username, case_insensitive=True) is None:
194
194
195 # autogenerate email for ldap account without one
195 # autogenerate email for ldap account without one
196 generate_email = lambda usr: '%s@ldap.account' % usr
196 generate_email = lambda usr: '%s@ldap.account' % usr
197
197
198 try:
198 try:
199 new_user = User()
199 new_user = User()
200 username = username.lower()
200 username = username.lower()
201 # add ldap account always lowercase
201 # add ldap account always lowercase
202 new_user.username = username
202 new_user.username = username
203 new_user.password = get_crypt_password(password)
203 new_user.password = get_crypt_password(password)
204 new_user.api_key = generate_api_key(username)
204 new_user.api_key = generate_api_key(username)
205 new_user.email = attrs['email'] or generate_email(username)
205 new_user.email = attrs['email'] or generate_email(username)
206 new_user.active = attrs.get('active', True)
206 new_user.active = attrs.get('active', True)
207 new_user.ldap_dn = safe_unicode(user_dn)
207 new_user.ldap_dn = safe_unicode(user_dn)
208 new_user.name = attrs['name']
208 new_user.name = attrs['name']
209 new_user.lastname = attrs['lastname']
209 new_user.lastname = attrs['lastname']
210
210
211 self.sa.add(new_user)
211 self.sa.add(new_user)
212 return new_user
212 return new_user
213 except (DatabaseError,):
213 except (DatabaseError,):
214 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
215 self.sa.rollback()
215 self.sa.rollback()
216 raise
216 raise
217 log.debug('this %s user exists skipping creation of ldap account',
217 log.debug('this %s user exists skipping creation of ldap account',
218 username)
218 username)
219 return None
219 return None
220
220
221 def create_registration(self, form_data):
221 def create_registration(self, form_data):
222 from rhodecode.model.notification import NotificationModel
222 from rhodecode.model.notification import NotificationModel
223
223
224 try:
224 try:
225 form_data['admin'] = False
225 form_data['admin'] = False
226 new_user = self.create(form_data)
226 new_user = self.create(form_data)
227
227
228 self.sa.add(new_user)
228 self.sa.add(new_user)
229 self.sa.flush()
229 self.sa.flush()
230
230
231 # notification to admins
231 # notification to admins
232 subject = _('new user registration')
232 subject = _('new user registration')
233 body = ('New user registration\n'
233 body = ('New user registration\n'
234 '---------------------\n'
234 '---------------------\n'
235 '- Username: %s\n'
235 '- Username: %s\n'
236 '- Full Name: %s\n'
236 '- Full Name: %s\n'
237 '- Email: %s\n')
237 '- Email: %s\n')
238 body = body % (new_user.username, new_user.full_name,
238 body = body % (new_user.username, new_user.full_name,
239 new_user.email)
239 new_user.email)
240 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
240 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
241 kw = {'registered_user_url': edit_url}
241 kw = {'registered_user_url': edit_url}
242 NotificationModel().create(created_by=new_user, subject=subject,
242 NotificationModel().create(created_by=new_user, subject=subject,
243 body=body, recipients=None,
243 body=body, recipients=None,
244 type_=Notification.TYPE_REGISTRATION,
244 type_=Notification.TYPE_REGISTRATION,
245 email_kwargs=kw)
245 email_kwargs=kw)
246
246
247 except:
247 except:
248 log.error(traceback.format_exc())
248 log.error(traceback.format_exc())
249 raise
249 raise
250
250
251 def update(self, user_id, form_data, skip_attrs=[]):
251 def update(self, user_id, form_data, skip_attrs=[]):
252 from rhodecode.lib.auth import get_crypt_password
252 from rhodecode.lib.auth import get_crypt_password
253 try:
253 try:
254 user = self.get(user_id, cache=False)
254 user = self.get(user_id, cache=False)
255 if user.username == 'default':
255 if user.username == 'default':
256 raise DefaultUserException(
256 raise DefaultUserException(
257 _("You can't Edit this user since it's"
257 _("You can't Edit this user since it's"
258 " crucial for entire application"))
258 " crucial for entire application"))
259
259
260 for k, v in form_data.items():
260 for k, v in form_data.items():
261 if k in skip_attrs:
261 if k in skip_attrs:
262 continue
262 continue
263 if k == 'new_password' and v:
263 if k == 'new_password' and v:
264 user.password = get_crypt_password(v)
264 user.password = get_crypt_password(v)
265 user.api_key = generate_api_key(user.username)
265 user.api_key = generate_api_key(user.username)
266 else:
266 else:
267 if k == 'firstname':
267 if k == 'firstname':
268 k = 'name'
268 k = 'name'
269 setattr(user, k, v)
269 setattr(user, k, v)
270 self.sa.add(user)
270 self.sa.add(user)
271 except:
271 except:
272 log.error(traceback.format_exc())
272 log.error(traceback.format_exc())
273 raise
273 raise
274
274
275 def update_user(self, user, **kwargs):
275 def update_user(self, user, **kwargs):
276 from rhodecode.lib.auth import get_crypt_password
276 from rhodecode.lib.auth import get_crypt_password
277 try:
277 try:
278 user = self._get_user(user)
278 user = self._get_user(user)
279 if user.username == 'default':
279 if user.username == 'default':
280 raise DefaultUserException(
280 raise DefaultUserException(
281 _("You can't Edit this user since it's"
281 _("You can't Edit this user since it's"
282 " crucial for entire application")
282 " crucial for entire application")
283 )
283 )
284
284
285 for k, v in kwargs.items():
285 for k, v in kwargs.items():
286 if k == 'password' and v:
286 if k == 'password' and v:
287 v = get_crypt_password(v)
287 v = get_crypt_password(v)
288 user.api_key = generate_api_key(user.username)
288 user.api_key = generate_api_key(user.username)
289
289
290 setattr(user, k, v)
290 setattr(user, k, v)
291 self.sa.add(user)
291 self.sa.add(user)
292 return user
292 return user
293 except:
293 except:
294 log.error(traceback.format_exc())
294 log.error(traceback.format_exc())
295 raise
295 raise
296
296
297 def update_my_account(self, user_id, form_data):
297 def update_my_account(self, user_id, form_data):
298 from rhodecode.lib.auth import get_crypt_password
298 from rhodecode.lib.auth import get_crypt_password
299 try:
299 try:
300 user = self.get(user_id, cache=False)
300 user = self.get(user_id, cache=False)
301 if user.username == 'default':
301 if user.username == 'default':
302 raise DefaultUserException(
302 raise DefaultUserException(
303 _("You can't Edit this user since it's"
303 _("You can't Edit this user since it's"
304 " crucial for entire application")
304 " crucial for entire application")
305 )
305 )
306 for k, v in form_data.items():
306 for k, v in form_data.items():
307 if k == 'new_password' and v:
307 if k == 'new_password' and v:
308 user.password = get_crypt_password(v)
308 user.password = get_crypt_password(v)
309 user.api_key = generate_api_key(user.username)
309 user.api_key = generate_api_key(user.username)
310 else:
310 else:
311 if k == 'firstname':
311 if k == 'firstname':
312 k = 'name'
312 k = 'name'
313 if k not in ['admin', 'active']:
313 if k not in ['admin', 'active']:
314 setattr(user, k, v)
314 setattr(user, k, v)
315
315
316 self.sa.add(user)
316 self.sa.add(user)
317 except:
317 except:
318 log.error(traceback.format_exc())
318 log.error(traceback.format_exc())
319 raise
319 raise
320
320
321 def delete(self, user):
321 def delete(self, user):
322 user = self._get_user(user)
322 user = self._get_user(user)
323
323
324 try:
324 try:
325 if user.username == 'default':
325 if user.username == 'default':
326 raise DefaultUserException(
326 raise DefaultUserException(
327 _(u"You can't remove this user since it's"
327 _(u"You can't remove this user since it's"
328 " crucial for entire application")
328 " crucial for entire application")
329 )
329 )
330 if user.repositories:
330 if user.repositories:
331 repos = [x.repo_name for x in user.repositories]
331 repos = [x.repo_name for x in user.repositories]
332 raise UserOwnsReposException(
332 raise UserOwnsReposException(
333 _(u'user "%s" still owns %s repositories and cannot be '
333 _(u'user "%s" still owns %s repositories and cannot be '
334 'removed. Switch owners or remove those repositories. %s')
334 'removed. Switch owners or remove those repositories. %s')
335 % (user.username, len(repos), ', '.join(repos))
335 % (user.username, len(repos), ', '.join(repos))
336 )
336 )
337 self.sa.delete(user)
337 self.sa.delete(user)
338 except:
338 except:
339 log.error(traceback.format_exc())
339 log.error(traceback.format_exc())
340 raise
340 raise
341
341
342 def reset_password_link(self, data):
342 def reset_password_link(self, data):
343 from rhodecode.lib.celerylib import tasks, run_task
343 from rhodecode.lib.celerylib import tasks, run_task
344 run_task(tasks.send_password_link, data['email'])
344 run_task(tasks.send_password_link, data['email'])
345
345
346 def reset_password(self, data):
346 def reset_password(self, data):
347 from rhodecode.lib.celerylib import tasks, run_task
347 from rhodecode.lib.celerylib import tasks, run_task
348 run_task(tasks.reset_user_password, data['email'])
348 run_task(tasks.reset_user_password, data['email'])
349
349
350 def fill_data(self, auth_user, user_id=None, api_key=None):
350 def fill_data(self, auth_user, user_id=None, api_key=None):
351 """
351 """
352 Fetches auth_user by user_id,or api_key if present.
352 Fetches auth_user by user_id,or api_key if present.
353 Fills auth_user attributes with those taken from database.
353 Fills auth_user attributes with those taken from database.
354 Additionally set's is_authenitated if lookup fails
354 Additionally set's is_authenitated if lookup fails
355 present in database
355 present in database
356
356
357 :param auth_user: instance of user to set attributes
357 :param auth_user: instance of user to set attributes
358 :param user_id: user id to fetch by
358 :param user_id: user id to fetch by
359 :param api_key: api key to fetch by
359 :param api_key: api key to fetch by
360 """
360 """
361 if user_id is None and api_key is None:
361 if user_id is None and api_key is None:
362 raise Exception('You need to pass user_id or api_key')
362 raise Exception('You need to pass user_id or api_key')
363
363
364 try:
364 try:
365 if api_key:
365 if api_key:
366 dbuser = self.get_by_api_key(api_key)
366 dbuser = self.get_by_api_key(api_key)
367 else:
367 else:
368 dbuser = self.get(user_id)
368 dbuser = self.get(user_id)
369
369
370 if dbuser is not None and dbuser.active:
370 if dbuser is not None and dbuser.active:
371 log.debug('filling %s data' % dbuser)
371 log.debug('filling %s data' % dbuser)
372 for k, v in dbuser.get_dict().items():
372 for k, v in dbuser.get_dict().items():
373 setattr(auth_user, k, v)
373 setattr(auth_user, k, v)
374 else:
374 else:
375 return False
375 return False
376
376
377 except:
377 except:
378 log.error(traceback.format_exc())
378 log.error(traceback.format_exc())
379 auth_user.is_authenticated = False
379 auth_user.is_authenticated = False
380 return False
380 return False
381
381
382 return True
382 return True
383
383
384 def fill_perms(self, user, explicit=True, algo='higherwin'):
384 def fill_perms(self, user, explicit=True, algo='higherwin'):
385 """
385 """
386 Fills user permission attribute with permissions taken from database
386 Fills user permission attribute with permissions taken from database
387 works for permissions given for repositories, and for permissions that
387 works for permissions given for repositories, and for permissions that
388 are granted to groups
388 are granted to groups
389
389
390 :param user: user instance to fill his perms
390 :param user: user instance to fill his perms
391 :param explicit: In case there are permissions both for user and a group
391 :param explicit: In case there are permissions both for user and a group
392 that user is part of, explicit flag will defiine if user will
392 that user is part of, explicit flag will defiine if user will
393 explicitly override permissions from group, if it's False it will
393 explicitly override permissions from group, if it's False it will
394 make decision based on the algo
394 make decision based on the algo
395 :param algo: algorithm to decide what permission should be choose if
395 :param algo: algorithm to decide what permission should be choose if
396 it's multiple defined, eg user in two different groups. It also
396 it's multiple defined, eg user in two different groups. It also
397 decides if explicit flag is turned off how to specify the permission
397 decides if explicit flag is turned off how to specify the permission
398 for case when user is in a group + have defined separate permission
398 for case when user is in a group + have defined separate permission
399 """
399 """
400 RK = 'repositories'
400 RK = 'repositories'
401 GK = 'repositories_groups'
401 GK = 'repositories_groups'
402 GLOBAL = 'global'
402 GLOBAL = 'global'
403 user.permissions[RK] = {}
403 user.permissions[RK] = {}
404 user.permissions[GK] = {}
404 user.permissions[GK] = {}
405 user.permissions[GLOBAL] = set()
405 user.permissions[GLOBAL] = set()
406
406
407 def _choose_perm(new_perm, cur_perm):
407 def _choose_perm(new_perm, cur_perm):
408 new_perm_val = PERM_WEIGHTS[new_perm]
408 new_perm_val = PERM_WEIGHTS[new_perm]
409 cur_perm_val = PERM_WEIGHTS[cur_perm]
409 cur_perm_val = PERM_WEIGHTS[cur_perm]
410 if algo == 'higherwin':
410 if algo == 'higherwin':
411 if new_perm_val > cur_perm_val:
411 if new_perm_val > cur_perm_val:
412 return new_perm
412 return new_perm
413 return cur_perm
413 return cur_perm
414 elif algo == 'lowerwin':
414 elif algo == 'lowerwin':
415 if new_perm_val < cur_perm_val:
415 if new_perm_val < cur_perm_val:
416 return new_perm
416 return new_perm
417 return cur_perm
417 return cur_perm
418
418
419 #======================================================================
419 #======================================================================
420 # fetch default permissions
420 # fetch default permissions
421 #======================================================================
421 #======================================================================
422 default_user = User.get_by_username('default', cache=True)
422 default_user = User.get_by_username('default', cache=True)
423 default_user_id = default_user.user_id
423 default_user_id = default_user.user_id
424
424
425 default_repo_perms = Permission.get_default_perms(default_user_id)
425 default_repo_perms = Permission.get_default_perms(default_user_id)
426 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
426 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
427
427
428 if user.is_admin:
428 if user.is_admin:
429 #==================================================================
429 #==================================================================
430 # admin user have all default rights for repositories
430 # admin user have all default rights for repositories
431 # and groups set to admin
431 # and groups set to admin
432 #==================================================================
432 #==================================================================
433 user.permissions[GLOBAL].add('hg.admin')
433 user.permissions[GLOBAL].add('hg.admin')
434
434
435 # repositories
435 # repositories
436 for perm in default_repo_perms:
436 for perm in default_repo_perms:
437 r_k = perm.UserRepoToPerm.repository.repo_name
437 r_k = perm.UserRepoToPerm.repository.repo_name
438 p = 'repository.admin'
438 p = 'repository.admin'
439 user.permissions[RK][r_k] = p
439 user.permissions[RK][r_k] = p
440
440
441 # repositories groups
441 # repositories groups
442 for perm in default_repo_groups_perms:
442 for perm in default_repo_groups_perms:
443 rg_k = perm.UserRepoGroupToPerm.group.group_name
443 rg_k = perm.UserRepoGroupToPerm.group.group_name
444 p = 'group.admin'
444 p = 'group.admin'
445 user.permissions[GK][rg_k] = p
445 user.permissions[GK][rg_k] = p
446 return user
446 return user
447
447
448 #==================================================================
448 #==================================================================
449 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
449 # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS
450 #==================================================================
450 #==================================================================
451 uid = user.user_id
451 uid = user.user_id
452
452
453 # default global permissions taken fron the default user
453 # default global permissions taken fron the default user
454 default_global_perms = self.sa.query(UserToPerm)\
454 default_global_perms = self.sa.query(UserToPerm)\
455 .filter(UserToPerm.user_id == default_user_id)
455 .filter(UserToPerm.user_id == default_user_id)
456
456
457 for perm in default_global_perms:
457 for perm in default_global_perms:
458 user.permissions[GLOBAL].add(perm.permission.permission_name)
458 user.permissions[GLOBAL].add(perm.permission.permission_name)
459
459
460 # defaults for repositories, taken from default user
460 # defaults for repositories, taken from default user
461 for perm in default_repo_perms:
461 for perm in default_repo_perms:
462 r_k = perm.UserRepoToPerm.repository.repo_name
462 r_k = perm.UserRepoToPerm.repository.repo_name
463 if perm.Repository.private and not (perm.Repository.user_id == uid):
463 if perm.Repository.private and not (perm.Repository.user_id == uid):
464 # disable defaults for private repos,
464 # disable defaults for private repos,
465 p = 'repository.none'
465 p = 'repository.none'
466 elif perm.Repository.user_id == uid:
466 elif perm.Repository.user_id == uid:
467 # set admin if owner
467 # set admin if owner
468 p = 'repository.admin'
468 p = 'repository.admin'
469 else:
469 else:
470 p = perm.Permission.permission_name
470 p = perm.Permission.permission_name
471
471
472 user.permissions[RK][r_k] = p
472 user.permissions[RK][r_k] = p
473
473
474 # defaults for repositories groups taken from default user permission
474 # defaults for repositories groups taken from default user permission
475 # on given group
475 # on given group
476 for perm in default_repo_groups_perms:
476 for perm in default_repo_groups_perms:
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
477 rg_k = perm.UserRepoGroupToPerm.group.group_name
478 p = perm.Permission.permission_name
478 p = perm.Permission.permission_name
479 user.permissions[GK][rg_k] = p
479 user.permissions[GK][rg_k] = p
480
480
481 #======================================================================
481 #======================================================================
482 # !! OVERRIDE GLOBALS !! with user permissions if any found
482 # !! OVERRIDE GLOBALS !! with user permissions if any found
483 #======================================================================
483 #======================================================================
484 # those can be configured from groups or users explicitly
484 # those can be configured from groups or users explicitly
485 _configurable = set(['hg.fork.none', 'hg.fork.repository',
485 _configurable = set(['hg.fork.none', 'hg.fork.repository',
486 'hg.create.none', 'hg.create.repository'])
486 'hg.create.none', 'hg.create.repository'])
487
487
488 # USER GROUPS comes first
488 # USER GROUPS comes first
489 # users group global permissions
489 # users group global permissions
490 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
490 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
491 .options(joinedload(UsersGroupToPerm.permission))\
491 .options(joinedload(UsersGroupToPerm.permission))\
492 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
492 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
493 UsersGroupMember.users_group_id))\
493 UsersGroupMember.users_group_id))\
494 .filter(UsersGroupMember.user_id == uid)\
494 .filter(UsersGroupMember.user_id == uid)\
495 .order_by(UsersGroupToPerm.users_group_id)\
495 .order_by(UsersGroupToPerm.users_group_id)\
496 .all()
496 .all()
497 #need to group here by groups since user can be in more than one group
497 #need to group here by groups since user can be in more than one group
498 _grouped = [[x, list(y)] for x, y in
498 _grouped = [[x, list(y)] for x, y in
499 itertools.groupby(user_perms_from_users_groups,
499 itertools.groupby(user_perms_from_users_groups,
500 lambda x:x.users_group)]
500 lambda x:x.users_group)]
501 for gr, perms in _grouped:
501 for gr, perms in _grouped:
502 # since user can be in multiple groups iterate over them and
502 # since user can be in multiple groups iterate over them and
503 # select the lowest permissions first (more explicit)
503 # select the lowest permissions first (more explicit)
504 ##TODO: do this^^
504 ##TODO: do this^^
505 if not gr.inherit_default_permissions:
505 if not gr.inherit_default_permissions:
506 # NEED TO IGNORE all configurable permissions and
506 # NEED TO IGNORE all configurable permissions and
507 # replace them with explicitly set
507 # replace them with explicitly set
508 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
508 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
509 .difference(_configurable)
509 .difference(_configurable)
510 for perm in perms:
510 for perm in perms:
511 user.permissions[GLOBAL].add(perm.permission.permission_name)
511 user.permissions[GLOBAL].add(perm.permission.permission_name)
512
512
513 # user specific global permissions
513 # user specific global permissions
514 user_perms = self.sa.query(UserToPerm)\
514 user_perms = self.sa.query(UserToPerm)\
515 .options(joinedload(UserToPerm.permission))\
515 .options(joinedload(UserToPerm.permission))\
516 .filter(UserToPerm.user_id == uid).all()
516 .filter(UserToPerm.user_id == uid).all()
517
517
518 if not user.inherit_default_permissions:
518 if not user.inherit_default_permissions:
519 # NEED TO IGNORE all configurable permissions and
519 # NEED TO IGNORE all configurable permissions and
520 # replace them with explicitly set
520 # replace them with explicitly set
521 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
521 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
522 .difference(_configurable)
522 .difference(_configurable)
523
523
524 for perm in user_perms:
524 for perm in user_perms:
525 user.permissions[GLOBAL].add(perm.permission.permission_name)
525 user.permissions[GLOBAL].add(perm.permission.permission_name)
526
526
527 #======================================================================
527 #======================================================================
528 # !! PERMISSIONS FOR REPOSITORIES !!
528 # !! PERMISSIONS FOR REPOSITORIES !!
529 #======================================================================
529 #======================================================================
530 #======================================================================
530 #======================================================================
531 # check if user is part of user groups for this repository and
531 # check if user is part of user groups for this repository and
532 # fill in his permission from it. _choose_perm decides of which
532 # fill in his permission from it. _choose_perm decides of which
533 # permission should be selected based on selected method
533 # permission should be selected based on selected method
534 #======================================================================
534 #======================================================================
535
535
536 # users group for repositories permissions
536 # users group for repositories permissions
537 user_repo_perms_from_users_groups = \
537 user_repo_perms_from_users_groups = \
538 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
538 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
539 .join((Repository, UsersGroupRepoToPerm.repository_id ==
539 .join((Repository, UsersGroupRepoToPerm.repository_id ==
540 Repository.repo_id))\
540 Repository.repo_id))\
541 .join((Permission, UsersGroupRepoToPerm.permission_id ==
541 .join((Permission, UsersGroupRepoToPerm.permission_id ==
542 Permission.permission_id))\
542 Permission.permission_id))\
543 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
543 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id ==
544 UsersGroupMember.users_group_id))\
544 UsersGroupMember.users_group_id))\
545 .filter(UsersGroupMember.user_id == uid)\
545 .filter(UsersGroupMember.user_id == uid)\
546 .all()
546 .all()
547
547
548 multiple_counter = collections.Counter()
548 multiple_counter = collections.defaultdict(int)
549 for perm in user_repo_perms_from_users_groups:
549 for perm in user_repo_perms_from_users_groups:
550 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
550 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
551 multiple_counter[r_k] += 1
551 multiple_counter[r_k] += 1
552 p = perm.Permission.permission_name
552 p = perm.Permission.permission_name
553 cur_perm = user.permissions[RK][r_k]
553 cur_perm = user.permissions[RK][r_k]
554
554
555 if perm.Repository.user_id == uid:
555 if perm.Repository.user_id == uid:
556 # set admin if owner
556 # set admin if owner
557 p = 'repository.admin'
557 p = 'repository.admin'
558 else:
558 else:
559 if multiple_counter[r_k] > 1:
559 if multiple_counter[r_k] > 1:
560 p = _choose_perm(p, cur_perm)
560 p = _choose_perm(p, cur_perm)
561 user.permissions[RK][r_k] = p
561 user.permissions[RK][r_k] = p
562
562
563 # user explicit permissions for repositories, overrides any specified
563 # user explicit permissions for repositories, overrides any specified
564 # by the group permission
564 # by the group permission
565 user_repo_perms = \
565 user_repo_perms = \
566 self.sa.query(UserRepoToPerm, Permission, Repository)\
566 self.sa.query(UserRepoToPerm, Permission, Repository)\
567 .join((Repository, UserRepoToPerm.repository_id ==
567 .join((Repository, UserRepoToPerm.repository_id ==
568 Repository.repo_id))\
568 Repository.repo_id))\
569 .join((Permission, UserRepoToPerm.permission_id ==
569 .join((Permission, UserRepoToPerm.permission_id ==
570 Permission.permission_id))\
570 Permission.permission_id))\
571 .filter(UserRepoToPerm.user_id == uid)\
571 .filter(UserRepoToPerm.user_id == uid)\
572 .all()
572 .all()
573
573
574 for perm in user_repo_perms:
574 for perm in user_repo_perms:
575 r_k = perm.UserRepoToPerm.repository.repo_name
575 r_k = perm.UserRepoToPerm.repository.repo_name
576 cur_perm = user.permissions[RK][r_k]
576 cur_perm = user.permissions[RK][r_k]
577 # set admin if owner
577 # set admin if owner
578 if perm.Repository.user_id == uid:
578 if perm.Repository.user_id == uid:
579 p = 'repository.admin'
579 p = 'repository.admin'
580 else:
580 else:
581 p = perm.Permission.permission_name
581 p = perm.Permission.permission_name
582 if not explicit:
582 if not explicit:
583 p = _choose_perm(p, cur_perm)
583 p = _choose_perm(p, cur_perm)
584 user.permissions[RK][r_k] = p
584 user.permissions[RK][r_k] = p
585
585
586 #======================================================================
586 #======================================================================
587 # !! PERMISSIONS FOR REPOSITORIES GROUPS !!
587 # !! PERMISSIONS FOR REPOSITORIES GROUPS !!
588 #======================================================================
588 #======================================================================
589 #======================================================================
589 #======================================================================
590 # check if user is part of user groups for this repository groups and
590 # check if user is part of user groups for this repository groups and
591 # fill in his permission from it. _choose_perm decides of which
591 # fill in his permission from it. _choose_perm decides of which
592 # permission should be selected based on selected method
592 # permission should be selected based on selected method
593 #======================================================================
593 #======================================================================
594 # users group for repo groups permissions
594 # users group for repo groups permissions
595 user_repo_group_perms_from_users_groups = \
595 user_repo_group_perms_from_users_groups = \
596 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
596 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
597 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
597 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
598 .join((Permission, UsersGroupRepoGroupToPerm.permission_id
598 .join((Permission, UsersGroupRepoGroupToPerm.permission_id
599 == Permission.permission_id))\
599 == Permission.permission_id))\
600 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id
600 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id
601 == UsersGroupMember.users_group_id))\
601 == UsersGroupMember.users_group_id))\
602 .filter(UsersGroupMember.user_id == uid)\
602 .filter(UsersGroupMember.user_id == uid)\
603 .all()
603 .all()
604
604
605 multiple_counter = collections.Counter()
605 multiple_counter = collections.defaultdict(int)
606 for perm in user_repo_group_perms_from_users_groups:
606 for perm in user_repo_group_perms_from_users_groups:
607 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
607 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
608 multiple_counter[g_k] += 1
608 multiple_counter[g_k] += 1
609 p = perm.Permission.permission_name
609 p = perm.Permission.permission_name
610 cur_perm = user.permissions[GK][g_k]
610 cur_perm = user.permissions[GK][g_k]
611 if multiple_counter[g_k] > 1:
611 if multiple_counter[g_k] > 1:
612 p = _choose_perm(p, cur_perm)
612 p = _choose_perm(p, cur_perm)
613 user.permissions[GK][g_k] = p
613 user.permissions[GK][g_k] = p
614
614
615 # user explicit permissions for repository groups
615 # user explicit permissions for repository groups
616 user_repo_groups_perms = \
616 user_repo_groups_perms = \
617 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
617 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
618 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
618 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
619 .join((Permission, UserRepoGroupToPerm.permission_id
619 .join((Permission, UserRepoGroupToPerm.permission_id
620 == Permission.permission_id))\
620 == Permission.permission_id))\
621 .filter(UserRepoGroupToPerm.user_id == uid)\
621 .filter(UserRepoGroupToPerm.user_id == uid)\
622 .all()
622 .all()
623
623
624 for perm in user_repo_groups_perms:
624 for perm in user_repo_groups_perms:
625 rg_k = perm.UserRepoGroupToPerm.group.group_name
625 rg_k = perm.UserRepoGroupToPerm.group.group_name
626 p = perm.Permission.permission_name
626 p = perm.Permission.permission_name
627 cur_perm = user.permissions[GK][rg_k]
627 cur_perm = user.permissions[GK][rg_k]
628 if not explicit:
628 if not explicit:
629 p = _choose_perm(p, cur_perm)
629 p = _choose_perm(p, cur_perm)
630 user.permissions[GK][rg_k] = p
630 user.permissions[GK][rg_k] = p
631
631
632 return user
632 return user
633
633
634 def has_perm(self, user, perm):
634 def has_perm(self, user, perm):
635 perm = self._get_perm(perm)
635 perm = self._get_perm(perm)
636 user = self._get_user(user)
636 user = self._get_user(user)
637
637
638 return UserToPerm.query().filter(UserToPerm.user == user)\
638 return UserToPerm.query().filter(UserToPerm.user == user)\
639 .filter(UserToPerm.permission == perm).scalar() is not None
639 .filter(UserToPerm.permission == perm).scalar() is not None
640
640
641 def grant_perm(self, user, perm):
641 def grant_perm(self, user, perm):
642 """
642 """
643 Grant user global permissions
643 Grant user global permissions
644
644
645 :param user:
645 :param user:
646 :param perm:
646 :param perm:
647 """
647 """
648 user = self._get_user(user)
648 user = self._get_user(user)
649 perm = self._get_perm(perm)
649 perm = self._get_perm(perm)
650 # if this permission is already granted skip it
650 # if this permission is already granted skip it
651 _perm = UserToPerm.query()\
651 _perm = UserToPerm.query()\
652 .filter(UserToPerm.user == user)\
652 .filter(UserToPerm.user == user)\
653 .filter(UserToPerm.permission == perm)\
653 .filter(UserToPerm.permission == perm)\
654 .scalar()
654 .scalar()
655 if _perm:
655 if _perm:
656 return
656 return
657 new = UserToPerm()
657 new = UserToPerm()
658 new.user = user
658 new.user = user
659 new.permission = perm
659 new.permission = perm
660 self.sa.add(new)
660 self.sa.add(new)
661
661
662 def revoke_perm(self, user, perm):
662 def revoke_perm(self, user, perm):
663 """
663 """
664 Revoke users global permissions
664 Revoke users global permissions
665
665
666 :param user:
666 :param user:
667 :param perm:
667 :param perm:
668 """
668 """
669 user = self._get_user(user)
669 user = self._get_user(user)
670 perm = self._get_perm(perm)
670 perm = self._get_perm(perm)
671
671
672 obj = UserToPerm.query()\
672 obj = UserToPerm.query()\
673 .filter(UserToPerm.user == user)\
673 .filter(UserToPerm.user == user)\
674 .filter(UserToPerm.permission == perm)\
674 .filter(UserToPerm.permission == perm)\
675 .scalar()
675 .scalar()
676 if obj:
676 if obj:
677 self.sa.delete(obj)
677 self.sa.delete(obj)
678
678
679 def add_extra_email(self, user, email):
679 def add_extra_email(self, user, email):
680 """
680 """
681 Adds email address to UserEmailMap
681 Adds email address to UserEmailMap
682
682
683 :param user:
683 :param user:
684 :param email:
684 :param email:
685 """
685 """
686 from rhodecode.model import forms
686 from rhodecode.model import forms
687 form = forms.UserExtraEmailForm()()
687 form = forms.UserExtraEmailForm()()
688 data = form.to_python(dict(email=email))
688 data = form.to_python(dict(email=email))
689 user = self._get_user(user)
689 user = self._get_user(user)
690
690
691 obj = UserEmailMap()
691 obj = UserEmailMap()
692 obj.user = user
692 obj.user = user
693 obj.email = data['email']
693 obj.email = data['email']
694 self.sa.add(obj)
694 self.sa.add(obj)
695 return obj
695 return obj
696
696
697 def delete_extra_email(self, user, email_id):
697 def delete_extra_email(self, user, email_id):
698 """
698 """
699 Removes email address from UserEmailMap
699 Removes email address from UserEmailMap
700
700
701 :param user:
701 :param user:
702 :param email_id:
702 :param email_id:
703 """
703 """
704 user = self._get_user(user)
704 user = self._get_user(user)
705 obj = UserEmailMap.query().get(email_id)
705 obj = UserEmailMap.query().get(email_id)
706 if obj:
706 if obj:
707 self.sa.delete(obj)
707 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now