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