diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py
--- a/rhodecode/apps/admin/__init__.py
+++ b/rhodecode/apps/admin/__init__.py
@@ -53,5 +53,16 @@ def includeme(config):
name='admin_settings_sessions_cleanup',
pattern=ADMIN_PREFIX + '/settings/sessions/cleanup')
+ # user auth tokens
+ config.add_route(
+ name='edit_user_auth_tokens',
+ pattern=ADMIN_PREFIX + '/users/{user_id:\d+}/edit/auth_tokens')
+ config.add_route(
+ name='edit_user_auth_tokens_add',
+ pattern=ADMIN_PREFIX + '/users/{user_id:\d+}/edit/auth_tokens/new')
+ config.add_route(
+ name='edit_user_auth_tokens_delete',
+ pattern=ADMIN_PREFIX + '/users/{user_id:\d+}/edit/auth_tokens/delete')
+
# Scan module for configuration decorators.
config.scan()
diff --git a/rhodecode/apps/admin/views/users.py b/rhodecode/apps/admin/views/users.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/admin/views/users.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2016-2017 RhodeCode GmbH
+#
+# 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 .
+#
+# 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
+
+from pyramid.httpexceptions import HTTPFound
+from pyramid.view import view_config
+
+from rhodecode.apps._base import BaseAppView
+from rhodecode.lib.auth import (
+ LoginRequired, HasPermissionAllDecorator, CSRFRequired)
+from rhodecode.lib import helpers as h
+from rhodecode.lib.utils import PartialRenderer
+from rhodecode.lib.utils2 import safe_int
+from rhodecode.model.auth_token import AuthTokenModel
+from rhodecode.model.db import User
+from rhodecode.model.meta import Session
+
+log = logging.getLogger(__name__)
+
+
+class AdminUsersView(BaseAppView):
+ 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.auth_user = self.request.user
+ c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
+ self._register_global_c(c)
+ return c
+
+ def _redirect_for_default_user(self, username):
+ _ = self.request.translate
+ if username == User.DEFAULT_USER:
+ h.flash(_("You can't edit this user"), category='warning')
+ # TODO(marcink): redirect to 'users' admin panel once this
+ # is a pyramid view
+ raise HTTPFound('/')
+
+ @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()
+
+ user_id = self.request.matchdict.get('user_id')
+ c.user = User.get_or_404(user_id, pyramid_exc=True)
+ self._redirect_for_default_user(c.user.username)
+
+ c.active = 'auth_tokens'
+
+ c.lifetime_values = [
+ (str(-1), _('forever')),
+ (str(5), _('5 minutes')),
+ (str(60), _('1 hour')),
+ (str(60 * 24), _('1 day')),
+ (str(60 * 24 * 30), _('1 month')),
+ ]
+ c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
+ 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)
+ 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()
+
+ user_id = self.request.matchdict.get('user_id')
+ c.user = User.get_or_404(user_id, pyramid_exc=True)
+ self._redirect_for_default_user(c.user.username)
+
+ 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)
+ self.maybe_attach_token_scope(token)
+ 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()
+
+ user_id = self.request.matchdict.get('user_id')
+ c.user = User.get_or_404(user_id, pyramid_exc=True)
+ self._redirect_for_default_user(c.user.username)
+
+ del_auth_token = self.request.POST.get('del_auth_token')
+
+ if del_auth_token:
+ AuthTokenModel().delete(del_auth_token, c.user.user_id)
+ Session().commit()
+ h.flash(_("Auth token successfully deleted"), category='success')
+
+ return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -315,13 +315,6 @@ def make_map(config):
m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
action='update_advanced', conditions={'method': ['PUT']})
- m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
- action='edit_auth_tokens', conditions={'method': ['GET']})
- m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
- action='add_auth_token', conditions={'method': ['PUT']})
- m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
- action='delete_auth_token', conditions={'method': ['DELETE']})
-
m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
action='edit_global_perms', conditions={'method': ['GET']})
m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
diff --git a/rhodecode/controllers/admin/users.py b/rhodecode/controllers/admin/users.py
--- a/rhodecode/controllers/admin/users.py
+++ b/rhodecode/controllers/admin/users.py
@@ -452,70 +452,6 @@ class UsersController(BaseController):
force_defaults=False)
@HasPermissionAllDecorator('hg.admin')
- def edit_auth_tokens(self, user_id):
- user_id = safe_int(user_id)
- c.user = User.get_or_404(user_id)
- if c.user.username == User.DEFAULT_USER:
- h.flash(_("You can't edit this user"), category='warning')
- return redirect(url('users'))
-
- c.active = 'auth_tokens'
- show_expired = True
- c.lifetime_values = [
- (str(-1), _('forever')),
- (str(5), _('5 minutes')),
- (str(60), _('1 hour')),
- (str(60 * 24), _('1 day')),
- (str(60 * 24 * 30), _('1 month')),
- ]
- c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
- 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=show_expired)
- defaults = c.user.get_dict()
- return htmlfill.render(
- render('admin/users/user_edit.mako'),
- defaults=defaults,
- encoding="UTF-8",
- force_defaults=False)
-
- @HasPermissionAllDecorator('hg.admin')
- @auth.CSRFRequired()
- def add_auth_token(self, user_id):
- user_id = safe_int(user_id)
- c.user = User.get_or_404(user_id)
- if c.user.username == User.DEFAULT_USER:
- h.flash(_("You can't edit this user"), category='warning')
- return redirect(url('users'))
-
- lifetime = safe_int(request.POST.get('lifetime'), -1)
- description = request.POST.get('description')
- role = request.POST.get('role')
- AuthTokenModel().create(c.user.user_id, description, lifetime, role)
- Session().commit()
- h.flash(_("Auth token successfully created"), category='success')
- return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
-
- @HasPermissionAllDecorator('hg.admin')
- @auth.CSRFRequired()
- def delete_auth_token(self, user_id):
- user_id = safe_int(user_id)
- c.user = User.get_or_404(user_id)
- if c.user.username == User.DEFAULT_USER:
- h.flash(_("You can't edit this user"), category='warning')
- return redirect(url('users'))
-
- del_auth_token = request.POST.get('del_auth_token')
- if del_auth_token:
- AuthTokenModel().delete(del_auth_token, c.user.user_id)
- Session().commit()
- h.flash(_("Auth token successfully deleted"), category='success')
-
- return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
-
- @HasPermissionAllDecorator('hg.admin')
def edit_global_perms(self, user_id):
user_id = safe_int(user_id)
c.user = User.get_or_404(user_id)
diff --git a/rhodecode/templates/admin/my_account/my_account_auth_tokens.mako b/rhodecode/templates/admin/my_account/my_account_auth_tokens.mako
--- a/rhodecode/templates/admin/my_account/my_account_auth_tokens.mako
+++ b/rhodecode/templates/admin/my_account/my_account_auth_tokens.mako
@@ -3,20 +3,21 @@
${_('Authentication Tokens')}
+
${_('Each token can have a role. Token with a role can be used only in given context, '
'e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only.')}
${_('Each token can have a role. Token with a role can be used only in given context, '
'e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only.')}
- ${_('Additionally scope for VCS type token can narrow the use to chosen repository.')}