comparison rhodecode/model/user.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents 92da990f9eaf
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
5
6 users model for RhodeCode
7
8 :created_on: Apr 9, 2010
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify 2 # 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 3 # 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 4 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version. 5 # (at your option) any later version.
17 # 6 #
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details. 10 # GNU General Public License for more details.
22 # 11 #
23 # You should have received a copy of the GNU General Public License 12 # 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/>. 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
15 rhodecode.model.user
16 ~~~~~~~~~~~~~~~~~~~~
17
18 users model for RhodeCode
19
20 :created_on: Apr 9, 2010
21 :author: marcink
22 :copyright: (c) 2013 RhodeCode GmbH.
23 :license: GPLv3, see LICENSE for more details.
24 """
25
25 26
26 import logging 27 import logging
27 import traceback 28 import traceback
28 import itertools
29 import collections
30 from pylons import url 29 from pylons import url
31 from pylons.i18n.translation import _ 30 from pylons.i18n.translation import _
32 31
33 from sqlalchemy.exc import DatabaseError 32 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.orm import joinedload 33
35 34
36 from rhodecode.lib.utils2 import safe_unicode, generate_api_key, get_current_rhodecode_user 35 from rhodecode.lib.utils2 import safe_unicode, generate_api_key, get_current_rhodecode_user
37 from rhodecode.lib.caching_query import FromCache 36 from rhodecode.lib.caching_query import FromCache
38 from rhodecode.model import BaseModel 37 from rhodecode.model import BaseModel
39 from rhodecode.model.db import User, Repository, Permission, \ 38 from rhodecode.model.db import User, UserToPerm, Notification, \
40 UserToPerm, UserGroupRepoToPerm, UserGroupToPerm, UserGroupMember, \ 39 UserEmailMap, UserIpMap
41 Notification, RepoGroup, UserGroupRepoGroupToPerm, \
42 UserEmailMap, UserIpMap, UserGroupUserGroupToPerm, UserGroup
43 from rhodecode.lib.exceptions import DefaultUserException, \ 40 from rhodecode.lib.exceptions import DefaultUserException, \
44 UserOwnsReposException 41 UserOwnsReposException
45 from rhodecode.model.meta import Session 42 from rhodecode.model.meta import Session
46 43
47 44
48 log = logging.getLogger(__name__) 45 log = logging.getLogger(__name__)
49
50 PERM_WEIGHTS = Permission.PERM_WEIGHTS
51 46
52 47
53 class UserModel(BaseModel): 48 class UserModel(BaseModel):
54 cls = User 49 cls = User
55 50
66 def get_by_username(self, username, cache=False, case_insensitive=False): 61 def get_by_username(self, username, cache=False, case_insensitive=False):
67 62
68 if case_insensitive: 63 if case_insensitive:
69 user = self.sa.query(User).filter(User.username.ilike(username)) 64 user = self.sa.query(User).filter(User.username.ilike(username))
70 else: 65 else:
71 user = self.sa.query(User).filter(User.username == username) 66 user = self.sa.query(User)\
67 .filter(User.username == username)
72 if cache: 68 if cache:
73 user = user.options(FromCache("sql_cache_short", 69 user = user.options(FromCache("sql_cache_short",
74 "get_user_%s" % username)) 70 "get_user_%s" % username))
75 return user.scalar() 71 return user.scalar()
76 72
91 'email': _fd['email'], 'firstname': _fd['firstname'], 'lastname': _fd['lastname'], 87 'email': _fd['email'], 'firstname': _fd['firstname'], 'lastname': _fd['lastname'],
92 'active': _fd['active'], 'admin': False 88 'active': _fd['active'], 'admin': False
93 } 89 }
94 # raises UserCreationError if it's not allowed 90 # raises UserCreationError if it's not allowed
95 check_allowed_create_user(user_data, cur_user) 91 check_allowed_create_user(user_data, cur_user)
96
97 from rhodecode.lib.auth import get_crypt_password 92 from rhodecode.lib.auth import get_crypt_password
98 try: 93 try:
99 new_user = User() 94 new_user = User()
100 for k, v in form_data.items(): 95 for k, v in form_data.items():
101 if k == 'password': 96 if k == 'password':
112 except Exception: 107 except Exception:
113 log.error(traceback.format_exc()) 108 log.error(traceback.format_exc())
114 raise 109 raise
115 110
116 def create_or_update(self, username, password, email, firstname='', 111 def create_or_update(self, username, password, email, firstname='',
117 lastname='', active=True, admin=False, ldap_dn=None, 112 lastname='', active=True, admin=False,
118 cur_user=None): 113 extern_type=None, extern_name=None, cur_user=None):
119 """ 114 """
120 Creates a new instance if not found, or updates current one 115 Creates a new instance if not found, or updates current one
121 116
122 :param username: 117 :param username:
123 :param password: 118 :param password:
125 :param active: 120 :param active:
126 :param firstname: 121 :param firstname:
127 :param lastname: 122 :param lastname:
128 :param active: 123 :param active:
129 :param admin: 124 :param admin:
130 :param ldap_dn: 125 :param extern_name:
126 :param extern_type:
131 :param cur_user: 127 :param cur_user:
132 """ 128 """
133 if not cur_user: 129 if not cur_user:
134 cur_user = getattr(get_current_rhodecode_user(), 'username', None) 130 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
135 131
136 from rhodecode.lib.auth import get_crypt_password 132 from rhodecode.lib.auth import get_crypt_password, check_password
137 from rhodecode.lib.hooks import log_create_user, check_allowed_create_user 133 from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
138 user_data = { 134 user_data = {
139 'username': username, 'password': password, 135 'username': username, 'password': password,
140 'email': email, 'firstname': firstname, 'lastname': lastname, 136 'email': email, 'firstname': firstname, 'lastname': lastname,
141 'active': active, 'admin': admin 137 'active': active, 'admin': admin
155 edit = True 151 edit = True
156 152
157 try: 153 try:
158 new_user.username = username 154 new_user.username = username
159 new_user.admin = admin 155 new_user.admin = admin
160 # set password only if creating an user or password is changed
161 if not edit or user.password != password:
162 new_user.password = get_crypt_password(password) if password else None
163 new_user.api_key = generate_api_key(username)
164 new_user.email = email 156 new_user.email = email
165 new_user.active = active 157 new_user.active = active
166 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None 158 new_user.extern_name = safe_unicode(extern_name) if extern_name else None
159 new_user.extern_type = safe_unicode(extern_type) if extern_type else None
167 new_user.name = firstname 160 new_user.name = firstname
168 new_user.lastname = lastname 161 new_user.lastname = lastname
162
163 if not edit:
164 new_user.api_key = generate_api_key(username)
165
166 # set password only if creating an user or password is changed
167 password_change = new_user.password and not check_password(password,
168 new_user.password)
169 if not edit or password_change:
170 reason = 'new password' if edit else 'new user'
171 log.debug('Updating password reason=>%s' % (reason,))
172 new_user.password = get_crypt_password(password) if password else None
173
169 self.sa.add(new_user) 174 self.sa.add(new_user)
170 175
171 if not edit: 176 if not edit:
172 log_create_user(new_user.get_dict(), cur_user) 177 log_create_user(new_user.get_dict(), cur_user)
173 return new_user 178 return new_user
174 except (DatabaseError,): 179 except (DatabaseError,):
175 log.error(traceback.format_exc()) 180 log.error(traceback.format_exc())
176 raise 181 raise
177 182
178 def create_for_container_auth(self, username, attrs, cur_user=None):
179 """
180 Creates the given user if it's not already in the database
181
182 :param username:
183 :param attrs:
184 :param cur_user:
185 """
186 if not cur_user:
187 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
188 if self.get_by_username(username, case_insensitive=True) is None:
189 # autogenerate email for container account without one
190 generate_email = lambda usr: '%s@container_auth.account' % usr
191 firstname = attrs['name']
192 lastname = attrs['lastname']
193 active = attrs.get('active', True)
194 email = attrs['email'] or generate_email(username)
195
196 from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
197 user_data = {
198 'username': username, 'password': None,
199 'email': email, 'firstname': firstname, 'lastname': lastname,
200 'active': attrs.get('active', True), 'admin': False
201 }
202 # raises UserCreationError if it's not allowed
203 check_allowed_create_user(user_data, cur_user)
204
205 try:
206 new_user = User()
207 new_user.username = username
208 new_user.password = None
209 new_user.api_key = generate_api_key(username)
210 new_user.email = email
211 new_user.active = active
212 new_user.name = firstname
213 new_user.lastname = lastname
214
215 self.sa.add(new_user)
216 log_create_user(new_user.get_dict(), cur_user)
217 return new_user
218 except (DatabaseError,):
219 log.error(traceback.format_exc())
220 self.sa.rollback()
221 raise
222 log.debug('User %s already exists. Skipping creation of account'
223 ' for container auth.', username)
224 return None
225
226 def create_ldap(self, username, password, user_dn, attrs, cur_user=None):
227 """
228 Checks if user is in database, if not creates this user marked
229 as ldap user
230
231 :param username:
232 :param password:
233 :param user_dn:
234 :param attrs:
235 :param cur_user:
236 """
237 if not cur_user:
238 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
239 from rhodecode.lib.auth import get_crypt_password
240 log.debug('Checking for such ldap account in RhodeCode database')
241 if self.get_by_username(username, case_insensitive=True) is None:
242 # autogenerate email for container account without one
243 generate_email = lambda usr: '%s@ldap.account' % usr
244 password = get_crypt_password(password)
245 firstname = attrs['name']
246 lastname = attrs['lastname']
247 active = attrs.get('active', True)
248 email = attrs['email'] or generate_email(username)
249
250 from rhodecode.lib.hooks import log_create_user, check_allowed_create_user
251 user_data = {
252 'username': username, 'password': password,
253 'email': email, 'firstname': firstname, 'lastname': lastname,
254 'active': attrs.get('active', True), 'admin': False
255 }
256 # raises UserCreationError if it's not allowed
257 check_allowed_create_user(user_data, cur_user)
258
259 try:
260 new_user = User()
261 username = username.lower()
262 # add ldap account always lowercase
263 new_user.username = username
264 new_user.password = password
265 new_user.api_key = generate_api_key(username)
266 new_user.email = email
267 new_user.active = active
268 new_user.ldap_dn = safe_unicode(user_dn)
269 new_user.name = firstname
270 new_user.lastname = lastname
271 self.sa.add(new_user)
272
273 log_create_user(new_user.get_dict(), cur_user)
274 return new_user
275 except (DatabaseError,):
276 log.error(traceback.format_exc())
277 self.sa.rollback()
278 raise
279 log.debug('this %s user exists skipping creation of ldap account',
280 username)
281 return None
282
283 def create_registration(self, form_data): 183 def create_registration(self, form_data):
284 from rhodecode.model.notification import NotificationModel 184 from rhodecode.model.notification import NotificationModel
285 185
286 try: 186 try:
287 form_data['admin'] = False 187 form_data['admin'] = False
188 form_data['extern_name'] = 'rhodecode'
189 form_data['extern_type'] = 'rhodecode'
288 new_user = self.create(form_data) 190 new_user = self.create(form_data)
289 191
290 self.sa.add(new_user) 192 self.sa.add(new_user)
291 self.sa.flush() 193 self.sa.flush()
292 194
311 213
312 def update(self, user_id, form_data, skip_attrs=[]): 214 def update(self, user_id, form_data, skip_attrs=[]):
313 from rhodecode.lib.auth import get_crypt_password 215 from rhodecode.lib.auth import get_crypt_password
314 try: 216 try:
315 user = self.get(user_id, cache=False) 217 user = self.get(user_id, cache=False)
316 if user.username == 'default': 218 if user.username == User.DEFAULT_USER:
317 raise DefaultUserException( 219 raise DefaultUserException(
318 _("You can't Edit this user since it's" 220 _("You can't Edit this user since it's "
319 " crucial for entire application")) 221 "crucial for entire application"))
320 222
321 for k, v in form_data.items(): 223 for k, v in form_data.items():
322 if k in skip_attrs: 224 if k in skip_attrs:
323 continue 225 continue
324 if k == 'new_password' and v: 226 if k == 'new_password' and v:
325 user.password = get_crypt_password(v) 227 user.password = get_crypt_password(v)
326 user.api_key = generate_api_key(user.username)
327 else: 228 else:
229 # old legacy thing orm models store firstname as name,
230 # need proper refactor to username
328 if k == 'firstname': 231 if k == 'firstname':
329 k = 'name' 232 k = 'name'
330 setattr(user, k, v) 233 setattr(user, k, v)
331 self.sa.add(user) 234 self.sa.add(user)
332 except Exception: 235 except Exception:
335 238
336 def update_user(self, user, **kwargs): 239 def update_user(self, user, **kwargs):
337 from rhodecode.lib.auth import get_crypt_password 240 from rhodecode.lib.auth import get_crypt_password
338 try: 241 try:
339 user = self._get_user(user) 242 user = self._get_user(user)
340 if user.username == 'default': 243 if user.username == User.DEFAULT_USER:
341 raise DefaultUserException( 244 raise DefaultUserException(
342 _("You can't Edit this user since it's" 245 _("You can't Edit this user since it's"
343 " crucial for entire application") 246 " crucial for entire application")
344 ) 247 )
345 248
346 for k, v in kwargs.items(): 249 for k, v in kwargs.items():
347 if k == 'password' and v: 250 if k == 'password' and v:
348 v = get_crypt_password(v) 251 v = get_crypt_password(v)
349 user.api_key = generate_api_key(user.username)
350 252
351 setattr(user, k, v) 253 setattr(user, k, v)
352 self.sa.add(user) 254 self.sa.add(user)
353 return user 255 return user
354 except Exception: 256 except Exception:
359 if not cur_user: 261 if not cur_user:
360 cur_user = getattr(get_current_rhodecode_user(), 'username', None) 262 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
361 user = self._get_user(user) 263 user = self._get_user(user)
362 264
363 try: 265 try:
364 if user.username == 'default': 266 if user.username == User.DEFAULT_USER:
365 raise DefaultUserException( 267 raise DefaultUserException(
366 _(u"You can't remove this user since it's" 268 _(u"You can't remove this user since it's"
367 " crucial for entire application") 269 " crucial for entire application")
368 ) 270 )
369 if user.repositories: 271 if user.repositories:
416 user = User.get_by_email(user_email) 318 user = User.get_by_email(user_email)
417 new_passwd = auth.PasswordGenerator().gen_password(8, 319 new_passwd = auth.PasswordGenerator().gen_password(8,
418 auth.PasswordGenerator.ALPHABETS_BIG_SMALL) 320 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
419 if user: 321 if user:
420 user.password = auth.get_crypt_password(new_passwd) 322 user.password = auth.get_crypt_password(new_passwd)
421 user.api_key = auth.generate_api_key(user.username)
422 Session().add(user) 323 Session().add(user)
423 Session().commit() 324 Session().commit()
424 log.info('change password for %s' % user_email) 325 log.info('change password for %s' % user_email)
425 if new_passwd is None: 326 if new_passwd is None:
426 raise Exception('unable to generate new password') 327 raise Exception('unable to generate new password')
439 # run_task, we're pass rollback state this wouldn't work then 340 # run_task, we're pass rollback state this wouldn't work then
440 Session().rollback() 341 Session().rollback()
441 342
442 return True 343 return True
443 344
444 def fill_data(self, auth_user, user_id=None, api_key=None): 345 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
445 """ 346 """
446 Fetches auth_user by user_id,or api_key if present. 347 Fetches auth_user by user_id,or api_key if present.
447 Fills auth_user attributes with those taken from database. 348 Fills auth_user attributes with those taken from database.
448 Additionally set's is_authenitated if lookup fails 349 Additionally set's is_authenitated if lookup fails
449 present in database 350 present in database
450 351
451 :param auth_user: instance of user to set attributes 352 :param auth_user: instance of user to set attributes
452 :param user_id: user id to fetch by 353 :param user_id: user id to fetch by
453 :param api_key: api key to fetch by 354 :param api_key: api key to fetch by
454 """ 355 :param username: username to fetch by
455 if user_id is None and api_key is None: 356 """
456 raise Exception('You need to pass user_id or api_key') 357 if user_id is None and api_key is None and username is None:
457 358 raise Exception('You need to pass user_id, api_key or username')
458 try: 359
459 if api_key: 360 try:
361 dbuser = None
362 if user_id:
363 dbuser = self.get(user_id)
364 elif api_key:
460 dbuser = self.get_by_api_key(api_key) 365 dbuser = self.get_by_api_key(api_key)
461 else: 366 elif username:
462 dbuser = self.get(user_id) 367 dbuser = self.get_by_username(username)
463 368
464 if dbuser is not None and dbuser.active: 369 if dbuser is not None and dbuser.active:
465 log.debug('filling %s data' % dbuser) 370 log.debug('filling %s data' % dbuser)
466 for k, v in dbuser.get_dict().items(): 371 for k, v in dbuser.get_dict().iteritems():
467 setattr(auth_user, k, v) 372 if k not in ['api_keys', 'permissions']:
373 setattr(auth_user, k, v)
468 else: 374 else:
469 return False 375 return False
470 376
471 except Exception: 377 except Exception:
472 log.error(traceback.format_exc()) 378 log.error(traceback.format_exc())
473 auth_user.is_authenticated = False 379 auth_user.is_authenticated = False
474 return False 380 return False
475 381
476 return True 382 return True
477
478 def fill_perms(self, user, explicit=True, algo='higherwin'):
479 """
480 Fills user permission attribute with permissions taken from database
481 works for permissions given for repositories, and for permissions that
482 are granted to groups
483
484 :param user: user instance to fill his perms
485 :param explicit: In case there are permissions both for user and a group
486 that user is part of, explicit flag will defiine if user will
487 explicitly override permissions from group, if it's False it will
488 make decision based on the algo
489 :param algo: algorithm to decide what permission should be choose if
490 it's multiple defined, eg user in two different groups. It also
491 decides if explicit flag is turned off how to specify the permission
492 for case when user is in a group + have defined separate permission
493 """
494 RK = 'repositories'
495 GK = 'repositories_groups'
496 UK = 'user_groups'
497 GLOBAL = 'global'
498 user.permissions[RK] = {}
499 user.permissions[GK] = {}
500 user.permissions[UK] = {}
501 user.permissions[GLOBAL] = set()
502
503 def _choose_perm(new_perm, cur_perm):
504 new_perm_val = PERM_WEIGHTS[new_perm]
505 cur_perm_val = PERM_WEIGHTS[cur_perm]
506 if algo == 'higherwin':
507 if new_perm_val > cur_perm_val:
508 return new_perm
509 return cur_perm
510 elif algo == 'lowerwin':
511 if new_perm_val < cur_perm_val:
512 return new_perm
513 return cur_perm
514
515 #======================================================================
516 # fetch default permissions
517 #======================================================================
518 default_user = User.get_by_username('default', cache=True)
519 default_user_id = default_user.user_id
520
521 default_repo_perms = Permission.get_default_perms(default_user_id)
522 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
523 default_user_group_perms = Permission.get_default_user_group_perms(default_user_id)
524
525 if user.is_admin:
526 #==================================================================
527 # admin user have all default rights for repositories
528 # and groups set to admin
529 #==================================================================
530 user.permissions[GLOBAL].add('hg.admin')
531
532 # repositories
533 for perm in default_repo_perms:
534 r_k = perm.UserRepoToPerm.repository.repo_name
535 p = 'repository.admin'
536 user.permissions[RK][r_k] = p
537
538 # repository groups
539 for perm in default_repo_groups_perms:
540 rg_k = perm.UserRepoGroupToPerm.group.group_name
541 p = 'group.admin'
542 user.permissions[GK][rg_k] = p
543
544 # user groups
545 for perm in default_user_group_perms:
546 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
547 p = 'usergroup.admin'
548 user.permissions[UK][u_k] = p
549 return user
550
551 #==================================================================
552 # SET DEFAULTS GLOBAL, REPOS, REPOSITORY GROUPS
553 #==================================================================
554 uid = user.user_id
555
556 # default global permissions taken fron the default user
557 default_global_perms = self.sa.query(UserToPerm)\
558 .filter(UserToPerm.user_id == default_user_id)
559
560 for perm in default_global_perms:
561 user.permissions[GLOBAL].add(perm.permission.permission_name)
562
563 # defaults for repositories, taken from default user
564 for perm in default_repo_perms:
565 r_k = perm.UserRepoToPerm.repository.repo_name
566 if perm.Repository.private and not (perm.Repository.user_id == uid):
567 # disable defaults for private repos,
568 p = 'repository.none'
569 elif perm.Repository.user_id == uid:
570 # set admin if owner
571 p = 'repository.admin'
572 else:
573 p = perm.Permission.permission_name
574
575 user.permissions[RK][r_k] = p
576
577 # defaults for repository groups taken from default user permission
578 # on given group
579 for perm in default_repo_groups_perms:
580 rg_k = perm.UserRepoGroupToPerm.group.group_name
581 p = perm.Permission.permission_name
582 user.permissions[GK][rg_k] = p
583
584 # defaults for user groups taken from default user permission
585 # on given user group
586 for perm in default_user_group_perms:
587 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
588 p = perm.Permission.permission_name
589 user.permissions[UK][u_k] = p
590
591 #======================================================================
592 # !! OVERRIDE GLOBALS !! with user permissions if any found
593 #======================================================================
594 # those can be configured from groups or users explicitly
595 _configurable = set([
596 'hg.fork.none', 'hg.fork.repository',
597 'hg.create.none', 'hg.create.repository',
598 'hg.usergroup.create.false', 'hg.usergroup.create.true'
599 ])
600
601 # USER GROUPS comes first
602 # user group global permissions
603 user_perms_from_users_groups = self.sa.query(UserGroupToPerm)\
604 .options(joinedload(UserGroupToPerm.permission))\
605 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
606 UserGroupMember.users_group_id))\
607 .filter(UserGroupMember.user_id == uid)\
608 .order_by(UserGroupToPerm.users_group_id)\
609 .all()
610 #need to group here by groups since user can be in more than one group
611 _grouped = [[x, list(y)] for x, y in
612 itertools.groupby(user_perms_from_users_groups,
613 lambda x:x.users_group)]
614 for gr, perms in _grouped:
615 # since user can be in multiple groups iterate over them and
616 # select the lowest permissions first (more explicit)
617 ##TODO: do this^^
618 if not gr.inherit_default_permissions:
619 # NEED TO IGNORE all configurable permissions and
620 # replace them with explicitly set
621 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
622 .difference(_configurable)
623 for perm in perms:
624 user.permissions[GLOBAL].add(perm.permission.permission_name)
625
626 # user specific global permissions
627 user_perms = self.sa.query(UserToPerm)\
628 .options(joinedload(UserToPerm.permission))\
629 .filter(UserToPerm.user_id == uid).all()
630
631 if not user.inherit_default_permissions:
632 # NEED TO IGNORE all configurable permissions and
633 # replace them with explicitly set
634 user.permissions[GLOBAL] = user.permissions[GLOBAL]\
635 .difference(_configurable)
636
637 for perm in user_perms:
638 user.permissions[GLOBAL].add(perm.permission.permission_name)
639 ## END GLOBAL PERMISSIONS
640
641 #======================================================================
642 # !! PERMISSIONS FOR REPOSITORIES !!
643 #======================================================================
644 #======================================================================
645 # check if user is part of user groups for this repository and
646 # fill in his permission from it. _choose_perm decides of which
647 # permission should be selected based on selected method
648 #======================================================================
649
650 # user group for repositories permissions
651 user_repo_perms_from_users_groups = \
652 self.sa.query(UserGroupRepoToPerm, Permission, Repository,)\
653 .join((Repository, UserGroupRepoToPerm.repository_id ==
654 Repository.repo_id))\
655 .join((Permission, UserGroupRepoToPerm.permission_id ==
656 Permission.permission_id))\
657 .join((UserGroupMember, UserGroupRepoToPerm.users_group_id ==
658 UserGroupMember.users_group_id))\
659 .filter(UserGroupMember.user_id == uid)\
660 .all()
661
662 multiple_counter = collections.defaultdict(int)
663 for perm in user_repo_perms_from_users_groups:
664 r_k = perm.UserGroupRepoToPerm.repository.repo_name
665 multiple_counter[r_k] += 1
666 p = perm.Permission.permission_name
667 cur_perm = user.permissions[RK][r_k]
668
669 if perm.Repository.user_id == uid:
670 # set admin if owner
671 p = 'repository.admin'
672 else:
673 if multiple_counter[r_k] > 1:
674 p = _choose_perm(p, cur_perm)
675 user.permissions[RK][r_k] = p
676
677 # user explicit permissions for repositories, overrides any specified
678 # by the group permission
679 user_repo_perms = Permission.get_default_perms(uid)
680 for perm in user_repo_perms:
681 r_k = perm.UserRepoToPerm.repository.repo_name
682 cur_perm = user.permissions[RK][r_k]
683 # set admin if owner
684 if perm.Repository.user_id == uid:
685 p = 'repository.admin'
686 else:
687 p = perm.Permission.permission_name
688 if not explicit:
689 p = _choose_perm(p, cur_perm)
690 user.permissions[RK][r_k] = p
691
692 #======================================================================
693 # !! PERMISSIONS FOR REPOSITORY GROUPS !!
694 #======================================================================
695 #======================================================================
696 # check if user is part of user groups for this repository groups and
697 # fill in his permission from it. _choose_perm decides of which
698 # permission should be selected based on selected method
699 #======================================================================
700 # user group for repo groups permissions
701 user_repo_group_perms_from_users_groups = \
702 self.sa.query(UserGroupRepoGroupToPerm, Permission, RepoGroup)\
703 .join((RepoGroup, UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
704 .join((Permission, UserGroupRepoGroupToPerm.permission_id
705 == Permission.permission_id))\
706 .join((UserGroupMember, UserGroupRepoGroupToPerm.users_group_id
707 == UserGroupMember.users_group_id))\
708 .filter(UserGroupMember.user_id == uid)\
709 .all()
710
711 multiple_counter = collections.defaultdict(int)
712 for perm in user_repo_group_perms_from_users_groups:
713 g_k = perm.UserGroupRepoGroupToPerm.group.group_name
714 multiple_counter[g_k] += 1
715 p = perm.Permission.permission_name
716 cur_perm = user.permissions[GK][g_k]
717 if multiple_counter[g_k] > 1:
718 p = _choose_perm(p, cur_perm)
719 user.permissions[GK][g_k] = p
720
721 # user explicit permissions for repository groups
722 user_repo_groups_perms = Permission.get_default_group_perms(uid)
723 for perm in user_repo_groups_perms:
724 rg_k = perm.UserRepoGroupToPerm.group.group_name
725 p = perm.Permission.permission_name
726 cur_perm = user.permissions[GK][rg_k]
727 if not explicit:
728 p = _choose_perm(p, cur_perm)
729 user.permissions[GK][rg_k] = p
730
731 #======================================================================
732 # !! PERMISSIONS FOR USER GROUPS !!
733 #======================================================================
734 # user group for user group permissions
735 user_group_user_groups_perms = \
736 self.sa.query(UserGroupUserGroupToPerm, Permission, UserGroup)\
737 .join((UserGroup, UserGroupUserGroupToPerm.target_user_group_id
738 == UserGroup.users_group_id))\
739 .join((Permission, UserGroupUserGroupToPerm.permission_id
740 == Permission.permission_id))\
741 .join((UserGroupMember, UserGroupUserGroupToPerm.user_group_id
742 == UserGroupMember.users_group_id))\
743 .filter(UserGroupMember.user_id == uid)\
744 .all()
745
746 multiple_counter = collections.defaultdict(int)
747 for perm in user_group_user_groups_perms:
748 g_k = perm.UserGroupUserGroupToPerm.target_user_group.users_group_name
749 multiple_counter[g_k] += 1
750 p = perm.Permission.permission_name
751 cur_perm = user.permissions[UK][g_k]
752 if multiple_counter[g_k] > 1:
753 p = _choose_perm(p, cur_perm)
754 user.permissions[UK][g_k] = p
755
756 #user explicit permission for user groups
757 user_user_groups_perms = Permission.get_default_user_group_perms(uid)
758 for perm in user_user_groups_perms:
759 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
760 p = perm.Permission.permission_name
761 cur_perm = user.permissions[UK][u_k]
762 if not explicit:
763 p = _choose_perm(p, cur_perm)
764 user.permissions[UK][u_k] = p
765
766 return user
767 383
768 def has_perm(self, user, perm): 384 def has_perm(self, user, perm):
769 perm = self._get_perm(perm) 385 perm = self._get_perm(perm)
770 user = self._get_user(user) 386 user = self._get_user(user)
771 387
790 return 406 return
791 new = UserToPerm() 407 new = UserToPerm()
792 new.user = user 408 new.user = user
793 new.permission = perm 409 new.permission = perm
794 self.sa.add(new) 410 self.sa.add(new)
411 return new
795 412
796 def revoke_perm(self, user, perm): 413 def revoke_perm(self, user, perm):
797 """ 414 """
798 Revoke users global permissions 415 Revoke users global permissions
799 416