diff --git a/rhodecode/apps/_base/__init__.py b/rhodecode/apps/_base/__init__.py
--- a/rhodecode/apps/_base/__init__.py
+++ b/rhodecode/apps/_base/__init__.py
@@ -26,6 +26,10 @@ from rhodecode.lib.utils2 import StrictA
log = logging.getLogger(__name__)
+ADMIN_PREFIX = '/_admin'
+STATIC_FILE_PREFIX = '/_static'
+
+
class TemplateArgs(StrictAttributeDict):
pass
@@ -41,10 +45,17 @@ class BaseAppView(object):
def _get_local_tmpl_context(self):
return TemplateArgs()
+ def _register_global_c(self, tmpl_args):
+ """
+ Registers attributes to pylons global `c`
+ """
+ # TODO(marcink): remove once pyramid migration is finished
+ for k, v in tmpl_args.items():
+ setattr(c, k, v)
+
def _get_template_context(self, tmpl_args):
- for k, v in tmpl_args.items():
- setattr(c, k, v)
+ self._register_global_c(tmpl_args)
return {
'defaults': {},
diff --git a/rhodecode/apps/my_account/__init__.py b/rhodecode/apps/my_account/__init__.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/my_account/__init__.py
@@ -0,0 +1,39 @@
+# -*- 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/
+
+
+from rhodecode.apps._base import ADMIN_PREFIX
+
+
+def includeme(config):
+ config.add_route(
+ name='my_account_auth_tokens',
+ pattern=ADMIN_PREFIX + '/my_account/auth_tokens')
+ config.add_route(
+ name='my_account_auth_tokens_add',
+ pattern=ADMIN_PREFIX + '/my_account/auth_tokens/new',
+ )
+ config.add_route(
+ name='my_account_auth_tokens_delete',
+ pattern=ADMIN_PREFIX + '/my_account/auth_tokens/delete',
+ )
+
+ # Scan module for configuration decorators.
+ config.scan()
diff --git a/rhodecode/apps/my_account/tests/__init__.py b/rhodecode/apps/my_account/tests/__init__.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/my_account/tests/__init__.py
@@ -0,0 +1,19 @@
+# -*- 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/
diff --git a/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010-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 pytest
+
+from rhodecode.apps._base import ADMIN_PREFIX
+from rhodecode.model.db import User
+from rhodecode.tests import (
+ TestController, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
+ TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, assert_session_flash)
+from rhodecode.tests.fixture import Fixture
+from rhodecode.tests.utils import AssertResponse
+
+fixture = Fixture()
+
+
+def route_path(name, **kwargs):
+ return {
+ 'my_account_auth_tokens':
+ ADMIN_PREFIX + '/my_account/auth_tokens',
+ 'my_account_auth_tokens_add':
+ ADMIN_PREFIX + '/my_account/auth_tokens/new',
+ 'my_account_auth_tokens_delete':
+ ADMIN_PREFIX + '/my_account/auth_tokens/delete',
+ }[name].format(**kwargs)
+
+
+class TestMyAccountAuthTokens(TestController):
+
+ def test_my_account_auth_tokens(self):
+ usr = self.log_user('test_regular2', 'test12')
+ user = User.get(usr['user_id'])
+ response = self.app.get(route_path('my_account_auth_tokens'))
+ for token in user.auth_tokens:
+ response.mustcontain(token)
+ response.mustcontain('never')
+
+ def test_my_account_add_auth_tokens_wrong_csrf(self, user_util):
+ user = user_util.create_user(password='qweqwe')
+ self.log_user(user.username, 'qweqwe')
+
+ self.app.post(
+ route_path('my_account_auth_tokens_add'),
+ {'description': 'desc', 'lifetime': -1}, status=403)
+
+ @pytest.mark.parametrize("desc, lifetime", [
+ ('forever', -1),
+ ('5mins', 60*5),
+ ('30days', 60*60*24*30),
+ ])
+ def test_my_account_add_auth_tokens(self, desc, lifetime, user_util):
+ user = user_util.create_user(password='qweqwe')
+ user_id = user.user_id
+ self.log_user(user.username, 'qweqwe')
+
+ response = self.app.post(
+ route_path('my_account_auth_tokens_add'),
+ {'description': desc, 'lifetime': lifetime,
+ 'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'Auth token successfully created')
+
+ response = response.follow()
+ user = User.get(user_id)
+ for auth_token in user.auth_tokens:
+ response.mustcontain(auth_token)
+
+ def test_my_account_delete_auth_token(self, user_util):
+ user = user_util.create_user(password='qweqwe')
+ user_id = user.user_id
+ self.log_user(user.username, 'qweqwe')
+
+ user = User.get(user_id)
+ keys = user.extra_auth_tokens
+ assert 2 == len(keys)
+
+ response = self.app.post(
+ route_path('my_account_auth_tokens_add'),
+ {'description': 'desc', 'lifetime': -1,
+ 'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'Auth token successfully created')
+ response.follow()
+
+ user = User.get(user_id)
+ keys = user.extra_auth_tokens
+ assert 3 == len(keys)
+
+ response = self.app.post(
+ route_path('my_account_auth_tokens_delete'),
+ {'del_auth_token': keys[0].api_key, 'csrf_token': self.csrf_token})
+ assert_session_flash(response, 'Auth token successfully deleted')
+
+ user = User.get(user_id)
+ keys = user.extra_auth_tokens
+ assert 2 == len(keys)
diff --git a/rhodecode/apps/my_account/views.py b/rhodecode/apps/my_account/views.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/my_account/views.py
@@ -0,0 +1,111 @@
+# -*- 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, NotAnonymous, CSRFRequired
+from rhodecode.lib.utils2 import safe_int
+from rhodecode.lib import helpers as h
+from rhodecode.model.auth_token import AuthTokenModel
+from rhodecode.model.meta import Session
+
+log = logging.getLogger(__name__)
+
+
+class MyAccountView(BaseAppView):
+
+ def load_default_context(self):
+ c = self._get_local_tmpl_context()
+
+ c.auth_user = self.request.user
+ c.user = c.auth_user.get_instance()
+
+ self._register_global_c(c)
+ return c
+
+ @LoginRequired()
+ @NotAnonymous()
+ @view_config(
+ route_name='my_account_auth_tokens', request_method='GET',
+ renderer='rhodecode:templates/admin/my_account/my_account.mako')
+ def my_account_auth_tokens(self):
+ _ = self.request.translate
+
+ c = self.load_default_context()
+ 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)
+ return self._get_template_context(c)
+
+ @LoginRequired()
+ @NotAnonymous()
+ @CSRFRequired()
+ @view_config(
+ route_name='my_account_auth_tokens_add', request_method='POST')
+ def my_account_auth_tokens_add(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+
+ lifetime = safe_int(self.request.POST.get('lifetime'), -1)
+ description = self.request.POST.get('description')
+ role = self.request.POST.get('role')
+
+ AuthTokenModel().create(c.user.user_id, description, lifetime, role)
+ Session().commit()
+ h.flash(_("Auth token successfully created"), category='success')
+
+ return HTTPFound(h.route_path('my_account_auth_tokens'))
+
+ @LoginRequired()
+ @NotAnonymous()
+ @CSRFRequired()
+ @view_config(
+ route_name='my_account_auth_tokens_delete', request_method='POST')
+ def my_account_auth_tokens_delete(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+
+ 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('my_account_auth_tokens'))
diff --git a/rhodecode/apps/user_profile/tests/__init__.py b/rhodecode/apps/user_profile/tests/__init__.py
--- a/rhodecode/apps/user_profile/tests/__init__.py
+++ b/rhodecode/apps/user_profile/tests/__init__.py
@@ -0,0 +1,19 @@
+# -*- 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/
diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py
--- a/rhodecode/config/middleware.py
+++ b/rhodecode/config/middleware.py
@@ -286,6 +286,7 @@ def includeme(config):
config.include('rhodecode.apps.channelstream')
config.include('rhodecode.apps.login')
config.include('rhodecode.apps.user_profile')
+ config.include('rhodecode.apps.my_account')
config.include('rhodecode.tweens')
config.include('rhodecode.api')
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -543,12 +543,6 @@ def make_map(config):
m.connect('my_account_emails', '/my_account/emails',
action='my_account_emails_delete', conditions={'method': ['DELETE']})
- m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
- action='my_account_auth_tokens', conditions={'method': ['GET']})
- m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
- action='my_account_auth_tokens_add', conditions={'method': ['POST']})
- m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
- action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
m.connect('my_account_notifications', '/my_account/notifications',
action='my_notifications',
conditions={'method': ['GET']})
diff --git a/rhodecode/controllers/admin/my_account.py b/rhodecode/controllers/admin/my_account.py
--- a/rhodecode/controllers/admin/my_account.py
+++ b/rhodecode/controllers/admin/my_account.py
@@ -33,13 +33,12 @@ from pylons import request, tmpl_context
from pylons.controllers.util import redirect
from pylons.i18n.translation import _
from sqlalchemy.orm import joinedload
-from webob.exc import HTTPBadGateway
from rhodecode import forms
from rhodecode.lib import helpers as h
from rhodecode.lib import auth
from rhodecode.lib.auth import (
- LoginRequired, NotAnonymous, AuthUser, generate_auth_token)
+ LoginRequired, NotAnonymous, AuthUser)
from rhodecode.lib.base import BaseController, render
from rhodecode.lib.utils import jsonify
from rhodecode.lib.utils2 import safe_int, md5, str2bool
@@ -54,7 +53,6 @@ from rhodecode.model.forms import UserFo
from rhodecode.model.scm import RepoList
from rhodecode.model.user import UserModel
from rhodecode.model.repo import RepoModel
-from rhodecode.model.auth_token import AuthTokenModel
from rhodecode.model.meta import Session
from rhodecode.model.pull_request import PullRequestModel
from rhodecode.model.comment import CommentsModel
@@ -376,47 +374,6 @@ class MyAccountController(BaseController
else:
return json.dumps(data)
- def my_account_auth_tokens(self):
- c.active = 'auth_tokens'
- self.__load_data()
- 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.rhodecode_user.user_id, show_expired=show_expired)
- return render('admin/my_account/my_account.mako')
-
- @auth.CSRFRequired()
- def my_account_auth_tokens_add(self):
- lifetime = safe_int(request.POST.get('lifetime'), -1)
- description = request.POST.get('description')
- role = request.POST.get('role')
- AuthTokenModel().create(c.rhodecode_user.user_id, description, lifetime,
- role)
- Session().commit()
- h.flash(_("Auth token successfully created"), category='success')
- return redirect(url('my_account_auth_tokens'))
-
- @auth.CSRFRequired()
- def my_account_auth_tokens_delete(self):
- del_auth_token = request.POST.get('del_auth_token')
-
- if del_auth_token:
- AuthTokenModel().delete(del_auth_token, c.rhodecode_user.user_id)
- Session().commit()
- h.flash(_("Auth token successfully deleted"), category='success')
-
- return redirect(url('my_account_auth_tokens'))
-
def my_notifications(self):
c.active = 'notifications'
return render('admin/my_account/my_account.mako')
diff --git a/rhodecode/templates/admin/my_account/my_account.mako b/rhodecode/templates/admin/my_account/my_account.mako
--- a/rhodecode/templates/admin/my_account/my_account.mako
+++ b/rhodecode/templates/admin/my_account/my_account.mako
@@ -28,7 +28,7 @@