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