##// END OF EJS Templates
users-admin: moved views into pyramid for editing emails and ips....
marcink -
r1821:a4cc42be default
parent child Browse files
Show More
@@ -64,6 +64,11 b' def admin_routes(config):'
64 name='admin_settings_sessions_cleanup',
64 name='admin_settings_sessions_cleanup',
65 pattern='/settings/sessions/cleanup')
65 pattern='/settings/sessions/cleanup')
66
66
67 # global permissions
68 config.add_route(
69 name='admin_permissions_ips',
70 pattern='/permissions/ips')
71
67 # users admin
72 # users admin
68 config.add_route(
73 config.add_route(
69 name='users',
74 name='users',
@@ -84,6 +89,28 b' def admin_routes(config):'
84 name='edit_user_auth_tokens_delete',
89 name='edit_user_auth_tokens_delete',
85 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete')
90 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete')
86
91
92 # user emails
93 config.add_route(
94 name='edit_user_emails',
95 pattern='/users/{user_id:\d+}/edit/emails')
96 config.add_route(
97 name='edit_user_emails_add',
98 pattern='/users/{user_id:\d+}/edit/emails/new')
99 config.add_route(
100 name='edit_user_emails_delete',
101 pattern='/users/{user_id:\d+}/edit/emails/delete')
102
103 # user IPs
104 config.add_route(
105 name='edit_user_ips',
106 pattern='/users/{user_id:\d+}/edit/ips')
107 config.add_route(
108 name='edit_user_ips_add',
109 pattern='/users/{user_id:\d+}/edit/ips/new')
110 config.add_route(
111 name='edit_user_ips_delete',
112 pattern='/users/{user_id:\d+}/edit/ips/delete')
113
87 # user groups management
114 # user groups management
88 config.add_route(
115 config.add_route(
89 name='edit_user_groups_management',
116 name='edit_user_groups_management',
@@ -20,7 +20,9 b''
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.model.db import User, UserApiKeys
23 from rhodecode.model.db import User, UserApiKeys, UserEmailMap
24 from rhodecode.model.meta import Session
25 from rhodecode.model.user import UserModel
24
26
25 from rhodecode.tests import (
27 from rhodecode.tests import (
26 TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash)
28 TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash)
@@ -44,6 +46,20 b' def route_path(name, params=None, **kwar'
44 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/new',
46 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/new',
45 'edit_user_auth_tokens_delete':
47 'edit_user_auth_tokens_delete':
46 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/delete',
48 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/delete',
49
50 'edit_user_emails':
51 ADMIN_PREFIX + '/users/{user_id}/edit/emails',
52 'edit_user_emails_add':
53 ADMIN_PREFIX + '/users/{user_id}/edit/emails/new',
54 'edit_user_emails_delete':
55 ADMIN_PREFIX + '/users/{user_id}/edit/emails/delete',
56
57 'edit_user_ips':
58 ADMIN_PREFIX + '/users/{user_id}/edit/ips',
59 'edit_user_ips_add':
60 ADMIN_PREFIX + '/users/{user_id}/edit/ips/new',
61 'edit_user_ips_delete':
62 ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete',
47 }[name].format(**kwargs)
63 }[name].format(**kwargs)
48
64
49 if params:
65 if params:
@@ -135,8 +151,131 b' class TestAdminUsersView(TestController)'
135
151
136 response = self.app.post(
152 response = self.app.post(
137 route_path('edit_user_auth_tokens_delete', user_id=user_id),
153 route_path('edit_user_auth_tokens_delete', user_id=user_id),
138 {'del_auth_token': keys[0].api_key, 'csrf_token': self.csrf_token})
154 {'del_auth_token': keys[0].user_api_key_id,
155 'csrf_token': self.csrf_token})
139
156
140 assert_session_flash(response, 'Auth token successfully deleted')
157 assert_session_flash(response, 'Auth token successfully deleted')
141 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
158 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
142 assert 2 == len(keys)
159 assert 2 == len(keys)
160
161 def test_ips(self):
162 self.log_user()
163 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
164 response = self.app.get(route_path('edit_user_ips', user_id=user.user_id))
165 response.mustcontain('All IP addresses are allowed')
166
167 @pytest.mark.parametrize("test_name, ip, ip_range, failure", [
168 ('127/24', '127.0.0.1/24', '127.0.0.0 - 127.0.0.255', False),
169 ('10/32', '10.0.0.10/32', '10.0.0.10 - 10.0.0.10', False),
170 ('0/16', '0.0.0.0/16', '0.0.0.0 - 0.0.255.255', False),
171 ('0/8', '0.0.0.0/8', '0.0.0.0 - 0.255.255.255', False),
172 ('127_bad_mask', '127.0.0.1/99', '127.0.0.1 - 127.0.0.1', True),
173 ('127_bad_ip', 'foobar', 'foobar', True),
174 ])
175 def test_ips_add(self, user_util, test_name, ip, ip_range, failure):
176 self.log_user()
177 user = user_util.create_user(username=test_name)
178 user_id = user.user_id
179
180 response = self.app.post(
181 route_path('edit_user_ips_add', user_id=user_id),
182 params={'new_ip': ip, 'csrf_token': self.csrf_token})
183
184 if failure:
185 assert_session_flash(
186 response, 'Please enter a valid IPv4 or IpV6 address')
187 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
188
189 response.mustcontain(no=[ip])
190 response.mustcontain(no=[ip_range])
191
192 else:
193 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
194 response.mustcontain(ip)
195 response.mustcontain(ip_range)
196
197 def test_ips_delete(self, user_util):
198 self.log_user()
199 user = user_util.create_user()
200 user_id = user.user_id
201 ip = '127.0.0.1/32'
202 ip_range = '127.0.0.1 - 127.0.0.1'
203 new_ip = UserModel().add_extra_ip(user_id, ip)
204 Session().commit()
205 new_ip_id = new_ip.ip_id
206
207 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
208 response.mustcontain(ip)
209 response.mustcontain(ip_range)
210
211 self.app.post(
212 route_path('edit_user_ips_delete', user_id=user_id),
213 params={'del_ip_id': new_ip_id, 'csrf_token': self.csrf_token})
214
215 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
216 response.mustcontain('All IP addresses are allowed')
217 response.mustcontain(no=[ip])
218 response.mustcontain(no=[ip_range])
219
220 def test_emails(self):
221 self.log_user()
222 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
223 response = self.app.get(route_path('edit_user_emails', user_id=user.user_id))
224 response.mustcontain('No additional emails specified')
225
226 def test_emails_add(self, user_util):
227 self.log_user()
228 user = user_util.create_user()
229 user_id = user.user_id
230
231 self.app.post(
232 route_path('edit_user_emails_add', user_id=user_id),
233 params={'new_email': 'example@rhodecode.com',
234 'csrf_token': self.csrf_token})
235
236 response = self.app.get(route_path('edit_user_emails', user_id=user_id))
237 response.mustcontain('example@rhodecode.com')
238
239 def test_emails_add_existing_email(self, user_util, user_regular):
240 existing_email = user_regular.email
241
242 self.log_user()
243 user = user_util.create_user()
244 user_id = user.user_id
245
246 response = self.app.post(
247 route_path('edit_user_emails_add', user_id=user_id),
248 params={'new_email': existing_email,
249 'csrf_token': self.csrf_token})
250 assert_session_flash(
251 response, 'This e-mail address is already taken')
252
253 response = self.app.get(route_path('edit_user_emails', user_id=user_id))
254 response.mustcontain(no=[existing_email])
255
256 def test_emails_delete(self, user_util):
257 self.log_user()
258 user = user_util.create_user()
259 user_id = user.user_id
260
261 self.app.post(
262 route_path('edit_user_emails_add', user_id=user_id),
263 params={'new_email': 'example@rhodecode.com',
264 'csrf_token': self.csrf_token})
265
266 response = self.app.get(route_path('edit_user_emails', user_id=user_id))
267 response.mustcontain('example@rhodecode.com')
268
269 user_email = UserEmailMap.query()\
270 .filter(UserEmailMap.email == 'example@rhodecode.com') \
271 .filter(UserEmailMap.user_id == user_id)\
272 .one()
273
274 del_email_id = user_email.email_id
275 self.app.post(
276 route_path('edit_user_emails_delete', user_id=user_id),
277 params={'del_email_id': del_email_id,
278 'csrf_token': self.csrf_token})
279
280 response = self.app.get(route_path('edit_user_emails', user_id=user_id))
281 response.mustcontain(no=['example@rhodecode.com']) No newline at end of file
@@ -20,15 +20,16 b''
20
20
21 import logging
21 import logging
22 import datetime
22 import datetime
23 import formencode
23
24
24 from pyramid.httpexceptions import HTTPFound
25 from pyramid.httpexceptions import HTTPFound
25 from pyramid.view import view_config
26 from pyramid.view import view_config
26 from sqlalchemy.sql.functions import coalesce
27 from sqlalchemy.sql.functions import coalesce
27
28
28 from rhodecode.lib.helpers import Page
29 from rhodecode.apps._base import BaseAppView, DataGridAppView
30
31 from rhodecode.lib import audit_logger
29 from rhodecode.lib.ext_json import json
32 from rhodecode.lib.ext_json import json
30
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
33 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
34 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
@@ -37,7 +38,7 b' from rhodecode.lib.utils2 import safe_in'
37 from rhodecode.model.auth_token import AuthTokenModel
38 from rhodecode.model.auth_token import AuthTokenModel
38 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user_group import UserGroupModel
40 from rhodecode.model.user_group import UserGroupModel
40 from rhodecode.model.db import User, or_
41 from rhodecode.model.db import User, or_, UserIpMap, UserEmailMap, UserApiKeys
41 from rhodecode.model.meta import Session
42 from rhodecode.model.meta import Session
42
43
43 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
@@ -194,15 +195,23 b' class AdminUsersView(BaseAppView, DataGr'
194
195
195 user_id = self.request.matchdict.get('user_id')
196 user_id = self.request.matchdict.get('user_id')
196 c.user = User.get_or_404(user_id, pyramid_exc=True)
197 c.user = User.get_or_404(user_id, pyramid_exc=True)
198
197 self._redirect_for_default_user(c.user.username)
199 self._redirect_for_default_user(c.user.username)
198
200
201 user_data = c.user.get_api_data()
199 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
202 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
200 description = self.request.POST.get('description')
203 description = self.request.POST.get('description')
201 role = self.request.POST.get('role')
204 role = self.request.POST.get('role')
202
205
203 token = AuthTokenModel().create(
206 token = AuthTokenModel().create(
204 c.user.user_id, description, lifetime, role)
207 c.user.user_id, description, lifetime, role)
208 token_data = token.get_api_data()
209
205 self.maybe_attach_token_scope(token)
210 self.maybe_attach_token_scope(token)
211 audit_logger.store(
212 action='user.edit.token.add',
213 action_data={'data': {'token': token_data, 'user': user_data}},
214 user=self._rhodecode_user, )
206 Session().commit()
215 Session().commit()
207
216
208 h.flash(_("Auth token successfully created"), category='success')
217 h.flash(_("Auth token successfully created"), category='success')
@@ -220,16 +229,214 b' class AdminUsersView(BaseAppView, DataGr'
220 user_id = self.request.matchdict.get('user_id')
229 user_id = self.request.matchdict.get('user_id')
221 c.user = User.get_or_404(user_id, pyramid_exc=True)
230 c.user = User.get_or_404(user_id, pyramid_exc=True)
222 self._redirect_for_default_user(c.user.username)
231 self._redirect_for_default_user(c.user.username)
232 user_data = c.user.get_api_data()
223
233
224 del_auth_token = self.request.POST.get('del_auth_token')
234 del_auth_token = self.request.POST.get('del_auth_token')
225
235
226 if del_auth_token:
236 if del_auth_token:
237 token = UserApiKeys.get_or_404(del_auth_token, pyramid_exc=True)
238 token_data = token.get_api_data()
239
227 AuthTokenModel().delete(del_auth_token, c.user.user_id)
240 AuthTokenModel().delete(del_auth_token, c.user.user_id)
241 audit_logger.store(
242 action='user.edit.token.delete',
243 action_data={'data': {'token': token_data, 'user': user_data}},
244 user=self._rhodecode_user,)
228 Session().commit()
245 Session().commit()
229 h.flash(_("Auth token successfully deleted"), category='success')
246 h.flash(_("Auth token successfully deleted"), category='success')
230
247
231 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
248 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
232
249
250
251
252
253
254
255 @LoginRequired()
256 @HasPermissionAllDecorator('hg.admin')
257 @view_config(
258 route_name='edit_user_emails', request_method='GET',
259 renderer='rhodecode:templates/admin/users/user_edit.mako')
260 def emails(self):
261 _ = self.request.translate
262 c = self.load_default_context()
263
264 user_id = self.request.matchdict.get('user_id')
265 c.user = User.get_or_404(user_id, pyramid_exc=True)
266 self._redirect_for_default_user(c.user.username)
267
268 c.active = 'emails'
269 c.user_email_map = UserEmailMap.query() \
270 .filter(UserEmailMap.user == c.user).all()
271
272 return self._get_template_context(c)
273
274 @LoginRequired()
275 @HasPermissionAllDecorator('hg.admin')
276 @CSRFRequired()
277 @view_config(
278 route_name='edit_user_emails_add', request_method='POST')
279 def emails_add(self):
280 _ = self.request.translate
281 c = self.load_default_context()
282
283 user_id = self.request.matchdict.get('user_id')
284 c.user = User.get_or_404(user_id, pyramid_exc=True)
285 self._redirect_for_default_user(c.user.username)
286
287 email = self.request.POST.get('new_email')
288 user_data = c.user.get_api_data()
289 try:
290 UserModel().add_extra_email(c.user.user_id, email)
291 audit_logger.store_web(
292 'user.edit.email.add',
293 action_data={'email': email, 'user': user_data},
294 user=self._rhodecode_user)
295 Session().commit()
296 h.flash(_("Added new email address `%s` for user account") % email,
297 category='success')
298 except formencode.Invalid as error:
299 msg = error.error_dict['email']
300 h.flash(msg, category='error')
301 except Exception:
302 log.exception("Exception during email saving")
303 h.flash(_('An error occurred during email saving'),
304 category='error')
305 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
306
307 @LoginRequired()
308 @HasPermissionAllDecorator('hg.admin')
309 @CSRFRequired()
310 @view_config(
311 route_name='edit_user_emails_delete', request_method='POST')
312 def emails_delete(self):
313 _ = self.request.translate
314 c = self.load_default_context()
315
316 user_id = self.request.matchdict.get('user_id')
317 c.user = User.get_or_404(user_id, pyramid_exc=True)
318 self._redirect_for_default_user(c.user.username)
319
320 email_id = self.request.POST.get('del_email_id')
321 user_model = UserModel()
322
323 email = UserEmailMap.query().get(email_id).email
324 user_data = c.user.get_api_data()
325 user_model.delete_extra_email(c.user.user_id, email_id)
326 audit_logger.store_web(
327 'user.edit.email.delete',
328 action_data={'email': email, 'user': user_data},
329 user=self._rhodecode_user)
330 Session().commit()
331 h.flash(_("Removed email address from user account"),
332 category='success')
333 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
334
335 @LoginRequired()
336 @HasPermissionAllDecorator('hg.admin')
337 @view_config(
338 route_name='edit_user_ips', request_method='GET',
339 renderer='rhodecode:templates/admin/users/user_edit.mako')
340 def ips(self):
341 _ = self.request.translate
342 c = self.load_default_context()
343
344 user_id = self.request.matchdict.get('user_id')
345 c.user = User.get_or_404(user_id, pyramid_exc=True)
346 self._redirect_for_default_user(c.user.username)
347
348 c.active = 'ips'
349 c.user_ip_map = UserIpMap.query() \
350 .filter(UserIpMap.user == c.user).all()
351
352 c.inherit_default_ips = c.user.inherit_default_permissions
353 c.default_user_ip_map = UserIpMap.query() \
354 .filter(UserIpMap.user == User.get_default_user()).all()
355
356 return self._get_template_context(c)
357
358 @LoginRequired()
359 @HasPermissionAllDecorator('hg.admin')
360 @CSRFRequired()
361 @view_config(
362 route_name='edit_user_ips_add', request_method='POST')
363 def ips_add(self):
364 _ = self.request.translate
365 c = self.load_default_context()
366
367 user_id = self.request.matchdict.get('user_id')
368 c.user = User.get_or_404(user_id, pyramid_exc=True)
369 # NOTE(marcink): this view is allowed for default users, as we can
370 # edit their IP white list
371
372 user_model = UserModel()
373 desc = self.request.POST.get('description')
374 try:
375 ip_list = user_model.parse_ip_range(
376 self.request.POST.get('new_ip'))
377 except Exception as e:
378 ip_list = []
379 log.exception("Exception during ip saving")
380 h.flash(_('An error occurred during ip saving:%s' % (e,)),
381 category='error')
382 added = []
383 user_data = c.user.get_api_data()
384 for ip in ip_list:
385 try:
386 user_model.add_extra_ip(c.user.user_id, ip, desc)
387 audit_logger.store_web(
388 'user.edit.ip.add',
389 action_data={'ip': ip, 'user': user_data},
390 user=self._rhodecode_user)
391 Session().commit()
392 added.append(ip)
393 except formencode.Invalid as error:
394 msg = error.error_dict['ip']
395 h.flash(msg, category='error')
396 except Exception:
397 log.exception("Exception during ip saving")
398 h.flash(_('An error occurred during ip saving'),
399 category='error')
400 if added:
401 h.flash(
402 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
403 category='success')
404 if 'default_user' in self.request.POST:
405 # case for editing global IP list we do it for 'DEFAULT' user
406 raise HTTPFound(h.route_path('admin_permissions_ips'))
407 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
408
409 @LoginRequired()
410 @HasPermissionAllDecorator('hg.admin')
411 @CSRFRequired()
412 @view_config(
413 route_name='edit_user_ips_delete', request_method='POST')
414 def ips_delete(self):
415 _ = self.request.translate
416 c = self.load_default_context()
417
418 user_id = self.request.matchdict.get('user_id')
419 c.user = User.get_or_404(user_id, pyramid_exc=True)
420 # NOTE(marcink): this view is allowed for default users, as we can
421 # edit their IP white list
422
423 ip_id = self.request.POST.get('del_ip_id')
424 user_model = UserModel()
425 user_data = c.user.get_api_data()
426 ip = UserIpMap.query().get(ip_id).ip_addr
427 user_model.delete_extra_ip(c.user.user_id, ip_id)
428 audit_logger.store_web(
429 'user.edit.ip.delete',
430 action_data={'ip': ip, 'user': user_data},
431 user=self._rhodecode_user)
432 Session().commit()
433 h.flash(_("Removed ip address from user whitelist"), category='success')
434
435 if 'default_user' in self.request.POST:
436 # case for editing global IP list we do it for 'DEFAULT' user
437 raise HTTPFound(h.route_path('admin_permissions_ips'))
438 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
439
233 @LoginRequired()
440 @LoginRequired()
234 @HasPermissionAllDecorator('hg.admin')
441 @HasPermissionAllDecorator('hg.admin')
235 @view_config(
442 @view_config(
@@ -301,8 +508,8 b' class AdminUsersView(BaseAppView, DataGr'
301 kw['filter'] = filter_term
508 kw['filter'] = filter_term
302 return self.request.current_route_path(_query=kw)
509 return self.request.current_route_path(_query=kw)
303
510
304 c.audit_logs = Page(user_log, page=p, items_per_page=10,
511 c.audit_logs = h.Page(
305 url=url_generator)
512 user_log, page=p, items_per_page=10, url=url_generator)
306 c.filter_term = filter_term
513 c.filter_term = filter_term
307 return self._get_template_context(c)
514 return self._get_template_context(c)
308
515
@@ -287,19 +287,6 b' def make_map(config):'
287 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
287 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
288 action='edit_perms_summary', conditions={'method': ['GET']})
288 action='edit_perms_summary', conditions={'method': ['GET']})
289
289
290 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
291 action='edit_emails', conditions={'method': ['GET']})
292 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
293 action='add_email', conditions={'method': ['PUT']})
294 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
295 action='delete_email', conditions={'method': ['DELETE']})
296
297 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
298 action='edit_ips', conditions={'method': ['GET']})
299 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
300 action='add_ip', conditions={'method': ['PUT']})
301 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
302 action='delete_ip', conditions={'method': ['DELETE']})
303
290
304 # ADMIN USER GROUPS REST ROUTES
291 # ADMIN USER GROUPS REST ROUTES
305 with rmap.submapper(path_prefix=ADMIN_PREFIX,
292 with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -491,153 +491,3 b' class UsersController(BaseController):'
491
491
492 return render('admin/users/user_edit.mako')
492 return render('admin/users/user_edit.mako')
493
493
494 @HasPermissionAllDecorator('hg.admin')
495 def edit_emails(self, user_id):
496 user_id = safe_int(user_id)
497 c.user = User.get_or_404(user_id)
498 if c.user.username == User.DEFAULT_USER:
499 h.flash(_("You can't edit this user"), category='warning')
500 return redirect(h.route_path('users'))
501
502 c.active = 'emails'
503 c.user_email_map = UserEmailMap.query() \
504 .filter(UserEmailMap.user == c.user).all()
505
506 defaults = c.user.get_dict()
507 return htmlfill.render(
508 render('admin/users/user_edit.mako'),
509 defaults=defaults,
510 encoding="UTF-8",
511 force_defaults=False)
512
513 @HasPermissionAllDecorator('hg.admin')
514 @auth.CSRFRequired()
515 def add_email(self, user_id):
516 user_id = safe_int(user_id)
517 c.user = User.get_or_404(user_id)
518
519 email = request.POST.get('new_email')
520 user_model = UserModel()
521 user_data = c.user.get_api_data()
522 try:
523 user_model.add_extra_email(user_id, email)
524 audit_logger.store_web(
525 'user.edit.email.add',
526 action_data={'email': email, 'user': user_data},
527 user=c.rhodecode_user)
528 Session().commit()
529 h.flash(_("Added new email address `%s` for user account") % email,
530 category='success')
531 except formencode.Invalid as error:
532 msg = error.error_dict['email']
533 h.flash(msg, category='error')
534 except Exception:
535 log.exception("Exception during email saving")
536 h.flash(_('An error occurred during email saving'),
537 category='error')
538 return redirect(url('edit_user_emails', user_id=user_id))
539
540 @HasPermissionAllDecorator('hg.admin')
541 @auth.CSRFRequired()
542 def delete_email(self, user_id):
543 user_id = safe_int(user_id)
544 c.user = User.get_or_404(user_id)
545 email_id = request.POST.get('del_email_id')
546 user_model = UserModel()
547
548 email = UserEmailMap.query().get(email_id).email
549 user_data = c.user.get_api_data()
550 user_model.delete_extra_email(user_id, email_id)
551 audit_logger.store_web(
552 'user.edit.email.delete',
553 action_data={'email': email, 'user': user_data},
554 user=c.rhodecode_user)
555 Session().commit()
556 h.flash(_("Removed email address from user account"), category='success')
557 return redirect(url('edit_user_emails', user_id=user_id))
558
559 @HasPermissionAllDecorator('hg.admin')
560 def edit_ips(self, user_id):
561 user_id = safe_int(user_id)
562 c.user = User.get_or_404(user_id)
563 if c.user.username == User.DEFAULT_USER:
564 h.flash(_("You can't edit this user"), category='warning')
565 return redirect(h.route_path('users'))
566
567 c.active = 'ips'
568 c.user_ip_map = UserIpMap.query() \
569 .filter(UserIpMap.user == c.user).all()
570
571 c.inherit_default_ips = c.user.inherit_default_permissions
572 c.default_user_ip_map = UserIpMap.query() \
573 .filter(UserIpMap.user == User.get_default_user()).all()
574
575 defaults = c.user.get_dict()
576 return htmlfill.render(
577 render('admin/users/user_edit.mako'),
578 defaults=defaults,
579 encoding="UTF-8",
580 force_defaults=False)
581
582 @HasPermissionAllDecorator('hg.admin')
583 @auth.CSRFRequired()
584 def add_ip(self, user_id):
585 user_id = safe_int(user_id)
586 c.user = User.get_or_404(user_id)
587 user_model = UserModel()
588 try:
589 ip_list = user_model.parse_ip_range(request.POST.get('new_ip'))
590 except Exception as e:
591 ip_list = []
592 log.exception("Exception during ip saving")
593 h.flash(_('An error occurred during ip saving:%s' % (e,)),
594 category='error')
595
596 desc = request.POST.get('description')
597 added = []
598 user_data = c.user.get_api_data()
599 for ip in ip_list:
600 try:
601 user_model.add_extra_ip(user_id, ip, desc)
602 audit_logger.store_web(
603 'user.edit.ip.add',
604 action_data={'ip': ip, 'user': user_data},
605 user=c.rhodecode_user)
606 Session().commit()
607 added.append(ip)
608 except formencode.Invalid as error:
609 msg = error.error_dict['ip']
610 h.flash(msg, category='error')
611 except Exception:
612 log.exception("Exception during ip saving")
613 h.flash(_('An error occurred during ip saving'),
614 category='error')
615 if added:
616 h.flash(
617 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
618 category='success')
619 if 'default_user' in request.POST:
620 return redirect(url('admin_permissions_ips'))
621 return redirect(url('edit_user_ips', user_id=user_id))
622
623 @HasPermissionAllDecorator('hg.admin')
624 @auth.CSRFRequired()
625 def delete_ip(self, user_id):
626 user_id = safe_int(user_id)
627 c.user = User.get_or_404(user_id)
628
629 ip_id = request.POST.get('del_ip_id')
630 user_model = UserModel()
631 user_data = c.user.get_api_data()
632 ip = UserIpMap.query().get(ip_id).ip_addr
633 user_model.delete_extra_ip(user_id, ip_id)
634 audit_logger.store_web(
635 'user.edit.ip.delete',
636 action_data={'ip': ip, 'user': user_data},
637 user=c.rhodecode_user)
638 Session().commit()
639 h.flash(_("Removed ip address from user whitelist"), category='success')
640
641 if 'default_user' in request.POST:
642 return redirect(url('admin_permissions_ips'))
643 return redirect(url('edit_user_ips', user_id=user_id))
@@ -73,11 +73,18 b' function registerRCRoutes() {'
73 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
73 pyroutes.register('admin_settings_system_update', '_admin/settings/system/updates', []);
74 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
74 pyroutes.register('admin_settings_sessions', '_admin/settings/sessions', []);
75 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
75 pyroutes.register('admin_settings_sessions_cleanup', '_admin/settings/sessions/cleanup', []);
76 pyroutes.register('admin_permissions_ips', '_admin/permissions/ips', []);
76 pyroutes.register('users', '_admin/users', []);
77 pyroutes.register('users', '_admin/users', []);
77 pyroutes.register('users_data', '_admin/users_data', []);
78 pyroutes.register('users_data', '_admin/users_data', []);
78 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
79 pyroutes.register('edit_user_auth_tokens', '_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
79 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
80 pyroutes.register('edit_user_auth_tokens_add', '_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
80 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
81 pyroutes.register('edit_user_auth_tokens_delete', '_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
82 pyroutes.register('edit_user_emails', '_admin/users/%(user_id)s/edit/emails', ['user_id']);
83 pyroutes.register('edit_user_emails_add', '_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
84 pyroutes.register('edit_user_emails_delete', '_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
85 pyroutes.register('edit_user_ips', '_admin/users/%(user_id)s/edit/ips', ['user_id']);
86 pyroutes.register('edit_user_ips_add', '_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
87 pyroutes.register('edit_user_ips_delete', '_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
81 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
88 pyroutes.register('edit_user_groups_management', '_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
82 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
89 pyroutes.register('edit_user_groups_management_updates', '_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
83 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
90 pyroutes.register('edit_user_audit_logs', '_admin/users/%(user_id)s/edit/audit', ['user_id']);
@@ -20,7 +20,7 b''
20 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
20 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
21 <td class="td-description"><div class="ip">${ip.description}</div></td>
21 <td class="td-description"><div class="ip">${ip.description}</div></td>
22 <td class="td-action">
22 <td class="td-action">
23 ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='delete')}
23 ${h.secure_form(h.route_path('edit_user_ips_delete', user_id=c.user.user_id), method='POST')}
24 ${h.hidden('del_ip_id',ip.ip_id)}
24 ${h.hidden('del_ip_id',ip.ip_id)}
25 ${h.hidden('default_user', 'True')}
25 ${h.hidden('default_user', 'True')}
26 ${h.submit('remove_',_('Delete'),id="remove_ip_%s" % ip.ip_id,
26 ${h.submit('remove_',_('Delete'),id="remove_ip_%s" % ip.ip_id,
@@ -40,7 +40,7 b''
40 </table>
40 </table>
41 </div>
41 </div>
42
42
43 ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='put')}
43 ${h.secure_form(h.route_path('edit_user_ips_add', user_id=c.user.user_id), method='POST')}
44 <div class="form">
44 <div class="form">
45 <!-- fields -->
45 <!-- fields -->
46 <div class="fields">
46 <div class="fields">
@@ -40,8 +40,8 b''
40 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_advanced', user_id=c.user.user_id)}">${_('Advanced')}</a></li>
40 <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_advanced', user_id=c.user.user_id)}">${_('Advanced')}</a></li>
41 <li class="${'active' if c.active=='global_perms' else ''}"><a href="${h.url('edit_user_global_perms', user_id=c.user.user_id)}">${_('Global permissions')}</a></li>
41 <li class="${'active' if c.active=='global_perms' else ''}"><a href="${h.url('edit_user_global_perms', user_id=c.user.user_id)}">${_('Global permissions')}</a></li>
42 <li class="${'active' if c.active=='perms_summary' else ''}"><a href="${h.url('edit_user_perms_summary', user_id=c.user.user_id)}">${_('Permissions summary')}</a></li>
42 <li class="${'active' if c.active=='perms_summary' else ''}"><a href="${h.url('edit_user_perms_summary', user_id=c.user.user_id)}">${_('Permissions summary')}</a></li>
43 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('edit_user_emails', user_id=c.user.user_id)}">${_('Emails')}</a></li>
43 <li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('edit_user_emails', user_id=c.user.user_id)}">${_('Emails')}</a></li>
44 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.url('edit_user_ips', user_id=c.user.user_id)}">${_('Ip Whitelist')}</a></li>
44 <li class="${'active' if c.active=='ips' else ''}"><a href="${h.route_path('edit_user_ips', user_id=c.user.user_id)}">${_('Ip Whitelist')}</a></li>
45 <li class="${'active' if c.active=='groups' else ''}"><a href="${h.route_path('edit_user_groups_management', user_id=c.user.user_id)}">${_('User Groups Management')}</a></li>
45 <li class="${'active' if c.active=='groups' else ''}"><a href="${h.route_path('edit_user_groups_management', user_id=c.user.user_id)}">${_('User Groups Management')}</a></li>
46 <li class="${'active' if c.active=='audit' else ''}"><a href="${h.route_path('edit_user_audit_logs', user_id=c.user.user_id)}">${_('User audit')}</a></li>
46 <li class="${'active' if c.active=='audit' else ''}"><a href="${h.route_path('edit_user_audit_logs', user_id=c.user.user_id)}">${_('User audit')}</a></li>
47 </ul>
47 </ul>
@@ -38,10 +38,10 b''
38 %endif
38 %endif
39 </td>
39 </td>
40 <td class="td-action">
40 <td class="td-action">
41 ${h.secure_form(h.route_path('edit_user_auth_tokens_delete', user_id=c.user.user_id), method='post')}
41 ${h.secure_form(h.route_path('edit_user_auth_tokens_delete', user_id=c.user.user_id), method='POST')}
42 ${h.hidden('del_auth_token',auth_token.api_key)}
42 ${h.hidden('del_auth_token', auth_token.user_api_key_id)}
43 <button class="btn btn-link btn-danger" type="submit"
43 <button class="btn btn-link btn-danger" type="submit"
44 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.api_key}');">
44 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.token_obfuscated}');">
45 ${_('Delete')}
45 ${_('Delete')}
46 </button>
46 </button>
47 ${h.end_form()}
47 ${h.end_form()}
@@ -55,7 +55,7 b''
55 </div>
55 </div>
56
56
57 <div class="user_auth_tokens">
57 <div class="user_auth_tokens">
58 ${h.secure_form(h.route_path('edit_user_auth_tokens_add', user_id=c.user.user_id), method='post')}
58 ${h.secure_form(h.route_path('edit_user_auth_tokens_add', user_id=c.user.user_id), method='POST')}
59 <div class="form form-vertical">
59 <div class="form form-vertical">
60 <!-- fields -->
60 <!-- fields -->
61 <div class="fields">
61 <div class="fields">
@@ -24,8 +24,8 b''
24 <span class="user email">${em.email}</span>
24 <span class="user email">${em.email}</span>
25 </td>
25 </td>
26 <td class="td-action">
26 <td class="td-action">
27 ${h.secure_form(url('edit_user_emails', user_id=c.user.user_id),method='delete')}
27 ${h.secure_form(h.route_path('edit_user_emails_delete', user_id=c.user.user_id), method='POST')}
28 ${h.hidden('del_email_id',em.email_id)}
28 ${h.hidden('del_email_id', em.email_id)}
29 <button class="btn btn-link btn-danger" type="submit"
29 <button class="btn btn-link btn-danger" type="submit"
30 onclick="return confirm('${_('Confirm to delete this email: %s') % em.email}');">
30 onclick="return confirm('${_('Confirm to delete this email: %s') % em.email}');">
31 ${_('Delete')}
31 ${_('Delete')}
@@ -46,7 +46,7 b''
46 </table>
46 </table>
47 </div>
47 </div>
48
48
49 ${h.secure_form(url('edit_user_emails', user_id=c.user.user_id),method='put')}
49 ${h.secure_form(h.route_path('edit_user_emails_add', user_id=c.user.user_id), method='POST')}
50 <div class="form">
50 <div class="form">
51 <!-- fields -->
51 <!-- fields -->
52 <div class="fields">
52 <div class="fields">
@@ -30,9 +30,9 b''
30 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
30 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
31 <td class="td-description"><div class="ip">${ip.description}</div></td>
31 <td class="td-description"><div class="ip">${ip.description}</div></td>
32 <td class="td-action">
32 <td class="td-action">
33 ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='delete')}
33 ${h.secure_form(h.route_path('edit_user_ips_delete', user_id=c.user.user_id), method='POST')}
34 ${h.hidden('del_ip_id',ip.ip_id)}
34 ${h.hidden('del_ip_id', ip.ip_id)}
35 ${h.submit('remove_',_('Delete'),id="remove_ip_%s" % ip.ip_id,
35 ${h.submit('remove_', _('Delete'),id="remove_ip_%s" % ip.ip_id,
36 class_="btn btn-link btn-danger", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
36 class_="btn btn-link btn-danger", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
37 ${h.end_form()}
37 ${h.end_form()}
38 </td>
38 </td>
@@ -51,7 +51,7 b''
51 </div>
51 </div>
52
52
53 <div>
53 <div>
54 ${h.secure_form(url('edit_user_ips', user_id=c.user.user_id),method='put')}
54 ${h.secure_form(h.route_path('edit_user_ips_add', user_id=c.user.user_id), method='POST')}
55 <div class="form">
55 <div class="form">
56 <!-- fields -->
56 <!-- fields -->
57 <div class="fields">
57 <div class="fields">
@@ -25,6 +25,24 b' from rhodecode.tests import ('
25 TestController, url, clear_all_caches, assert_session_flash)
25 TestController, url, clear_all_caches, assert_session_flash)
26
26
27
27
28 def route_path(name, params=None, **kwargs):
29 import urllib
30 from rhodecode.apps._base import ADMIN_PREFIX
31
32 base_url = {
33 'edit_user_ips':
34 ADMIN_PREFIX + '/users/{user_id}/edit/ips',
35 'edit_user_ips_add':
36 ADMIN_PREFIX + '/users/{user_id}/edit/ips/new',
37 'edit_user_ips_delete':
38 ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete',
39 }[name].format(**kwargs)
40
41 if params:
42 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
43 return base_url
44
45
28 class TestAdminPermissionsController(TestController):
46 class TestAdminPermissionsController(TestController):
29
47
30 @pytest.fixture(scope='class', autouse=True)
48 @pytest.fixture(scope='class', autouse=True)
@@ -181,10 +199,9 b' class TestAdminPermissionsController(Tes'
181
199
182 # ADD
200 # ADD
183 default_user_id = User.get_default_user().user_id
201 default_user_id = User.get_default_user().user_id
184 response = self.app.post(
202 self.app.post(
185 url('edit_user_ips', user_id=default_user_id),
203 route_path('edit_user_ips_add', user_id=default_user_id),
186 params={'new_ip': '127.0.0.0/24', '_method': 'put',
204 params={'new_ip': '127.0.0.0/24', 'csrf_token': self.csrf_token})
187 'csrf_token': self.csrf_token})
188
205
189 response = self.app.get(url('admin_permissions_ips'))
206 response = self.app.get(url('admin_permissions_ips'))
190 response.mustcontain('127.0.0.0/24')
207 response.mustcontain('127.0.0.0/24')
@@ -196,9 +213,8 b' class TestAdminPermissionsController(Tes'
196 default_user_id).first().ip_id
213 default_user_id).first().ip_id
197
214
198 response = self.app.post(
215 response = self.app.post(
199 url('edit_user_ips', user_id=default_user_id),
216 route_path('edit_user_ips_delete', user_id=default_user_id),
200 params={'_method': 'delete', 'del_ip_id': del_ip_id,
217 params={'del_ip_id': del_ip_id, 'csrf_token': self.csrf_token})
201 'csrf_token': self.csrf_token})
202
218
203 assert_session_flash(response, 'Removed ip address from user whitelist')
219 assert_session_flash(response, 'Removed ip address from user whitelist')
204
220
@@ -510,66 +510,3 b' class TestAdminUsersController(TestContr'
510 element = assert_response.get_element(css_selector)
510 element = assert_response.get_element(css_selector)
511 assert element.value == default_permissions[permission]
511 assert element.value == default_permissions[permission]
512
512
513 def test_ips(self):
514 self.log_user()
515 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
516 response = self.app.get(url('edit_user_ips', user_id=user.user_id))
517 response.mustcontain('All IP addresses are allowed')
518
519 @pytest.mark.parametrize("test_name, ip, ip_range, failure", [
520 ('127/24', '127.0.0.1/24', '127.0.0.0 - 127.0.0.255', False),
521 ('10/32', '10.0.0.10/32', '10.0.0.10 - 10.0.0.10', False),
522 ('0/16', '0.0.0.0/16', '0.0.0.0 - 0.0.255.255', False),
523 ('0/8', '0.0.0.0/8', '0.0.0.0 - 0.255.255.255', False),
524 ('127_bad_mask', '127.0.0.1/99', '127.0.0.1 - 127.0.0.1', True),
525 ('127_bad_ip', 'foobar', 'foobar', True),
526 ])
527 def test_add_ip(self, test_name, ip, ip_range, failure):
528 self.log_user()
529 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
530 user_id = user.user_id
531
532 response = self.app.post(url('edit_user_ips', user_id=user_id),
533 params={'new_ip': ip, '_method': 'put',
534 'csrf_token': self.csrf_token})
535
536 if failure:
537 assert_session_flash(
538 response, 'Please enter a valid IPv4 or IpV6 address')
539 response = self.app.get(url('edit_user_ips', user_id=user_id))
540 response.mustcontain(no=[ip])
541 response.mustcontain(no=[ip_range])
542
543 else:
544 response = self.app.get(url('edit_user_ips', user_id=user_id))
545 response.mustcontain(ip)
546 response.mustcontain(ip_range)
547
548 # cleanup
549 for del_ip in UserIpMap.query().filter(
550 UserIpMap.user_id == user_id).all():
551 Session().delete(del_ip)
552 Session().commit()
553
554 def test_delete_ip(self):
555 self.log_user()
556 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
557 user_id = user.user_id
558 ip = '127.0.0.1/32'
559 ip_range = '127.0.0.1 - 127.0.0.1'
560 new_ip = UserModel().add_extra_ip(user_id, ip)
561 Session().commit()
562 new_ip_id = new_ip.ip_id
563
564 response = self.app.get(url('edit_user_ips', user_id=user_id))
565 response.mustcontain(ip)
566 response.mustcontain(ip_range)
567
568 self.app.post(url('edit_user_ips', user_id=user_id),
569 params={'_method': 'delete', 'del_ip_id': new_ip_id,
570 'csrf_token': self.csrf_token})
571
572 response = self.app.get(url('edit_user_ips', user_id=user_id))
573 response.mustcontain('All IP addresses are allowed')
574 response.mustcontain(no=[ip])
575 response.mustcontain(no=[ip_range])
General Comments 0
You need to be logged in to leave comments. Login now