##// END OF EJS Templates
users: personal repo-group shouldn't be available for default user.
marcink -
r1690:5e538546 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

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