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