##// END OF EJS Templates
caches: use individual namespaces per user to prevent beaker caching problems....
caches: use individual namespaces per user to prevent beaker caching problems. - especially for mysql in case large number of data in caches there could be critical errors storing cache, and thus preventing users from authentication. This is caused by the fact that we used single namespace for ALL users. It means it grew as number of users grew reaching mysql single column limit. This changes the behaviour and now we use namespace per-user it means that each user-id will have it's own cache namespace fragmenting maximum column data to a single user cache. Which we should never reach.

File last commit:

r2487:fcee5614 default
r2591:36829a17 stable
Show More
users.py
1189 lines | 44.3 KiB | text/x-python | PythonLexer
admin: moved auth tokens into pyramid view....
r1518 # -*- coding: utf-8 -*-
release: update copyright year to 2018
r2487 # Copyright (C) 2016-2018 RhodeCode GmbH
admin: moved auth tokens into pyramid view....
r1518 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
admin-users: replace the previous nullslast() with db independent solution....
r1630 import datetime
users-admin: moved views into pyramid for editing emails and ips....
r1821 import formencode
admin: cleanup imports.
r2079 import formencode.htmlfill
admin: moved auth tokens into pyramid view....
r1518
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
users: ported controllers from pylons into pyramid views.
r2114 from pyramid.renderers import render
from pyramid.response import Response
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
ssh: added support for auto generating authorized_keys from stored ssh keys.
r1994 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.authentication.plugins import auth_rhodecode
ssh: added support for auto generating authorized_keys from stored ssh keys.
r1994 from rhodecode.events import trigger
users-admin: moved views into pyramid for editing emails and ips....
r1821
from rhodecode.lib import audit_logger
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.lib.exceptions import (
UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
UserOwnsUserGroupsException, DefaultUserException)
admin: fix wrong ext_json import from tools.
r1750 from rhodecode.lib.ext_json import json
admin: moved auth tokens into pyramid view....
r1518 from rhodecode.lib.auth import (
LoginRequired, HasPermissionAllDecorator, CSRFRequired)
from rhodecode.lib import helpers as h
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
admin: moved auth tokens into pyramid view....
r1518 from rhodecode.model.auth_token import AuthTokenModel
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.model.forms import (
pylons: remove pylons as dependency...
r2351 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
UserExtraEmailForm, UserExtraIpForm)
users: ported controllers from pylons into pyramid views.
r2114 from rhodecode.model.permission import PermissionModel
from rhodecode.model.repo_group import RepoGroupModel
users: added SSH key management for user admin pages
r1993 from rhodecode.model.ssh_key import SshKeyModel
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559 from rhodecode.model.user import UserModel
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556 from rhodecode.model.user_group import UserGroupModel
users: added SSH key management for user admin pages
r1993 from rhodecode.model.db import (
users: ported controllers from pylons into pyramid views.
r2114 or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap,
UserApiKeys, UserSshKeys, RepoGroup)
admin: moved auth tokens into pyramid view....
r1518 from rhodecode.model.meta import Session
log = logging.getLogger(__name__)
admin-users: fix wrong class name used.
r1653 class AdminUsersView(BaseAppView, DataGridAppView):
admin: moved auth tokens into pyramid view....
r1518
def load_default_context(self):
c = self._get_local_tmpl_context()
return c
auth: added @LoginRequired() decorators for user/user_group views....
r2001 @LoginRequired()
admin-users: moved grid browsing to pyramid....
r1520 @HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='users', request_method='GET',
renderer='rhodecode:templates/admin/users/users.mako')
def users_list(self):
c = self.load_default_context()
return self._get_template_context(c)
auth: added @LoginRequired() decorators for user/user_group views....
r2001 @LoginRequired()
admin-users: moved grid browsing to pyramid....
r1520 @HasPermissionAllDecorator('hg.admin')
@view_config(
# renderer defined below
admin-users: use new json_ext renderer
r1665 route_name='users_data', request_method='GET',
renderer='json_ext', xhr=True)
admin-users: moved grid browsing to pyramid....
r1520 def users_list_data(self):
views: load template context for XHR views....
r2308 self.load_default_context()
user-groups: moved the display of user group into a pyramid view
r1980 column_map = {
'first_name': 'name',
'last_name': 'lastname',
}
admin-users: moved grid browsing to pyramid....
r1520 draw, start, limit = self._extract_chunk(self.request)
user-groups: moved the display of user group into a pyramid view
r1980 search_q, order_by, order_dir = self._extract_ordering(
self.request, column_map=column_map)
admin-users: moved grid browsing to pyramid....
r1520
core: use new style pyramid partial renderer where possible.
r1897 _render = self.request.get_partial_renderer(
partial-renderer: use package resource format for templates....
r2313 'rhodecode:templates/data_table/_dt_elements.mako')
admin-users: moved grid browsing to pyramid....
r1520
def user_actions(user_id, username):
return _render("user_actions", user_id, username)
users_data_total_count = User.query()\
.filter(User.username != User.DEFAULT_USER) \
.count()
# json generate
base_q = User.query().filter(User.username != User.DEFAULT_USER)
if search_q:
admin-users: use full ilike search on filtering
r1521 like_expression = u'%{}%'.format(safe_unicode(search_q))
admin-users: moved grid browsing to pyramid....
r1520 base_q = base_q.filter(or_(
User.username.ilike(like_expression),
User._email.ilike(like_expression),
User.name.ilike(like_expression),
User.lastname.ilike(like_expression),
))
users_data_total_filtered_count = base_q.count()
sort_col = getattr(User, order_by, None)
admin-users: replace the previous nullslast() with db independent solution....
r1630 if sort_col:
if order_dir == 'asc':
# handle null values properly to order by NULL last
if order_by in ['last_activity']:
sort_col = coalesce(sort_col, datetime.date.max)
sort_col = sort_col.asc()
else:
# handle null values properly to order by NULL last
if order_by in ['last_activity']:
sort_col = coalesce(sort_col, datetime.date.min)
sort_col = sort_col.desc()
admin-users: moved grid browsing to pyramid....
r1520
admin-users: replace the previous nullslast() with db independent solution....
r1630 base_q = base_q.order_by(sort_col)
admin-users: moved grid browsing to pyramid....
r1520 base_q = base_q.offset(start).limit(limit)
admin-users: replace the previous nullslast() with db independent solution....
r1630
admin-users: moved grid browsing to pyramid....
r1520 users_list = base_q.all()
users_data = []
for user in users_list:
users_data.append({
renderer: remove usage of old non request PartialRenderer
r1947 "username": h.gravatar_with_user(self.request, user.username),
admin-users: moved grid browsing to pyramid....
r1520 "email": user.email,
security: use new safe escaped user attributes across the application....
r1815 "first_name": user.first_name,
"last_name": user.last_name,
admin-users: moved grid browsing to pyramid....
r1520 "last_login": h.format_date(user.last_login),
users: change last activity to re-use new column.
r1546 "last_activity": h.format_date(user.last_activity),
admin-users: moved grid browsing to pyramid....
r1520 "active": h.bool2icon(user.active),
"active_raw": user.active,
"admin": h.bool2icon(user.admin),
"extern_type": user.extern_type,
"extern_name": user.extern_name,
"action": user_actions(user.user_id, user.username),
})
data = ({
'draw': draw,
'data': users_data,
'recordsTotal': users_data_total_count,
'recordsFiltered': users_data_total_filtered_count,
})
return data
users: ported controllers from pylons into pyramid views.
r2114 def _set_personal_repo_group_template_vars(self, c_obj):
DummyUser = AttributeDict({
'username': '${username}',
'user_id': '${user_id}',
})
c_obj.default_create_repo_group = RepoGroupModel() \
.get_default_create_personal_repo_group()
c_obj.personal_repo_group_name = RepoGroupModel() \
.get_personal_group_name(DummyUser)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='users_new', request_method='GET',
renderer='rhodecode:templates/admin/users/user_add.mako')
def users_new(self):
_ = self.request.translate
c = self.load_default_context()
c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
self._set_personal_repo_group_template_vars(c)
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='users_create', request_method='POST',
renderer='rhodecode:templates/admin/users/user_add.mako')
def users_create(self):
_ = self.request.translate
c = self.load_default_context()
c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
user_model = UserModel()
pylons: remove pylons as dependency...
r2351 user_form = UserForm(self.request.translate)()
users: ported controllers from pylons into pyramid views.
r2114 try:
form_result = user_form.to_python(dict(self.request.POST))
user = user_model.create(form_result)
Session().flush()
creation_data = user.get_api_data()
username = form_result['username']
audit_logger.store_web(
'user.create', action_data={'data': creation_data},
user=c.rhodecode_user)
user_link = h.link_to(
h.escape(username),
h.route_path('user_edit', user_id=user.user_id))
h.flash(h.literal(_('Created user %(user_link)s')
% {'user_link': user_link}), category='success')
Session().commit()
except formencode.Invalid as errors:
self._set_personal_repo_group_template_vars(c)
data = render(
'rhodecode:templates/admin/users/user_add.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
except UserCreationError as e:
h.flash(e, 'error')
except Exception:
log.exception("Exception creation of user")
h.flash(_('Error occurred during creation of user %s')
% self.request.POST.get('username'), category='error')
raise HTTPFound(h.route_path('users'))
class UsersView(UserAppView):
ALLOW_SCOPED_TOKENS = False
"""
This view has alternative version inside EE, if modified please take a look
in there as well.
"""
def load_default_context(self):
c = self._get_local_tmpl_context()
c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
c.allowed_languages = [
('en', 'English (en)'),
('de', 'German (de)'),
('fr', 'French (fr)'),
('it', 'Italian (it)'),
('ja', 'Japanese (ja)'),
('pl', 'Polish (pl)'),
('pt', 'Portuguese (pt)'),
('ru', 'Russian (ru)'),
('zh', 'Chinese (zh)'),
]
req = self.request
c.available_permissions = req.registry.settings['available_permissions']
PermissionModel().set_global_permission_choices(
c, gettext_translator=req.translate)
return c
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='user_update', request_method='POST',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_update(self):
_ = self.request.translate
c = self.load_default_context()
user_id = self.db_user_id
c.user = self.db_user
c.active = 'profile'
c.extern_type = c.user.extern_type
c.extern_name = c.user.extern_name
c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
available_languages = [x[0] for x in c.allowed_languages]
pylons: remove pylons as dependency...
r2351 _form = UserForm(self.request.translate, edit=True,
available_languages=available_languages,
users: ported controllers from pylons into pyramid views.
r2114 old_data={'user_id': user_id,
'email': c.user.email})()
form_result = {}
old_values = c.user.get_api_data()
try:
form_result = _form.to_python(dict(self.request.POST))
skip_attrs = ['extern_type', 'extern_name']
# TODO: plugin should define if username can be updated
if c.extern_type != "rhodecode":
# forbid updating username for external accounts
skip_attrs.append('username')
UserModel().update_user(
user_id, skip_attrs=skip_attrs, **form_result)
audit_logger.store_web(
'user.edit', action_data={'old_data': old_values},
user=c.rhodecode_user)
Session().commit()
h.flash(_('User updated successfully'), category='success')
except formencode.Invalid as errors:
data = render(
'rhodecode:templates/admin/users/user_edit.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
except UserCreationError as e:
h.flash(e, 'error')
except Exception:
log.exception("Exception updating user")
h.flash(_('Error occurred during update of user %s')
% form_result.get('username'), category='error')
raise HTTPFound(h.route_path('user_edit', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='user_delete', request_method='POST',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_delete(self):
_ = self.request.translate
c = self.load_default_context()
c.user = self.db_user
_repos = c.user.repositories
_repo_groups = c.user.repository_groups
_user_groups = c.user.user_groups
handle_repos = None
handle_repo_groups = None
handle_user_groups = None
# dummy call for flash of handle
set_handle_flash_repos = lambda: None
set_handle_flash_repo_groups = lambda: None
set_handle_flash_user_groups = lambda: None
if _repos and self.request.POST.get('user_repos'):
do = self.request.POST['user_repos']
if do == 'detach':
handle_repos = 'detach'
set_handle_flash_repos = lambda: h.flash(
_('Detached %s repositories') % len(_repos),
category='success')
elif do == 'delete':
handle_repos = 'delete'
set_handle_flash_repos = lambda: h.flash(
_('Deleted %s repositories') % len(_repos),
category='success')
if _repo_groups and self.request.POST.get('user_repo_groups'):
do = self.request.POST['user_repo_groups']
if do == 'detach':
handle_repo_groups = 'detach'
set_handle_flash_repo_groups = lambda: h.flash(
_('Detached %s repository groups') % len(_repo_groups),
category='success')
elif do == 'delete':
handle_repo_groups = 'delete'
set_handle_flash_repo_groups = lambda: h.flash(
_('Deleted %s repository groups') % len(_repo_groups),
category='success')
if _user_groups and self.request.POST.get('user_user_groups'):
do = self.request.POST['user_user_groups']
if do == 'detach':
handle_user_groups = 'detach'
set_handle_flash_user_groups = lambda: h.flash(
_('Detached %s user groups') % len(_user_groups),
category='success')
elif do == 'delete':
handle_user_groups = 'delete'
set_handle_flash_user_groups = lambda: h.flash(
_('Deleted %s user groups') % len(_user_groups),
category='success')
old_values = c.user.get_api_data()
try:
UserModel().delete(c.user, handle_repos=handle_repos,
handle_repo_groups=handle_repo_groups,
handle_user_groups=handle_user_groups)
audit_logger.store_web(
'user.delete', action_data={'old_data': old_values},
user=c.rhodecode_user)
Session().commit()
set_handle_flash_repos()
set_handle_flash_repo_groups()
set_handle_flash_user_groups()
h.flash(_('Successfully deleted user'), category='success')
except (UserOwnsReposException, UserOwnsRepoGroupsException,
UserOwnsUserGroupsException, DefaultUserException) as e:
h.flash(e, category='warning')
except Exception:
log.exception("Exception during deletion of user")
h.flash(_('An error occurred during deletion of user'),
category='error')
raise HTTPFound(h.route_path('users'))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='user_edit', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_edit(self):
_ = self.request.translate
c = self.load_default_context()
c.user = self.db_user
c.active = 'profile'
c.extern_type = c.user.extern_type
c.extern_name = c.user.extern_name
c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
defaults = c.user.get_dict()
defaults.update({'language': c.user.user_data.get('language')})
data = render(
'rhodecode:templates/admin/users/user_edit.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='user_edit_advanced', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_edit_advanced(self):
_ = self.request.translate
c = self.load_default_context()
user_id = self.db_user_id
c.user = self.db_user
c.active = 'advanced'
c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id)
c.personal_repo_group_name = RepoGroupModel()\
.get_personal_group_name(c.user)
c.user_to_review_rules = sorted(
(x.user for x in c.user.user_review_rules),
key=lambda u: u.username.lower())
c.first_admin = User.get_first_super_admin()
defaults = c.user.get_dict()
# Interim workaround if the user participated on any pull requests as a
# reviewer.
has_review = len(c.user.reviewer_pull_requests)
c.can_delete_user = not has_review
c.can_delete_user_message = ''
inactive_link = h.link_to(
'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active'))
if has_review == 1:
c.can_delete_user_message = h.literal(_(
'The user participates as reviewer in {} pull request and '
'cannot be deleted. \nYou can set the user to '
'"{}" instead of deleting it.').format(
has_review, inactive_link))
elif has_review:
c.can_delete_user_message = h.literal(_(
'The user participates as reviewer in {} pull requests and '
'cannot be deleted. \nYou can set the user to '
'"{}" instead of deleting it.').format(
has_review, inactive_link))
data = render(
'rhodecode:templates/admin/users/user_edit.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='user_edit_global_perms', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_edit_global_perms(self):
_ = self.request.translate
c = self.load_default_context()
c.user = self.db_user
c.active = 'global_perms'
c.default_user = User.get_default_user()
defaults = c.user.get_dict()
defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
defaults.update(c.default_user.get_default_perms())
defaults.update(c.user.get_default_perms())
data = render(
'rhodecode:templates/admin/users/user_edit.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=defaults,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='user_edit_global_perms_update', request_method='POST',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_edit_global_perms_update(self):
_ = self.request.translate
c = self.load_default_context()
user_id = self.db_user_id
c.user = self.db_user
c.active = 'global_perms'
try:
# first stage that verifies the checkbox
pylons: remove pylons as dependency...
r2351 _form = UserIndividualPermissionsForm(self.request.translate)
users: ported controllers from pylons into pyramid views.
r2114 form_result = _form.to_python(dict(self.request.POST))
inherit_perms = form_result['inherit_default_permissions']
c.user.inherit_default_permissions = inherit_perms
Session().add(c.user)
if not inherit_perms:
# only update the individual ones if we un check the flag
_form = UserPermissionsForm(
pylons: remove pylons as dependency...
r2351 self.request.translate,
users: ported controllers from pylons into pyramid views.
r2114 [x[0] for x in c.repo_create_choices],
[x[0] for x in c.repo_create_on_write_choices],
[x[0] for x in c.repo_group_create_choices],
[x[0] for x in c.user_group_create_choices],
[x[0] for x in c.fork_choices],
[x[0] for x in c.inherit_default_permission_choices])()
form_result = _form.to_python(dict(self.request.POST))
form_result.update({'perm_user_id': c.user.user_id})
PermissionModel().update_user_permissions(form_result)
# TODO(marcink): implement global permissions
# audit_log.store_web('user.edit.permissions')
Session().commit()
h.flash(_('User global permissions updated successfully'),
category='success')
except formencode.Invalid as errors:
data = render(
'rhodecode:templates/admin/users/user_edit.mako',
self._get_template_context(c), self.request)
html = formencode.htmlfill.render(
data,
defaults=errors.value,
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8",
force_defaults=False
)
return Response(html)
except Exception:
log.exception("Exception during permissions saving")
h.flash(_('An error occurred during permissions saving'),
category='error')
raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='user_force_password_reset', request_method='POST',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_force_password_reset(self):
"""
toggle reset password flag for this user
"""
_ = self.request.translate
c = self.load_default_context()
user_id = self.db_user_id
c.user = self.db_user
try:
old_value = c.user.user_data.get('force_password_change')
c.user.update_userdata(force_password_change=not old_value)
if old_value:
msg = _('Force password change disabled for user')
audit_logger.store_web(
'user.edit.password_reset.disabled',
user=c.rhodecode_user)
else:
msg = _('Force password change enabled for user')
audit_logger.store_web(
'user.edit.password_reset.enabled',
user=c.rhodecode_user)
Session().commit()
h.flash(msg, category='success')
except Exception:
log.exception("Exception during password reset for user")
h.flash(_('An error occurred during password reset for user'),
category='error')
raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='user_create_personal_repo_group', request_method='POST',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_create_personal_repo_group(self):
"""
Create personal repository group for this user
"""
from rhodecode.model.repo_group import RepoGroupModel
_ = self.request.translate
c = self.load_default_context()
user_id = self.db_user_id
c.user = self.db_user
personal_repo_group = RepoGroup.get_user_personal_repo_group(
c.user.user_id)
if personal_repo_group:
raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
personal_repo_group_name = RepoGroupModel().get_personal_group_name(
c.user)
named_personal_group = RepoGroup.get_by_group_name(
personal_repo_group_name)
try:
if named_personal_group and named_personal_group.user_id == c.user.user_id:
# migrate the same named group, and mark it as personal
named_personal_group.personal = True
Session().add(named_personal_group)
Session().commit()
msg = _('Linked repository group `%s` as personal' % (
personal_repo_group_name,))
h.flash(msg, category='success')
elif not named_personal_group:
RepoGroupModel().create_personal_repo_group(c.user)
msg = _('Created repository group `%s`' % (
personal_repo_group_name,))
h.flash(msg, category='success')
else:
msg = _('Repository group `%s` is already taken' % (
personal_repo_group_name,))
h.flash(msg, category='warning')
except Exception:
log.exception("Exception during repository group creation")
msg = _(
'An error occurred during repository group creation for user')
h.flash(msg, category='error')
Session().rollback()
raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
admin: moved auth tokens into pyramid view....
r1518 @LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_auth_tokens', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def auth_tokens(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
admin: moved auth tokens into pyramid view....
r1518
c.active = 'auth_tokens'
auth-tokens: allow specifing custom expiration date manually....
r2083 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
admin: moved auth tokens into pyramid view....
r1518 c.role_values = [
(x, AuthTokenModel.cls._get_role_name(x))
for x in AuthTokenModel.cls.ROLES]
c.role_options = [(c.role_values, _("Role"))]
c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
c.user.user_id, show_expired=True)
repo-auth-tokens: UX, set and disable to VCS scope if selected an repo from select2
r2118 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
admin: moved auth tokens into pyramid view....
r1518 return self._get_template_context(c)
def maybe_attach_token_scope(self, token):
# implemented in EE edition
pass
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_auth_tokens_add', request_method='POST')
def auth_tokens_add(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
admin: moved auth tokens into pyramid view....
r1518
users-admin: moved views into pyramid for editing emails and ips....
r1821 user_data = c.user.get_api_data()
admin: moved auth tokens into pyramid view....
r1518 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
description = self.request.POST.get('description')
role = self.request.POST.get('role')
token = AuthTokenModel().create(
c.user.user_id, description, lifetime, role)
users-admin: moved views into pyramid for editing emails and ips....
r1821 token_data = token.get_api_data()
admin: moved auth tokens into pyramid view....
r1518 self.maybe_attach_token_scope(token)
audit-logs: consistent data between my-account and admin user logs.
r1822 audit_logger.store_web(
audit-logs: implemented full audit logs across application....
r1829 'user.edit.token.add', action_data={
'data': {'token': token_data, 'user': user_data}},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user, )
admin: moved auth tokens into pyramid view....
r1518 Session().commit()
h.flash(_("Auth token successfully created"), category='success')
return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_auth_tokens_delete', request_method='POST')
def auth_tokens_delete(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821 user_data = c.user.get_api_data()
admin: moved auth tokens into pyramid view....
r1518
del_auth_token = self.request.POST.get('del_auth_token')
if del_auth_token:
core: no longer rely on webob exception inside get_or_404 function....
r1956 token = UserApiKeys.get_or_404(del_auth_token)
users-admin: moved views into pyramid for editing emails and ips....
r1821 token_data = token.get_api_data()
admin: moved auth tokens into pyramid view....
r1518 AuthTokenModel().delete(del_auth_token, c.user.user_id)
audit-logs: consistent data between my-account and admin user logs.
r1822 audit_logger.store_web(
audit-logs: implemented full audit logs across application....
r1829 'user.edit.token.delete', action_data={
'data': {'token': token_data, 'user': user_data}},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user,)
admin: moved auth tokens into pyramid view....
r1518 Session().commit()
h.flash(_("Auth token successfully deleted"), category='success')
return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556
users-admin: moved views into pyramid for editing emails and ips....
r1821 @LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
users: added SSH key management for user admin pages
r1993 route_name='edit_user_ssh_keys', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def ssh_keys(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
users: added SSH key management for user admin pages
r1993
c.active = 'ssh_keys'
c.default_key = self.request.GET.get('default_key')
c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def ssh_keys_generate_keypair(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
users: added SSH key management for user admin pages
r1993
c.active = 'ssh_keys_generate'
comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_ssh_keys_add', request_method='POST')
def ssh_keys_add(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users: added SSH key management for user admin pages
r1993
user_data = c.user.get_api_data()
key_data = self.request.POST.get('key_data')
description = self.request.POST.get('description')
try:
if not key_data:
raise ValueError('Please add a valid public key')
key = SshKeyModel().parse_key(key_data.strip())
fingerprint = key.hash_md5()
ssh_key = SshKeyModel().create(
c.user.user_id, fingerprint, key_data, description)
ssh_key_data = ssh_key.get_api_data()
audit_logger.store_web(
'user.edit.ssh_key.add', action_data={
'data': {'ssh_key': ssh_key_data, 'user': user_data}},
user=self._rhodecode_user, )
Session().commit()
ssh: added support for auto generating authorized_keys from stored ssh keys.
r1994 # Trigger an event on change of keys.
trigger(SshKeyFileChangeEvent(), self.request.registry)
users: added SSH key management for user admin pages
r1993 h.flash(_("Ssh Key successfully created"), category='success')
except IntegrityError:
log.exception("Exception during ssh key saving")
h.flash(_('An error occurred during ssh key saving: {}').format(
'Such key already exists, please use a different one'),
category='error')
except Exception as e:
log.exception("Exception during ssh key saving")
h.flash(_('An error occurred during ssh key saving: {}').format(e),
category='error')
return HTTPFound(
h.route_path('edit_user_ssh_keys', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_ssh_keys_delete', request_method='POST')
def ssh_keys_delete(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users: added SSH key management for user admin pages
r1993 user_data = c.user.get_api_data()
del_ssh_key = self.request.POST.get('del_ssh_key')
if del_ssh_key:
ssh_key = UserSshKeys.get_or_404(del_ssh_key)
ssh_key_data = ssh_key.get_api_data()
SshKeyModel().delete(del_ssh_key, c.user.user_id)
audit_logger.store_web(
'user.edit.ssh_key.delete', action_data={
'data': {'ssh_key': ssh_key_data, 'user': user_data}},
user=self._rhodecode_user,)
Session().commit()
ssh: added support for auto generating authorized_keys from stored ssh keys.
r1994 # Trigger an event on change of keys.
trigger(SshKeyFileChangeEvent(), self.request.registry)
users: added SSH key management for user admin pages
r1993 h.flash(_("Ssh key successfully deleted"), category='success')
return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
users-admin: moved views into pyramid for editing emails and ips....
r1821 route_name='edit_user_emails', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def emails(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
c.active = 'emails'
c.user_email_map = UserEmailMap.query() \
.filter(UserEmailMap.user == c.user).all()
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_emails_add', request_method='POST')
def emails_add(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
email = self.request.POST.get('new_email')
user_data = c.user.get_api_data()
try:
pylons: remove pylons as dependency...
r2351
form = UserExtraEmailForm(self.request.translate)()
data = form.to_python({'email': email})
email = data['email']
users-admin: moved views into pyramid for editing emails and ips....
r1821 UserModel().add_extra_email(c.user.user_id, email)
audit_logger.store_web(
users: ported controllers from pylons into pyramid views.
r2114 'user.edit.email.add',
action_data={'email': email, 'user': user_data},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user)
Session().commit()
h.flash(_("Added new email address `%s` for user account") % email,
category='success')
except formencode.Invalid as error:
security: fix self-xss inside the email add functionality.
r1828 h.flash(h.escape(error.error_dict['email']), category='error')
users: ported controllers from pylons into pyramid views.
r2114 except IntegrityError:
log.warning("Email %s already exists", email)
h.flash(_('Email `{}` is already registered for another user.').format(email),
category='error')
users-admin: moved views into pyramid for editing emails and ips....
r1821 except Exception:
log.exception("Exception during email saving")
h.flash(_('An error occurred during email saving'),
category='error')
raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_emails_delete', request_method='POST')
def emails_delete(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
email_id = self.request.POST.get('del_email_id')
user_model = UserModel()
email = UserEmailMap.query().get(email_id).email
user_data = c.user.get_api_data()
user_model.delete_extra_email(c.user.user_id, email_id)
audit_logger.store_web(
users: ported controllers from pylons into pyramid views.
r2114 'user.edit.email.delete',
action_data={'email': email, 'user': user_data},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user)
Session().commit()
h.flash(_("Removed email address from user account"),
category='success')
raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_ips', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def ips(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
c.active = 'ips'
c.user_ip_map = UserIpMap.query() \
.filter(UserIpMap.user == c.user).all()
c.inherit_default_ips = c.user.inherit_default_permissions
c.default_user_ip_map = UserIpMap.query() \
.filter(UserIpMap.user == User.get_default_user()).all()
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_ips_add', request_method='POST')
users: ported controllers from pylons into pyramid views.
r2114 # NOTE(marcink): this view is allowed for default users, as we can
# edit their IP white list
users-admin: moved views into pyramid for editing emails and ips....
r1821 def ips_add(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
user_model = UserModel()
desc = self.request.POST.get('description')
try:
ip_list = user_model.parse_ip_range(
self.request.POST.get('new_ip'))
except Exception as e:
ip_list = []
log.exception("Exception during ip saving")
h.flash(_('An error occurred during ip saving:%s' % (e,)),
category='error')
added = []
user_data = c.user.get_api_data()
for ip in ip_list:
try:
pylons: remove pylons as dependency...
r2351 form = UserExtraIpForm(self.request.translate)()
data = form.to_python({'ip': ip})
ip = data['ip']
users-admin: moved views into pyramid for editing emails and ips....
r1821 user_model.add_extra_ip(c.user.user_id, ip, desc)
audit_logger.store_web(
users: ported controllers from pylons into pyramid views.
r2114 'user.edit.ip.add',
action_data={'ip': ip, 'user': user_data},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user)
Session().commit()
added.append(ip)
except formencode.Invalid as error:
msg = error.error_dict['ip']
h.flash(msg, category='error')
except Exception:
log.exception("Exception during ip saving")
h.flash(_('An error occurred during ip saving'),
category='error')
if added:
h.flash(
_("Added ips %s to user whitelist") % (', '.join(ip_list), ),
category='success')
if 'default_user' in self.request.POST:
# case for editing global IP list we do it for 'DEFAULT' user
raise HTTPFound(h.route_path('admin_permissions_ips'))
raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@CSRFRequired()
@view_config(
route_name='edit_user_ips_delete', request_method='POST')
users: ported controllers from pylons into pyramid views.
r2114 # NOTE(marcink): this view is allowed for default users, as we can
# edit their IP white list
users-admin: moved views into pyramid for editing emails and ips....
r1821 def ips_delete(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
users-admin: moved views into pyramid for editing emails and ips....
r1821
ip_id = self.request.POST.get('del_ip_id')
user_model = UserModel()
user_data = c.user.get_api_data()
ip = UserIpMap.query().get(ip_id).ip_addr
user_model.delete_extra_ip(c.user.user_id, ip_id)
audit_logger.store_web(
audit-logs: implemented full audit logs across application....
r1829 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
users-admin: moved views into pyramid for editing emails and ips....
r1821 user=self._rhodecode_user)
Session().commit()
h.flash(_("Removed ip address from user whitelist"), category='success')
if 'default_user' in self.request.POST:
# case for editing global IP list we do it for 'DEFAULT' user
raise HTTPFound(h.route_path('admin_permissions_ips'))
raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556 @LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_groups_management', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def groups_management(self):
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
c.data = c.user.group_member
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556
user-groups: moved get_user_groups from RepoModel to UserGroupModel.
r1676 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
for group in c.user.group_member]
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556 c.groups = json.dumps(groups)
c.active = 'groups'
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
security: added missing csrf checks in few missing views.
r1811 @CSRFRequired()
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556 @view_config(
route_name='edit_user_groups_management_updates', request_method='POST')
def groups_management_updates(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 user_id = self.db_user_id
c.user = self.db_user
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556
users: changed spelling of users_groups to user_groups. Because English :]
r2067 user_groups = set(self.request.POST.getall('users_group_id'))
user_groups_objects = []
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556
users: changed spelling of users_groups to user_groups. Because English :]
r2067 for ugid in user_groups:
user_groups_objects.append(
UserGroupModel().get_group(safe_int(ugid)))
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556 user_group_model = UserGroupModel()
users: ported controllers from pylons into pyramid views.
r2114 added_to_groups, removed_from_groups = \
user_group_model.change_groups(c.user, user_groups_objects)
user_data = c.user.get_api_data()
for user_group_id in added_to_groups:
user_group = UserGroup.get(user_group_id)
old_values = user_group.get_api_data()
audit_logger.store_web(
'user_group.edit.member.add',
action_data={'user': user_data, 'old_data': old_values},
user=self._rhodecode_user)
for user_group_id in removed_from_groups:
user_group = UserGroup.get(user_group_id)
old_values = user_group.get_api_data()
audit_logger.store_web(
'user_group.edit.member.delete',
action_data={'user': user_data, 'old_data': old_values},
user=self._rhodecode_user)
Bartłomiej Wołyńczyk
admin-users: add view for user groups managment...
r1556
Session().commit()
c.active = 'user_groups_management'
h.flash(_("Groups successfully changed"), category='success')
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559 return HTTPFound(h.route_path(
'edit_user_groups_management', user_id=user_id))
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_audit_logs', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_audit_logs(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559
c.active = 'audit'
p = safe_int(self.request.GET.get('page', 1), 1)
filter_term = self.request.GET.get('filter')
user-audit: share same template for rendering audit logs between user and admin views.
r1696 user_log = UserModel().get_user_log(c.user, filter_term)
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559
def url_generator(**kw):
if filter_term:
kw['filter'] = filter_term
return self.request.current_route_path(_query=kw)
users-admin: moved views into pyramid for editing emails and ips....
r1821 c.audit_logs = h.Page(
user_log, page=p, items_per_page=10, url=url_generator)
admin-users: add audit page to allow showing user actions in RhodeCode....
r1559 c.filter_term = filter_term
return self._get_template_context(c)
users/user_groups: ported permission summary pages into pyramid....
r1998 @LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_perms_summary', request_method='GET',
renderer='rhodecode:templates/admin/users/user_edit.mako')
def user_perms_summary(self):
_ = self.request.translate
c = self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 c.user = self.db_user
users/user_groups: ported permission summary pages into pyramid....
r1998
c.active = 'perms_summary'
c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
return self._get_template_context(c)
@LoginRequired()
@HasPermissionAllDecorator('hg.admin')
@view_config(
route_name='edit_user_perms_summary_json', request_method='GET',
renderer='json_ext')
def user_perms_summary_json(self):
self.load_default_context()
users: ported controllers from pylons into pyramid views.
r2114 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
users/user_groups: ported permission summary pages into pyramid....
r1998
return perm_user.permissions