##// END OF EJS Templates
Improved message about deleting user who owns repositories
marcink -
r2153:fa637dc3 beta
parent child Browse files
Show More
@@ -1,588 +1,589 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users model for RhodeCode
7 7
8 8 :created_on: Apr 9, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28
29 29 from pylons import url
30 30 from pylons.i18n.translation import _
31 31
32 32 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
33 33 from rhodecode.lib.caching_query import FromCache
34 34
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
37 37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
38 38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroup,\
39 39 UsersGroupRepoGroupToPerm
40 40 from rhodecode.lib.exceptions import DefaultUserException, \
41 41 UserOwnsReposException
42 42
43 43 from sqlalchemy.exc import DatabaseError
44 44
45 45 from sqlalchemy.orm import joinedload
46 46
47 47 log = logging.getLogger(__name__)
48 48
49 49
50 50 PERM_WEIGHTS = {
51 51 'repository.none': 0,
52 52 'repository.read': 1,
53 53 'repository.write': 3,
54 54 'repository.admin': 4,
55 55 'group.none': 0,
56 56 'group.read': 1,
57 57 'group.write': 3,
58 58 'group.admin': 4,
59 59 }
60 60
61 61
62 62 class UserModel(BaseModel):
63 63
64 64 def __get_user(self, user):
65 65 return self._get_instance(User, user, callback=User.get_by_username)
66 66
67 67 def __get_perm(self, permission):
68 68 return self._get_instance(Permission, permission,
69 69 callback=Permission.get_by_key)
70 70
71 71 def get(self, user_id, cache=False):
72 72 user = self.sa.query(User)
73 73 if cache:
74 74 user = user.options(FromCache("sql_cache_short",
75 75 "get_user_%s" % user_id))
76 76 return user.get(user_id)
77 77
78 78 def get_user(self, user):
79 79 return self.__get_user(user)
80 80
81 81 def get_by_username(self, username, cache=False, case_insensitive=False):
82 82
83 83 if case_insensitive:
84 84 user = self.sa.query(User).filter(User.username.ilike(username))
85 85 else:
86 86 user = self.sa.query(User)\
87 87 .filter(User.username == username)
88 88 if cache:
89 89 user = user.options(FromCache("sql_cache_short",
90 90 "get_user_%s" % username))
91 91 return user.scalar()
92 92
93 93 def get_by_api_key(self, api_key, cache=False):
94 94 return User.get_by_api_key(api_key, cache)
95 95
96 96 def create(self, form_data):
97 97 try:
98 98 new_user = User()
99 99 for k, v in form_data.items():
100 100 setattr(new_user, k, v)
101 101
102 102 new_user.api_key = generate_api_key(form_data['username'])
103 103 self.sa.add(new_user)
104 104 return new_user
105 105 except:
106 106 log.error(traceback.format_exc())
107 107 raise
108 108
109 109 def create_or_update(self, username, password, email, name, lastname,
110 110 active=True, admin=False, ldap_dn=None):
111 111 """
112 112 Creates a new instance if not found, or updates current one
113 113
114 114 :param username:
115 115 :param password:
116 116 :param email:
117 117 :param active:
118 118 :param name:
119 119 :param lastname:
120 120 :param active:
121 121 :param admin:
122 122 :param ldap_dn:
123 123 """
124 124
125 125 from rhodecode.lib.auth import get_crypt_password
126 126
127 127 log.debug('Checking for %s account in RhodeCode database' % username)
128 128 user = User.get_by_username(username, case_insensitive=True)
129 129 if user is None:
130 130 log.debug('creating new user %s' % username)
131 131 new_user = User()
132 132 else:
133 133 log.debug('updating user %s' % username)
134 134 new_user = user
135 135
136 136 try:
137 137 new_user.username = username
138 138 new_user.admin = admin
139 139 new_user.password = get_crypt_password(password)
140 140 new_user.api_key = generate_api_key(username)
141 141 new_user.email = email
142 142 new_user.active = active
143 143 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
144 144 new_user.name = name
145 145 new_user.lastname = lastname
146 146 self.sa.add(new_user)
147 147 return new_user
148 148 except (DatabaseError,):
149 149 log.error(traceback.format_exc())
150 150 raise
151 151
152 152 def create_for_container_auth(self, username, attrs):
153 153 """
154 154 Creates the given user if it's not already in the database
155 155
156 156 :param username:
157 157 :param attrs:
158 158 """
159 159 if self.get_by_username(username, case_insensitive=True) is None:
160 160
161 161 # autogenerate email for container account without one
162 162 generate_email = lambda usr: '%s@container_auth.account' % usr
163 163
164 164 try:
165 165 new_user = User()
166 166 new_user.username = username
167 167 new_user.password = None
168 168 new_user.api_key = generate_api_key(username)
169 169 new_user.email = attrs['email']
170 170 new_user.active = attrs.get('active', True)
171 171 new_user.name = attrs['name'] or generate_email(username)
172 172 new_user.lastname = attrs['lastname']
173 173
174 174 self.sa.add(new_user)
175 175 return new_user
176 176 except (DatabaseError,):
177 177 log.error(traceback.format_exc())
178 178 self.sa.rollback()
179 179 raise
180 180 log.debug('User %s already exists. Skipping creation of account'
181 181 ' for container auth.', username)
182 182 return None
183 183
184 184 def create_ldap(self, username, password, user_dn, attrs):
185 185 """
186 186 Checks if user is in database, if not creates this user marked
187 187 as ldap user
188 188
189 189 :param username:
190 190 :param password:
191 191 :param user_dn:
192 192 :param attrs:
193 193 """
194 194 from rhodecode.lib.auth import get_crypt_password
195 195 log.debug('Checking for such ldap account in RhodeCode database')
196 196 if self.get_by_username(username, case_insensitive=True) is None:
197 197
198 198 # autogenerate email for ldap account without one
199 199 generate_email = lambda usr: '%s@ldap.account' % usr
200 200
201 201 try:
202 202 new_user = User()
203 203 username = username.lower()
204 204 # add ldap account always lowercase
205 205 new_user.username = username
206 206 new_user.password = get_crypt_password(password)
207 207 new_user.api_key = generate_api_key(username)
208 208 new_user.email = attrs['email'] or generate_email(username)
209 209 new_user.active = attrs.get('active', True)
210 210 new_user.ldap_dn = safe_unicode(user_dn)
211 211 new_user.name = attrs['name']
212 212 new_user.lastname = attrs['lastname']
213 213
214 214 self.sa.add(new_user)
215 215 return new_user
216 216 except (DatabaseError,):
217 217 log.error(traceback.format_exc())
218 218 self.sa.rollback()
219 219 raise
220 220 log.debug('this %s user exists skipping creation of ldap account',
221 221 username)
222 222 return None
223 223
224 224 def create_registration(self, form_data):
225 225 from rhodecode.model.notification import NotificationModel
226 226
227 227 try:
228 228 new_user = User()
229 229 for k, v in form_data.items():
230 230 if k != 'admin':
231 231 setattr(new_user, k, v)
232 232
233 233 self.sa.add(new_user)
234 234 self.sa.flush()
235 235
236 236 # notification to admins
237 237 subject = _('new user registration')
238 238 body = ('New user registration\n'
239 239 '---------------------\n'
240 240 '- Username: %s\n'
241 241 '- Full Name: %s\n'
242 242 '- Email: %s\n')
243 243 body = body % (new_user.username, new_user.full_name,
244 244 new_user.email)
245 245 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
246 246 kw = {'registered_user_url': edit_url}
247 247 NotificationModel().create(created_by=new_user, subject=subject,
248 248 body=body, recipients=None,
249 249 type_=Notification.TYPE_REGISTRATION,
250 250 email_kwargs=kw)
251 251
252 252 except:
253 253 log.error(traceback.format_exc())
254 254 raise
255 255
256 256 def update(self, user_id, form_data):
257 257 try:
258 258 user = self.get(user_id, cache=False)
259 259 if user.username == 'default':
260 260 raise DefaultUserException(
261 261 _("You can't Edit this user since it's"
262 262 " crucial for entire application"))
263 263
264 264 for k, v in form_data.items():
265 265 if k == 'new_password' and v != '':
266 266 user.password = v
267 267 user.api_key = generate_api_key(user.username)
268 268 else:
269 269 setattr(user, k, v)
270 270
271 271 self.sa.add(user)
272 272 except:
273 273 log.error(traceback.format_exc())
274 274 raise
275 275
276 276 def update_my_account(self, user_id, form_data):
277 277 try:
278 278 user = self.get(user_id, cache=False)
279 279 if user.username == 'default':
280 280 raise DefaultUserException(
281 281 _("You can't Edit this user since it's"
282 282 " crucial for entire application"))
283 283 for k, v in form_data.items():
284 284 if k == 'new_password' and v != '':
285 285 user.password = v
286 286 user.api_key = generate_api_key(user.username)
287 287 else:
288 288 if k not in ['admin', 'active']:
289 289 setattr(user, k, v)
290 290
291 291 self.sa.add(user)
292 292 except:
293 293 log.error(traceback.format_exc())
294 294 raise
295 295
296 296 def delete(self, user):
297 297 user = self.__get_user(user)
298 298
299 299 try:
300 300 if user.username == 'default':
301 301 raise DefaultUserException(
302 _("You can't remove this user since it's"
302 _(u"You can't remove this user since it's"
303 303 " crucial for entire application")
304 304 )
305 305 if user.repositories:
306 repos = [x.repo_name for x in user.repositories]
306 307 raise UserOwnsReposException(
307 _('user "%s" still owns %s repositories and cannot be '
308 'removed. Switch owners or remove those repositories')
309 % (user.username, user.repositories)
308 _(u'user "%s" still owns %s repositories and cannot be '
309 'removed. Switch owners or remove those repositories. %s')
310 % (user.username, len(repos), ', '.join(repos))
310 311 )
311 312 self.sa.delete(user)
312 313 except:
313 314 log.error(traceback.format_exc())
314 315 raise
315 316
316 317 def reset_password_link(self, data):
317 318 from rhodecode.lib.celerylib import tasks, run_task
318 319 run_task(tasks.send_password_link, data['email'])
319 320
320 321 def reset_password(self, data):
321 322 from rhodecode.lib.celerylib import tasks, run_task
322 323 run_task(tasks.reset_user_password, data['email'])
323 324
324 325 def fill_data(self, auth_user, user_id=None, api_key=None):
325 326 """
326 327 Fetches auth_user by user_id,or api_key if present.
327 328 Fills auth_user attributes with those taken from database.
328 329 Additionally set's is_authenitated if lookup fails
329 330 present in database
330 331
331 332 :param auth_user: instance of user to set attributes
332 333 :param user_id: user id to fetch by
333 334 :param api_key: api key to fetch by
334 335 """
335 336 if user_id is None and api_key is None:
336 337 raise Exception('You need to pass user_id or api_key')
337 338
338 339 try:
339 340 if api_key:
340 341 dbuser = self.get_by_api_key(api_key)
341 342 else:
342 343 dbuser = self.get(user_id)
343 344
344 345 if dbuser is not None and dbuser.active:
345 346 log.debug('filling %s data' % dbuser)
346 347 for k, v in dbuser.get_dict().items():
347 348 setattr(auth_user, k, v)
348 349 else:
349 350 return False
350 351
351 352 except:
352 353 log.error(traceback.format_exc())
353 354 auth_user.is_authenticated = False
354 355 return False
355 356
356 357 return True
357 358
358 359 def fill_perms(self, user):
359 360 """
360 361 Fills user permission attribute with permissions taken from database
361 362 works for permissions given for repositories, and for permissions that
362 363 are granted to groups
363 364
364 365 :param user: user instance to fill his perms
365 366 """
366 367 RK = 'repositories'
367 368 GK = 'repositories_groups'
368 369 GLOBAL = 'global'
369 370 user.permissions[RK] = {}
370 371 user.permissions[GK] = {}
371 372 user.permissions[GLOBAL] = set()
372 373
373 374 #======================================================================
374 375 # fetch default permissions
375 376 #======================================================================
376 377 default_user = User.get_by_username('default', cache=True)
377 378 default_user_id = default_user.user_id
378 379
379 380 default_repo_perms = Permission.get_default_perms(default_user_id)
380 381 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
381 382
382 383 if user.is_admin:
383 384 #==================================================================
384 385 # admin user have all default rights for repositories
385 386 # and groups set to admin
386 387 #==================================================================
387 388 user.permissions[GLOBAL].add('hg.admin')
388 389
389 390 # repositories
390 391 for perm in default_repo_perms:
391 392 r_k = perm.UserRepoToPerm.repository.repo_name
392 393 p = 'repository.admin'
393 394 user.permissions[RK][r_k] = p
394 395
395 396 # repositories groups
396 397 for perm in default_repo_groups_perms:
397 398 rg_k = perm.UserRepoGroupToPerm.group.group_name
398 399 p = 'group.admin'
399 400 user.permissions[GK][rg_k] = p
400 401
401 402 else:
402 403 #==================================================================
403 404 # set default permissions first for repositories and groups
404 405 #==================================================================
405 406 uid = user.user_id
406 407
407 408 # default global permissions
408 409 default_global_perms = self.sa.query(UserToPerm)\
409 410 .filter(UserToPerm.user_id == default_user_id)
410 411
411 412 for perm in default_global_perms:
412 413 user.permissions[GLOBAL].add(perm.permission.permission_name)
413 414
414 415 # defaults for repositories, taken from default user
415 416 for perm in default_repo_perms:
416 417 r_k = perm.UserRepoToPerm.repository.repo_name
417 418 if perm.Repository.private and not (perm.Repository.user_id == uid):
418 419 # disable defaults for private repos,
419 420 p = 'repository.none'
420 421 elif perm.Repository.user_id == uid:
421 422 # set admin if owner
422 423 p = 'repository.admin'
423 424 else:
424 425 p = perm.Permission.permission_name
425 426
426 427 user.permissions[RK][r_k] = p
427 428
428 429 # defaults for repositories groups taken from default user permission
429 430 # on given group
430 431 for perm in default_repo_groups_perms:
431 432 rg_k = perm.UserRepoGroupToPerm.group.group_name
432 433 p = perm.Permission.permission_name
433 434 user.permissions[GK][rg_k] = p
434 435
435 436 #==================================================================
436 437 # overwrite defaults with user permissions if any found
437 438 #==================================================================
438 439
439 440 # user global permissions
440 441 user_perms = self.sa.query(UserToPerm)\
441 442 .options(joinedload(UserToPerm.permission))\
442 443 .filter(UserToPerm.user_id == uid).all()
443 444
444 445 for perm in user_perms:
445 446 user.permissions[GLOBAL].add(perm.permission.permission_name)
446 447
447 448 # user explicit permissions for repositories
448 449 user_repo_perms = \
449 450 self.sa.query(UserRepoToPerm, Permission, Repository)\
450 451 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
451 452 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
452 453 .filter(UserRepoToPerm.user_id == uid)\
453 454 .all()
454 455
455 456 for perm in user_repo_perms:
456 457 # set admin if owner
457 458 r_k = perm.UserRepoToPerm.repository.repo_name
458 459 if perm.Repository.user_id == uid:
459 460 p = 'repository.admin'
460 461 else:
461 462 p = perm.Permission.permission_name
462 463 user.permissions[RK][r_k] = p
463 464
464 465 #==================================================================
465 466 # check if user is part of user groups for this repository and
466 467 # fill in (or replace with higher) permissions
467 468 #==================================================================
468 469
469 470 # users group global
470 471 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
471 472 .options(joinedload(UsersGroupToPerm.permission))\
472 473 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
473 474 UsersGroupMember.users_group_id))\
474 475 .filter(UsersGroupMember.user_id == uid).all()
475 476
476 477 for perm in user_perms_from_users_groups:
477 478 user.permissions[GLOBAL].add(perm.permission.permission_name)
478 479
479 480 # users group for repositories permissions
480 481 user_repo_perms_from_users_groups = \
481 482 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
482 483 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
483 484 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
484 485 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
485 486 .filter(UsersGroupMember.user_id == uid)\
486 487 .all()
487 488
488 489 for perm in user_repo_perms_from_users_groups:
489 490 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
490 491 p = perm.Permission.permission_name
491 492 cur_perm = user.permissions[RK][r_k]
492 493 # overwrite permission only if it's greater than permission
493 494 # given from other sources
494 495 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
495 496 user.permissions[RK][r_k] = p
496 497
497 498 #==================================================================
498 499 # get access for this user for repos group and override defaults
499 500 #==================================================================
500 501
501 502 # user explicit permissions for repository
502 503 user_repo_groups_perms = \
503 504 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
504 505 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
505 506 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
506 507 .filter(UserRepoGroupToPerm.user_id == uid)\
507 508 .all()
508 509
509 510 for perm in user_repo_groups_perms:
510 511 rg_k = perm.UserRepoGroupToPerm.group.group_name
511 512 p = perm.Permission.permission_name
512 513 cur_perm = user.permissions[GK][rg_k]
513 514 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
514 515 user.permissions[GK][rg_k] = p
515 516
516 517 #==================================================================
517 518 # check if user is part of user groups for this repo group and
518 519 # fill in (or replace with higher) permissions
519 520 #==================================================================
520 521
521 522 # users group for repositories permissions
522 523 user_repo_group_perms_from_users_groups = \
523 524 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
524 525 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
525 526 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
526 527 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
527 528 .filter(UsersGroupMember.user_id == uid)\
528 529 .all()
529 530
530 531 for perm in user_repo_group_perms_from_users_groups:
531 532 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
532 533 print perm, g_k
533 534 p = perm.Permission.permission_name
534 535 cur_perm = user.permissions[GK][g_k]
535 536 # overwrite permission only if it's greater than permission
536 537 # given from other sources
537 538 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
538 539 user.permissions[GK][g_k] = p
539 540
540 541 return user
541 542
542 543 def has_perm(self, user, perm):
543 544 if not isinstance(perm, Permission):
544 545 raise Exception('perm needs to be an instance of Permission class '
545 546 'got %s instead' % type(perm))
546 547
547 548 user = self.__get_user(user)
548 549
549 550 return UserToPerm.query().filter(UserToPerm.user == user)\
550 551 .filter(UserToPerm.permission == perm).scalar() is not None
551 552
552 553 def grant_perm(self, user, perm):
553 554 """
554 555 Grant user global permissions
555 556
556 557 :param user:
557 558 :param perm:
558 559 """
559 560 user = self.__get_user(user)
560 561 perm = self.__get_perm(perm)
561 562 # if this permission is already granted skip it
562 563 _perm = UserToPerm.query()\
563 564 .filter(UserToPerm.user == user)\
564 565 .filter(UserToPerm.permission == perm)\
565 566 .scalar()
566 567 if _perm:
567 568 return
568 569 new = UserToPerm()
569 570 new.user = user
570 571 new.permission = perm
571 572 self.sa.add(new)
572 573
573 574 def revoke_perm(self, user, perm):
574 575 """
575 576 Revoke users global permissions
576 577
577 578 :param user:
578 579 :param perm:
579 580 """
580 581 user = self.__get_user(user)
581 582 perm = self.__get_perm(perm)
582 583
583 584 obj = UserToPerm.query()\
584 585 .filter(UserToPerm.user == user)\
585 586 .filter(UserToPerm.permission == perm)\
586 587 .scalar()
587 588 if obj:
588 589 self.sa.delete(obj)
General Comments 0
You need to be logged in to leave comments. Login now