Show More
@@ -0,0 +1,103 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import json | |
|
22 | ||
|
23 | from . import assert_and_get_content | |
|
24 | from rhodecode.tests import TestController | |
|
25 | from rhodecode.tests.fixture import Fixture | |
|
26 | from rhodecode.model.db import Repository | |
|
27 | ||
|
28 | fixture = Fixture() | |
|
29 | ||
|
30 | ||
|
31 | def route_path(name, params=None, **kwargs): | |
|
32 | import urllib | |
|
33 | ||
|
34 | base_url = { | |
|
35 | 'repo_list_data': '/_repos', | |
|
36 | }[name].format(**kwargs) | |
|
37 | ||
|
38 | if params: | |
|
39 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |
|
40 | return base_url | |
|
41 | ||
|
42 | ||
|
43 | class TestRepoListData(TestController): | |
|
44 | ||
|
45 | def test_returns_list_of_repos_and_groups(self, xhr_header): | |
|
46 | self.log_user() | |
|
47 | ||
|
48 | response = self.app.get( | |
|
49 | route_path('repo_list_data'), | |
|
50 | extra_environ=xhr_header, status=200) | |
|
51 | result = json.loads(response.body)['results'] | |
|
52 | ||
|
53 | repos, groups, commits = assert_and_get_content(result) | |
|
54 | ||
|
55 | assert len(repos) == len(Repository.get_all()) | |
|
56 | assert len(groups) == 0 | |
|
57 | assert len(commits) == 0 | |
|
58 | ||
|
59 | def test_returns_list_of_repos_and_groups_filtered(self, xhr_header): | |
|
60 | self.log_user() | |
|
61 | ||
|
62 | response = self.app.get( | |
|
63 | route_path('repo_list_data'), | |
|
64 | params={'query': 'vcs_test_git'}, | |
|
65 | extra_environ=xhr_header, status=200) | |
|
66 | result = json.loads(response.body)['results'] | |
|
67 | ||
|
68 | repos, groups, commits = assert_and_get_content(result) | |
|
69 | ||
|
70 | assert len(repos) == len(Repository.query().filter( | |
|
71 | Repository.repo_name.ilike('%vcs_test_git%')).all()) | |
|
72 | assert len(groups) == 0 | |
|
73 | assert len(commits) == 0 | |
|
74 | ||
|
75 | def test_returns_list_of_repos_and_groups_filtered_with_type(self, xhr_header): | |
|
76 | self.log_user() | |
|
77 | ||
|
78 | response = self.app.get( | |
|
79 | route_path('repo_list_data'), | |
|
80 | params={'query': 'vcs_test_git', 'repo_type': 'git'}, | |
|
81 | extra_environ=xhr_header, status=200) | |
|
82 | result = json.loads(response.body)['results'] | |
|
83 | ||
|
84 | repos, groups, commits = assert_and_get_content(result) | |
|
85 | ||
|
86 | assert len(repos) == len(Repository.query().filter( | |
|
87 | Repository.repo_name.ilike('%vcs_test_git%')).all()) | |
|
88 | assert len(groups) == 0 | |
|
89 | assert len(commits) == 0 | |
|
90 | ||
|
91 | def test_returns_list_of_repos_non_ascii_query(self, xhr_header): | |
|
92 | self.log_user() | |
|
93 | response = self.app.get( | |
|
94 | route_path('repo_list_data'), | |
|
95 | params={'query': 'ć_vcs_test_ą', 'repo_type': 'git'}, | |
|
96 | extra_environ=xhr_header, status=200) | |
|
97 | result = json.loads(response.body)['results'] | |
|
98 | ||
|
99 | repos, groups, commits = assert_and_get_content(result) | |
|
100 | ||
|
101 | assert len(repos) == 0 | |
|
102 | assert len(groups) == 0 | |
|
103 | assert len(commits) == 0 |
@@ -29,5 +29,9 b' def includeme(config):' | |||
|
29 | 29 | name='user_group_autocomplete_data', |
|
30 | 30 | pattern='/_user_groups') |
|
31 | 31 | |
|
32 | config.add_route( | |
|
33 | name='repo_list_data', | |
|
34 | pattern='/_repos') | |
|
35 | ||
|
32 | 36 | # Scan module for configuration decorators. |
|
33 | 37 | config.scan() |
@@ -17,3 +17,24 b'' | |||
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | ||
|
21 | ||
|
22 | def assert_and_get_content(result): | |
|
23 | repos = [] | |
|
24 | groups = [] | |
|
25 | commits = [] | |
|
26 | for data in result: | |
|
27 | for data_item in data['children']: | |
|
28 | assert data_item['id'] | |
|
29 | assert data_item['text'] | |
|
30 | assert data_item['url'] | |
|
31 | if data_item['type'] == 'repo': | |
|
32 | repos.append(data_item) | |
|
33 | elif data_item['type'] == 'group': | |
|
34 | groups.append(data_item) | |
|
35 | elif data_item['type'] == 'commit': | |
|
36 | commits.append(data_item) | |
|
37 | else: | |
|
38 | raise Exception('invalid type %s' % data_item['type']) | |
|
39 | ||
|
40 | return repos, groups, commits No newline at end of file |
@@ -23,9 +23,13 b' import logging' | |||
|
23 | 23 | from pyramid.view import view_config |
|
24 | 24 | |
|
25 | 25 | from rhodecode.apps._base import BaseAppView |
|
26 | from rhodecode.lib import helpers as h | |
|
26 | 27 | from rhodecode.lib.auth import LoginRequired, NotAnonymous |
|
27 | from rhodecode.lib.utils2 import str2bool | |
|
28 | from rhodecode.lib.utils2 import safe_unicode, str2bool | |
|
29 | from rhodecode.model.db import func, Repository | |
|
28 | 30 | from rhodecode.model.repo import RepoModel |
|
31 | from rhodecode.model.scm import ScmModel | |
|
32 | ||
|
29 | 33 | |
|
30 | 34 | log = logging.getLogger(__name__) |
|
31 | 35 | |
@@ -79,3 +83,56 b' class HomeView(BaseAppView):' | |||
|
79 | 83 | _user_groups = _user_groups |
|
80 | 84 | |
|
81 | 85 | return {'suggestions': _user_groups} |
|
86 | ||
|
87 | def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): | |
|
88 | query = Repository.query()\ | |
|
89 | .order_by(func.length(Repository.repo_name))\ | |
|
90 | .order_by(Repository.repo_name) | |
|
91 | ||
|
92 | if repo_type: | |
|
93 | query = query.filter(Repository.repo_type == repo_type) | |
|
94 | ||
|
95 | if name_contains: | |
|
96 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) | |
|
97 | query = query.filter( | |
|
98 | Repository.repo_name.ilike(ilike_expression)) | |
|
99 | query = query.limit(limit) | |
|
100 | ||
|
101 | all_repos = query.all() | |
|
102 | # permission checks are inside this function | |
|
103 | repo_iter = ScmModel().get_repos(all_repos) | |
|
104 | return [ | |
|
105 | { | |
|
106 | 'id': obj['name'], | |
|
107 | 'text': obj['name'], | |
|
108 | 'type': 'repo', | |
|
109 | 'obj': obj['dbrepo'], | |
|
110 | 'url': h.url('summary_home', repo_name=obj['name']) | |
|
111 | } | |
|
112 | for obj in repo_iter] | |
|
113 | ||
|
114 | @LoginRequired() | |
|
115 | @view_config( | |
|
116 | route_name='repo_list_data', request_method='GET', | |
|
117 | renderer='json_ext', xhr=True) | |
|
118 | def repo_list_data(self): | |
|
119 | _ = self.request.translate | |
|
120 | ||
|
121 | query = self.request.GET.get('query') | |
|
122 | repo_type = self.request.GET.get('repo_type') | |
|
123 | log.debug('generating repo list, query:%s, repo_type:%s', | |
|
124 | query, repo_type) | |
|
125 | ||
|
126 | res = [] | |
|
127 | repos = self._get_repo_list(query, repo_type=repo_type) | |
|
128 | if repos: | |
|
129 | res.append({ | |
|
130 | 'text': _('Repositories'), | |
|
131 | 'children': repos | |
|
132 | }) | |
|
133 | ||
|
134 | data = { | |
|
135 | 'more': False, | |
|
136 | 'results': res | |
|
137 | } | |
|
138 | return data |
@@ -190,8 +190,6 b' def make_map(config):' | |||
|
190 | 190 | rmap.connect('home', '/', controller='home', action='index', jsroute=True) |
|
191 | 191 | rmap.connect('goto_switcher_data', '/_goto_data', controller='home', |
|
192 | 192 | action='goto_switcher_data') |
|
193 | rmap.connect('repo_list_data', '/_repos', controller='home', | |
|
194 | action='repo_list_data') | |
|
195 | 193 | |
|
196 | 194 | # TODO: johbo: Static links, to be replaced by our redirection mechanism |
|
197 | 195 | rmap.connect('rst_help', |
@@ -233,25 +233,3 b' class HomeController(BaseController):' | |||
|
233 | 233 | 'results': res |
|
234 | 234 | } |
|
235 | 235 | return data |
|
236 | ||
|
237 | @LoginRequired() | |
|
238 | @XHRRequired() | |
|
239 | @jsonify | |
|
240 | def repo_list_data(self): | |
|
241 | query = request.GET.get('query') | |
|
242 | repo_type = request.GET.get('repo_type') | |
|
243 | log.debug('generating repo list, query:%s', query) | |
|
244 | ||
|
245 | res = [] | |
|
246 | repos = self._get_repo_list(query, repo_type=repo_type) | |
|
247 | if repos: | |
|
248 | res.append({ | |
|
249 | 'text': _('Repositories'), | |
|
250 | 'children': repos | |
|
251 | }) | |
|
252 | ||
|
253 | data = { | |
|
254 | 'more': False, | |
|
255 | 'results': res | |
|
256 | } | |
|
257 | return data |
@@ -13,8 +13,6 b'' | |||
|
13 | 13 | function registerRCRoutes() { |
|
14 | 14 | // routes registration |
|
15 | 15 | pyroutes.register('home', '/', []); |
|
16 | pyroutes.register('user_autocomplete_data', '/_users', []); | |
|
17 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); | |
|
18 | 16 | pyroutes.register('new_repo', '/_admin/create_repository', []); |
|
19 | 17 | pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); |
|
20 | 18 | pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']); |
@@ -95,6 +93,9 b' function registerRCRoutes() {' | |||
|
95 | 93 | pyroutes.register('register', '/_admin/register', []); |
|
96 | 94 | pyroutes.register('reset_password', '/_admin/password_reset', []); |
|
97 | 95 | pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []); |
|
96 | pyroutes.register('user_autocomplete_data', '/_users', []); | |
|
97 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); | |
|
98 | pyroutes.register('repo_list_data', '/_repos', []); | |
|
98 | 99 | pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']); |
|
99 | 100 | pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']); |
|
100 | 101 | pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']); |
@@ -139,7 +139,7 b' var repoFilter = function(data) {' | |||
|
139 | 139 | query.callback({results: cachedData.results}); |
|
140 | 140 | } else { |
|
141 | 141 | $.ajax({ |
|
142 |
url: |
|
|
142 | url: pyroutes.url('repo_list_data'), | |
|
143 | 143 | data: {'query': query.term}, |
|
144 | 144 | dataType: 'json', |
|
145 | 145 | type: 'GET', |
@@ -191,7 +191,7 b' var repoTypeFilter = function(data) {' | |||
|
191 | 191 | query.callback({results: cachedData.results}); |
|
192 | 192 | } else { |
|
193 | 193 | $.ajax({ |
|
194 |
url: |
|
|
194 | url: pyroutes.url('repo_list_data'), | |
|
195 | 195 | data: {'query': query.term, repo_type: '${c.repo_info.repo_type}'}, |
|
196 | 196 | dataType: 'json', |
|
197 | 197 | type: 'GET', |
@@ -136,7 +136,7 b' var repoFilter = function(data) {' | |||
|
136 | 136 | query.callback({results: cachedData.results}); |
|
137 | 137 | } else { |
|
138 | 138 | $.ajax({ |
|
139 |
url: |
|
|
139 | url: pyroutes.url('repo_list_data'), | |
|
140 | 140 | data: {'query': query.term}, |
|
141 | 141 | dataType: 'json', |
|
142 | 142 | type: 'GET', |
@@ -255,65 +255,3 b' class TestGotoSwitcherData(TestControlle' | |||
|
255 | 255 | test_groups = [x['text'] for x in groups[:4]] |
|
256 | 256 | assert ['abc_repos', 'repos_abc', |
|
257 | 257 | 'forked-abc', 'forked-abc/a'] == test_groups |
|
258 | ||
|
259 | ||
|
260 | class TestRepoListData(TestController): | |
|
261 | def test_returns_list_of_repos_and_groups(self, user_util): | |
|
262 | self.log_user() | |
|
263 | ||
|
264 | response = self.app.get( | |
|
265 | url(controller='home', action='repo_list_data'), | |
|
266 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) | |
|
267 | result = json.loads(response.body)['results'] | |
|
268 | ||
|
269 | repos, groups, commits = assert_and_get_content(result) | |
|
270 | ||
|
271 | assert len(repos) == len(Repository.get_all()) | |
|
272 | assert len(groups) == 0 | |
|
273 | assert len(commits) == 0 | |
|
274 | ||
|
275 | def test_returns_list_of_repos_and_groups_filtered(self): | |
|
276 | self.log_user() | |
|
277 | ||
|
278 | response = self.app.get( | |
|
279 | url(controller='home', action='repo_list_data'), | |
|
280 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, | |
|
281 | params={'query': 'vcs_test_git'}, status=200) | |
|
282 | result = json.loads(response.body)['results'] | |
|
283 | ||
|
284 | repos, groups, commits = assert_and_get_content(result) | |
|
285 | ||
|
286 | assert len(repos) == len(Repository.query().filter( | |
|
287 | Repository.repo_name.ilike('%vcs_test_git%')).all()) | |
|
288 | assert len(groups) == 0 | |
|
289 | assert len(commits) == 0 | |
|
290 | ||
|
291 | def test_returns_list_of_repos_and_groups_filtered_with_type(self): | |
|
292 | self.log_user() | |
|
293 | ||
|
294 | response = self.app.get( | |
|
295 | url(controller='home', action='repo_list_data'), | |
|
296 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, | |
|
297 | params={'query': 'vcs_test_git', 'repo_type': 'git'}, status=200) | |
|
298 | result = json.loads(response.body)['results'] | |
|
299 | ||
|
300 | repos, groups, commits = assert_and_get_content(result) | |
|
301 | ||
|
302 | assert len(repos) == len(Repository.query().filter( | |
|
303 | Repository.repo_name.ilike('%vcs_test_git%')).all()) | |
|
304 | assert len(groups) == 0 | |
|
305 | assert len(commits) == 0 | |
|
306 | ||
|
307 | def test_returns_list_of_repos_non_ascii_query(self): | |
|
308 | self.log_user() | |
|
309 | response = self.app.get( | |
|
310 | url(controller='home', action='repo_list_data'), | |
|
311 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, | |
|
312 | params={'query': 'ć_vcs_test_ą', 'repo_type': 'git'}, status=200) | |
|
313 | result = json.loads(response.body)['results'] | |
|
314 | ||
|
315 | repos, groups, commits = assert_and_get_content(result) | |
|
316 | ||
|
317 | assert len(repos) == 0 | |
|
318 | assert len(groups) == 0 | |
|
319 | assert len(commits) == 0 |
General Comments 0
You need to be logged in to leave comments.
Login now