##// END OF EJS Templates
users: made the function for account deactivation easier to use inside ishell.
marcink -
r1946:fcc350c9 default
parent child Browse files
Show More
@@ -1,908 +1,909 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 users model for RhodeCode
23 23 """
24 24
25 25 import logging
26 26 import traceback
27 27
28 28 import datetime
29 29 from pylons.i18n.translation import _
30 30
31 31 import ipaddress
32 32 from sqlalchemy.exc import DatabaseError
33 33
34 34 from rhodecode import events
35 35 from rhodecode.lib.user_log_filter import user_log_filter
36 36 from rhodecode.lib.utils2 import (
37 37 safe_unicode, get_current_rhodecode_user, action_logger_generic,
38 38 AttributeDict, str2bool)
39 39 from rhodecode.lib.exceptions import (
40 40 DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException,
41 41 UserOwnsUserGroupsException, NotAllowedToCreateUserError)
42 42 from rhodecode.lib.caching_query import FromCache
43 43 from rhodecode.model import BaseModel
44 44 from rhodecode.model.auth_token import AuthTokenModel
45 45 from rhodecode.model.db import (
46 46 _hash_key, true, false, or_, joinedload, User, UserToPerm,
47 47 UserEmailMap, UserIpMap, UserLog)
48 48 from rhodecode.model.meta import Session
49 49 from rhodecode.model.repo_group import RepoGroupModel
50 50
51 51
52 52 log = logging.getLogger(__name__)
53 53
54 54
55 55 class UserModel(BaseModel):
56 56 cls = User
57 57
58 58 def get(self, user_id, cache=False):
59 59 user = self.sa.query(User)
60 60 if cache:
61 61 user = user.options(
62 62 FromCache("sql_cache_short", "get_user_%s" % user_id))
63 63 return user.get(user_id)
64 64
65 65 def get_user(self, user):
66 66 return self._get_user(user)
67 67
68 68 def _serialize_user(self, user):
69 69 import rhodecode.lib.helpers as h
70 70
71 71 return {
72 72 'id': user.user_id,
73 73 'first_name': user.first_name,
74 74 'last_name': user.last_name,
75 75 'username': user.username,
76 76 'email': user.email,
77 77 'icon_link': h.gravatar_url(user.email, 30),
78 78 'value_display': h.escape(h.person(user)),
79 79 'value': user.username,
80 80 'value_type': 'user',
81 81 'active': user.active,
82 82 }
83 83
84 84 def get_users(self, name_contains=None, limit=20, only_active=True):
85 85
86 86 query = self.sa.query(User)
87 87 if only_active:
88 88 query = query.filter(User.active == true())
89 89
90 90 if name_contains:
91 91 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
92 92 query = query.filter(
93 93 or_(
94 94 User.name.ilike(ilike_expression),
95 95 User.lastname.ilike(ilike_expression),
96 96 User.username.ilike(ilike_expression)
97 97 )
98 98 )
99 99 query = query.limit(limit)
100 100 users = query.all()
101 101
102 102 _users = [
103 103 self._serialize_user(user) for user in users
104 104 ]
105 105 return _users
106 106
107 107 def get_by_username(self, username, cache=False, case_insensitive=False):
108 108
109 109 if case_insensitive:
110 110 user = self.sa.query(User).filter(User.username.ilike(username))
111 111 else:
112 112 user = self.sa.query(User)\
113 113 .filter(User.username == username)
114 114 if cache:
115 115 name_key = _hash_key(username)
116 116 user = user.options(
117 117 FromCache("sql_cache_short", "get_user_%s" % name_key))
118 118 return user.scalar()
119 119
120 120 def get_by_email(self, email, cache=False, case_insensitive=False):
121 121 return User.get_by_email(email, case_insensitive, cache)
122 122
123 123 def get_by_auth_token(self, auth_token, cache=False):
124 124 return User.get_by_auth_token(auth_token, cache)
125 125
126 126 def get_active_user_count(self, cache=False):
127 127 return User.query().filter(
128 128 User.active == True).filter(
129 129 User.username != User.DEFAULT_USER).count()
130 130
131 131 def create(self, form_data, cur_user=None):
132 132 if not cur_user:
133 133 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
134 134
135 135 user_data = {
136 136 'username': form_data['username'],
137 137 'password': form_data['password'],
138 138 'email': form_data['email'],
139 139 'firstname': form_data['firstname'],
140 140 'lastname': form_data['lastname'],
141 141 'active': form_data['active'],
142 142 'extern_type': form_data['extern_type'],
143 143 'extern_name': form_data['extern_name'],
144 144 'admin': False,
145 145 'cur_user': cur_user
146 146 }
147 147
148 148 if 'create_repo_group' in form_data:
149 149 user_data['create_repo_group'] = str2bool(
150 150 form_data.get('create_repo_group'))
151 151
152 152 try:
153 153 if form_data.get('password_change'):
154 154 user_data['force_password_change'] = True
155 155 return UserModel().create_or_update(**user_data)
156 156 except Exception:
157 157 log.error(traceback.format_exc())
158 158 raise
159 159
160 160 def update_user(self, user, skip_attrs=None, **kwargs):
161 161 from rhodecode.lib.auth import get_crypt_password
162 162
163 163 user = self._get_user(user)
164 164 if user.username == User.DEFAULT_USER:
165 165 raise DefaultUserException(
166 166 _("You can't Edit this user since it's"
167 167 " crucial for entire application"))
168 168
169 169 # first store only defaults
170 170 user_attrs = {
171 171 'updating_user_id': user.user_id,
172 172 'username': user.username,
173 173 'password': user.password,
174 174 'email': user.email,
175 175 'firstname': user.name,
176 176 'lastname': user.lastname,
177 177 'active': user.active,
178 178 'admin': user.admin,
179 179 'extern_name': user.extern_name,
180 180 'extern_type': user.extern_type,
181 181 'language': user.user_data.get('language')
182 182 }
183 183
184 184 # in case there's new_password, that comes from form, use it to
185 185 # store password
186 186 if kwargs.get('new_password'):
187 187 kwargs['password'] = kwargs['new_password']
188 188
189 189 # cleanups, my_account password change form
190 190 kwargs.pop('current_password', None)
191 191 kwargs.pop('new_password', None)
192 192
193 193 # cleanups, user edit password change form
194 194 kwargs.pop('password_confirmation', None)
195 195 kwargs.pop('password_change', None)
196 196
197 197 # create repo group on user creation
198 198 kwargs.pop('create_repo_group', None)
199 199
200 200 # legacy forms send name, which is the firstname
201 201 firstname = kwargs.pop('name', None)
202 202 if firstname:
203 203 kwargs['firstname'] = firstname
204 204
205 205 for k, v in kwargs.items():
206 206 # skip if we don't want to update this
207 207 if skip_attrs and k in skip_attrs:
208 208 continue
209 209
210 210 user_attrs[k] = v
211 211
212 212 try:
213 213 return self.create_or_update(**user_attrs)
214 214 except Exception:
215 215 log.error(traceback.format_exc())
216 216 raise
217 217
218 218 def create_or_update(
219 219 self, username, password, email, firstname='', lastname='',
220 220 active=True, admin=False, extern_type=None, extern_name=None,
221 221 cur_user=None, plugin=None, force_password_change=False,
222 222 allow_to_create_user=True, create_repo_group=None,
223 223 updating_user_id=None, language=None, strict_creation_check=True):
224 224 """
225 225 Creates a new instance if not found, or updates current one
226 226
227 227 :param username:
228 228 :param password:
229 229 :param email:
230 230 :param firstname:
231 231 :param lastname:
232 232 :param active:
233 233 :param admin:
234 234 :param extern_type:
235 235 :param extern_name:
236 236 :param cur_user:
237 237 :param plugin: optional plugin this method was called from
238 238 :param force_password_change: toggles new or existing user flag
239 239 for password change
240 240 :param allow_to_create_user: Defines if the method can actually create
241 241 new users
242 242 :param create_repo_group: Defines if the method should also
243 243 create an repo group with user name, and owner
244 244 :param updating_user_id: if we set it up this is the user we want to
245 245 update this allows to editing username.
246 246 :param language: language of user from interface.
247 247
248 248 :returns: new User object with injected `is_new_user` attribute.
249 249 """
250 250 if not cur_user:
251 251 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
252 252
253 253 from rhodecode.lib.auth import (
254 254 get_crypt_password, check_password, generate_auth_token)
255 255 from rhodecode.lib.hooks_base import (
256 256 log_create_user, check_allowed_create_user)
257 257
258 258 def _password_change(new_user, password):
259 259 # empty password
260 260 if not new_user.password:
261 261 return False
262 262
263 263 # password check is only needed for RhodeCode internal auth calls
264 264 # in case it's a plugin we don't care
265 265 if not plugin:
266 266
267 267 # first check if we gave crypted password back, and if it
268 268 # matches it's not password change
269 269 if new_user.password == password:
270 270 return False
271 271
272 272 password_match = check_password(password, new_user.password)
273 273 if not password_match:
274 274 return True
275 275
276 276 return False
277 277
278 278 # read settings on default personal repo group creation
279 279 if create_repo_group is None:
280 280 default_create_repo_group = RepoGroupModel()\
281 281 .get_default_create_personal_repo_group()
282 282 create_repo_group = default_create_repo_group
283 283
284 284 user_data = {
285 285 'username': username,
286 286 'password': password,
287 287 'email': email,
288 288 'firstname': firstname,
289 289 'lastname': lastname,
290 290 'active': active,
291 291 'admin': admin
292 292 }
293 293
294 294 if updating_user_id:
295 295 log.debug('Checking for existing account in RhodeCode '
296 296 'database with user_id `%s` ' % (updating_user_id,))
297 297 user = User.get(updating_user_id)
298 298 else:
299 299 log.debug('Checking for existing account in RhodeCode '
300 300 'database with username `%s` ' % (username,))
301 301 user = User.get_by_username(username, case_insensitive=True)
302 302
303 303 if user is None:
304 304 # we check internal flag if this method is actually allowed to
305 305 # create new user
306 306 if not allow_to_create_user:
307 307 msg = ('Method wants to create new user, but it is not '
308 308 'allowed to do so')
309 309 log.warning(msg)
310 310 raise NotAllowedToCreateUserError(msg)
311 311
312 312 log.debug('Creating new user %s', username)
313 313
314 314 # only if we create user that is active
315 315 new_active_user = active
316 316 if new_active_user and strict_creation_check:
317 317 # raises UserCreationError if it's not allowed for any reason to
318 318 # create new active user, this also executes pre-create hooks
319 319 check_allowed_create_user(user_data, cur_user, strict_check=True)
320 320 events.trigger(events.UserPreCreate(user_data))
321 321 new_user = User()
322 322 edit = False
323 323 else:
324 324 log.debug('updating user %s', username)
325 325 events.trigger(events.UserPreUpdate(user, user_data))
326 326 new_user = user
327 327 edit = True
328 328
329 329 # we're not allowed to edit default user
330 330 if user.username == User.DEFAULT_USER:
331 331 raise DefaultUserException(
332 332 _("You can't edit this user (`%(username)s`) since it's "
333 333 "crucial for entire application") % {'username': user.username})
334 334
335 335 # inject special attribute that will tell us if User is new or old
336 336 new_user.is_new_user = not edit
337 337 # for users that didn's specify auth type, we use RhodeCode built in
338 338 from rhodecode.authentication.plugins import auth_rhodecode
339 339 extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.name
340 340 extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.name
341 341
342 342 try:
343 343 new_user.username = username
344 344 new_user.admin = admin
345 345 new_user.email = email
346 346 new_user.active = active
347 347 new_user.extern_name = safe_unicode(extern_name)
348 348 new_user.extern_type = safe_unicode(extern_type)
349 349 new_user.name = firstname
350 350 new_user.lastname = lastname
351 351
352 352 # set password only if creating an user or password is changed
353 353 if not edit or _password_change(new_user, password):
354 354 reason = 'new password' if edit else 'new user'
355 355 log.debug('Updating password reason=>%s', reason)
356 356 new_user.password = get_crypt_password(password) if password else None
357 357
358 358 if force_password_change:
359 359 new_user.update_userdata(force_password_change=True)
360 360 if language:
361 361 new_user.update_userdata(language=language)
362 362 new_user.update_userdata(notification_status=True)
363 363
364 364 self.sa.add(new_user)
365 365
366 366 if not edit and create_repo_group:
367 367 RepoGroupModel().create_personal_repo_group(
368 368 new_user, commit_early=False)
369 369
370 370 if not edit:
371 371 # add the RSS token
372 372 AuthTokenModel().create(username,
373 373 description='Generated feed token',
374 374 role=AuthTokenModel.cls.ROLE_FEED)
375 375 log_create_user(created_by=cur_user, **new_user.get_dict())
376 376 events.trigger(events.UserPostCreate(user_data))
377 377 return new_user
378 378 except (DatabaseError,):
379 379 log.error(traceback.format_exc())
380 380 raise
381 381
382 382 def create_registration(self, form_data):
383 383 from rhodecode.model.notification import NotificationModel
384 384 from rhodecode.model.notification import EmailNotificationModel
385 385
386 386 try:
387 387 form_data['admin'] = False
388 388 form_data['extern_name'] = 'rhodecode'
389 389 form_data['extern_type'] = 'rhodecode'
390 390 new_user = self.create(form_data)
391 391
392 392 self.sa.add(new_user)
393 393 self.sa.flush()
394 394
395 395 user_data = new_user.get_dict()
396 396 kwargs = {
397 397 # use SQLALCHEMY safe dump of user data
398 398 'user': AttributeDict(user_data),
399 399 'date': datetime.datetime.now()
400 400 }
401 401 notification_type = EmailNotificationModel.TYPE_REGISTRATION
402 402 # pre-generate the subject for notification itself
403 403 (subject,
404 404 _h, _e, # we don't care about those
405 405 body_plaintext) = EmailNotificationModel().render_email(
406 406 notification_type, **kwargs)
407 407
408 408 # create notification objects, and emails
409 409 NotificationModel().create(
410 410 created_by=new_user,
411 411 notification_subject=subject,
412 412 notification_body=body_plaintext,
413 413 notification_type=notification_type,
414 414 recipients=None, # all admins
415 415 email_kwargs=kwargs,
416 416 )
417 417
418 418 return new_user
419 419 except Exception:
420 420 log.error(traceback.format_exc())
421 421 raise
422 422
423 423 def _handle_user_repos(self, username, repositories, handle_mode=None):
424 424 _superadmin = self.cls.get_first_super_admin()
425 425 left_overs = True
426 426
427 427 from rhodecode.model.repo import RepoModel
428 428
429 429 if handle_mode == 'detach':
430 430 for obj in repositories:
431 431 obj.user = _superadmin
432 432 # set description we know why we super admin now owns
433 433 # additional repositories that were orphaned !
434 434 obj.description += ' \n::detached repository from deleted user: %s' % (username,)
435 435 self.sa.add(obj)
436 436 left_overs = False
437 437 elif handle_mode == 'delete':
438 438 for obj in repositories:
439 439 RepoModel().delete(obj, forks='detach')
440 440 left_overs = False
441 441
442 442 # if nothing is done we have left overs left
443 443 return left_overs
444 444
445 445 def _handle_user_repo_groups(self, username, repository_groups,
446 446 handle_mode=None):
447 447 _superadmin = self.cls.get_first_super_admin()
448 448 left_overs = True
449 449
450 450 from rhodecode.model.repo_group import RepoGroupModel
451 451
452 452 if handle_mode == 'detach':
453 453 for r in repository_groups:
454 454 r.user = _superadmin
455 455 # set description we know why we super admin now owns
456 456 # additional repositories that were orphaned !
457 457 r.group_description += ' \n::detached repository group from deleted user: %s' % (username,)
458 458 self.sa.add(r)
459 459 left_overs = False
460 460 elif handle_mode == 'delete':
461 461 for r in repository_groups:
462 462 RepoGroupModel().delete(r)
463 463 left_overs = False
464 464
465 465 # if nothing is done we have left overs left
466 466 return left_overs
467 467
468 468 def _handle_user_user_groups(self, username, user_groups, handle_mode=None):
469 469 _superadmin = self.cls.get_first_super_admin()
470 470 left_overs = True
471 471
472 472 from rhodecode.model.user_group import UserGroupModel
473 473
474 474 if handle_mode == 'detach':
475 475 for r in user_groups:
476 476 for user_user_group_to_perm in r.user_user_group_to_perm:
477 477 if user_user_group_to_perm.user.username == username:
478 478 user_user_group_to_perm.user = _superadmin
479 479 r.user = _superadmin
480 480 # set description we know why we super admin now owns
481 481 # additional repositories that were orphaned !
482 482 r.user_group_description += ' \n::detached user group from deleted user: %s' % (username,)
483 483 self.sa.add(r)
484 484 left_overs = False
485 485 elif handle_mode == 'delete':
486 486 for r in user_groups:
487 487 UserGroupModel().delete(r)
488 488 left_overs = False
489 489
490 490 # if nothing is done we have left overs left
491 491 return left_overs
492 492
493 493 def delete(self, user, cur_user=None, handle_repos=None,
494 494 handle_repo_groups=None, handle_user_groups=None):
495 495 if not cur_user:
496 496 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
497 497 user = self._get_user(user)
498 498
499 499 try:
500 500 if user.username == User.DEFAULT_USER:
501 501 raise DefaultUserException(
502 502 _(u"You can't remove this user since it's"
503 503 u" crucial for entire application"))
504 504
505 505 left_overs = self._handle_user_repos(
506 506 user.username, user.repositories, handle_repos)
507 507 if left_overs and user.repositories:
508 508 repos = [x.repo_name for x in user.repositories]
509 509 raise UserOwnsReposException(
510 510 _(u'user "%s" still owns %s repositories and cannot be '
511 511 u'removed. Switch owners or remove those repositories:%s')
512 512 % (user.username, len(repos), ', '.join(repos)))
513 513
514 514 left_overs = self._handle_user_repo_groups(
515 515 user.username, user.repository_groups, handle_repo_groups)
516 516 if left_overs and user.repository_groups:
517 517 repo_groups = [x.group_name for x in user.repository_groups]
518 518 raise UserOwnsRepoGroupsException(
519 519 _(u'user "%s" still owns %s repository groups and cannot be '
520 520 u'removed. Switch owners or remove those repository groups:%s')
521 521 % (user.username, len(repo_groups), ', '.join(repo_groups)))
522 522
523 523 left_overs = self._handle_user_user_groups(
524 524 user.username, user.user_groups, handle_user_groups)
525 525 if left_overs and user.user_groups:
526 526 user_groups = [x.users_group_name for x in user.user_groups]
527 527 raise UserOwnsUserGroupsException(
528 528 _(u'user "%s" still owns %s user groups and cannot be '
529 529 u'removed. Switch owners or remove those user groups:%s')
530 530 % (user.username, len(user_groups), ', '.join(user_groups)))
531 531
532 532 # we might change the user data with detach/delete, make sure
533 533 # the object is marked as expired before actually deleting !
534 534 self.sa.expire(user)
535 535 self.sa.delete(user)
536 536 from rhodecode.lib.hooks_base import log_delete_user
537 537 log_delete_user(deleted_by=cur_user, **user.get_dict())
538 538 except Exception:
539 539 log.error(traceback.format_exc())
540 540 raise
541 541
542 542 def reset_password_link(self, data, pwd_reset_url):
543 543 from rhodecode.lib.celerylib import tasks, run_task
544 544 from rhodecode.model.notification import EmailNotificationModel
545 545 user_email = data['email']
546 546 try:
547 547 user = User.get_by_email(user_email)
548 548 if user:
549 549 log.debug('password reset user found %s', user)
550 550
551 551 email_kwargs = {
552 552 'password_reset_url': pwd_reset_url,
553 553 'user': user,
554 554 'email': user_email,
555 555 'date': datetime.datetime.now()
556 556 }
557 557
558 558 (subject, headers, email_body,
559 559 email_body_plaintext) = EmailNotificationModel().render_email(
560 560 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
561 561
562 562 recipients = [user_email]
563 563
564 564 action_logger_generic(
565 565 'sending password reset email to user: {}'.format(
566 566 user), namespace='security.password_reset')
567 567
568 568 run_task(tasks.send_email, recipients, subject,
569 569 email_body_plaintext, email_body)
570 570
571 571 else:
572 572 log.debug("password reset email %s not found", user_email)
573 573 except Exception:
574 574 log.error(traceback.format_exc())
575 575 return False
576 576
577 577 return True
578 578
579 579 def reset_password(self, data):
580 580 from rhodecode.lib.celerylib import tasks, run_task
581 581 from rhodecode.model.notification import EmailNotificationModel
582 582 from rhodecode.lib import auth
583 583 user_email = data['email']
584 584 pre_db = True
585 585 try:
586 586 user = User.get_by_email(user_email)
587 587 new_passwd = auth.PasswordGenerator().gen_password(
588 588 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
589 589 if user:
590 590 user.password = auth.get_crypt_password(new_passwd)
591 591 # also force this user to reset his password !
592 592 user.update_userdata(force_password_change=True)
593 593
594 594 Session().add(user)
595 595
596 596 # now delete the token in question
597 597 UserApiKeys = AuthTokenModel.cls
598 598 UserApiKeys().query().filter(
599 599 UserApiKeys.api_key == data['token']).delete()
600 600
601 601 Session().commit()
602 602 log.info('successfully reset password for `%s`', user_email)
603 603
604 604 if new_passwd is None:
605 605 raise Exception('unable to generate new password')
606 606
607 607 pre_db = False
608 608
609 609 email_kwargs = {
610 610 'new_password': new_passwd,
611 611 'user': user,
612 612 'email': user_email,
613 613 'date': datetime.datetime.now()
614 614 }
615 615
616 616 (subject, headers, email_body,
617 617 email_body_plaintext) = EmailNotificationModel().render_email(
618 618 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
619 619 **email_kwargs)
620 620
621 621 recipients = [user_email]
622 622
623 623 action_logger_generic(
624 624 'sent new password to user: {} with email: {}'.format(
625 625 user, user_email), namespace='security.password_reset')
626 626
627 627 run_task(tasks.send_email, recipients, subject,
628 628 email_body_plaintext, email_body)
629 629
630 630 except Exception:
631 631 log.error('Failed to update user password')
632 632 log.error(traceback.format_exc())
633 633 if pre_db:
634 634 # we rollback only if local db stuff fails. If it goes into
635 635 # run_task, we're pass rollback state this wouldn't work then
636 636 Session().rollback()
637 637
638 638 return True
639 639
640 640 def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
641 641 """
642 642 Fetches auth_user by user_id,or api_key if present.
643 643 Fills auth_user attributes with those taken from database.
644 644 Additionally set's is_authenitated if lookup fails
645 645 present in database
646 646
647 647 :param auth_user: instance of user to set attributes
648 648 :param user_id: user id to fetch by
649 649 :param api_key: api key to fetch by
650 650 :param username: username to fetch by
651 651 """
652 652 if user_id is None and api_key is None and username is None:
653 653 raise Exception('You need to pass user_id, api_key or username')
654 654
655 655 log.debug(
656 656 'doing fill data based on: user_id:%s api_key:%s username:%s',
657 657 user_id, api_key, username)
658 658 try:
659 659 dbuser = None
660 660 if user_id:
661 661 dbuser = self.get(user_id)
662 662 elif api_key:
663 663 dbuser = self.get_by_auth_token(api_key)
664 664 elif username:
665 665 dbuser = self.get_by_username(username)
666 666
667 667 if not dbuser:
668 668 log.warning(
669 669 'Unable to lookup user by id:%s api_key:%s username:%s',
670 670 user_id, api_key, username)
671 671 return False
672 672 if not dbuser.active:
673 673 log.debug('User `%s:%s` is inactive, skipping fill data',
674 674 username, user_id)
675 675 return False
676 676
677 677 log.debug('filling user:%s data', dbuser)
678 678
679 679 # TODO: johbo: Think about this and find a clean solution
680 680 user_data = dbuser.get_dict()
681 681 user_data.update(dbuser.get_api_data(include_secrets=True))
682 682 user_data.update({
683 683 # set explicit the safe escaped values
684 684 'first_name': dbuser.first_name,
685 685 'last_name': dbuser.last_name,
686 686 })
687 687
688 688 for k, v in user_data.iteritems():
689 689 # properties of auth user we dont update
690 690 if k not in ['auth_tokens', 'permissions']:
691 691 setattr(auth_user, k, v)
692 692
693 693 # few extras
694 694 setattr(auth_user, 'feed_token', dbuser.feed_token)
695 695 except Exception:
696 696 log.error(traceback.format_exc())
697 697 auth_user.is_authenticated = False
698 698 return False
699 699
700 700 return True
701 701
702 702 def has_perm(self, user, perm):
703 703 perm = self._get_perm(perm)
704 704 user = self._get_user(user)
705 705
706 706 return UserToPerm.query().filter(UserToPerm.user == user)\
707 707 .filter(UserToPerm.permission == perm).scalar() is not None
708 708
709 709 def grant_perm(self, user, perm):
710 710 """
711 711 Grant user global permissions
712 712
713 713 :param user:
714 714 :param perm:
715 715 """
716 716 user = self._get_user(user)
717 717 perm = self._get_perm(perm)
718 718 # if this permission is already granted skip it
719 719 _perm = UserToPerm.query()\
720 720 .filter(UserToPerm.user == user)\
721 721 .filter(UserToPerm.permission == perm)\
722 722 .scalar()
723 723 if _perm:
724 724 return
725 725 new = UserToPerm()
726 726 new.user = user
727 727 new.permission = perm
728 728 self.sa.add(new)
729 729 return new
730 730
731 731 def revoke_perm(self, user, perm):
732 732 """
733 733 Revoke users global permissions
734 734
735 735 :param user:
736 736 :param perm:
737 737 """
738 738 user = self._get_user(user)
739 739 perm = self._get_perm(perm)
740 740
741 741 obj = UserToPerm.query()\
742 742 .filter(UserToPerm.user == user)\
743 743 .filter(UserToPerm.permission == perm)\
744 744 .scalar()
745 745 if obj:
746 746 self.sa.delete(obj)
747 747
748 748 def add_extra_email(self, user, email):
749 749 """
750 750 Adds email address to UserEmailMap
751 751
752 752 :param user:
753 753 :param email:
754 754 """
755 755 from rhodecode.model import forms
756 756 form = forms.UserExtraEmailForm()()
757 757 data = form.to_python({'email': email})
758 758 user = self._get_user(user)
759 759
760 760 obj = UserEmailMap()
761 761 obj.user = user
762 762 obj.email = data['email']
763 763 self.sa.add(obj)
764 764 return obj
765 765
766 766 def delete_extra_email(self, user, email_id):
767 767 """
768 768 Removes email address from UserEmailMap
769 769
770 770 :param user:
771 771 :param email_id:
772 772 """
773 773 user = self._get_user(user)
774 774 obj = UserEmailMap.query().get(email_id)
775 775 if obj and obj.user_id == user.user_id:
776 776 self.sa.delete(obj)
777 777
778 778 def parse_ip_range(self, ip_range):
779 779 ip_list = []
780 780
781 781 def make_unique(value):
782 782 seen = []
783 783 return [c for c in value if not (c in seen or seen.append(c))]
784 784
785 785 # firsts split by commas
786 786 for ip_range in ip_range.split(','):
787 787 if not ip_range:
788 788 continue
789 789 ip_range = ip_range.strip()
790 790 if '-' in ip_range:
791 791 start_ip, end_ip = ip_range.split('-', 1)
792 792 start_ip = ipaddress.ip_address(safe_unicode(start_ip.strip()))
793 793 end_ip = ipaddress.ip_address(safe_unicode(end_ip.strip()))
794 794 parsed_ip_range = []
795 795
796 796 for index in xrange(int(start_ip), int(end_ip) + 1):
797 797 new_ip = ipaddress.ip_address(index)
798 798 parsed_ip_range.append(str(new_ip))
799 799 ip_list.extend(parsed_ip_range)
800 800 else:
801 801 ip_list.append(ip_range)
802 802
803 803 return make_unique(ip_list)
804 804
805 805 def add_extra_ip(self, user, ip, description=None):
806 806 """
807 807 Adds ip address to UserIpMap
808 808
809 809 :param user:
810 810 :param ip:
811 811 """
812 812 from rhodecode.model import forms
813 813 form = forms.UserExtraIpForm()()
814 814 data = form.to_python({'ip': ip})
815 815 user = self._get_user(user)
816 816
817 817 obj = UserIpMap()
818 818 obj.user = user
819 819 obj.ip_addr = data['ip']
820 820 obj.description = description
821 821 self.sa.add(obj)
822 822 return obj
823 823
824 824 def delete_extra_ip(self, user, ip_id):
825 825 """
826 826 Removes ip address from UserIpMap
827 827
828 828 :param user:
829 829 :param ip_id:
830 830 """
831 831 user = self._get_user(user)
832 832 obj = UserIpMap.query().get(ip_id)
833 833 if obj and obj.user_id == user.user_id:
834 834 self.sa.delete(obj)
835 835
836 836 def get_accounts_in_creation_order(self, current_user=None):
837 837 """
838 838 Get accounts in order of creation for deactivation for license limits
839 839
840 840 pick currently logged in user, and append to the list in position 0
841 841 pick all super-admins in order of creation date and add it to the list
842 842 pick all other accounts in order of creation and add it to the list.
843 843
844 844 Based on that list, the last accounts can be disabled as they are
845 845 created at the end and don't include any of the super admins as well
846 846 as the current user.
847 847
848 848 :param current_user: optionally current user running this operation
849 849 """
850 850
851 851 if not current_user:
852 852 current_user = get_current_rhodecode_user()
853 853 active_super_admins = [
854 854 x.user_id for x in User.query()
855 855 .filter(User.user_id != current_user.user_id)
856 856 .filter(User.active == true())
857 857 .filter(User.admin == true())
858 858 .order_by(User.created_on.asc())]
859 859
860 860 active_regular_users = [
861 861 x.user_id for x in User.query()
862 862 .filter(User.user_id != current_user.user_id)
863 863 .filter(User.active == true())
864 864 .filter(User.admin == false())
865 865 .order_by(User.created_on.asc())]
866 866
867 867 list_of_accounts = [current_user.user_id]
868 868 list_of_accounts += active_super_admins
869 869 list_of_accounts += active_regular_users
870 870
871 871 return list_of_accounts
872 872
873 def deactivate_last_users(self, expected_users):
873 def deactivate_last_users(self, expected_users, current_user=None):
874 874 """
875 875 Deactivate accounts that are over the license limits.
876 876 Algorithm of which accounts to disabled is based on the formula:
877 877
878 878 Get current user, then super admins in creation order, then regular
879 879 active users in creation order.
880 880
881 881 Using that list we mark all accounts from the end of it as inactive.
882 882 This way we block only latest created accounts.
883 883
884 884 :param expected_users: list of users in special order, we deactivate
885 885 the end N ammoun of users from that list
886 886 """
887 887
888 list_of_accounts = self.get_accounts_in_creation_order()
888 list_of_accounts = self.get_accounts_in_creation_order(
889 current_user=current_user)
889 890
890 891 for acc_id in list_of_accounts[expected_users + 1:]:
891 892 user = User.get(acc_id)
892 893 log.info('Deactivating account %s for license unlock', user)
893 894 user.active = False
894 895 Session().add(user)
895 896 Session().commit()
896 897
897 898 return
898 899
899 900 def get_user_log(self, user, filter_term):
900 901 user_log = UserLog.query()\
901 902 .filter(or_(UserLog.user_id == user.user_id,
902 903 UserLog.username == user.username))\
903 904 .options(joinedload(UserLog.user))\
904 905 .options(joinedload(UserLog.repository))\
905 906 .order_by(UserLog.action_date.desc())
906 907
907 908 user_log = user_log_filter(user_log, filter_term)
908 909 return user_log
General Comments 0
You need to be logged in to leave comments. Login now