core: moved users and user groups autocomplete into pyramid.

- added more tests
- added some logging
This commit is contained in:
Marcin Kuzminski 2017-04-19 14:34:57 +02:00
parent 0cf9a67567
commit 5627c638be
10 changed files with 367 additions and 109 deletions

View file

@ -0,0 +1,33 @@
# -*- 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 <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/
def includeme(config):
config.add_route(
name='user_autocomplete_data',
pattern='/_users')
config.add_route(
name='user_group_autocomplete_data',
pattern='/_user_groups')
# Scan module for configuration decorators.
config.scan()

View file

@ -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 <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/

View file

@ -0,0 +1,112 @@
# -*- 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 <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 json
import pytest
from rhodecode.tests import TestController
from rhodecode.tests.fixture import Fixture
fixture = Fixture()
def route_path(name, params=None, **kwargs):
import urllib
base_url = {
'user_autocomplete_data': '/_users',
'user_group_autocomplete_data': '/_user_groups'
}[name].format(**kwargs)
if params:
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
return base_url
class TestUserAutocompleteData(TestController):
def test_returns_list_of_users(self, user_util, xhr_header):
self.log_user()
user = user_util.create_user(active=True)
user_name = user.username
response = self.app.get(
route_path('user_autocomplete_data'),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_name in values
def test_returns_inactive_users_when_active_flag_sent(
self, user_util, xhr_header):
self.log_user()
user = user_util.create_user(active=False)
user_name = user.username
response = self.app.get(
route_path('user_autocomplete_data',
params=dict(user_groups='true', active='0')),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_name in values
response = self.app.get(
route_path('user_autocomplete_data',
params=dict(user_groups='true', active='1')),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_name not in values
def test_returns_groups_when_user_groups_flag_sent(
self, user_util, xhr_header):
self.log_user()
group = user_util.create_user_group(user_groups_active=True)
group_name = group.users_group_name
response = self.app.get(
route_path('user_autocomplete_data',
params=dict(user_groups='true')),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert group_name in values
@pytest.mark.parametrize('query, count', [
('hello1', 0),
('dev', 2),
])
def test_result_is_limited_when_query_is_sent(self, user_util, xhr_header,
query, count):
self.log_user()
user_util._test_name = 'dev-test'
user_util.create_user()
user_util._test_name = 'dev-group-test'
user_util.create_user_group()
response = self.app.get(
route_path('user_autocomplete_data',
params=dict(user_groups='true', query=query)),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
assert len(result['suggestions']) == count

View file

@ -0,0 +1,117 @@
# -*- 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 <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/
# -*- 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 <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 json
import pytest
from rhodecode.tests import TestController
from rhodecode.tests.fixture import Fixture
fixture = Fixture()
def route_path(name, params=None, **kwargs):
import urllib
base_url = {
'user_autocomplete_data': '/_users',
'user_group_autocomplete_data': '/_user_groups'
}[name].format(**kwargs)
if params:
base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
return base_url
class TestUserGroupAutocompleteData(TestController):
def test_returns_list_of_user_groups(self, user_util, xhr_header):
self.log_user()
user_group = user_util.create_user_group(active=True)
user_group_name = user_group.users_group_name
response = self.app.get(
route_path('user_group_autocomplete_data'),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_group_name in values
def test_returns_inactive_user_groups_when_active_flag_sent(
self, user_util, xhr_header):
self.log_user()
user_group = user_util.create_user_group(active=False)
user_group_name = user_group.users_group_name
response = self.app.get(
route_path('user_group_autocomplete_data',
params=dict(active='0')),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_group_name in values
response = self.app.get(
route_path('user_group_autocomplete_data',
params=dict(active='1')),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_group_name not in values
@pytest.mark.parametrize('query, count', [
('hello1', 0),
('dev', 1),
])
def test_result_is_limited_when_query_is_sent(self, user_util, xhr_header, query, count):
self.log_user()
user_util._test_name = 'dev-test'
user_util.create_user_group()
response = self.app.get(
route_path('user_group_autocomplete_data',
params=dict(user_groups='true',
query=query)),
extra_environ=xhr_header, status=200)
result = json.loads(response.body)
assert len(result['suggestions']) == count

View file

@ -0,0 +1,81 @@
# -*- 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 <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
from pyramid.view import view_config
from rhodecode.apps._base import BaseAppView
from rhodecode.lib.auth import LoginRequired, NotAnonymous
from rhodecode.lib.utils2 import str2bool
from rhodecode.model.repo import RepoModel
log = logging.getLogger(__name__)
class HomeView(BaseAppView):
def load_default_context(self):
c = self._get_local_tmpl_context()
c.user = c.auth_user.get_instance()
self._register_global_c(c)
return c
@LoginRequired()
@view_config(
route_name='user_autocomplete_data', request_method='GET',
renderer='json_ext', xhr=True)
def user_autocomplete_data(self):
query = self.request.GET.get('query')
active = str2bool(self.request.GET.get('active') or True)
include_groups = str2bool(self.request.GET.get('user_groups'))
log.debug('generating user list, query:%s, active:%s, with_groups:%s',
query, active, include_groups)
repo_model = RepoModel()
_users = repo_model.get_users(
name_contains=query, only_active=active)
if include_groups:
# extend with user groups
_user_groups = repo_model.get_user_groups(
name_contains=query, only_active=active)
_users = _users + _user_groups
return {'suggestions': _users}
@LoginRequired()
@NotAnonymous()
@view_config(
route_name='user_group_autocomplete_data', request_method='GET',
renderer='json_ext', xhr=True)
def user_group_autocomplete_data(self):
query = self.request.GET.get('query')
active = str2bool(self.request.GET.get('active') or True)
log.debug('generating user group list, query:%s, active:%s',
query, active)
repo_model = RepoModel()
_user_groups = repo_model.get_user_groups(
name_contains=query, only_active=active)
_user_groups = _user_groups
return {'suggestions': _user_groups}

View file

@ -288,6 +288,7 @@ def includeme(config):
config.include('rhodecode.apps.admin')
config.include('rhodecode.apps.channelstream')
config.include('rhodecode.apps.login')
config.include('rhodecode.apps.home')
config.include('rhodecode.apps.repository')
config.include('rhodecode.apps.user_profile')
config.include('rhodecode.apps.my_account')

View file

@ -193,11 +193,6 @@ def make_map(config):
rmap.connect('repo_list_data', '/_repos', controller='home',
action='repo_list_data')
rmap.connect('user_autocomplete_data', '/_users', controller='home',
action='user_autocomplete_data', jsroute=True)
rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
action='user_group_autocomplete_data', jsroute=True)
# TODO: johbo: Static links, to be replaced by our redirection mechanism
rmap.connect('rst_help',
'http://docutils.sourceforge.net/docs/user/rst/quickref.html',

View file

@ -255,36 +255,3 @@ class HomeController(BaseController):
'results': res
}
return data
@LoginRequired()
@XHRRequired()
@jsonify
def user_autocomplete_data(self):
query = request.GET.get('query')
active = str2bool(request.GET.get('active') or True)
repo_model = RepoModel()
_users = repo_model.get_users(
name_contains=query, only_active=active)
if request.GET.get('user_groups'):
# extend with user groups
_user_groups = repo_model.get_user_groups(
name_contains=query, only_active=active)
_users = _users + _user_groups
return {'suggestions': _users}
@LoginRequired()
@XHRRequired()
@jsonify
def user_group_autocomplete_data(self):
query = request.GET.get('query')
active = str2bool(request.GET.get('active') or True)
repo_model = RepoModel()
_user_groups = repo_model.get_user_groups(
name_contains=query, only_active=active)
_user_groups = _user_groups
return {'suggestions': _user_groups}

View file

@ -286,6 +286,10 @@ class Fixture(object):
gr = UserGroup.get_by_group_name(group_name=name)
if gr:
return gr
# map active flag to the real attribute. For API consistency of fixtures
if 'active' in kwargs:
kwargs['users_group_active'] = kwargs['active']
del kwargs['active']
form_data = self._get_user_group_create_params(name, **kwargs)
owner = kwargs.get('cur_user', TEST_USER_ADMIN_LOGIN)
user_group = UserGroupModel().create(

View file

@ -132,77 +132,6 @@ class TestHomeController(TestController):
response.mustcontain(no=[version_string])
class TestUserAutocompleteData(TestController):
def test_returns_list_of_users(self, user_util):
self.log_user()
user = user_util.create_user(is_active=True)
user_name = user.username
response = self.app.get(
url(controller='home', action='user_autocomplete_data'),
headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_name in values
def test_returns_inactive_users_when_active_flag_sent(self, user_util):
self.log_user()
user = user_util.create_user(is_active=False)
user_name = user.username
response = self.app.get(
url(controller='home', action='user_autocomplete_data',
user_groups='true', active='0'),
headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert user_name in values
def test_returns_groups_when_user_groups_sent(self, user_util):
self.log_user()
group = user_util.create_user_group(user_groups_active=True)
group_name = group.users_group_name
response = self.app.get(
url(controller='home', action='user_autocomplete_data',
user_groups='true'),
headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
result = json.loads(response.body)
values = [suggestion['value'] for suggestion in result['suggestions']]
assert group_name in values
def test_result_is_limited_when_query_is_sent(self):
self.log_user()
fake_result = [
{
'first_name': 'John',
'value_display': 'hello{} (John Smith)'.format(i),
'icon_link': '/images/user14.png',
'value': 'hello{}'.format(i),
'last_name': 'Smith',
'username': 'hello{}'.format(i),
'id': i,
'value_type': u'user'
}
for i in range(10)
]
users_patcher = patch.object(
RepoModel, 'get_users', return_value=fake_result)
groups_patcher = patch.object(
RepoModel, 'get_user_groups', return_value=fake_result)
query = 'hello'
with users_patcher as users_mock, groups_patcher as groups_mock:
response = self.app.get(
url(controller='home', action='user_autocomplete_data',
user_groups='true', query=query),
headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
result = json.loads(response.body)
users_mock.assert_called_once_with(
name_contains=query, only_active=True)
groups_mock.assert_called_once_with(
name_contains=query, only_active=True)
assert len(result['suggestions']) == 20
def assert_and_get_content(result):
repos = []
groups = []