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