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
@@ -72,10 +72,36 @@ def admin_routes(config):
pattern='/settings/process_management/signal')
# global permissions
+
+ config.add_route(
+ name='admin_permissions_application',
+ pattern='/permissions/application')
+ config.add_route(
+ name='admin_permissions_application_update',
+ pattern='/permissions/application/update')
+
+ config.add_route(
+ name='admin_permissions_global',
+ pattern='/permissions/global')
+ config.add_route(
+ name='admin_permissions_global_update',
+ pattern='/permissions/global/update')
+
+ config.add_route(
+ name='admin_permissions_object',
+ pattern='/permissions/object')
+ config.add_route(
+ name='admin_permissions_object_update',
+ pattern='/permissions/object/update')
+
config.add_route(
name='admin_permissions_ips',
pattern='/permissions/ips')
+ config.add_route(
+ name='admin_permissions_overview',
+ pattern='/permissions/overview')
+
# users admin
config.add_route(
name='users',
diff --git a/rhodecode/tests/functional/test_admin_permissions.py b/rhodecode/apps/admin/tests/test_admin_permissions.py
rename from rhodecode/tests/functional/test_admin_permissions.py
rename to rhodecode/apps/admin/tests/test_admin_permissions.py
--- a/rhodecode/tests/functional/test_admin_permissions.py
+++ b/rhodecode/apps/admin/tests/test_admin_permissions.py
@@ -22,7 +22,7 @@ import pytest
from rhodecode.model.db import User, UserIpMap
from rhodecode.model.permission import PermissionModel
from rhodecode.tests import (
- TestController, url, clear_all_caches, assert_session_flash)
+ TestController, clear_all_caches, assert_session_flash)
def route_path(name, params=None, **kwargs):
@@ -36,6 +36,27 @@ def route_path(name, params=None, **kwar
ADMIN_PREFIX + '/users/{user_id}/edit/ips/new',
'edit_user_ips_delete':
ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete',
+
+ 'admin_permissions_application':
+ ADMIN_PREFIX + '/permissions/application',
+ 'admin_permissions_application_update':
+ ADMIN_PREFIX + '/permissions/application/update',
+
+ 'admin_permissions_global':
+ ADMIN_PREFIX + '/permissions/global',
+ 'admin_permissions_global_update':
+ ADMIN_PREFIX + '/permissions/global/update',
+
+ 'admin_permissions_object':
+ ADMIN_PREFIX + '/permissions/object',
+ 'admin_permissions_object_update':
+ ADMIN_PREFIX + '/permissions/object/update',
+
+ 'admin_permissions_ips':
+ ADMIN_PREFIX + '/permissions/ips',
+ 'admin_permissions_overview':
+ ADMIN_PREFIX + '/permissions/overview'
+
}[name].format(**kwargs)
if params:
@@ -55,7 +76,7 @@ class TestAdminPermissionsController(Tes
def test_index_application(self):
self.log_user()
- self.app.get(url('admin_permissions_application'))
+ self.app.get(route_path('admin_permissions_application'))
@pytest.mark.parametrize(
'anonymous, default_register, default_register_message, default_password_reset,'
@@ -87,7 +108,7 @@ class TestAdminPermissionsController(Tes
'default_password_reset': default_password_reset,
'default_extern_activate': default_extern_activate,
}
- response = self.app.post(url('admin_permissions_application'),
+ response = self.app.post(route_path('admin_permissions_application_update'),
params=params)
if expect_form_error:
assert response.status_int == 200
@@ -101,7 +122,7 @@ class TestAdminPermissionsController(Tes
def test_index_object(self):
self.log_user()
- self.app.get(url('admin_permissions_object'))
+ self.app.get(route_path('admin_permissions_object'))
@pytest.mark.parametrize(
'repo, repo_group, user_group, expect_error, expect_form_error', [
@@ -127,7 +148,7 @@ class TestAdminPermissionsController(Tes
'default_user_group_perm': user_group,
'overwrite_default_user_group': False,
}
- response = self.app.post(url('admin_permissions_object'),
+ response = self.app.post(route_path('admin_permissions_object_update'),
params=params)
if expect_form_error:
assert response.status_int == 200
@@ -141,7 +162,7 @@ class TestAdminPermissionsController(Tes
def test_index_global(self):
self.log_user()
- self.app.get(url('admin_permissions_global'))
+ self.app.get(route_path('admin_permissions_global'))
@pytest.mark.parametrize(
'repo_create, repo_create_write, user_group_create, repo_group_create,'
@@ -175,7 +196,7 @@ class TestAdminPermissionsController(Tes
'default_fork_create': fork_create,
'default_inherit_default_permissions': inherit_default_permissions
}
- response = self.app.post(url('admin_permissions_global'),
+ response = self.app.post(route_path('admin_permissions_global_update'),
params=params)
if expect_form_error:
assert response.status_int == 200
@@ -189,7 +210,7 @@ class TestAdminPermissionsController(Tes
def test_index_ips(self):
self.log_user()
- response = self.app.get(url('admin_permissions_ips'))
+ response = self.app.get(route_path('admin_permissions_ips'))
# TODO: Test response...
response.mustcontain('All IP addresses are allowed')
@@ -203,7 +224,7 @@ class TestAdminPermissionsController(Tes
route_path('edit_user_ips_add', user_id=default_user_id),
params={'new_ip': '127.0.0.0/24', 'csrf_token': self.csrf_token})
- response = self.app.get(url('admin_permissions_ips'))
+ response = self.app.get(route_path('admin_permissions_ips'))
response.mustcontain('127.0.0.0/24')
response.mustcontain('127.0.0.0 - 127.0.0.255')
@@ -219,11 +240,11 @@ class TestAdminPermissionsController(Tes
assert_session_flash(response, 'Removed ip address from user whitelist')
clear_all_caches()
- response = self.app.get(url('admin_permissions_ips'))
+ response = self.app.get(route_path('admin_permissions_ips'))
response.mustcontain('All IP addresses are allowed')
response.mustcontain(no=['127.0.0.0/24'])
response.mustcontain(no=['127.0.0.0 - 127.0.0.255'])
def test_index_overview(self):
self.log_user()
- self.app.get(url('admin_permissions_overview'))
+ self.app.get(route_path('admin_permissions_overview'))
diff --git a/rhodecode/apps/admin/views/permissions.py b/rhodecode/apps/admin/views/permissions.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/admin/views/permissions.py
@@ -0,0 +1,310 @@
+# -*- 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
+import formencode
+
+from pyramid.view import view_config
+from pyramid.httpexceptions import HTTPFound
+from pyramid.renderers import render
+from pyramid.response import Response
+
+from rhodecode.apps._base import BaseAppView
+
+from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import (
+ LoginRequired, HasPermissionAllDecorator, CSRFRequired)
+from rhodecode.model.db import User, UserIpMap
+from rhodecode.model.forms import (
+ ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
+from rhodecode.model.meta import Session
+from rhodecode.model.permission import PermissionModel
+from rhodecode.model.settings import SettingsModel
+
+
+log = logging.getLogger(__name__)
+
+
+class AdminPermissionsView(BaseAppView):
+ def load_default_context(self):
+ c = self._get_local_tmpl_context()
+
+ self._register_global_c(c)
+ PermissionModel().set_global_permission_choices(
+ c, gettext_translator=self.request.translate)
+ return c
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_permissions_application', request_method='GET',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_application(self):
+ c = self.load_default_context()
+ c.active = 'application'
+
+ c.user = User.get_default_user(refresh=True)
+
+ app_settings = SettingsModel().get_all_settings()
+ defaults = {
+ 'anonymous': c.user.active,
+ 'default_register_message': app_settings.get(
+ 'rhodecode_register_message')
+ }
+ defaults.update(c.user.get_default_perms())
+
+ data = render('rhodecode:templates/admin/permissions/permissions.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='admin_permissions_application_update', request_method='POST',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_application_update(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+ c.active = 'application'
+
+ _form = ApplicationPermissionsForm(
+ [x[0] for x in c.register_choices],
+ [x[0] for x in c.password_reset_choices],
+ [x[0] for x in c.extern_activate_choices])()
+
+ try:
+ form_result = _form.to_python(dict(self.request.POST))
+ form_result.update({'perm_user_name': User.DEFAULT_USER})
+ PermissionModel().update_application_permissions(form_result)
+
+ settings = [
+ ('register_message', 'default_register_message'),
+ ]
+ for setting, form_key in settings:
+ sett = SettingsModel().create_or_update_setting(
+ setting, form_result[form_key])
+ Session().add(sett)
+
+ Session().commit()
+ h.flash(_('Application permissions updated successfully'),
+ category='success')
+
+ except formencode.Invalid as errors:
+ defaults = errors.value
+
+ data = render(
+ 'rhodecode:templates/admin/permissions/permissions.mako',
+ self._get_template_context(c), self.request)
+ html = formencode.htmlfill.render(
+ data,
+ defaults=defaults,
+ errors=errors.error_dict or {},
+ prefix_error=False,
+ encoding="UTF-8",
+ force_defaults=False
+ )
+ return Response(html)
+
+ except Exception:
+ log.exception("Exception during update of permissions")
+ h.flash(_('Error occurred during update of permissions'),
+ category='error')
+
+ raise HTTPFound(h.route_path('admin_permissions_application'))
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_permissions_object', request_method='GET',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_objects(self):
+ c = self.load_default_context()
+ c.active = 'objects'
+
+ c.user = User.get_default_user(refresh=True)
+ defaults = {}
+ defaults.update(c.user.get_default_perms())
+
+ data = render(
+ 'rhodecode:templates/admin/permissions/permissions.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='admin_permissions_object_update', request_method='POST',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_objects_update(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+ c.active = 'objects'
+
+ _form = ObjectPermissionsForm(
+ [x[0] for x in c.repo_perms_choices],
+ [x[0] for x in c.group_perms_choices],
+ [x[0] for x in c.user_group_perms_choices])()
+
+ try:
+ form_result = _form.to_python(dict(self.request.POST))
+ form_result.update({'perm_user_name': User.DEFAULT_USER})
+ PermissionModel().update_object_permissions(form_result)
+
+ Session().commit()
+ h.flash(_('Object permissions updated successfully'),
+ category='success')
+
+ except formencode.Invalid as errors:
+ defaults = errors.value
+
+ data = render(
+ 'rhodecode:templates/admin/permissions/permissions.mako',
+ self._get_template_context(c), self.request)
+ html = formencode.htmlfill.render(
+ data,
+ defaults=defaults,
+ errors=errors.error_dict or {},
+ prefix_error=False,
+ encoding="UTF-8",
+ force_defaults=False
+ )
+ return Response(html)
+ except Exception:
+ log.exception("Exception during update of permissions")
+ h.flash(_('Error occurred during update of permissions'),
+ category='error')
+
+ raise HTTPFound(h.route_path('admin_permissions_object'))
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_permissions_global', request_method='GET',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_global(self):
+ c = self.load_default_context()
+ c.active = 'global'
+
+ c.user = User.get_default_user(refresh=True)
+ defaults = {}
+ defaults.update(c.user.get_default_perms())
+
+ data = render(
+ 'rhodecode:templates/admin/permissions/permissions.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='admin_permissions_global_update', request_method='POST',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_global_update(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+ c.active = 'global'
+
+ _form = UserPermissionsForm(
+ [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])()
+
+ try:
+ form_result = _form.to_python(dict(self.request.POST))
+ form_result.update({'perm_user_name': User.DEFAULT_USER})
+ PermissionModel().update_user_permissions(form_result)
+
+ Session().commit()
+ h.flash(_('Global permissions updated successfully'),
+ category='success')
+
+ except formencode.Invalid as errors:
+ defaults = errors.value
+
+ data = render(
+ 'rhodecode:templates/admin/permissions/permissions.mako',
+ self._get_template_context(c), self.request)
+ html = formencode.htmlfill.render(
+ data,
+ defaults=defaults,
+ errors=errors.error_dict or {},
+ prefix_error=False,
+ encoding="UTF-8",
+ force_defaults=False
+ )
+ return Response(html)
+ except Exception:
+ log.exception("Exception during update of permissions")
+ h.flash(_('Error occurred during update of permissions'),
+ category='error')
+
+ raise HTTPFound(h.route_path('admin_permissions_global'))
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_permissions_ips', request_method='GET',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_ips(self):
+ c = self.load_default_context()
+ c.active = 'ips'
+
+ c.user = User.get_default_user(refresh=True)
+ c.user_ip_map = (
+ UserIpMap.query().filter(UserIpMap.user == c.user).all())
+
+ return self._get_template_context(c)
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_permissions_overview', request_method='GET',
+ renderer='rhodecode:templates/admin/permissions/permissions.mako')
+ def permissions_overview(self):
+ c = self.load_default_context()
+ c.active = 'perms'
+
+ c.user = User.get_default_user(refresh=True)
+ c.perm_user = c.user.AuthUser
+ return self._get_template_context(c)
diff --git a/rhodecode/tests/functional/test_login.py b/rhodecode/apps/login/tests/test_login.py
rename from rhodecode/tests/functional/test_login.py
rename to rhodecode/apps/login/tests/test_login.py
--- a/rhodecode/tests/functional/test_login.py
+++ b/rhodecode/apps/login/tests/test_login.py
@@ -23,9 +23,8 @@ import urlparse
import mock
import pytest
-from rhodecode.config.routing import ADMIN_PREFIX
from rhodecode.tests import (
- assert_session_flash, url, HG_REPO, TEST_USER_ADMIN_LOGIN,
+ assert_session_flash, HG_REPO, TEST_USER_ADMIN_LOGIN,
no_newline_id_generator)
from rhodecode.tests.fixture import Fixture
from rhodecode.lib.auth import check_password
@@ -37,14 +36,32 @@ from rhodecode.model.meta import Session
fixture = Fixture()
-# Hardcode URLs because we don't have a request object to use
-# pyramids URL generation methods.
-index_url = '/'
-login_url = ADMIN_PREFIX + '/login'
-logut_url = ADMIN_PREFIX + '/logout'
-register_url = ADMIN_PREFIX + '/register'
-pwd_reset_url = ADMIN_PREFIX + '/password_reset'
-pwd_reset_confirm_url = ADMIN_PREFIX + '/password_reset_confirmation'
+
+def route_path(name, params=None, **kwargs):
+ import urllib
+ from rhodecode.apps._base import ADMIN_PREFIX
+
+ base_url = {
+ 'login': ADMIN_PREFIX + '/login',
+ 'logout': ADMIN_PREFIX + '/logout',
+ 'register': ADMIN_PREFIX + '/register',
+ 'reset_password':
+ ADMIN_PREFIX + '/password_reset',
+ 'reset_password_confirmation':
+ ADMIN_PREFIX + '/password_reset_confirmation',
+
+ 'admin_permissions_application':
+ ADMIN_PREFIX + '/permissions/application',
+ 'admin_permissions_application_update':
+ ADMIN_PREFIX + '/permissions/application/update',
+
+ 'repo_commit_raw': '/{repo_name}/raw-changeset/{commit_id}'
+
+ }[name].format(**kwargs)
+
+ if params:
+ base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
+ return base_url
@pytest.mark.usefixtures('app')
@@ -63,12 +80,12 @@ class TestLoginController(object):
assert Notification.query().all() == []
def test_index(self):
- response = self.app.get(login_url)
+ response = self.app.get(route_path('login'))
assert response.status == '200 OK'
# Test response...
def test_login_admin_ok(self):
- response = self.app.post(login_url,
+ response = self.app.post(route_path('login'),
{'username': 'test_admin',
'password': 'test12'})
assert response.status == '302 Found'
@@ -79,7 +96,7 @@ class TestLoginController(object):
response.mustcontain('/%s' % HG_REPO)
def test_login_regular_ok(self):
- response = self.app.post(login_url,
+ response = self.app.post(route_path('login'),
{'username': 'test_regular',
'password': 'test12'})
@@ -92,7 +109,7 @@ class TestLoginController(object):
def test_login_ok_came_from(self):
test_came_from = '/_admin/users?branch=stable'
- _url = '{}?came_from={}'.format(login_url, test_came_from)
+ _url = '{}?came_from={}'.format(route_path('login'), test_came_from)
response = self.app.post(
_url, {'username': 'test_admin', 'password': 'test12'})
assert response.status == '302 Found'
@@ -113,7 +130,7 @@ class TestLoginController(object):
assert 'branch=stable' in response_query[0][1]
def test_login_form_with_get_args(self):
- _url = '{}?came_from=/_admin/users,branch=stable'.format(login_url)
+ _url = '{}?came_from=/_admin/users,branch=stable'.format(route_path('login'))
response = self.app.get(_url)
assert 'branch%3Dstable' in response.form.action
@@ -126,7 +143,7 @@ class TestLoginController(object):
'/\r\nX-Forwarded-Host: http://example.org',
], ids=no_newline_id_generator)
def test_login_bad_came_froms(self, url_came_from):
- _url = '{}?came_from={}'.format(login_url, url_came_from)
+ _url = '{}?came_from={}'.format(route_path('login'), url_came_from)
response = self.app.post(
_url,
{'username': 'test_admin', 'password': 'test12'})
@@ -136,7 +153,7 @@ class TestLoginController(object):
assert response.request.path == '/'
def test_login_short_password(self):
- response = self.app.post(login_url,
+ response = self.app.post(route_path('login'),
{'username': 'test_admin',
'password': 'as'})
assert response.status == '200 OK'
@@ -145,7 +162,7 @@ class TestLoginController(object):
def test_login_wrong_non_ascii_password(self, user_regular):
response = self.app.post(
- login_url,
+ route_path('login'),
{'username': user_regular.username,
'password': u'invalid-non-asci\xe4'.encode('utf8')})
@@ -156,13 +173,13 @@ class TestLoginController(object):
password = u'valid-non-ascii\xe4'
user = user_util.create_user(password=password)
response = self.app.post(
- login_url,
+ route_path('login'),
{'username': user.username,
'password': password.encode('utf-8')})
assert response.status_code == 302
def test_login_wrong_username_password(self):
- response = self.app.post(login_url,
+ response = self.app.post(route_path('login'),
{'username': 'error',
'password': 'test12'})
@@ -180,7 +197,7 @@ class TestLoginController(object):
Session().add(user)
Session().commit()
self.destroy_users.add(temp_user)
- response = self.app.post(login_url,
+ response = self.app.post(route_path('login'),
{'username': temp_user,
'password': 'test123'})
@@ -197,13 +214,13 @@ class TestLoginController(object):
# REGISTRATIONS
def test_register(self):
- response = self.app.get(register_url)
+ response = self.app.get(route_path('register'))
response.mustcontain('Create an Account')
def test_register_err_same_username(self):
uname = 'test_admin'
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': uname,
'password': 'test12',
@@ -221,7 +238,7 @@ class TestLoginController(object):
def test_register_err_same_email(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'test_admin_0',
'password': 'test12',
@@ -238,7 +255,7 @@ class TestLoginController(object):
def test_register_err_same_email_case_sensitive(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'test_admin_1',
'password': 'test12',
@@ -254,7 +271,7 @@ class TestLoginController(object):
def test_register_err_wrong_data(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'xs',
'password': 'test',
@@ -270,7 +287,7 @@ class TestLoginController(object):
def test_register_err_username(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'error user',
'password': 'test12',
@@ -291,7 +308,7 @@ class TestLoginController(object):
def test_register_err_case_sensitive(self):
usr = 'Test_Admin'
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': usr,
'password': 'test12',
@@ -309,7 +326,7 @@ class TestLoginController(object):
def test_register_special_chars(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'xxxaxn',
'password': 'ąćźżąśśśś',
@@ -325,7 +342,7 @@ class TestLoginController(object):
def test_register_password_mismatch(self):
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': 'xs',
'password': '123qwe',
@@ -346,7 +363,7 @@ class TestLoginController(object):
lastname = 'testlastname'
response = self.app.post(
- register_url,
+ route_path('register'),
{
'username': username,
'password': password,
@@ -374,29 +391,29 @@ class TestLoginController(object):
def test_forgot_password_wrong_mail(self):
bad_email = 'marcin@wrongmail.org'
response = self.app.post(
- pwd_reset_url, {'email': bad_email, }
+ route_path('reset_password'), {'email': bad_email, }
)
assert_session_flash(response,
'If such email exists, a password reset link was sent to it.')
def test_forgot_password(self, user_util):
- response = self.app.get(pwd_reset_url)
+ response = self.app.get(route_path('reset_password'))
assert response.status == '200 OK'
user = user_util.create_user()
user_id = user.user_id
email = user.email
- response = self.app.post(pwd_reset_url, {'email': email, })
+ response = self.app.post(route_path('reset_password'), {'email': email, })
assert_session_flash(response,
'If such email exists, a password reset link was sent to it.')
# BAD KEY
- confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, 'badkey')
+ confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), 'badkey')
response = self.app.get(confirm_url)
assert response.status == '302 Found'
- assert response.location.endswith(pwd_reset_url)
+ assert response.location.endswith(route_path('reset_password'))
assert_session_flash(response, 'Given reset token is invalid')
response.follow() # cleanup flash
@@ -409,10 +426,10 @@ class TestLoginController(object):
assert key
- confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, key.api_key)
+ confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), key.api_key)
response = self.app.get(confirm_url)
assert response.status == '302 Found'
- assert response.location.endswith(login_url)
+ assert response.location.endswith(route_path('login'))
assert_session_flash(
response,
@@ -442,11 +459,11 @@ class TestLoginController(object):
auth_token = user_admin.api_key
with fixture.anon_access(False):
- self.app.get(url(controller='changeset',
- action='changeset_raw',
- repo_name=HG_REPO, revision='tip',
- api_key=auth_token),
- status=302)
+ self.app.get(
+ route_path('repo_commit_raw',
+ repo_name=HG_REPO, commit_id='tip',
+ params=dict(api_key=auth_token)),
+ status=302)
@pytest.mark.parametrize("test_name, auth_token, code", [
('none', None, 302),
@@ -468,11 +485,11 @@ class TestLoginController(object):
assert auth_token
with fixture.anon_access(False):
- self.app.get(url(controller='changeset',
- action='changeset_raw',
- repo_name=HG_REPO, revision='tip',
- api_key=auth_token),
- status=code)
+ self.app.get(
+ route_path('repo_commit_raw',
+ repo_name=HG_REPO, commit_id='tip',
+ params=dict(api_key=auth_token)),
+ status=code)
def test_access_page_via_extra_auth_token(self):
whitelist = self._get_api_whitelist(
@@ -485,11 +502,11 @@ class TestLoginController(object):
TEST_USER_ADMIN_LOGIN, 'test')
Session().commit()
with fixture.anon_access(False):
- self.app.get(url(controller='changeset',
- action='changeset_raw',
- repo_name=HG_REPO, revision='tip',
- api_key=new_auth_token.api_key),
- status=200)
+ self.app.get(
+ route_path('repo_commit_raw',
+ repo_name=HG_REPO, commit_id='tip',
+ params=dict(api_key=new_auth_token.api_key)),
+ status=200)
def test_access_page_via_expired_auth_token(self):
whitelist = self._get_api_whitelist(
@@ -506,8 +523,8 @@ class TestLoginController(object):
Session().add(new_auth_token)
Session().commit()
with fixture.anon_access(False):
- self.app.get(url(controller='changeset',
- action='changeset_raw',
- repo_name=HG_REPO, revision='tip',
- api_key=new_auth_token.api_key),
- status=302)
+ self.app.get(
+ route_path('repo_commit_raw',
+ repo_name=HG_REPO, commit_id='tip',
+ params=dict(api_key=new_auth_token.api_key)),
+ status=302)
diff --git a/rhodecode/tests/functional/test_password_reset.py b/rhodecode/apps/login/tests/test_password_reset.py
rename from rhodecode/tests/functional/test_password_reset.py
rename to rhodecode/apps/login/tests/test_password_reset.py
--- a/rhodecode/tests/functional/test_password_reset.py
+++ b/rhodecode/apps/login/tests/test_password_reset.py
@@ -20,23 +20,38 @@
import pytest
-from rhodecode.config.routing import ADMIN_PREFIX
+from rhodecode.lib import helpers as h
from rhodecode.tests import (
- TestController, clear_all_caches, url,
+ TestController, clear_all_caches,
TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
from rhodecode.tests.fixture import Fixture
from rhodecode.tests.utils import AssertResponse
fixture = Fixture()
-# Hardcode URLs because we don't have a request object to use
-# pyramids URL generation methods.
-index_url = '/'
-login_url = ADMIN_PREFIX + '/login'
-logut_url = ADMIN_PREFIX + '/logout'
-register_url = ADMIN_PREFIX + '/register'
-pwd_reset_url = ADMIN_PREFIX + '/password_reset'
-pwd_reset_confirm_url = ADMIN_PREFIX + '/password_reset_confirmation'
+
+def route_path(name, params=None, **kwargs):
+ import urllib
+ from rhodecode.apps._base import ADMIN_PREFIX
+
+ base_url = {
+ 'login': ADMIN_PREFIX + '/login',
+ 'logout': ADMIN_PREFIX + '/logout',
+ 'register': ADMIN_PREFIX + '/register',
+ 'reset_password':
+ ADMIN_PREFIX + '/password_reset',
+ 'reset_password_confirmation':
+ ADMIN_PREFIX + '/password_reset_confirmation',
+
+ 'admin_permissions_application':
+ ADMIN_PREFIX + '/permissions/application',
+ 'admin_permissions_application_update':
+ ADMIN_PREFIX + '/permissions/application/update',
+ }[name].format(**kwargs)
+
+ if params:
+ base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
+ return base_url
class TestPasswordReset(TestController):
@@ -59,12 +74,12 @@ class TestPasswordReset(TestController):
'default_password_reset': pwd_reset_setting,
'default_extern_activate': 'hg.extern_activate.auto',
}
- resp = self.app.post(url('admin_permissions_application'), params=params)
+ resp = self.app.post(route_path('admin_permissions_application_update'), params=params)
self.logout_user()
- login_page = self.app.get(login_url)
+ login_page = self.app.get(route_path('login'))
asr_login = AssertResponse(login_page)
- index_page = self.app.get(index_url)
+ index_page = self.app.get(h.route_path('home'))
asr_index = AssertResponse(index_page)
if show_link:
@@ -74,7 +89,7 @@ class TestPasswordReset(TestController):
asr_login.no_element_exists('a.pwd_reset')
asr_index.no_element_exists('a.pwd_reset')
- response = self.app.get(pwd_reset_url)
+ response = self.app.get(route_path('reset_password'))
assert_response = AssertResponse(response)
if show_reset:
@@ -96,11 +111,11 @@ class TestPasswordReset(TestController):
'default_password_reset': 'hg.password_reset.disabled',
'default_extern_activate': 'hg.extern_activate.auto',
}
- self.app.post(url('admin_permissions_application'), params=params)
+ self.app.post(route_path('admin_permissions_application_update'), params=params)
self.logout_user()
response = self.app.post(
- pwd_reset_url, {'email': 'lisa@rhodecode.com',}
+ route_path('reset_password'), {'email': 'lisa@rhodecode.com',}
)
response = response.follow()
response.mustcontain('Password reset is disabled.')
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -321,32 +321,6 @@ def make_map(config):
'/user_groups/{user_group_id}/edit/members', jsroute=True,
action='user_group_members', conditions={'method': ['GET']})
- # ADMIN PERMISSIONS ROUTES
- with rmap.submapper(path_prefix=ADMIN_PREFIX,
- controller='admin/permissions') as m:
- m.connect('admin_permissions_application', '/permissions/application',
- action='permission_application_update', conditions={'method': ['POST']})
- m.connect('admin_permissions_application', '/permissions/application',
- action='permission_application', conditions={'method': ['GET']})
-
- m.connect('admin_permissions_global', '/permissions/global',
- action='permission_global_update', conditions={'method': ['POST']})
- m.connect('admin_permissions_global', '/permissions/global',
- action='permission_global', conditions={'method': ['GET']})
-
- m.connect('admin_permissions_object', '/permissions/object',
- action='permission_objects_update', conditions={'method': ['POST']})
- m.connect('admin_permissions_object', '/permissions/object',
- action='permission_objects', conditions={'method': ['GET']})
-
- m.connect('admin_permissions_ips', '/permissions/ips',
- action='permission_ips', conditions={'method': ['POST']})
- m.connect('admin_permissions_ips', '/permissions/ips',
- action='permission_ips', conditions={'method': ['GET']})
-
- m.connect('admin_permissions_overview', '/permissions/overview',
- action='permission_perms', conditions={'method': ['GET']})
-
# ADMIN DEFAULTS REST ROUTES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
controller='admin/defaults') as m:
diff --git a/rhodecode/controllers/admin/permissions.py b/rhodecode/controllers/admin/permissions.py
deleted file mode 100644
--- a/rhodecode/controllers/admin/permissions.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# -*- 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/
-
-
-"""
-permissions controller for RhodeCode Enterprise
-"""
-
-
-import logging
-
-import formencode
-from formencode import htmlfill
-from pylons import request, tmpl_context as c, url
-from pylons.controllers.util import redirect
-from pylons.i18n.translation import _
-
-from rhodecode.lib import helpers as h
-from rhodecode.lib import auth
-from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
-from rhodecode.lib.base import BaseController, render
-from rhodecode.model.db import User, UserIpMap
-from rhodecode.model.forms import (
- ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
-from rhodecode.model.meta import Session
-from rhodecode.model.permission import PermissionModel
-from rhodecode.model.settings import SettingsModel
-
-log = logging.getLogger(__name__)
-
-
-class PermissionsController(BaseController):
- """REST Controller styled on the Atom Publishing Protocol"""
- # To properly map this controller, ensure your config/routing.py
- # file has a resource setup:
- # map.resource('permission', 'permissions')
-
- @LoginRequired()
- def __before__(self):
- super(PermissionsController, self).__before__()
-
- def __load_data(self):
- PermissionModel().set_global_permission_choices(c, gettext_translator=_)
-
- @HasPermissionAllDecorator('hg.admin')
- def permission_application(self):
- c.active = 'application'
- self.__load_data()
-
- c.user = User.get_default_user(refresh=True)
-
- app_settings = SettingsModel().get_all_settings()
- defaults = {
- 'anonymous': c.user.active,
- 'default_register_message': app_settings.get(
- 'rhodecode_register_message')
- }
- defaults.update(c.user.get_default_perms())
-
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- encoding="UTF-8",
- force_defaults=False)
-
- @HasPermissionAllDecorator('hg.admin')
- @auth.CSRFRequired()
- def permission_application_update(self):
- c.active = 'application'
- self.__load_data()
- _form = ApplicationPermissionsForm(
- [x[0] for x in c.register_choices],
- [x[0] for x in c.password_reset_choices],
- [x[0] for x in c.extern_activate_choices])()
-
- try:
- form_result = _form.to_python(dict(request.POST))
- form_result.update({'perm_user_name': User.DEFAULT_USER})
- PermissionModel().update_application_permissions(form_result)
-
- settings = [
- ('register_message', 'default_register_message'),
- ]
- for setting, form_key in settings:
- sett = SettingsModel().create_or_update_setting(
- setting, form_result[form_key])
- Session().add(sett)
-
- Session().commit()
- h.flash(_('Application permissions updated successfully'),
- category='success')
-
- except formencode.Invalid as errors:
- defaults = errors.value
-
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- errors=errors.error_dict or {},
- prefix_error=False,
- encoding="UTF-8",
- force_defaults=False)
- except Exception:
- log.exception("Exception during update of permissions")
- h.flash(_('Error occurred during update of permissions'),
- category='error')
-
- return redirect(url('admin_permissions_application'))
-
- @HasPermissionAllDecorator('hg.admin')
- def permission_objects(self):
- c.active = 'objects'
- self.__load_data()
- c.user = User.get_default_user()
- defaults = {}
- defaults.update(c.user.get_default_perms())
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- encoding="UTF-8",
- force_defaults=False)
-
- @HasPermissionAllDecorator('hg.admin')
- @auth.CSRFRequired()
- def permission_objects_update(self):
- c.active = 'objects'
- self.__load_data()
- _form = ObjectPermissionsForm(
- [x[0] for x in c.repo_perms_choices],
- [x[0] for x in c.group_perms_choices],
- [x[0] for x in c.user_group_perms_choices])()
-
- try:
- form_result = _form.to_python(dict(request.POST))
- form_result.update({'perm_user_name': User.DEFAULT_USER})
- PermissionModel().update_object_permissions(form_result)
-
- Session().commit()
- h.flash(_('Object permissions updated successfully'),
- category='success')
-
- except formencode.Invalid as errors:
- defaults = errors.value
-
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- errors=errors.error_dict or {},
- prefix_error=False,
- encoding="UTF-8",
- force_defaults=False)
- except Exception:
- log.exception("Exception during update of permissions")
- h.flash(_('Error occurred during update of permissions'),
- category='error')
-
- return redirect(url('admin_permissions_object'))
-
- @HasPermissionAllDecorator('hg.admin')
- def permission_global(self):
- c.active = 'global'
- self.__load_data()
-
- c.user = User.get_default_user()
- defaults = {}
- defaults.update(c.user.get_default_perms())
-
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- encoding="UTF-8",
- force_defaults=False)
-
- @HasPermissionAllDecorator('hg.admin')
- @auth.CSRFRequired()
- def permission_global_update(self):
- c.active = 'global'
- self.__load_data()
- _form = UserPermissionsForm(
- [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])()
-
- try:
- form_result = _form.to_python(dict(request.POST))
- form_result.update({'perm_user_name': User.DEFAULT_USER})
- PermissionModel().update_user_permissions(form_result)
-
- Session().commit()
- h.flash(_('Global permissions updated successfully'),
- category='success')
-
- except formencode.Invalid as errors:
- defaults = errors.value
-
- return htmlfill.render(
- render('admin/permissions/permissions.mako'),
- defaults=defaults,
- errors=errors.error_dict or {},
- prefix_error=False,
- encoding="UTF-8",
- force_defaults=False)
- except Exception:
- log.exception("Exception during update of permissions")
- h.flash(_('Error occurred during update of permissions'),
- category='error')
-
- return redirect(url('admin_permissions_global'))
-
- @HasPermissionAllDecorator('hg.admin')
- def permission_ips(self):
- c.active = 'ips'
- c.user = User.get_default_user()
- c.user_ip_map = (
- UserIpMap.query().filter(UserIpMap.user == c.user).all())
-
- return render('admin/permissions/permissions.mako')
-
- @HasPermissionAllDecorator('hg.admin')
- def permission_perms(self):
- c.active = 'perms'
- c.user = User.get_default_user()
- c.perm_user = c.user.AuthUser
- return render('admin/permissions/permissions.mako')
diff --git a/rhodecode/model/permission.py b/rhodecode/model/permission.py
--- a/rhodecode/model/permission.py
+++ b/rhodecode/model/permission.py
@@ -62,62 +62,63 @@ class PermissionModel(BaseModel):
}
def set_global_permission_choices(self, c_obj, gettext_translator):
+ _ = gettext_translator
c_obj.repo_perms_choices = [
- ('repository.none', gettext_translator('None'),),
- ('repository.read', gettext_translator('Read'),),
- ('repository.write', gettext_translator('Write'),),
- ('repository.admin', gettext_translator('Admin'),)]
+ ('repository.none', _('None'),),
+ ('repository.read', _('Read'),),
+ ('repository.write', _('Write'),),
+ ('repository.admin', _('Admin'),)]
c_obj.group_perms_choices = [
- ('group.none', gettext_translator('None'),),
- ('group.read', gettext_translator('Read'),),
- ('group.write', gettext_translator('Write'),),
- ('group.admin', gettext_translator('Admin'),)]
+ ('group.none', _('None'),),
+ ('group.read', _('Read'),),
+ ('group.write', _('Write'),),
+ ('group.admin', _('Admin'),)]
c_obj.user_group_perms_choices = [
- ('usergroup.none', gettext_translator('None'),),
- ('usergroup.read', gettext_translator('Read'),),
- ('usergroup.write', gettext_translator('Write'),),
- ('usergroup.admin', gettext_translator('Admin'),)]
+ ('usergroup.none', _('None'),),
+ ('usergroup.read', _('Read'),),
+ ('usergroup.write', _('Write'),),
+ ('usergroup.admin', _('Admin'),)]
c_obj.register_choices = [
- ('hg.register.none', gettext_translator('Disabled')),
- ('hg.register.manual_activate', gettext_translator('Allowed with manual account activation')),
- ('hg.register.auto_activate', gettext_translator('Allowed with automatic account activation')),]
+ ('hg.register.none', _('Disabled')),
+ ('hg.register.manual_activate', _('Allowed with manual account activation')),
+ ('hg.register.auto_activate', _('Allowed with automatic account activation')),]
c_obj.password_reset_choices = [
- ('hg.password_reset.enabled', gettext_translator('Allow password recovery')),
- ('hg.password_reset.hidden', gettext_translator('Hide password recovery link')),
- ('hg.password_reset.disabled', gettext_translator('Disable password recovery')),]
+ ('hg.password_reset.enabled', _('Allow password recovery')),
+ ('hg.password_reset.hidden', _('Hide password recovery link')),
+ ('hg.password_reset.disabled', _('Disable password recovery')),]
c_obj.extern_activate_choices = [
- ('hg.extern_activate.manual', gettext_translator('Manual activation of external account')),
- ('hg.extern_activate.auto', gettext_translator('Automatic activation of external account')),]
+ ('hg.extern_activate.manual', _('Manual activation of external account')),
+ ('hg.extern_activate.auto', _('Automatic activation of external account')),]
c_obj.repo_create_choices = [
- ('hg.create.none', gettext_translator('Disabled')),
- ('hg.create.repository', gettext_translator('Enabled'))]
+ ('hg.create.none', _('Disabled')),
+ ('hg.create.repository', _('Enabled'))]
c_obj.repo_create_on_write_choices = [
- ('hg.create.write_on_repogroup.false', gettext_translator('Disabled')),
- ('hg.create.write_on_repogroup.true', gettext_translator('Enabled'))]
+ ('hg.create.write_on_repogroup.false', _('Disabled')),
+ ('hg.create.write_on_repogroup.true', _('Enabled'))]
c_obj.user_group_create_choices = [
- ('hg.usergroup.create.false', gettext_translator('Disabled')),
- ('hg.usergroup.create.true', gettext_translator('Enabled'))]
+ ('hg.usergroup.create.false', _('Disabled')),
+ ('hg.usergroup.create.true', _('Enabled'))]
c_obj.repo_group_create_choices = [
- ('hg.repogroup.create.false', gettext_translator('Disabled')),
- ('hg.repogroup.create.true', gettext_translator('Enabled'))]
+ ('hg.repogroup.create.false', _('Disabled')),
+ ('hg.repogroup.create.true', _('Enabled'))]
c_obj.fork_choices = [
- ('hg.fork.none', gettext_translator('Disabled')),
- ('hg.fork.repository', gettext_translator('Enabled'))]
+ ('hg.fork.none', _('Disabled')),
+ ('hg.fork.repository', _('Enabled'))]
c_obj.inherit_default_permission_choices = [
- ('hg.inherit_default_perms.false', gettext_translator('Disabled')),
- ('hg.inherit_default_perms.true', gettext_translator('Enabled'))]
+ ('hg.inherit_default_perms.false', _('Disabled')),
+ ('hg.inherit_default_perms.true', _('Enabled'))]
def get_default_perms(self, object_perms, suffix):
defaults = {}
diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js
--- a/rhodecode/public/js/rhodecode/routes.js
+++ b/rhodecode/public/js/rhodecode/routes.js
@@ -63,7 +63,14 @@ function registerRCRoutes() {
pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
+ pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
+ pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
+ pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
+ pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
+ pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
+ pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
+ pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
pyroutes.register('users', '/_admin/users', []);
pyroutes.register('users_data', '/_admin/users_data', []);
pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
diff --git a/rhodecode/templates/admin/permissions/permissions.mako b/rhodecode/templates/admin/permissions/permissions.mako
--- a/rhodecode/templates/admin/permissions/permissions.mako
+++ b/rhodecode/templates/admin/permissions/permissions.mako
@@ -30,19 +30,19 @@
diff --git a/rhodecode/templates/admin/permissions/permissions_application.mako b/rhodecode/templates/admin/permissions/permissions_application.mako
--- a/rhodecode/templates/admin/permissions/permissions_application.mako
+++ b/rhodecode/templates/admin/permissions/permissions_application.mako
@@ -3,7 +3,7 @@
${_('System Wide Application Permissions')}
- ${h.secure_form(h.url('admin_permissions_application'), method='post')}
+ ${h.secure_form(h.route_path('admin_permissions_application_update'), method='POST', request=request)}
diff --git a/rhodecode/templates/admin/permissions/permissions_global.mako b/rhodecode/templates/admin/permissions/permissions_global.mako
--- a/rhodecode/templates/admin/permissions/permissions_global.mako
+++ b/rhodecode/templates/admin/permissions/permissions_global.mako
@@ -1,5 +1,5 @@
-${h.secure_form(h.url('admin_permissions_global'), method='post')}
+${h.secure_form(h.route_path('admin_permissions_global_update'), method='POST', request=request)}