##// END OF EJS Templates
core: moved goto_switcher views into pyramid.
marcink -
r1668:6a5ff1d6 default
parent child Browse files
Show More
@@ -0,0 +1,151 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 import pytest
24
25 from . import assert_and_get_content
26 from rhodecode.tests import TestController, TEST_USER_ADMIN_LOGIN
27 from rhodecode.tests.fixture import Fixture
28
29 from rhodecode.lib.utils import map_groups
30 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.repo_group import RepoGroupModel
32 from rhodecode.model.db import Session, Repository, RepoGroup
33
34 fixture = Fixture()
35
36
37 def route_path(name, params=None, **kwargs):
38 import urllib
39
40 base_url = {
41 'goto_switcher_data': '/_goto_data',
42 }[name].format(**kwargs)
43
44 if params:
45 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
46 return base_url
47
48
49 class TestGotoSwitcherData(TestController):
50
51 required_repos_with_groups = [
52 'abc',
53 'abc-fork',
54 'forks/abcd',
55 'abcd',
56 'abcde',
57 'a/abc',
58 'aa/abc',
59 'aaa/abc',
60 'aaaa/abc',
61 'repos_abc/aaa/abc',
62 'abc_repos/abc',
63 'abc_repos/abcd',
64 'xxx/xyz',
65 'forked-abc/a/abc'
66 ]
67
68 @pytest.fixture(autouse=True, scope='class')
69 def prepare(self, request, pylonsapp):
70 for repo_and_group in self.required_repos_with_groups:
71 # create structure of groups and return the last group
72
73 repo_group = map_groups(repo_and_group)
74
75 RepoModel()._create_repo(
76 repo_and_group, 'hg', 'test-ac', TEST_USER_ADMIN_LOGIN,
77 repo_group=getattr(repo_group, 'group_id', None))
78
79 Session().commit()
80
81 request.addfinalizer(self.cleanup)
82
83 def cleanup(self):
84 # first delete all repos
85 for repo_and_groups in self.required_repos_with_groups:
86 repo = Repository.get_by_repo_name(repo_and_groups)
87 if repo:
88 RepoModel().delete(repo)
89 Session().commit()
90
91 # then delete all empty groups
92 for repo_and_groups in self.required_repos_with_groups:
93 if '/' in repo_and_groups:
94 r_group = repo_and_groups.rsplit('/', 1)[0]
95 repo_group = RepoGroup.get_by_group_name(r_group)
96 if not repo_group:
97 continue
98 parents = repo_group.parents
99 RepoGroupModel().delete(repo_group, force_delete=True)
100 Session().commit()
101
102 for el in reversed(parents):
103 RepoGroupModel().delete(el, force_delete=True)
104 Session().commit()
105
106 def test_returns_list_of_repos_and_groups(self, xhr_header):
107 self.log_user()
108
109 response = self.app.get(
110 route_path('goto_switcher_data'),
111 extra_environ=xhr_header, status=200)
112 result = json.loads(response.body)['results']
113
114 repos, groups, commits = assert_and_get_content(result)
115
116 assert len(repos) == len(Repository.get_all())
117 assert len(groups) == len(RepoGroup.get_all())
118 assert len(commits) == 0
119
120 def test_returns_list_of_repos_and_groups_filtered(self, xhr_header):
121 self.log_user()
122
123 response = self.app.get(
124 route_path('goto_switcher_data'),
125 params={'query': 'abc'},
126 extra_environ=xhr_header, status=200)
127 result = json.loads(response.body)['results']
128
129 repos, groups, commits = assert_and_get_content(result)
130
131 assert len(repos) == 13
132 assert len(groups) == 5
133 assert len(commits) == 0
134
135 def test_returns_list_of_properly_sorted_and_filtered(self, xhr_header):
136 self.log_user()
137
138 response = self.app.get(
139 route_path('goto_switcher_data'),
140 params={'query': 'abc'},
141 extra_environ=xhr_header, status=200)
142 result = json.loads(response.body)['results']
143
144 repos, groups, commits = assert_and_get_content(result)
145
146 test_repos = [x['text'] for x in repos[:4]]
147 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
148
149 test_groups = [x['text'] for x in groups[:4]]
150 assert ['abc_repos', 'repos_abc',
151 'forked-abc', 'forked-abc/a'] == test_groups
@@ -33,5 +33,9 b' def includeme(config):'
33 33 name='repo_list_data',
34 34 pattern='/_repos')
35 35
36 config.add_route(
37 name='goto_switcher_data',
38 pattern='/_goto_data')
39
36 40 # Scan module for configuration decorators.
37 41 config.scan()
@@ -18,6 +18,7 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import re
21 22 import logging
22 23
23 24 from pyramid.view import view_config
@@ -25,8 +26,9 b' from pyramid.view import view_config'
25 26 from rhodecode.apps._base import BaseAppView
26 27 from rhodecode.lib import helpers as h
27 28 from rhodecode.lib.auth import LoginRequired, NotAnonymous
29 from rhodecode.lib.index import searcher_from_config
28 30 from rhodecode.lib.utils2 import safe_unicode, str2bool
29 from rhodecode.model.db import func, Repository
31 from rhodecode.model.db import func, Repository, RepoGroup
30 32 from rhodecode.model.repo import RepoModel
31 33 from rhodecode.model.scm import ScmModel
32 34
@@ -111,6 +113,57 b' class HomeView(BaseAppView):'
111 113 }
112 114 for obj in repo_iter]
113 115
116 def _get_repo_group_list(self, name_contains=None, limit=20):
117 query = RepoGroup.query()\
118 .order_by(func.length(RepoGroup.group_name))\
119 .order_by(RepoGroup.group_name)
120
121 if name_contains:
122 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
123 query = query.filter(
124 RepoGroup.group_name.ilike(ilike_expression))
125 query = query.limit(limit)
126
127 all_groups = query.all()
128 repo_groups_iter = ScmModel().get_repo_groups(all_groups)
129 return [
130 {
131 'id': obj.group_name,
132 'text': obj.group_name,
133 'type': 'group',
134 'obj': {},
135 'url': h.url('repo_group_home', group_name=obj.group_name)
136 }
137 for obj in repo_groups_iter]
138
139 def _get_hash_commit_list(self, auth_user, hash_starts_with=None):
140 if not hash_starts_with or len(hash_starts_with) < 3:
141 return []
142
143 commit_hashes = re.compile('([0-9a-f]{2,40})').findall(hash_starts_with)
144
145 if len(commit_hashes) != 1:
146 return []
147
148 commit_hash_prefix = commit_hashes[0]
149
150 searcher = searcher_from_config(self.request.registry.settings)
151 result = searcher.search(
152 'commit_id:%s*' % commit_hash_prefix, 'commit', auth_user,
153 raise_on_exc=False)
154
155 return [
156 {
157 'id': entry['commit_id'],
158 'text': entry['commit_id'],
159 'type': 'commit',
160 'obj': {'repo': entry['repository']},
161 'url': h.url('changeset_home',
162 repo_name=entry['repository'],
163 revision=entry['commit_id'])
164 }
165 for entry in result['results']]
166
114 167 @LoginRequired()
115 168 @view_config(
116 169 route_name='repo_list_data', request_method='GET',
@@ -136,3 +189,49 b' class HomeView(BaseAppView):'
136 189 'results': res
137 190 }
138 191 return data
192
193 @LoginRequired()
194 @view_config(
195 route_name='goto_switcher_data', request_method='GET',
196 renderer='json_ext', xhr=True)
197 def goto_switcher_data(self):
198 c = self.load_default_context()
199
200 _ = self.request.translate
201
202 query = self.request.GET.get('query')
203 log.debug('generating goto switcher list, query %s', query)
204
205 res = []
206 repo_groups = self._get_repo_group_list(query)
207 if repo_groups:
208 res.append({
209 'text': _('Groups'),
210 'children': repo_groups
211 })
212
213 repos = self._get_repo_list(query)
214 if repos:
215 res.append({
216 'text': _('Repositories'),
217 'children': repos
218 })
219
220 commits = self._get_hash_commit_list(c.auth_user, query)
221 if commits:
222 unique_repos = {}
223 for commit in commits:
224 unique_repos.setdefault(commit['obj']['repo'], []
225 ).append(commit)
226
227 for repo in unique_repos:
228 res.append({
229 'text': _('Commits in %(repo)s') % {'repo': repo},
230 'children': unique_repos[repo]
231 })
232
233 data = {
234 'more': False,
235 'results': res
236 }
237 return data
@@ -188,8 +188,6 b' def make_map(config):'
188 188
189 189 # MAIN PAGE
190 190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 action='goto_switcher_data')
193 191
194 192 # TODO: johbo: Static links, to be replaced by our redirection mechanism
195 193 rmap.connect('rst_help',
@@ -24,20 +24,15 b' Home controller for RhodeCode Enterprise'
24 24
25 25 import logging
26 26 import time
27 import re
28 27
29 from pylons import tmpl_context as c, request, url, config
30 from pylons.i18n.translation import _
31 from sqlalchemy.sql import func
28 from pylons import tmpl_context as c
32 29
33 30 from rhodecode.lib.auth import (
34 LoginRequired, HasPermissionAllDecorator, AuthUser,
35 HasRepoGroupPermissionAnyDecorator, XHRRequired)
31 LoginRequired, HasPermissionAllDecorator,
32 HasRepoGroupPermissionAnyDecorator)
36 33 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.index import searcher_from_config
34
38 35 from rhodecode.lib.ext_json import json
39 from rhodecode.lib.utils import jsonify
40 from rhodecode.lib.utils2 import safe_unicode, str2bool
41 36 from rhodecode.model.db import Repository, RepoGroup
42 37 from rhodecode.model.repo import RepoModel
43 38 from rhodecode.model.repo_group import RepoGroupModel
@@ -113,123 +108,3 b' class HomeController(BaseController):'
113 108 c.repo_groups_data = json.dumps(repo_group_data)
114 109
115 110 return render('index_repo_group.mako')
116
117 def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
118 query = Repository.query()\
119 .order_by(func.length(Repository.repo_name))\
120 .order_by(Repository.repo_name)
121
122 if repo_type:
123 query = query.filter(Repository.repo_type == repo_type)
124
125 if name_contains:
126 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
127 query = query.filter(
128 Repository.repo_name.ilike(ilike_expression))
129 query = query.limit(limit)
130
131 all_repos = query.all()
132 repo_iter = self.scm_model.get_repos(all_repos)
133 return [
134 {
135 'id': obj['name'],
136 'text': obj['name'],
137 'type': 'repo',
138 'obj': obj['dbrepo'],
139 'url': url('summary_home', repo_name=obj['name'])
140 }
141 for obj in repo_iter]
142
143 def _get_repo_group_list(self, name_contains=None, limit=20):
144 query = RepoGroup.query()\
145 .order_by(func.length(RepoGroup.group_name))\
146 .order_by(RepoGroup.group_name)
147
148 if name_contains:
149 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
150 query = query.filter(
151 RepoGroup.group_name.ilike(ilike_expression))
152 query = query.limit(limit)
153
154 all_groups = query.all()
155 repo_groups_iter = self.scm_model.get_repo_groups(all_groups)
156 return [
157 {
158 'id': obj.group_name,
159 'text': obj.group_name,
160 'type': 'group',
161 'obj': {},
162 'url': url('repo_group_home', group_name=obj.group_name)
163 }
164 for obj in repo_groups_iter]
165
166 def _get_hash_commit_list(self, hash_starts_with=None, limit=20):
167 if not hash_starts_with or len(hash_starts_with) < 3:
168 return []
169
170 commit_hashes = re.compile('([0-9a-f]{2,40})').findall(hash_starts_with)
171
172 if len(commit_hashes) != 1:
173 return []
174
175 commit_hash_prefix = commit_hashes[0]
176
177 auth_user = AuthUser(
178 user_id=c.rhodecode_user.user_id, ip_addr=self.ip_addr)
179 searcher = searcher_from_config(config)
180 result = searcher.search(
181 'commit_id:%s*' % commit_hash_prefix, 'commit', auth_user,
182 raise_on_exc=False)
183
184 return [
185 {
186 'id': entry['commit_id'],
187 'text': entry['commit_id'],
188 'type': 'commit',
189 'obj': {'repo': entry['repository']},
190 'url': url('changeset_home',
191 repo_name=entry['repository'],
192 revision=entry['commit_id'])
193 }
194 for entry in result['results']]
195
196 @LoginRequired()
197 @XHRRequired()
198 @jsonify
199 def goto_switcher_data(self):
200 query = request.GET.get('query')
201 log.debug('generating goto switcher list, query %s', query)
202
203 res = []
204 repo_groups = self._get_repo_group_list(query)
205 if repo_groups:
206 res.append({
207 'text': _('Groups'),
208 'children': repo_groups
209 })
210
211 repos = self._get_repo_list(query)
212 if repos:
213 res.append({
214 'text': _('Repositories'),
215 'children': repos
216 })
217
218 commits = self._get_hash_commit_list(query)
219 if commits:
220 unique_repos = {}
221 for commit in commits:
222 unique_repos.setdefault(commit['obj']['repo'], []
223 ).append(commit)
224
225 for repo in unique_repos:
226 res.append({
227 'text': _('Commits in %(repo)s') % {'repo': repo},
228 'children': unique_repos[repo]
229 })
230
231 data = {
232 'more': False,
233 'results': res
234 }
235 return data
@@ -96,6 +96,7 b' function registerRCRoutes() {'
96 96 pyroutes.register('user_autocomplete_data', '/_users', []);
97 97 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
98 98 pyroutes.register('repo_list_data', '/_repos', []);
99 pyroutes.register('goto_switcher_data', '/_goto_data', []);
99 100 pyroutes.register('repo_maintenance', '/%(repo_name)s/maintenance', ['repo_name']);
100 101 pyroutes.register('repo_maintenance_execute', '/%(repo_name)s/maintenance/execute', ['repo_name']);
101 102 pyroutes.register('strip', '/%(repo_name)s/strip', ['repo_name']);
@@ -503,7 +503,7 b''
503 503 query.callback({results: cachedData.results});
504 504 } else {
505 505 $.ajax({
506 url: "${h.url('goto_switcher_data')}",
506 url: pyroutes.url('goto_switcher_data'),
507 507 data: {'query': query.term},
508 508 dataType: 'json',
509 509 type: 'GET',
@@ -18,20 +18,17 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import json
22 21
23 from mock import patch
24 22 import pytest
25 23 from pylons import tmpl_context as c
26 24
27 25 import rhodecode
28 from rhodecode.lib.utils import map_groups
29 from rhodecode.model.db import Repository, User, RepoGroup
26 from rhodecode.model.db import Repository, User
30 27 from rhodecode.model.meta import Session
31 28 from rhodecode.model.repo import RepoModel
32 29 from rhodecode.model.repo_group import RepoGroupModel
33 30 from rhodecode.model.settings import SettingsModel
34 from rhodecode.tests import TestController, url, TEST_USER_ADMIN_LOGIN
31 from rhodecode.tests import TestController, url
35 32 from rhodecode.tests.fixture import Fixture
36 33
37 34
@@ -130,128 +127,3 b' class TestHomeController(TestController)'
130 127 response.mustcontain(version_string)
131 128 if state is False:
132 129 response.mustcontain(no=[version_string])
133
134
135 def assert_and_get_content(result):
136 repos = []
137 groups = []
138 commits = []
139 for data in result:
140 for data_item in data['children']:
141 assert data_item['id']
142 assert data_item['text']
143 assert data_item['url']
144 if data_item['type'] == 'repo':
145 repos.append(data_item)
146 elif data_item['type'] == 'group':
147 groups.append(data_item)
148 elif data_item['type'] == 'commit':
149 commits.append(data_item)
150 else:
151 raise Exception('invalid type %s' % data_item['type'])
152
153 return repos, groups, commits
154
155
156 class TestGotoSwitcherData(TestController):
157 required_repos_with_groups = [
158 'abc',
159 'abc-fork',
160 'forks/abcd',
161 'abcd',
162 'abcde',
163 'a/abc',
164 'aa/abc',
165 'aaa/abc',
166 'aaaa/abc',
167 'repos_abc/aaa/abc',
168 'abc_repos/abc',
169 'abc_repos/abcd',
170 'xxx/xyz',
171 'forked-abc/a/abc'
172 ]
173
174 @pytest.fixture(autouse=True, scope='class')
175 def prepare(self, request, pylonsapp):
176 for repo_and_group in self.required_repos_with_groups:
177 # create structure of groups and return the last group
178
179 repo_group = map_groups(repo_and_group)
180
181 RepoModel()._create_repo(
182 repo_and_group, 'hg', 'test-ac', TEST_USER_ADMIN_LOGIN,
183 repo_group=getattr(repo_group, 'group_id', None))
184
185 Session().commit()
186
187 request.addfinalizer(self.cleanup)
188
189 def cleanup(self):
190 # first delete all repos
191 for repo_and_groups in self.required_repos_with_groups:
192 repo = Repository.get_by_repo_name(repo_and_groups)
193 if repo:
194 RepoModel().delete(repo)
195 Session().commit()
196
197 # then delete all empty groups
198 for repo_and_groups in self.required_repos_with_groups:
199 if '/' in repo_and_groups:
200 r_group = repo_and_groups.rsplit('/', 1)[0]
201 repo_group = RepoGroup.get_by_group_name(r_group)
202 if not repo_group:
203 continue
204 parents = repo_group.parents
205 RepoGroupModel().delete(repo_group, force_delete=True)
206 Session().commit()
207
208 for el in reversed(parents):
209 RepoGroupModel().delete(el, force_delete=True)
210 Session().commit()
211
212 def test_returns_list_of_repos_and_groups(self):
213 self.log_user()
214
215 response = self.app.get(
216 url(controller='home', action='goto_switcher_data'),
217 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200)
218 result = json.loads(response.body)['results']
219
220 repos, groups, commits = assert_and_get_content(result)
221
222 assert len(repos) == len(Repository.get_all())
223 assert len(groups) == len(RepoGroup.get_all())
224 assert len(commits) == 0
225
226 def test_returns_list_of_repos_and_groups_filtered(self):
227 self.log_user()
228
229 response = self.app.get(
230 url(controller='home', action='goto_switcher_data'),
231 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
232 params={'query': 'abc'}, status=200)
233 result = json.loads(response.body)['results']
234
235 repos, groups, commits = assert_and_get_content(result)
236
237 assert len(repos) == 13
238 assert len(groups) == 5
239 assert len(commits) == 0
240
241 def test_returns_list_of_properly_sorted_and_filtered(self):
242 self.log_user()
243
244 response = self.app.get(
245 url(controller='home', action='goto_switcher_data'),
246 headers={'X-REQUESTED-WITH': 'XMLHttpRequest', },
247 params={'query': 'abc'}, status=200)
248 result = json.loads(response.body)['results']
249
250 repos, groups, commits = assert_and_get_content(result)
251
252 test_repos = [x['text'] for x in repos[:4]]
253 assert ['abc', 'abcd', 'a/abc', 'abcde'] == test_repos
254
255 test_groups = [x['text'] for x in groups[:4]]
256 assert ['abc_repos', 'repos_abc',
257 'forked-abc', 'forked-abc/a'] == test_groups
General Comments 0
You need to be logged in to leave comments. Login now