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