diff --git a/rhodecode/apps/home/__init__.py b/rhodecode/apps/home/__init__.py --- a/rhodecode/apps/home/__init__.py +++ b/rhodecode/apps/home/__init__.py @@ -29,5 +29,9 @@ def includeme(config): name='user_group_autocomplete_data', pattern='/_user_groups') + config.add_route( + name='repo_list_data', + pattern='/_repos') + # Scan module for configuration decorators. config.scan() diff --git a/rhodecode/apps/home/tests/__init__.py b/rhodecode/apps/home/tests/__init__.py --- a/rhodecode/apps/home/tests/__init__.py +++ b/rhodecode/apps/home/tests/__init__.py @@ -17,3 +17,24 @@ # 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 assert_and_get_content(result): + repos = [] + groups = [] + commits = [] + for data in result: + for data_item in data['children']: + assert data_item['id'] + assert data_item['text'] + assert data_item['url'] + if data_item['type'] == 'repo': + repos.append(data_item) + elif data_item['type'] == 'group': + groups.append(data_item) + elif data_item['type'] == 'commit': + commits.append(data_item) + else: + raise Exception('invalid type %s' % data_item['type']) + + return repos, groups, commits \ No newline at end of file diff --git a/rhodecode/apps/home/tests/test_get_repo_list_data.py b/rhodecode/apps/home/tests/test_get_repo_list_data.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/home/tests/test_get_repo_list_data.py @@ -0,0 +1,103 @@ +# -*- 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 json + +from . import assert_and_get_content +from rhodecode.tests import TestController +from rhodecode.tests.fixture import Fixture +from rhodecode.model.db import Repository + +fixture = Fixture() + + +def route_path(name, params=None, **kwargs): + import urllib + + base_url = { + 'repo_list_data': '/_repos', + }[name].format(**kwargs) + + if params: + base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) + return base_url + + +class TestRepoListData(TestController): + + def test_returns_list_of_repos_and_groups(self, xhr_header): + self.log_user() + + response = self.app.get( + route_path('repo_list_data'), + extra_environ=xhr_header, status=200) + result = json.loads(response.body)['results'] + + repos, groups, commits = assert_and_get_content(result) + + assert len(repos) == len(Repository.get_all()) + assert len(groups) == 0 + assert len(commits) == 0 + + def test_returns_list_of_repos_and_groups_filtered(self, xhr_header): + self.log_user() + + response = self.app.get( + route_path('repo_list_data'), + params={'query': 'vcs_test_git'}, + extra_environ=xhr_header, status=200) + result = json.loads(response.body)['results'] + + repos, groups, commits = assert_and_get_content(result) + + assert len(repos) == len(Repository.query().filter( + Repository.repo_name.ilike('%vcs_test_git%')).all()) + assert len(groups) == 0 + assert len(commits) == 0 + + def test_returns_list_of_repos_and_groups_filtered_with_type(self, xhr_header): + self.log_user() + + response = self.app.get( + route_path('repo_list_data'), + params={'query': 'vcs_test_git', 'repo_type': 'git'}, + extra_environ=xhr_header, status=200) + result = json.loads(response.body)['results'] + + repos, groups, commits = assert_and_get_content(result) + + assert len(repos) == len(Repository.query().filter( + Repository.repo_name.ilike('%vcs_test_git%')).all()) + assert len(groups) == 0 + assert len(commits) == 0 + + def test_returns_list_of_repos_non_ascii_query(self, xhr_header): + self.log_user() + response = self.app.get( + route_path('repo_list_data'), + params={'query': 'ć_vcs_test_ą', 'repo_type': 'git'}, + extra_environ=xhr_header, status=200) + result = json.loads(response.body)['results'] + + repos, groups, commits = assert_and_get_content(result) + + assert len(repos) == 0 + assert len(groups) == 0 + assert len(commits) == 0 diff --git a/rhodecode/apps/home/views.py b/rhodecode/apps/home/views.py --- a/rhodecode/apps/home/views.py +++ b/rhodecode/apps/home/views.py @@ -23,9 +23,13 @@ import logging from pyramid.view import view_config from rhodecode.apps._base import BaseAppView +from rhodecode.lib import helpers as h from rhodecode.lib.auth import LoginRequired, NotAnonymous -from rhodecode.lib.utils2 import str2bool +from rhodecode.lib.utils2 import safe_unicode, str2bool +from rhodecode.model.db import func, Repository from rhodecode.model.repo import RepoModel +from rhodecode.model.scm import ScmModel + log = logging.getLogger(__name__) @@ -79,3 +83,56 @@ class HomeView(BaseAppView): _user_groups = _user_groups return {'suggestions': _user_groups} + + def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): + query = Repository.query()\ + .order_by(func.length(Repository.repo_name))\ + .order_by(Repository.repo_name) + + if repo_type: + query = query.filter(Repository.repo_type == repo_type) + + if name_contains: + ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) + query = query.filter( + Repository.repo_name.ilike(ilike_expression)) + query = query.limit(limit) + + all_repos = query.all() + # permission checks are inside this function + repo_iter = ScmModel().get_repos(all_repos) + return [ + { + 'id': obj['name'], + 'text': obj['name'], + 'type': 'repo', + 'obj': obj['dbrepo'], + 'url': h.url('summary_home', repo_name=obj['name']) + } + for obj in repo_iter] + + @LoginRequired() + @view_config( + route_name='repo_list_data', request_method='GET', + renderer='json_ext', xhr=True) + def repo_list_data(self): + _ = self.request.translate + + query = self.request.GET.get('query') + repo_type = self.request.GET.get('repo_type') + log.debug('generating repo list, query:%s, repo_type:%s', + query, repo_type) + + res = [] + repos = self._get_repo_list(query, repo_type=repo_type) + if repos: + res.append({ + 'text': _('Repositories'), + 'children': repos + }) + + data = { + 'more': False, + 'results': res + } + return data diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py --- a/rhodecode/config/routing.py +++ b/rhodecode/config/routing.py @@ -190,8 +190,6 @@ def make_map(config): rmap.connect('home', '/', controller='home', action='index', jsroute=True) rmap.connect('goto_switcher_data', '/_goto_data', controller='home', action='goto_switcher_data') - rmap.connect('repo_list_data', '/_repos', controller='home', - action='repo_list_data') # TODO: johbo: Static links, to be replaced by our redirection mechanism rmap.connect('rst_help', diff --git a/rhodecode/controllers/home.py b/rhodecode/controllers/home.py --- a/rhodecode/controllers/home.py +++ b/rhodecode/controllers/home.py @@ -233,25 +233,3 @@ class HomeController(BaseController): 'results': res } return data - - @LoginRequired() - @XHRRequired() - @jsonify - def repo_list_data(self): - query = request.GET.get('query') - repo_type = request.GET.get('repo_type') - log.debug('generating repo list, query:%s', query) - - res = [] - repos = self._get_repo_list(query, repo_type=repo_type) - if repos: - res.append({ - 'text': _('Repositories'), - 'children': repos - }) - - data = { - 'more': False, - 'results': res - } - return data 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 @@ -13,8 +13,6 @@ function registerRCRoutes() { // routes registration pyroutes.register('home', '/', []); - pyroutes.register('user_autocomplete_data', '/_users', []); - pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); pyroutes.register('new_repo', '/_admin/create_repository', []); pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']); @@ -95,6 +93,9 @@ function registerRCRoutes() { pyroutes.register('register', '/_admin/register', []); pyroutes.register('reset_password', '/_admin/password_reset', []); pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []); + pyroutes.register('user_autocomplete_data', '/_users', []); + pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); + pyroutes.register('repo_list_data', '/_repos', []); pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']); 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 @@ -139,7 +139,7 @@ var repoFilter = function(data) { query.callback({results: cachedData.results}); } else { $.ajax({ - url: "${h.url('repo_list_data')}", + url: pyroutes.url('repo_list_data'), data: {'query': query.term}, dataType: 'json', type: 'GET', diff --git a/rhodecode/templates/admin/repos/repo_edit_advanced.mako b/rhodecode/templates/admin/repos/repo_edit_advanced.mako --- a/rhodecode/templates/admin/repos/repo_edit_advanced.mako +++ b/rhodecode/templates/admin/repos/repo_edit_advanced.mako @@ -191,7 +191,7 @@ var repoTypeFilter = function(data) { query.callback({results: cachedData.results}); } else { $.ajax({ - url: "${h.url('repo_list_data')}", + url: pyroutes.url('repo_list_data'), data: {'query': query.term, repo_type: '${c.repo_info.repo_type}'}, dataType: 'json', type: 'GET', diff --git a/rhodecode/templates/admin/users/user_edit_auth_tokens.mako b/rhodecode/templates/admin/users/user_edit_auth_tokens.mako --- a/rhodecode/templates/admin/users/user_edit_auth_tokens.mako +++ b/rhodecode/templates/admin/users/user_edit_auth_tokens.mako @@ -136,7 +136,7 @@ var repoFilter = function(data) { query.callback({results: cachedData.results}); } else { $.ajax({ - url: "${h.url('repo_list_data')}", + url: pyroutes.url('repo_list_data'), data: {'query': query.term}, dataType: 'json', type: 'GET', diff --git a/rhodecode/tests/functional/test_home.py b/rhodecode/tests/functional/test_home.py --- a/rhodecode/tests/functional/test_home.py +++ b/rhodecode/tests/functional/test_home.py @@ -255,65 +255,3 @@ class TestGotoSwitcherData(TestControlle test_groups = [x['text'] for x in groups[:4]] assert ['abc_repos', 'repos_abc', 'forked-abc', 'forked-abc/a'] == test_groups - - -class TestRepoListData(TestController): - def test_returns_list_of_repos_and_groups(self, user_util): - self.log_user() - - response = self.app.get( - url(controller='home', action='repo_list_data'), - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) - result = json.loads(response.body)['results'] - - repos, groups, commits = assert_and_get_content(result) - - assert len(repos) == len(Repository.get_all()) - assert len(groups) == 0 - assert len(commits) == 0 - - def test_returns_list_of_repos_and_groups_filtered(self): - self.log_user() - - response = self.app.get( - url(controller='home', action='repo_list_data'), - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, - params={'query': 'vcs_test_git'}, status=200) - result = json.loads(response.body)['results'] - - repos, groups, commits = assert_and_get_content(result) - - assert len(repos) == len(Repository.query().filter( - Repository.repo_name.ilike('%vcs_test_git%')).all()) - assert len(groups) == 0 - assert len(commits) == 0 - - def test_returns_list_of_repos_and_groups_filtered_with_type(self): - self.log_user() - - response = self.app.get( - url(controller='home', action='repo_list_data'), - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, - params={'query': 'vcs_test_git', 'repo_type': 'git'}, status=200) - result = json.loads(response.body)['results'] - - repos, groups, commits = assert_and_get_content(result) - - assert len(repos) == len(Repository.query().filter( - Repository.repo_name.ilike('%vcs_test_git%')).all()) - assert len(groups) == 0 - assert len(commits) == 0 - - def test_returns_list_of_repos_non_ascii_query(self): - self.log_user() - response = self.app.get( - url(controller='home', action='repo_list_data'), - headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, - params={'query': 'ć_vcs_test_ą', 'repo_type': 'git'}, status=200) - result = json.loads(response.body)['results'] - - repos, groups, commits = assert_and_get_content(result) - - assert len(repos) == 0 - assert len(groups) == 0 - assert len(commits) == 0