##// END OF EJS Templates
repo-summary: re-implemented summary view as pyramid....
marcink -
r1785:1cce4ff2 default
parent child Browse files
Show More
@@ -0,0 +1,368 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-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 logging
22 import string
23
24 from pyramid.view import view_config
25
26 from beaker.cache import cache_region
27
28
29 from rhodecode.controllers import utils
30
31 from rhodecode.apps._base import RepoAppView
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
33 from rhodecode.lib import caches, helpers as h
34 from rhodecode.lib.helpers import RepoPage
35 from rhodecode.lib.utils2 import safe_str, safe_int
36 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
38 from rhodecode.lib.ext_json import json
39 from rhodecode.lib.vcs.backends.base import EmptyCommit
40 from rhodecode.lib.vcs.exceptions import CommitError, EmptyRepositoryError
41 from rhodecode.model.db import Statistics, CacheKey, User
42 from rhodecode.model.meta import Session
43 from rhodecode.model.repo import ReadmeFinder
44 from rhodecode.model.scm import ScmModel
45
46 log = logging.getLogger(__name__)
47
48
49 class RepoSummaryView(RepoAppView):
50
51 def load_default_context(self):
52 c = self._get_local_tmpl_context(include_app_defaults=True)
53
54 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
55 c.repo_info = self.db_repo
56 c.rhodecode_repo = None
57 if not c.repository_requirements_missing:
58 c.rhodecode_repo = self.rhodecode_vcs_repo
59
60 self._register_global_c(c)
61 return c
62
63 def _get_readme_data(self, db_repo, default_renderer):
64 repo_name = db_repo.repo_name
65 log.debug('Looking for README file')
66
67 @cache_region('long_term')
68 def _generate_readme(cache_key):
69 readme_data = None
70 readme_node = None
71 readme_filename = None
72 commit = self._get_landing_commit_or_none(db_repo)
73 if commit:
74 log.debug("Searching for a README file.")
75 readme_node = ReadmeFinder(default_renderer).search(commit)
76 if readme_node:
77 relative_url = h.url('files_raw_home',
78 repo_name=repo_name,
79 revision=commit.raw_id,
80 f_path=readme_node.path)
81 readme_data = self._render_readme_or_none(
82 commit, readme_node, relative_url)
83 readme_filename = readme_node.path
84 return readme_data, readme_filename
85
86 invalidator_context = CacheKey.repo_context_cache(
87 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
88
89 with invalidator_context as context:
90 context.invalidate()
91 computed = context.compute()
92
93 return computed
94
95 def _get_landing_commit_or_none(self, db_repo):
96 log.debug("Getting the landing commit.")
97 try:
98 commit = db_repo.get_landing_commit()
99 if not isinstance(commit, EmptyCommit):
100 return commit
101 else:
102 log.debug("Repository is empty, no README to render.")
103 except CommitError:
104 log.exception(
105 "Problem getting commit when trying to render the README.")
106
107 def _render_readme_or_none(self, commit, readme_node, relative_url):
108 log.debug(
109 'Found README file `%s` rendering...', readme_node.path)
110 renderer = MarkupRenderer()
111 try:
112 html_source = renderer.render(
113 readme_node.content, filename=readme_node.path)
114 if relative_url:
115 return relative_links(html_source, relative_url)
116 return html_source
117 except Exception:
118 log.exception(
119 "Exception while trying to render the README")
120
121 def _load_commits_context(self, c):
122 p = safe_int(self.request.GET.get('page'), 1)
123 size = safe_int(self.request.GET.get('size'), 10)
124
125 def url_generator(**kw):
126 query_params = {
127 'size': size
128 }
129 query_params.update(kw)
130 return h.route_path(
131 'repo_summary_commits',
132 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
133
134 pre_load = ['author', 'branch', 'date', 'message']
135 try:
136 collection = self.rhodecode_vcs_repo.get_commits(pre_load=pre_load)
137 except EmptyRepositoryError:
138 collection = self.rhodecode_vcs_repo
139
140 c.repo_commits = RepoPage(
141 collection, page=p, items_per_page=size, url=url_generator)
142 page_ids = [x.raw_id for x in c.repo_commits]
143 c.comments = self.db_repo.get_comments(page_ids)
144 c.statuses = self.db_repo.statuses(page_ids)
145
146 @LoginRequired()
147 @HasRepoPermissionAnyDecorator(
148 'repository.read', 'repository.write', 'repository.admin')
149 @view_config(
150 route_name='repo_summary_commits', request_method='GET',
151 renderer='rhodecode:templates/summary/summary_commits.mako')
152 def summary_commits(self):
153 c = self.load_default_context()
154 self._load_commits_context(c)
155 return self._get_template_context(c)
156
157 @LoginRequired()
158 @HasRepoPermissionAnyDecorator(
159 'repository.read', 'repository.write', 'repository.admin')
160 @view_config(
161 route_name='repo_summary', request_method='GET',
162 renderer='rhodecode:templates/summary/summary.mako')
163 @view_config(
164 route_name='repo_summary_slash', request_method='GET',
165 renderer='rhodecode:templates/summary/summary.mako')
166 def summary(self):
167 c = self.load_default_context()
168
169 # Prepare the clone URL
170 username = ''
171 if self._rhodecode_user.username != User.DEFAULT_USER:
172 username = safe_str(self._rhodecode_user.username)
173
174 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
175 if '{repo}' in _def_clone_uri:
176 _def_clone_uri_by_id = _def_clone_uri.replace(
177 '{repo}', '_{repoid}')
178 elif '{repoid}' in _def_clone_uri:
179 _def_clone_uri_by_id = _def_clone_uri.replace(
180 '_{repoid}', '{repo}')
181
182 c.clone_repo_url = self.db_repo.clone_url(
183 user=username, uri_tmpl=_def_clone_uri)
184 c.clone_repo_url_id = self.db_repo.clone_url(
185 user=username, uri_tmpl=_def_clone_uri_by_id)
186
187 # If enabled, get statistics data
188
189 c.show_stats = bool(self.db_repo.enable_statistics)
190
191 stats = Session().query(Statistics) \
192 .filter(Statistics.repository == self.db_repo) \
193 .scalar()
194
195 c.stats_percentage = 0
196
197 if stats and stats.languages:
198 c.no_data = False is self.db_repo.enable_statistics
199 lang_stats_d = json.loads(stats.languages)
200
201 # Sort first by decreasing count and second by the file extension,
202 # so we have a consistent output.
203 lang_stats_items = sorted(lang_stats_d.iteritems(),
204 key=lambda k: (-k[1], k[0]))[:10]
205 lang_stats = [(x, {"count": y,
206 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
207 for x, y in lang_stats_items]
208
209 c.trending_languages = json.dumps(lang_stats)
210 else:
211 c.no_data = True
212 c.trending_languages = json.dumps({})
213
214 scm_model = ScmModel()
215 c.enable_downloads = self.db_repo.enable_downloads
216 c.repository_followers = scm_model.get_followers(self.db_repo)
217 c.repository_forks = scm_model.get_forks(self.db_repo)
218 c.repository_is_user_following = scm_model.is_following_repo(
219 self.db_repo_name, self._rhodecode_user.user_id)
220
221 # first interaction with the VCS instance after here...
222 if c.repository_requirements_missing:
223 self.request.override_renderer = \
224 'rhodecode:templates/summary/missing_requirements.mako'
225 return self._get_template_context(c)
226
227 c.readme_data, c.readme_file = \
228 self._get_readme_data(self.db_repo, c.visual.default_renderer)
229
230 # loads the summary commits template context
231 self._load_commits_context(c)
232
233 return self._get_template_context(c)
234
235 def get_request_commit_id(self):
236 return self.request.matchdict['commit_id']
237
238 @LoginRequired()
239 @HasRepoPermissionAnyDecorator(
240 'repository.read', 'repository.write', 'repository.admin')
241 @view_config(
242 route_name='repo_stats', request_method='GET',
243 renderer='json_ext')
244 def repo_stats(self):
245 commit_id = self.get_request_commit_id()
246
247 _namespace = caches.get_repo_namespace_key(
248 caches.SUMMARY_STATS, self.db_repo_name)
249 show_stats = bool(self.db_repo.enable_statistics)
250 cache_manager = caches.get_cache_manager(
251 'repo_cache_long', _namespace)
252 _cache_key = caches.compute_key_from_params(
253 self.db_repo_name, commit_id, show_stats)
254
255 def compute_stats():
256 code_stats = {}
257 size = 0
258 try:
259 scm_instance = self.db_repo.scm_instance()
260 commit = scm_instance.get_commit(commit_id)
261
262 for node in commit.get_filenodes_generator():
263 size += node.size
264 if not show_stats:
265 continue
266 ext = string.lower(node.extension)
267 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
268 if ext_info:
269 if ext in code_stats:
270 code_stats[ext]['count'] += 1
271 else:
272 code_stats[ext] = {"count": 1, "desc": ext_info}
273 except EmptyRepositoryError:
274 pass
275 return {'size': h.format_byte_size_binary(size),
276 'code_stats': code_stats}
277
278 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
279 return stats
280
281 @LoginRequired()
282 @HasRepoPermissionAnyDecorator(
283 'repository.read', 'repository.write', 'repository.admin')
284 @view_config(
285 route_name='repo_refs_data', request_method='GET',
286 renderer='json_ext')
287 def repo_refs_data(self):
288 _ = self.request.translate
289 self.load_default_context()
290
291 repo = self.rhodecode_vcs_repo
292 refs_to_create = [
293 (_("Branch"), repo.branches, 'branch'),
294 (_("Tag"), repo.tags, 'tag'),
295 (_("Bookmark"), repo.bookmarks, 'book'),
296 ]
297 res = self._create_reference_data(
298 repo, self.db_repo_name, refs_to_create)
299 data = {
300 'more': False,
301 'results': res
302 }
303 return data
304
305 @LoginRequired()
306 @HasRepoPermissionAnyDecorator(
307 'repository.read', 'repository.write', 'repository.admin')
308 @view_config(
309 route_name='repo_refs_changelog_data', request_method='GET',
310 renderer='json_ext')
311 def repo_refs_changelog_data(self):
312 _ = self.request.translate
313 self.load_default_context()
314
315 repo = self.rhodecode_vcs_repo
316
317 refs_to_create = [
318 (_("Branches"), repo.branches, 'branch'),
319 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
320 # TODO: enable when vcs can handle bookmarks filters
321 # (_("Bookmarks"), repo.bookmarks, "book"),
322 ]
323 res = self._create_reference_data(
324 repo, self.db_repo_name, refs_to_create)
325 data = {
326 'more': False,
327 'results': res
328 }
329 return data
330
331 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
332 format_ref_id = utils.get_format_ref_id(repo)
333
334 result = []
335 for title, refs, ref_type in refs_to_create:
336 if refs:
337 result.append({
338 'text': title,
339 'children': self._create_reference_items(
340 repo, full_repo_name, refs, ref_type,
341 format_ref_id),
342 })
343 return result
344
345 def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
346 format_ref_id):
347 result = []
348 is_svn = h.is_svn(repo)
349 for ref_name, raw_id in refs.iteritems():
350 files_url = self._create_files_url(
351 repo, full_repo_name, ref_name, raw_id, is_svn)
352 result.append({
353 'text': ref_name,
354 'id': format_ref_id(ref_name, raw_id),
355 'raw_id': raw_id,
356 'type': ref_type,
357 'files_url': files_url,
358 })
359 return result
360
361 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
362 use_commit_id = '/' in ref_name or is_svn
363 return h.url(
364 'files_home',
365 repo_name=full_repo_name,
366 f_path=ref_name if is_svn else '',
367 revision=raw_id if use_commit_id else ref_name,
368 at=ref_name)
@@ -0,0 +1,136 b''
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.mako"/>
3 %if c.repo_commits:
4 <table class="rctable repo_summary table_disp">
5 <tr>
6
7 <th class="status" colspan="2"></th>
8 <th>${_('Commit')}</th>
9 <th>${_('Commit message')}</th>
10 <th>${_('Age')}</th>
11 <th>${_('Author')}</th>
12 <th>${_('Refs')}</th>
13 </tr>
14 %for cnt,cs in enumerate(c.repo_commits):
15 <tr class="parity${cnt%2}">
16
17 <td class="td-status">
18 %if c.statuses.get(cs.raw_id):
19 <div class="changeset-status-ico shortlog">
20 %if c.statuses.get(cs.raw_id)[2]:
21 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
22 <div class="${'flag_status %s' % c.statuses.get(cs.raw_id)[0]}"></div>
23 </a>
24 %else:
25 <a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(cs.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
26 <div class="${'flag_status %s' % c.statuses.get(cs.raw_id)[0]}"></div>
27 </a>
28 %endif
29 </div>
30 %else:
31 <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
32 %endif
33 </td>
34 <td class="td-comments">
35 %if c.comments.get(cs.raw_id,[]):
36 <a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id,anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
37 <i class="icon-comment"></i> ${len(c.comments[cs.raw_id])}
38 </a>
39 %endif
40 </td>
41 <td class="td-commit">
42 <pre><a href="${h.url('changeset_home', repo_name=c.repo_name, revision=cs.raw_id)}">${h.show_id(cs)}</a></pre>
43 </td>
44
45 <td class="td-description mid">
46 <div class="log-container truncate-wrap">
47 <div class="message truncate" id="c-${cs.raw_id}">${h.urlify_commit_message(cs.message, c.repo_name)}</div>
48 </div>
49 </td>
50
51 <td class="td-time">
52 ${h.age_component(cs.date)}
53 </td>
54 <td class="td-user author">
55 ${base.gravatar_with_user(cs.author)}
56 </td>
57
58 <td class="td-tags">
59 <div class="autoexpand">
60 %if h.is_hg(c.rhodecode_repo):
61 %for book in cs.bookmarks:
62 <span class="booktag tag" title="${_('Bookmark %s') % book}">
63 <a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
64 </span>
65 %endfor
66 %endif
67 ## tags
68 %for tag in cs.tags:
69 <span class="tagtag tag" title="${_('Tag %s') % tag}">
70 <a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
71 </span>
72 %endfor
73
74 ## branch
75 %if cs.branch:
76 <span class="branchtag tag" title="${_('Branch %s') % cs.branch}">
77 <a href="${h.url('changelog_home',repo_name=c.repo_name,branch=cs.branch)}"><i class="icon-code-fork"></i>${h.shorter(cs.branch)}</a>
78 </span>
79 %endif
80 </div>
81 </td>
82 </tr>
83 %endfor
84
85 </table>
86
87 <script type="text/javascript">
88 $(document).pjax('#shortlog_data .pager_link','#shortlog_data', {timeout: 2000, scrollTo: false });
89 $(document).on('pjax:success', function(){ timeagoActivate(); });
90 </script>
91
92 <div class="pagination-wh pagination-left">
93 ${c.repo_commits.pager('$link_previous ~2~ $link_next')}
94 </div>
95 %else:
96
97 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
98 <div class="quick_start">
99 <div class="fieldset">
100 <div class="left-label">${_('Add or upload files directly via RhodeCode:')}</div>
101 <div class="right-content">
102 <div id="add_node_id" class="add_node">
103 <a href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='', anchor='edit')}" class="btn btn-default">${_('Add New File')}</a>
104 </div>
105 </div>
106 %endif
107 </div>
108
109 %if not h.is_svn(c.rhodecode_repo):
110 <div class="fieldset">
111 <div class="left-label">${_('Push new repo:')}</div>
112 <div class="right-content">
113 <pre>
114 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
115 ${c.rhodecode_repo.alias} add README # add first file
116 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
117 ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
118 </pre>
119 </div>
120 </div>
121 <div class="fieldset">
122 <div class="left-label">${_('Existing repository?')}</div>
123 <div class="right-content">
124 <pre>
125 %if h.is_git(c.rhodecode_repo):
126 git remote add origin ${c.clone_repo_url}
127 git push -u origin master
128 %else:
129 hg push ${c.clone_repo_url}
130 %endif
131 </pre>
132 </div>
133 </div>
134 %endif
135 </div>
136 %endif
@@ -105,9 +105,14 b' class BaseAppView(object):'
105 105 raise HTTPFound(
106 106 self.request.route_path('my_account_password'))
107 107
108 def _get_local_tmpl_context(self):
108 def _get_local_tmpl_context(self, include_app_defaults=False):
109 109 c = TemplateArgs()
110 110 c.auth_user = self.request.user
111 if include_app_defaults:
112 # NOTE(marcink): after full pyramid migration include_app_defaults
113 # should be turned on by default
114 from rhodecode.lib.base import attach_context_attributes
115 attach_context_attributes(c, self.request, self.request.user.user_id)
111 116 return c
112 117
113 118 def _register_global_c(self, tmpl_args):
@@ -154,8 +159,10 b' class RepoAppView(BaseAppView):'
154 159 'Requirements are missing for repository %s: %s',
155 160 self.db_repo_name, error.message)
156 161
157 def _get_local_tmpl_context(self):
158 c = super(RepoAppView, self)._get_local_tmpl_context()
162 def _get_local_tmpl_context(self, include_app_defaults=False):
163 c = super(RepoAppView, self)._get_local_tmpl_context(
164 include_app_defaults=include_app_defaults)
165
159 166 # register common vars for this type of view
160 167 c.rhodecode_db_repo = self.db_repo
161 168 c.repo_name = self.db_repo_name
@@ -309,7 +316,7 b' class RepoTypeRoutePredicate(object):'
309 316 # _('Action not supported for %s.' % rhodecode_repo.alias)),
310 317 # category='warning')
311 318 # return redirect(
312 # url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
319 # route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
313 320
314 321 return False
315 322
@@ -123,7 +123,7 b' class HomeView(BaseAppView):'
123 123 'text': obj['name'],
124 124 'type': 'repo',
125 125 'obj': obj['dbrepo'],
126 'url': h.url('summary_home', repo_name=obj['name'])
126 'url': h.route_path('repo_summary', repo_name=obj['name'])
127 127 }
128 128 for obj in repo_iter]
129 129
@@ -17,18 +17,33 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 from rhodecode.apps._base import add_route_with_slash
20 21
21 22
22 23 def includeme(config):
23 24
24 25 # Summary
25 config.add_route(
26 name='repo_summary',
27 pattern='/{repo_name:.*?[^/]}', repo_route=True)
28
26 # NOTE(marcink): one additional route is defined in very bottom, catch
27 # all pattern
29 28 config.add_route(
30 29 name='repo_summary_explicit',
31 30 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
31 config.add_route(
32 name='repo_summary_commits',
33 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
34
35 # refs data
36 config.add_route(
37 name='repo_refs_data',
38 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
39
40 config.add_route(
41 name='repo_refs_changelog_data',
42 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
43
44 config.add_route(
45 name='repo_stats',
46 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
32 47
33 48 # Tags
34 49 config.add_route(
@@ -40,7 +55,6 b' def includeme(config):'
40 55 name='branches_home',
41 56 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
42 57
43 # Bookmarks
44 58 config.add_route(
45 59 name='bookmarks_home',
46 60 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
@@ -125,9 +139,10 b' def includeme(config):'
125 139 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
126 140
127 141 # NOTE(marcink): needs to be at the end for catch-all
128 # config.add_route(
129 # name='repo_summary',
130 # pattern='/{repo_name:.*?[^/]}', repo_route=True)
142 add_route_with_slash(
143 config,
144 name='repo_summary',
145 pattern='/{repo_name:.*?[^/]}', repo_route=True)
131 146
132 147 # Scan module for configuration decorators.
133 148 config.scan()
@@ -23,16 +23,16 b' import re'
23 23 import mock
24 24 import pytest
25 25
26 from rhodecode.controllers import summary
26 from rhodecode.apps.repository.views.repo_summary import RepoSummaryView
27 27 from rhodecode.lib import helpers as h
28 28 from rhodecode.lib.compat import OrderedDict
29 from rhodecode.lib.utils2 import AttributeDict
29 30 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
30 31 from rhodecode.model.db import Repository
31 32 from rhodecode.model.meta import Session
32 33 from rhodecode.model.repo import RepoModel
33 34 from rhodecode.model.scm import ScmModel
34 from rhodecode.tests import (
35 TestController, url, HG_REPO, assert_session_flash)
35 from rhodecode.tests import assert_session_flash
36 36 from rhodecode.tests.fixture import Fixture
37 37 from rhodecode.tests.utils import AssertResponse, repo_on_filesystem
38 38
@@ -40,14 +40,31 b' from rhodecode.tests.utils import Assert'
40 40 fixture = Fixture()
41 41
42 42
43 class TestSummaryController(TestController):
44 def test_index(self, backend, http_host_only_stub):
45 self.log_user()
43 def route_path(name, params=None, **kwargs):
44 import urllib
45
46 base_url = {
47 'repo_summary': '/{repo_name}',
48 'repo_stats': '/{repo_name}/repo_stats/{commit_id}',
49 'repo_refs_data': '/{repo_name}/refs-data',
50 'repo_refs_changelog_data': '/{repo_name}/refs-data-changelog'
51
52 }[name].format(**kwargs)
53
54 if params:
55 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
56 return base_url
57
58
59 @pytest.mark.usefixtures('app')
60 class TestSummaryView(object):
61 def test_index(self, autologin_user, backend, http_host_only_stub):
46 62 repo_id = backend.repo.repo_id
47 63 repo_name = backend.repo_name
48 64 with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy',
49 65 return_value=False):
50 response = self.app.get(url('summary_home', repo_name=repo_name))
66 response = self.app.get(
67 route_path('repo_summary', repo_name=repo_name))
51 68
52 69 # repo type
53 70 response.mustcontain(
@@ -66,11 +83,11 b' class TestSummaryController(TestControll'
66 83 'id="clone_url_id" readonly="readonly"'
67 84 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
68 85
69 def test_index_svn_without_proxy(self, backend_svn, http_host_only_stub):
70 self.log_user()
86 def test_index_svn_without_proxy(
87 self, autologin_user, backend_svn, http_host_only_stub):
71 88 repo_id = backend_svn.repo.repo_id
72 89 repo_name = backend_svn.repo_name
73 response = self.app.get(url('summary_home', repo_name=repo_name))
90 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
74 91 # clone url...
75 92 response.mustcontain(
76 93 'id="clone_url" disabled'
@@ -79,14 +96,15 b' class TestSummaryController(TestControll'
79 96 'id="clone_url_id" disabled'
80 97 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
81 98
82 def test_index_with_trailing_slash(self, autologin_user, backend,
83 http_host_only_stub):
99 def test_index_with_trailing_slash(
100 self, autologin_user, backend, http_host_only_stub):
101
84 102 repo_id = backend.repo.repo_id
85 103 repo_name = backend.repo_name
86 104 with mock.patch('rhodecode.lib.helpers.is_svn_without_proxy',
87 105 return_value=False):
88 106 response = self.app.get(
89 url('summary_home', repo_name=repo_name) + '/',
107 route_path('repo_summary', repo_name=repo_name) + '/',
90 108 status=200)
91 109
92 110 # clone url...
@@ -97,11 +115,10 b' class TestSummaryController(TestControll'
97 115 'id="clone_url_id" readonly="readonly"'
98 116 ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, ))
99 117
100 def test_index_by_id(self, backend):
101 self.log_user()
118 def test_index_by_id(self, autologin_user, backend):
102 119 repo_id = backend.repo.repo_id
103 response = self.app.get(url(
104 'summary_home', repo_name='_%s' % (repo_id,)))
120 response = self.app.get(
121 route_path('repo_summary', repo_name='_%s' % (repo_id,)))
105 122
106 123 # repo type
107 124 response.mustcontain(
@@ -112,10 +129,9 b' class TestSummaryController(TestControll'
112 129 """<i class="icon-unlock-alt">"""
113 130 )
114 131
115 def test_index_by_repo_having_id_path_in_name_hg(self):
116 self.log_user()
132 def test_index_by_repo_having_id_path_in_name_hg(self, autologin_user):
117 133 fixture.create_repo(name='repo_1')
118 response = self.app.get(url('summary_home', repo_name='repo_1'))
134 response = self.app.get(route_path('repo_summary', repo_name='repo_1'))
119 135
120 136 try:
121 137 response.mustcontain("repo_1")
@@ -123,11 +139,11 b' class TestSummaryController(TestControll'
123 139 RepoModel().delete(Repository.get_by_repo_name('repo_1'))
124 140 Session().commit()
125 141
126 def test_index_with_anonymous_access_disabled(self):
127 with fixture.anon_access(False):
128 response = self.app.get(url('summary_home', repo_name=HG_REPO),
129 status=302)
130 assert 'login' in response.location
142 def test_index_with_anonymous_access_disabled(
143 self, backend, disable_anonymous_user):
144 response = self.app.get(
145 route_path('repo_summary', repo_name=backend.repo_name), status=302)
146 assert 'login' in response.location
131 147
132 148 def _enable_stats(self, repo):
133 149 r = Repository.get_by_repo_name(repo)
@@ -174,17 +190,15 b' class TestSummaryController(TestControll'
174 190 },
175 191 }
176 192
177 def test_repo_stats(self, backend, xhr_header):
178 self.log_user()
193 def test_repo_stats(self, autologin_user, backend, xhr_header):
179 194 response = self.app.get(
180 url('repo_stats',
181 repo_name=backend.repo_name, commit_id='tip'),
195 route_path(
196 'repo_stats', repo_name=backend.repo_name, commit_id='tip'),
182 197 extra_environ=xhr_header,
183 198 status=200)
184 199 assert re.match(r'6[\d\.]+ KiB', response.json['size'])
185 200
186 def test_repo_stats_code_stats_enabled(self, backend, xhr_header):
187 self.log_user()
201 def test_repo_stats_code_stats_enabled(self, autologin_user, backend, xhr_header):
188 202 repo_name = backend.repo_name
189 203
190 204 # codes stats
@@ -192,8 +206,8 b' class TestSummaryController(TestControll'
192 206 ScmModel().mark_for_invalidation(repo_name)
193 207
194 208 response = self.app.get(
195 url('repo_stats',
196 repo_name=backend.repo_name, commit_id='tip'),
209 route_path(
210 'repo_stats', repo_name=backend.repo_name, commit_id='tip'),
197 211 extra_environ=xhr_header,
198 212 status=200)
199 213
@@ -204,7 +218,7 b' class TestSummaryController(TestControll'
204 218
205 219 def test_repo_refs_data(self, backend):
206 220 response = self.app.get(
207 url('repo_refs_data', repo_name=backend.repo_name),
221 route_path('repo_refs_data', repo_name=backend.repo_name),
208 222 status=200)
209 223
210 224 # Ensure that there is the correct amount of items in the result
@@ -221,72 +235,68 b' class TestSummaryController(TestControll'
221 235 Repository, 'scm_instance', side_effect=RepositoryRequirementError)
222 236
223 237 with scm_patcher:
224 response = self.app.get(url('summary_home', repo_name=repo_name))
238 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
225 239 assert_response = AssertResponse(response)
226 240 assert_response.element_contains(
227 241 '.main .alert-warning strong', 'Missing requirements')
228 242 assert_response.element_contains(
229 243 '.main .alert-warning',
230 'These commits cannot be displayed, because this repository'
231 ' uses the Mercurial largefiles extension, which was not enabled.')
244 'Commits cannot be displayed, because this repository '
245 'uses one or more extensions, which was not enabled.')
232 246
233 247 def test_missing_requirements_page_does_not_contains_switch_to(
234 self, backend):
235 self.log_user()
248 self, autologin_user, backend):
236 249 repo_name = backend.repo_name
237 250 scm_patcher = mock.patch.object(
238 251 Repository, 'scm_instance', side_effect=RepositoryRequirementError)
239 252
240 253 with scm_patcher:
241 response = self.app.get(url('summary_home', repo_name=repo_name))
254 response = self.app.get(route_path('repo_summary', repo_name=repo_name))
242 255 response.mustcontain(no='Switch To')
243 256
244 257
245 @pytest.mark.usefixtures('pylonsapp')
246 class TestSwitcherReferenceData:
258 @pytest.mark.usefixtures('app')
259 class TestRepoLocation(object):
247 260
248 def test_creates_reference_urls_based_on_name(self):
249 references = {
250 'name': 'commit_id',
251 }
252 controller = summary.SummaryController()
253 is_svn = False
254 result = controller._switcher_reference_data(
255 'repo_name', references, is_svn)
256 expected_url = h.url(
257 'files_home', repo_name='repo_name', revision='name',
258 at='name')
259 assert result[0]['files_url'] == expected_url
261 @pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii'])
262 def test_manual_delete(self, autologin_user, backend, suffix, csrf_token):
263 repo = backend.create_repo(name_suffix=suffix)
264 repo_name = repo.repo_name
265
266 # delete from file system
267 RepoModel()._delete_filesystem_repo(repo)
260 268
261 def test_urls_contain_commit_id_if_slash_in_name(self):
262 references = {
263 'name/with/slash': 'commit_id',
264 }
265 controller = summary.SummaryController()
266 is_svn = False
267 result = controller._switcher_reference_data(
268 'repo_name', references, is_svn)
269 expected_url = h.url(
270 'files_home', repo_name='repo_name', revision='commit_id',
271 at='name/with/slash')
272 assert result[0]['files_url'] == expected_url
269 # test if the repo is still in the database
270 new_repo = RepoModel().get_by_repo_name(repo_name)
271 assert new_repo.repo_name == repo_name
273 272
274 def test_adds_reference_to_path_for_svn(self):
275 references = {
276 'name/with/slash': 'commit_id',
277 }
278 controller = summary.SummaryController()
279 is_svn = True
280 result = controller._switcher_reference_data(
281 'repo_name', references, is_svn)
282 expected_url = h.url(
283 'files_home', repo_name='repo_name', f_path='name/with/slash',
284 revision='commit_id', at='name/with/slash')
285 assert result[0]['files_url'] == expected_url
273 # check if repo is not in the filesystem
274 assert not repo_on_filesystem(repo_name)
275 self.assert_repo_not_found_redirect(repo_name)
276
277 def assert_repo_not_found_redirect(self, repo_name):
278 # run the check page that triggers the other flash message
279 response = self.app.get(h.url('repo_check_home', repo_name=repo_name))
280 assert_session_flash(
281 response, 'The repository at %s cannot be located.' % repo_name)
286 282
287 283
288 @pytest.mark.usefixtures('pylonsapp')
289 class TestCreateReferenceData:
284 @pytest.fixture()
285 def summary_view(context_stub, request_stub, user_util):
286 """
287 Bootstrap view to test the view functions
288 """
289 request_stub.matched_route = AttributeDict(name='test_view')
290
291 request_stub.user = user_util.create_user().AuthUser
292 request_stub.db_repo = user_util.create_repo()
293
294 view = RepoSummaryView(context=context_stub, request=request_stub)
295 return view
296
297
298 @pytest.mark.usefixtures('app')
299 class TestCreateReferenceData(object):
290 300
291 301 @pytest.fixture
292 302 def example_refs(self):
@@ -297,14 +307,13 b' class TestCreateReferenceData:'
297 307 ]
298 308 return example_refs
299 309
300 def test_generates_refs_based_on_commit_ids(self, example_refs):
310 def test_generates_refs_based_on_commit_ids(self, example_refs, summary_view):
301 311 repo = mock.Mock()
302 312 repo.name = 'test-repo'
303 313 repo.alias = 'git'
304 314 full_repo_name = 'pytest-repo-group/' + repo.name
305 controller = summary.SummaryController()
306 315
307 result = controller._create_reference_data(
316 result = summary_view._create_reference_data(
308 317 repo, full_repo_name, example_refs)
309 318
310 319 expected_files_url = '/{}/files/'.format(full_repo_name)
@@ -333,13 +342,13 b' class TestCreateReferenceData:'
333 342 }]
334 343 assert result == expected_result
335 344
336 def test_generates_refs_with_path_for_svn(self, example_refs):
345 def test_generates_refs_with_path_for_svn(self, example_refs, summary_view):
337 346 repo = mock.Mock()
338 347 repo.name = 'test-repo'
339 348 repo.alias = 'svn'
340 349 full_repo_name = 'pytest-repo-group/' + repo.name
341 controller = summary.SummaryController()
342 result = controller._create_reference_data(
350
351 result = summary_view._create_reference_data(
343 352 repo, full_repo_name, example_refs)
344 353
345 354 expected_files_url = '/{}/files/'.format(full_repo_name)
@@ -373,35 +382,9 b' class TestCreateReferenceData:'
373 382 assert result == expected_result
374 383
375 384
376 @pytest.mark.usefixtures("app")
377 class TestRepoLocation:
378
379 @pytest.mark.parametrize("suffix", [u'', u'ąęł'], ids=['', 'non-ascii'])
380 def test_manual_delete(self, autologin_user, backend, suffix, csrf_token):
381 repo = backend.create_repo(name_suffix=suffix)
382 repo_name = repo.repo_name
383
384 # delete from file system
385 RepoModel()._delete_filesystem_repo(repo)
386
387 # test if the repo is still in the database
388 new_repo = RepoModel().get_by_repo_name(repo_name)
389 assert new_repo.repo_name == repo_name
385 class TestCreateFilesUrl(object):
390 386
391 # check if repo is not in the filesystem
392 assert not repo_on_filesystem(repo_name)
393 self.assert_repo_not_found_redirect(repo_name)
394
395 def assert_repo_not_found_redirect(self, repo_name):
396 # run the check page that triggers the other flash message
397 response = self.app.get(url('repo_check_home', repo_name=repo_name))
398 assert_session_flash(
399 response, 'The repository at %s cannot be located.' % repo_name)
400
401
402 class TestCreateFilesUrl(object):
403 def test_creates_non_svn_url(self):
404 controller = summary.SummaryController()
387 def test_creates_non_svn_url(self, summary_view):
405 388 repo = mock.Mock()
406 389 repo.name = 'abcde'
407 390 full_repo_name = 'test-repo-group/' + repo.name
@@ -409,16 +392,15 b' class TestCreateFilesUrl(object):'
409 392 raw_id = 'deadbeef0123456789'
410 393 is_svn = False
411 394
412 with mock.patch.object(summary.h, 'url') as url_mock:
413 result = controller._create_files_url(
395 with mock.patch('rhodecode.lib.helpers.url') as url_mock:
396 result = summary_view._create_files_url(
414 397 repo, full_repo_name, ref_name, raw_id, is_svn)
415 398 url_mock.assert_called_once_with(
416 399 'files_home', repo_name=full_repo_name, f_path='',
417 400 revision=ref_name, at=ref_name)
418 401 assert result == url_mock.return_value
419 402
420 def test_creates_svn_url(self):
421 controller = summary.SummaryController()
403 def test_creates_svn_url(self, summary_view):
422 404 repo = mock.Mock()
423 405 repo.name = 'abcde'
424 406 full_repo_name = 'test-repo-group/' + repo.name
@@ -426,16 +408,15 b' class TestCreateFilesUrl(object):'
426 408 raw_id = 'deadbeef0123456789'
427 409 is_svn = True
428 410
429 with mock.patch.object(summary.h, 'url') as url_mock:
430 result = controller._create_files_url(
411 with mock.patch('rhodecode.lib.helpers.url') as url_mock:
412 result = summary_view._create_files_url(
431 413 repo, full_repo_name, ref_name, raw_id, is_svn)
432 414 url_mock.assert_called_once_with(
433 415 'files_home', repo_name=full_repo_name, f_path=ref_name,
434 416 revision=raw_id, at=ref_name)
435 417 assert result == url_mock.return_value
436 418
437 def test_name_has_slashes(self):
438 controller = summary.SummaryController()
419 def test_name_has_slashes(self, summary_view):
439 420 repo = mock.Mock()
440 421 repo.name = 'abcde'
441 422 full_repo_name = 'test-repo-group/' + repo.name
@@ -443,8 +424,8 b' class TestCreateFilesUrl(object):'
443 424 raw_id = 'deadbeef0123456789'
444 425 is_svn = False
445 426
446 with mock.patch.object(summary.h, 'url') as url_mock:
447 result = controller._create_files_url(
427 with mock.patch('rhodecode.lib.helpers.url') as url_mock:
428 result = summary_view._create_files_url(
448 429 repo, full_repo_name, ref_name, raw_id, is_svn)
449 430 url_mock.assert_called_once_with(
450 431 'files_home', repo_name=full_repo_name, f_path='', revision=raw_id,
@@ -463,42 +444,39 b' class TestReferenceItems(object):'
463 444 def _format_function(name, id_):
464 445 return 'format_function_{}_{}'.format(name, id_)
465 446
466 def test_creates_required_amount_of_items(self):
447 def test_creates_required_amount_of_items(self, summary_view):
467 448 amount = 100
468 449 refs = {
469 450 'ref{}'.format(i): '{0:040d}'.format(i)
470 451 for i in range(amount)
471 452 }
472 453
473 controller = summary.SummaryController()
474
475 url_patcher = mock.patch.object(
476 controller, '_create_files_url')
477 svn_patcher = mock.patch.object(
478 summary.h, 'is_svn', return_value=False)
454 url_patcher = mock.patch.object(summary_view, '_create_files_url')
455 svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn',
456 return_value=False)
479 457
480 458 with url_patcher as url_mock, svn_patcher:
481 result = controller._create_reference_items(
459 result = summary_view._create_reference_items(
482 460 self.repo, self.repo_full_name, refs, self.ref_type,
483 461 self._format_function)
484 462 assert len(result) == amount
485 463 assert url_mock.call_count == amount
486 464
487 def test_single_item_details(self):
465 def test_single_item_details(self, summary_view):
488 466 ref_name = 'ref1'
489 467 ref_id = 'deadbeef'
490 468 refs = {
491 469 ref_name: ref_id
492 470 }
493 471
494 controller = summary.SummaryController()
472 svn_patcher = mock.patch('rhodecode.lib.helpers.is_svn',
473 return_value=False)
474
495 475 url_patcher = mock.patch.object(
496 controller, '_create_files_url', return_value=self.fake_url)
497 svn_patcher = mock.patch.object(
498 summary.h, 'is_svn', return_value=False)
476 summary_view, '_create_files_url', return_value=self.fake_url)
499 477
500 478 with url_patcher as url_mock, svn_patcher:
501 result = controller._create_reference_items(
479 result = summary_view._create_reference_items(
502 480 self.repo, self.repo_full_name, refs, self.ref_type,
503 481 self._format_function)
504 482
@@ -39,11 +39,15 b' from routes.middleware import RoutesMidd'
39 39 import routes.util
40 40
41 41 import rhodecode
42
42 43 from rhodecode.model import meta
43 44 from rhodecode.config import patches
44 45 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 46 from rhodecode.config.environment import (
46 47 load_environment, load_pyramid_environment)
48
49 from rhodecode.lib.vcs import VCSCommunicationError
50 from rhodecode.lib.exceptions import VCSServerUnavailable
47 51 from rhodecode.lib.middleware import csrf
48 52 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 53 from rhodecode.lib.middleware.error_handling import (
@@ -51,7 +55,7 b' from rhodecode.lib.middleware.error_hand'
51 55 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 56 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 57 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
58 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
55 59 from rhodecode.subscribers import (
56 60 scan_repositories_if_enabled, write_js_routes_if_enabled,
57 61 write_metadata_if_needed)
@@ -221,7 +225,6 b' def add_pylons_compat_data(registry, glo'
221 225
222 226 def error_handler(exception, request):
223 227 import rhodecode
224 from rhodecode.lib.utils2 import AttributeDict
225 228 from rhodecode.lib import helpers
226 229
227 230 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
@@ -230,6 +233,8 b' def error_handler(exception, request):'
230 233 # prefer original exception for the response since it may have headers set
231 234 if isinstance(exception, HTTPException):
232 235 base_response = exception
236 elif isinstance(exception, VCSCommunicationError):
237 base_response = VCSServerUnavailable()
233 238
234 239 def is_http_error(response):
235 240 # error which should have traceback
@@ -257,6 +262,7 b' def error_handler(exception, request):'
257 262 if hasattr(base_response, 'causes'):
258 263 c.causes = base_response.causes
259 264 c.messages = helpers.flash.pop_messages()
265
260 266 response = render_to_response(
261 267 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
262 268 response=base_response)
@@ -404,7 +410,6 b' def wrap_app_in_wsgi_middlewares(pyramid'
404 410 pool = meta.Base.metadata.bind.engine.pool
405 411 log.debug('sa pool status: %s', pool.status())
406 412
407
408 413 return pyramid_app_with_cleanup
409 414
410 415
@@ -117,8 +117,9 b' class JSRoutesMapper(Mapper):'
117 117
118 118 def make_map(config):
119 119 """Create, configure and return the routes Mapper"""
120 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
121 always_scan=config['debug'])
120 rmap = JSRoutesMapper(
121 directory=config['pylons.paths']['controllers'],
122 always_scan=config['debug'])
122 123 rmap.minimization = False
123 124 rmap.explicit = False
124 125
@@ -609,18 +610,6 b' def make_map(config):'
609 610 controller='admin/repos', action='repo_check',
610 611 requirements=URL_NAME_REQUIREMENTS)
611 612
612 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
613 controller='summary', action='repo_stats',
614 conditions={'function': check_repo},
615 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
616
617 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
618 controller='summary', action='repo_refs_data',
619 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
620 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
621 controller='summary', action='repo_refs_changelog_data',
622 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
623
624 613 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
625 614 controller='changeset', revision='tip',
626 615 conditions={'function': check_repo},
@@ -834,19 +823,10 b' def make_map(config):'
834 823 conditions={'function': check_repo, 'method': ['DELETE']},
835 824 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
836 825
837 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
838 controller='summary', conditions={'function': check_repo},
839 requirements=URL_NAME_REQUIREMENTS)
840
841 826 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
842 827 controller='changelog', conditions={'function': check_repo},
843 828 requirements=URL_NAME_REQUIREMENTS)
844 829
845 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
846 controller='changelog', action='changelog_summary',
847 conditions={'function': check_repo},
848 requirements=URL_NAME_REQUIREMENTS)
849
850 830 rmap.connect('changelog_file_home',
851 831 '/{repo_name}/changelog/{revision}/{f_path}',
852 832 controller='changelog', f_path=None,
@@ -999,19 +979,4 b' def make_map(config):'
999 979 conditions={'function': check_repo},
1000 980 requirements=URL_NAME_REQUIREMENTS)
1001 981
1002 # catch all, at the end
1003 _connect_with_slash(
1004 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1005 controller='summary', action='index',
1006 conditions={'function': check_repo},
1007 requirements=URL_NAME_REQUIREMENTS)
1008
1009 982 return rmap
1010
1011
1012 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1013 """
1014 Connect a route with an optional trailing slash in `path`.
1015 """
1016 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1017 mapper.connect(name, path, *args, **kwargs)
@@ -274,9 +274,9 b' class ReposController(BaseRepoController'
274 274 h.flash(_('Created repository %s from %s')
275 275 % (repo.repo_name, clone_uri), category='success')
276 276 else:
277 repo_url = h.link_to(repo.repo_name,
278 h.url('summary_home',
279 repo_name=repo.repo_name))
277 repo_url = h.link_to(
278 repo.repo_name,
279 h.route_path('repo_summary',repo_name=repo.repo_name))
280 280 fork = repo.fork
281 281 if fork:
282 282 fork_name = fork.repo_name
@@ -366,7 +366,7 b' class ReposController(BaseRepoController'
366 366 log.exception("Exception during unlocking")
367 367 h.flash(_('An error occurred during unlocking'),
368 368 category='error')
369 return redirect(url('summary_home', repo_name=repo_name))
369 return redirect(h.route_path('repo_summary', repo_name=repo_name))
370 370
371 371 @HasRepoPermissionAllDecorator('repository.admin')
372 372 @auth.CSRFRequired()
@@ -46,27 +46,6 b' log = logging.getLogger(__name__)'
46 46 DEFAULT_CHANGELOG_SIZE = 20
47 47
48 48
49 def _load_changelog_summary():
50 p = safe_int(request.GET.get('page'), 1)
51 size = safe_int(request.GET.get('size'), 10)
52
53 def url_generator(**kw):
54 return url('summary_home',
55 repo_name=c.rhodecode_db_repo.repo_name, size=size, **kw)
56
57 pre_load = ['author', 'branch', 'date', 'message']
58 try:
59 collection = c.rhodecode_repo.get_commits(pre_load=pre_load)
60 except EmptyRepositoryError:
61 collection = c.rhodecode_repo
62
63 c.repo_commits = RepoPage(
64 collection, page=p, items_per_page=size, url=url_generator)
65 page_ids = [x.raw_id for x in c.repo_commits]
66 c.comments = c.rhodecode_db_repo.get_comments(page_ids)
67 c.statuses = c.rhodecode_db_repo.statuses(page_ids)
68
69
70 49 class ChangelogController(BaseRepoController):
71 50
72 51 def __before__(self):
@@ -211,7 +190,7 b' class ChangelogController(BaseRepoContro'
211 190
212 191 except EmptyRepositoryError as e:
213 192 h.flash(safe_str(e), category='warning')
214 return redirect(url('summary_home', repo_name=repo_name))
193 return redirect(h.route_path('repo_summary', repo_name=repo_name))
215 194 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
216 195 msg = safe_str(e)
217 196 log.exception(msg)
@@ -279,12 +258,3 b' class ChangelogController(BaseRepoContro'
279 258 c.rhodecode_repo, c.pagination,
280 259 prev_data=prev_data, next_data=next_data)
281 260 return render('changelog/changelog_elements.mako')
282
283 @LoginRequired()
284 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
285 'repository.admin')
286 def changelog_summary(self, repo_name):
287 if request.environ.get('HTTP_X_PJAX'):
288 _load_changelog_summary()
289 return render('changelog/changelog_summary_data.mako')
290 raise HTTPNotFound()
@@ -63,14 +63,14 b' class CompareController(BaseRepoControll'
63 63 return repo.scm_instance().EMPTY_COMMIT
64 64 h.flash(h.literal(_('There are no commits yet')),
65 65 category='warning')
66 redirect(url('summary_home', repo_name=repo.repo_name))
66 redirect(h.route_path('repo_summary', repo_name=repo.repo_name))
67 67
68 68 except RepositoryError as e:
69 69 msg = safe_str(e)
70 70 log.exception(msg)
71 71 h.flash(msg, category='warning')
72 72 if not partial:
73 redirect(h.url('summary_home', repo_name=repo.repo_name))
73 redirect(h.route_path('repo_summary', repo_name=repo.repo_name))
74 74 raise HTTPBadRequest()
75 75
76 76 @LoginRequired()
@@ -113,7 +113,7 b' class FeedController(BaseRepoController)'
113 113 def _generate_feed(cache_key):
114 114 feed = Atom1Feed(
115 115 title=self.title % repo_name,
116 link=url('summary_home', repo_name=repo_name, qualified=True),
116 link=h.route_url('repo_summary', repo_name=repo_name),
117 117 description=self.description % repo_name,
118 118 language=self.language,
119 119 ttl=self.ttl
@@ -150,8 +150,7 b' class FeedController(BaseRepoController)'
150 150 def _generate_feed(cache_key):
151 151 feed = Rss201rev2Feed(
152 152 title=self.title % repo_name,
153 link=url('summary_home', repo_name=repo_name,
154 qualified=True),
153 link=h.route_url('repo_summary', repo_name=repo_name),
155 154 description=self.description % repo_name,
156 155 language=self.language,
157 156 ttl=self.ttl
@@ -101,7 +101,7 b' class FilesController(BaseRepoController'
101 101 add_new = ""
102 102 h.flash(h.literal(
103 103 _('There are no files yet. %s') % add_new), category='warning')
104 redirect(h.url('summary_home', repo_name=repo_name))
104 redirect(h.route_path('repo_summary', repo_name=repo_name))
105 105 except (CommitDoesNotExistError, LookupError):
106 106 msg = _('No such commit exists for this repository')
107 107 h.flash(msg, category='error')
@@ -669,14 +669,14 b' class FilesController(BaseRepoController'
669 669
670 670 # If there's no commit, redirect to repo summary
671 671 if type(c.commit) is EmptyCommit:
672 redirect_url = "summary_home"
672 redirect_url = h.route_path('repo_summary', repo_name=c.repo_name)
673 673 else:
674 redirect_url = "changeset_home"
674 redirect_url = url("changeset_home", repo_name=c.repo_name,
675 revision='tip')
675 676
676 677 if not filename:
677 678 h.flash(_('No filename'), category='warning')
678 return redirect(url(redirect_url, repo_name=c.repo_name,
679 revision='tip'))
679 return redirect(redirect_url)
680 680
681 681 # extract the location from filename,
682 682 # allows using foo/bar.txt syntax to create subdirectories
@@ -85,7 +85,7 b' class PullrequestsController(BaseRepoCon'
85 85 except EmptyRepositoryError:
86 86 h.flash(h.literal(_('There are no commits yet')),
87 87 category='warning')
88 redirect(url('summary_home', repo_name=source_repo.repo_name))
88 redirect(h.route_path('repo_summary', repo_name=source_repo.repo_name))
89 89
90 90 commit_id = request.GET.get('commit')
91 91 branch_ref = request.GET.get('branch')
@@ -161,8 +161,9 b' class ActionParser(object):'
161 161 return action_map
162 162
163 163 def get_fork_name(self):
164 from rhodecode.lib import helpers as h
164 165 repo_name = self.action_params
165 _url = url('summary_home', repo_name=repo_name)
166 _url = h.route_path('repo_summary', repo_name=repo_name)
166 167 return _('fork name %s') % link_to(self.action_params, _url)
167 168
168 169 def get_user_name(self):
@@ -1342,7 +1342,7 b' class HasAcceptedRepoType(object):'
1342 1342 _('Action not supported for %s.' % rhodecode_repo.alias)),
1343 1343 category='warning')
1344 1344 return redirect(
1345 url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
1345 h.route_path('repo_summary', repo_name=cls.rhodecode_db_repo.repo_name))
1346 1346
1347 1347
1348 1348 class PermsDecorator(object):
@@ -580,7 +580,7 b' class BaseRepoController(BaseController)'
580 580 'Requirements are missing for repository %s: %s',
581 581 c.repo_name, error.message)
582 582
583 summary_url = url('summary_home', repo_name=c.repo_name)
583 summary_url = h.route_path('repo_summary', repo_name=c.repo_name)
584 584 statistics_url = url('edit_repo_statistics', repo_name=c.repo_name)
585 585 settings_update_url = url('repo', repo_name=c.repo_name)
586 586 path = request.path
@@ -1538,7 +1538,7 b' def breadcrumb_repo_link(repo):'
1538 1538 link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name))
1539 1539 for group in repo.groups_with_parents
1540 1540 ] + [
1541 link_to(repo.just_name, url('summary_home', repo_name=repo.repo_name))
1541 link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name))
1542 1542 ]
1543 1543
1544 1544 return literal(' &raquo; '.join(path))
@@ -268,8 +268,7 b' class CommentsModel(BaseModel):'
268 268
269 269 target_repo_url = h.link_to(
270 270 repo.repo_name,
271 h.url('summary_home',
272 repo_name=repo.repo_name, qualified=True))
271 h.route_url('repo_summary', repo_name=repo.repo_name))
273 272
274 273 # commit specifics
275 274 kwargs.update({
@@ -300,13 +299,11 b' class CommentsModel(BaseModel):'
300 299 qualified=True,)
301 300
302 301 # set some variables for email notification
303 pr_target_repo_url = h.url(
304 'summary_home', repo_name=pr_target_repo.repo_name,
305 qualified=True)
302 pr_target_repo_url = h.route_url(
303 'repo_summary', repo_name=pr_target_repo.repo_name)
306 304
307 pr_source_repo_url = h.url(
308 'summary_home', repo_name=pr_source_repo.repo_name,
309 qualified=True)
305 pr_source_repo_url = h.route_url(
306 'repo_summary', repo_name=pr_source_repo.repo_name)
310 307
311 308 # pull request specifics
312 309 kwargs.update({
@@ -1765,6 +1765,7 b' class Repository(Base, BaseModel):'
1765 1765 # TODO: mikhail: Here there is an anti-pattern, we probably need to
1766 1766 # move this methods on models level.
1767 1767 from rhodecode.model.settings import SettingsModel
1768 from rhodecode.model.repo import RepoModel
1768 1769
1769 1770 repo = self
1770 1771 _user_id, _time, _reason = self.locked
@@ -1774,7 +1775,7 b' class Repository(Base, BaseModel):'
1774 1775 'repo_name': repo.repo_name,
1775 1776 'repo_type': repo.repo_type,
1776 1777 'clone_uri': repo.clone_uri or '',
1777 'url': repo.home_url(),
1778 'url': RepoModel().get_url(self),
1778 1779 'private': repo.private,
1779 1780 'created_on': repo.created_on,
1780 1781 'description': repo.description,
@@ -1935,10 +1936,6 b' class Repository(Base, BaseModel):'
1935 1936 repo_name=self.repo_name,
1936 1937 repo_id=self.repo_id, **override)
1937 1938
1938 def home_url(self):
1939 request = get_current_request()
1940 return request.route_url('repo_summary', repo_name=self.repo_name)
1941
1942 1939 def set_state(self, state):
1943 1940 self.repo_state = state
1944 1941 Session().add(self)
@@ -999,15 +999,11 b' class PullRequestModel(BaseModel):'
999 999 qualified=True,)
1000 1000
1001 1001 # set some variables for email notification
1002 pr_target_repo_url = h.url(
1003 'summary_home',
1004 repo_name=pr_target_repo.repo_name,
1005 qualified=True)
1002 pr_target_repo_url = h.route_url(
1003 'repo_summary', repo_name=pr_target_repo.repo_name)
1006 1004
1007 pr_source_repo_url = h.url(
1008 'summary_home',
1009 repo_name=pr_source_repo.repo_name,
1010 qualified=True)
1005 pr_source_repo_url = h.route_url(
1006 'repo_summary', repo_name=pr_source_repo.repo_name)
1011 1007
1012 1008 # pull request specifics
1013 1009 pull_request_commits = [
@@ -30,6 +30,7 b' import time'
30 30 import traceback
31 31 from datetime import datetime, timedelta
32 32
33 from pyramid.threadlocal import get_current_request
33 34 from zope.cachedescriptors.property import Lazy as LazyProperty
34 35
35 36 from rhodecode import events
@@ -154,9 +155,10 b' class RepoModel(BaseModel):'
154 155 repos = Repository.query().filter(Repository.group == root).all()
155 156 return repos
156 157
157 def get_url(self, repo):
158 return h.url('summary_home', repo_name=safe_str(repo.repo_name),
159 qualified=True)
158 def get_url(self, repo, request=None):
159 if not request:
160 request = get_current_request()
161 return request.route_url('repo_summary', repo_name=safe_str(repo.repo_name))
160 162
161 163 @classmethod
162 164 def update_repoinfo(cls, repositories=None):
@@ -215,6 +215,7 b''
215 215 float: left;
216 216 display: block;
217 217 position: relative;
218 width: 100%;
218 219
219 220 // adds some space to make copy and paste easier
220 221 .left-label,
@@ -62,7 +62,7 b' function setRCMouseBindings(repoName, re'
62 62 // nav in repo context
63 63 Mousetrap.bind(['g s'], function(e) {
64 64 window.location = pyroutes.url(
65 'summary_home', {'repo_name': repoName});
65 'repo_summary', {'repo_name': repoName});
66 66 });
67 67 Mousetrap.bind(['g c'], function(e) {
68 68 window.location = pyroutes.url(
@@ -18,9 +18,6 b' function registerRCRoutes() {'
18 18 pyroutes.register('gists', '/_admin/gists', []);
19 19 pyroutes.register('new_gist', '/_admin/gists/new', []);
20 20 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
21 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
22 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
23 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
24 21 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
25 22 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
26 23 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
@@ -46,8 +43,6 b' function registerRCRoutes() {'
46 43 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
47 44 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 45 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
49 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
50 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
51 46 pyroutes.register('favicon', '/favicon.ico', []);
52 47 pyroutes.register('robots', '/robots.txt', []);
53 48 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
@@ -99,8 +94,11 b' function registerRCRoutes() {'
99 94 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
100 95 pyroutes.register('repo_list_data', '/_repos', []);
101 96 pyroutes.register('goto_switcher_data', '/_goto_data', []);
102 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
103 97 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
98 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
99 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
100 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
101 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
104 102 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
105 103 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
106 104 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
@@ -122,6 +120,8 b' function registerRCRoutes() {'
122 120 pyroutes.register('strip', '/%(repo_name)s/settings/strip', ['repo_name']);
123 121 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
124 122 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
123 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
124 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
125 125 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
126 126 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
127 127 pyroutes.register('search', '/_admin/search', []);
@@ -45,7 +45,7 b''
45 45 </td>
46 46 <td class="td-componentname">
47 47 %if l.repository is not None:
48 ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
48 ${h.link_to(l.repository.repo_name, h.route_path('repo_summary',repo_name=l.repository.repo_name))}
49 49 %else:
50 50 ${l.repository_name}
51 51 %endif
@@ -160,7 +160,7 b''
160 160 </td>
161 161 <td class="td-scope">
162 162 %if integration.repo:
163 <a href="${h.url('summary_home', repo_name=integration.repo.repo_name)}">
163 <a href="${h.route_path('repo_summary', repo_name=integration.repo.repo_name)}">
164 164 ${_('repo')}:${integration.repo.repo_name}
165 165 </a>
166 166 %elif integration.repo_group:
@@ -48,12 +48,12 b''
48 48 if (jsonResponse === undefined) {
49 49 setTimeout(function () {
50 50 // we might have a backend problem, try dashboard again
51 window.location = "${h.url('summary_home', repo_name = c.repo)}";
51 window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
52 52 }, 3000);
53 53 } else {
54 54 if (skipCheck || jsonResponse.result === true) {
55 55 // success, means go to dashboard
56 window.location = "${h.url('summary_home', repo_name = c.repo)}";
56 window.location = "${h.route_path('repo_summary', repo_name = c.repo)}";
57 57 } else {
58 58 // Schedule the next request when the current one's complete
59 59 setTimeout(worker, 1000);
@@ -27,7 +27,7 b''
27 27 ${h.secure_form(h.route_path('edit_repo_advanced_fork', repo_name=c.repo_info.repo_name), method='POST')}
28 28
29 29 % if c.repo_info.fork:
30 <div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h.url('summary_home', repo_name=c.repo_info.fork.repo_name))})}
30 <div class="panel-body-title-text">${h.literal(_('This repository is a fork of %(repo_link)s') % {'repo_link': h.link_to_if(c.has_origin_repo_read_perm,c.repo_info.fork.repo_name, h.route_path('repo_summary', repo_name=c.repo_info.fork.repo_name))})}
31 31 | <button class="btn btn-link btn-danger" type="submit">Remove fork reference</button></div>
32 32 % endif
33 33
@@ -52,6 +52,6 b''
52 52 <script>
53 53 $('#check_for_update').click(function(e){
54 54 $('#update_notice').show();
55 $('#update_notice').load("${h.route_path('admin_settings_system_update',version=c.rhodecode_version, platform=c.platform)}");
55 $('#update_notice').load("${h.route_path('admin_settings_system_update')}");
56 56 })
57 57 </script>
@@ -186,7 +186,7 b''
186 186 %if repo_instance.fork:
187 187 <p>
188 188 <i class="icon-code-fork"></i> ${_('Fork of')}
189 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
189 <a href="${h.route_path('repo_summary',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
190 190 </p>
191 191 %endif
192 192
@@ -225,7 +225,7 b''
225 225 <div id="context-bar">
226 226 <div class="wrapper">
227 227 <ul id="context-pages" class="horizontal-list navigation">
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
229 229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
230 230 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
231 231 <li class="${is_active('compare')}">
@@ -124,7 +124,7 b''
124 124 <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
125 125 <td class="td-componentname">
126 126 %if section == 'repositories':
127 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
127 <a href="${h.route_path('repo_summary',repo_name=k)}">${k}</a>
128 128 %elif section == 'repositories_groups':
129 129 <a href="${h.route_path('repo_group_home', repo_group_name=k)}">${k}</a>
130 130 %elif section == 'user_groups':
@@ -9,7 +9,7 b''
9 9 <div class="menu_items_container hidden">
10 10 <ul class="menu_items">
11 11 <li>
12 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
12 <a title="${_('Summary')}" href="${h.route_path('repo_summary',repo_name=repo_name)}">
13 13 <span>${_('Summary')}</span>
14 14 </a>
15 15 </li>
@@ -42,7 +42,7 b''
42 42 %>
43 43 <div class="${'repo_state_pending' if rstate == 'repo_state_pending' else ''} truncate">
44 44 ##NAME
45 <a href="${h.route_path('edit_repo',repo_name=name) if admin else h.url('summary_home',repo_name=name)}">
45 <a href="${h.route_path('edit_repo',repo_name=name) if admin else h.route_path('repo_summary',repo_name=name)}">
46 46
47 47 ##TYPE OF REPO
48 48 %if h.is_hg(rtype):
@@ -64,7 +64,7 b''
64 64 ${get_name(name)}
65 65 </a>
66 66 %if fork_of:
67 <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
67 <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
68 68 %endif
69 69 %if rstate == 'repo_state_pending':
70 70 <i class="icon-cogs" title="${_('Repository creating in progress...')}"></i>
@@ -282,7 +282,7 b''
282 282
283 283 <%def name="pullrequest_target_repo(repo_name)">
284 284 <div class="truncate">
285 ${h.link_to(repo_name,h.url('summary_home',repo_name=repo_name))}
285 ${h.link_to(repo_name,h.route_path('repo_summary',repo_name=repo_name))}
286 286 </div>
287 287 </%def>
288 288 <%def name="pullrequest_status(status)">
@@ -16,7 +16,7 b''
16 16 ${base.gravatar_with_user(f.user.email, 16)}
17 17 </td>
18 18 <td class="td-componentname">
19 ${h.link_to(f.repo_name,h.url('summary_home',repo_name=f.repo_name))}
19 ${h.link_to(f.repo_name,h.route_path('repo_summary',repo_name=f.repo_name))}
20 20 </td>
21 21 <td class="td-description">
22 22 <div class="truncate">${f.description}</div>
@@ -20,7 +20,7 b''
20 20 <span class="journal_repo_name">
21 21 %if entry.repository is not None:
22 22 ${h.link_to(entry.repository.repo_name,
23 h.url('summary_home',repo_name=entry.repository.repo_name))}
23 h.route_path('repo_summary',repo_name=entry.repository.repo_name))}
24 24 %else:
25 25 ${entry.repository_name}
26 26 %endif
@@ -81,7 +81,7 b''
81 81 %endif
82 82 </span>
83 83 <span class="clone-url">
84 <a href="${h.url('summary_home', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
84 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.clone_url()}</a>
85 85 </span>
86 86 <br/>
87 87 % if c.ancestor_commit:
@@ -113,7 +113,7 b''
113 113 %endif
114 114 </span>
115 115 <span class="clone-url">
116 <a href="${h.url('summary_home', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
116 <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.clone_url()}</a>
117 117 </span>
118 118 </div>
119 119 </div>
@@ -27,7 +27,7 b''
27 27 %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
28 28 <i class="icon-svn"></i>
29 29 %endif
30 ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
30 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
31 31 </td>
32 32 <td class="td-commit">
33 33 ${h.link_to(h._shorten_commit_id(entry['commit_id']),
@@ -49,7 +49,7 b' for line_number in matching_lines:'
49 49 %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
50 50 <i class="icon-svn"></i>
51 51 %endif
52 ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
52 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
53 53 </h2>
54 54 <div class="stats">
55 55 ${h.link_to(h.literal(entry['f_path']), h.url('files_home',repo_name=entry['repository'],revision=entry.get('commit_id', 'tip'),f_path=entry['f_path']))}
@@ -16,7 +16,7 b''
16 16 %elif h.get_repo_type_by_name(entry.get('repository')) == 'svn':
17 17 <i class="icon-svn"></i>
18 18 %endif
19 ${h.link_to(entry['repository'], h.url('summary_home',repo_name=entry['repository']))}
19 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
20 20 </td>
21 21 <td class="td-componentname">
22 22 ${h.link_to(h.literal(entry['f_path']),
@@ -1,28 +1,28 b''
1 1 <%def name="refs_counters(branches, closed_branches, tags, bookmarks)">
2 2 <span class="branchtag tag">
3 3 <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
4 <i class="icon-branch"></i>${ungettext(
4 <i class="icon-branch"></i>${_ungettext(
5 5 '%(num)s Branch','%(num)s Branches', len(branches)) % {'num': len(branches)}}</a>
6 6 </span>
7 7
8 8 %if closed_branches:
9 9 <span class="branchtag tag">
10 10 <a href="${h.route_path('branches_home',repo_name=c.repo_name)}" class="childs">
11 <i class="icon-branch"></i>${ungettext(
11 <i class="icon-branch"></i>${_ungettext(
12 12 '%(num)s Closed Branch', '%(num)s Closed Branches', len(closed_branches)) % {'num': len(closed_branches)}}</a>
13 13 </span>
14 14 %endif
15 15
16 16 <span class="tagtag tag">
17 17 <a href="${h.route_path('tags_home',repo_name=c.repo_name)}" class="childs">
18 <i class="icon-tag"></i>${ungettext(
18 <i class="icon-tag"></i>${_ungettext(
19 19 '%(num)s Tag', '%(num)s Tags', len(tags)) % {'num': len(tags)}}</a>
20 20 </span>
21 21
22 22 %if bookmarks:
23 23 <span class="booktag tag">
24 24 <a href="${h.route_path('bookmarks_home',repo_name=c.repo_name)}" class="childs">
25 <i class="icon-bookmark"></i>${ungettext(
25 <i class="icon-bookmark"></i>${_ungettext(
26 26 '%(num)s Bookmark', '%(num)s Bookmarks', len(bookmarks)) % {'num': len(bookmarks)}}</a>
27 27 </span>
28 28 %endif
@@ -92,15 +92,15 b''
92 92
93 93 ## commits
94 94 % if commit_rev == -1:
95 ${ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
95 ${_ungettext('%(num)s Commit', '%(num)s Commits', 0) % {'num': 0}},
96 96 % else:
97 97 <a href="${h.url('changelog_home', repo_name=c.repo_name)}">
98 ${ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
98 ${_ungettext('%(num)s Commit', '%(num)s Commits', commit_rev) % {'num': commit_rev}}</a>,
99 99 % endif
100 100
101 101 ## forks
102 102 <a title="${_('Number of Repository Forks')}" href="${h.url('repo_forks_home', repo_name=c.repo_name)}">
103 ${c.repository_forks} ${ungettext('Fork', 'Forks', c.repository_forks)}</a>,
103 ${c.repository_forks} ${_ungettext('Fork', 'Forks', c.repository_forks)}</a>,
104 104
105 105 ## repo size
106 106 % if commit_rev == -1:
@@ -14,8 +14,14 b''
14 14
15 15 <div class="alert alert-dismissable alert-warning">
16 16 <strong>Missing requirements</strong>
17 These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.
18 Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable this extension in settings</a>, or contact the repository owner for help.
17 Commits cannot be displayed, because this repository uses one or more extensions, which was not enabled. <br/>
18 Please <a href="${h.url('repo_vcs_settings', repo_name=c.repo_name)}">enable extension in settings</a>, or contact the repository owner for help.
19 Missing extensions could be:
20 <pre>
21
22 - Mercurial largefiles
23 - Git LFS
24 </pre>
19 25 </div>
20 26
21 27 </%def>
@@ -36,7 +36,7 b''
36 36 %endif
37 37 <div class="table">
38 38 <div id="shortlog_data">
39 <%include file='../changelog/changelog_summary_data.mako'/>
39 <%include file='summary_commits.mako'/>
40 40 </div>
41 41 </div>
42 42 </div>
@@ -110,8 +110,7 b''
110 110
111 111 var callback = function (data) {
112 112 % if c.show_stats:
113 showRepoStats(
114 'lang_stats', data);
113 showRepoStats('lang_stats', data);
115 114 % endif
116 115 };
117 116
@@ -56,7 +56,7 b' def scm_extras(user_regular, repo_stub):'
56 56 RepoPreCreateEvent, RepoCreateEvent,
57 57 RepoPreDeleteEvent, RepoDeleteEvent,
58 58 ])
59 def test_repo_events_serialized(repo_stub, EventClass):
59 def test_repo_events_serialized(config_stub, repo_stub, EventClass):
60 60 event = EventClass(repo_stub)
61 61 data = event.as_dict()
62 62 assert data['name'] == EventClass.name
@@ -67,7 +67,7 b' def test_repo_events_serialized(repo_stu'
67 67 @pytest.mark.parametrize('EventClass', [
68 68 RepoPrePullEvent, RepoPullEvent, RepoPrePushEvent
69 69 ])
70 def test_vcs_repo_events_serialize(repo_stub, scm_extras, EventClass):
70 def test_vcs_repo_events_serialize(config_stub, repo_stub, scm_extras, EventClass):
71 71 event = EventClass(repo_name=repo_stub.repo_name, extras=scm_extras)
72 72 data = event.as_dict()
73 73 assert data['name'] == EventClass.name
@@ -76,7 +76,7 b' def test_vcs_repo_events_serialize(repo_'
76 76
77 77
78 78 @pytest.mark.parametrize('EventClass', [RepoPushEvent])
79 def test_vcs_repo_push_event_serialize(repo_stub, scm_extras, EventClass):
79 def test_vcs_repo_push_event_serialize(config_stub, repo_stub, scm_extras, EventClass):
80 80 event = EventClass(repo_name=repo_stub.repo_name,
81 81 pushed_commit_ids=scm_extras['commit_ids'],
82 82 extras=scm_extras)
@@ -24,10 +24,10 b' import mock'
24 24 import pytest
25 25
26 26 from rhodecode.lib import auth
27 from rhodecode.lib.utils2 import safe_str, str2bool, safe_unicode
28 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
29 from rhodecode.model.db import Repository, RepoGroup, UserRepoToPerm, User,\
30 Permission
27 from rhodecode.lib.utils2 import safe_str, str2bool
28 from rhodecode.lib import helpers as h
29 from rhodecode.model.db import (
30 Repository, RepoGroup, UserRepoToPerm, User, Permission)
31 31 from rhodecode.model.meta import Session
32 32 from rhodecode.model.repo import RepoModel
33 33 from rhodecode.model.repo_group import RepoGroupModel
@@ -475,7 +475,7 b' class TestAdminRepos(object):'
475 475 assert new_repo.description == description
476 476
477 477 # test if the repository is visible in the list ?
478 response = self.app.get(url('summary_home', repo_name=repo_name))
478 response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
479 479 response.mustcontain(repo_name)
480 480 response.mustcontain(backend.alias)
481 481
@@ -796,11 +796,12 b' class TestChangingFiles:'
796 796
797 797 # Not allowed, redirect to the summary
798 798 redirected = response.follow()
799 summary_url = url('summary_home', repo_name=repo.repo_name)
799 summary_url = h.route_path('repo_summary', repo_name=repo.repo_name)
800 800
801 801 # As there are no commits, displays the summary page with the error of
802 802 # creating a file with no filename
803 assert redirected.req.path == summary_url
803
804 assert redirected.request.path == summary_url
804 805
805 806 @pytest.mark.parametrize("location, filename", [
806 807 ('/abs', 'foo'),
@@ -22,6 +22,7 b' import pytest'
22 22
23 23 from rhodecode.tests import *
24 24 from rhodecode.tests.fixture import Fixture
25 from rhodecode.lib import helpers as h
25 26
26 27 from rhodecode.model.db import Repository
27 28 from rhodecode.model.repo import RepoModel
@@ -147,7 +148,7 b' class _BaseTest(TestController):'
147 148 assert fork_repo.fork.repo_name == repo_name
148 149
149 150 # test if the repository is visible in the list ?
150 response = self.app.get(url('summary_home', repo_name=fork_name_full))
151 response = self.app.get(h.route_path('repo_summary', repo_name=fork_name_full))
151 152 response.mustcontain(fork_name_full)
152 153 response.mustcontain(self.REPO_TYPE)
153 154
@@ -193,7 +194,7 b' class _BaseTest(TestController):'
193 194 assert fork_repo.fork.repo_name == repo_name
194 195
195 196 # test if the repository is visible in the list ?
196 response = self.app.get(url('summary_home', repo_name=fork_name))
197 response = self.app.get(h.route_path('repo_summary', repo_name=fork_name))
197 198 response.mustcontain(fork_name)
198 199 response.mustcontain(self.REPO_TYPE)
199 200 response.mustcontain('Fork of')
@@ -254,7 +255,7 b' class TestHG(_BaseTest):'
254 255
255 256 @pytest.mark.usefixtures('app', 'autologin_user')
256 257 @pytest.mark.skip_backends('git','hg')
257 class TestSVNFork:
258 class TestSVNFork(object):
258 259
259 260 def test_fork_redirects(self, backend):
260 261 denied_actions = ['fork','fork_create']
@@ -266,7 +267,7 b' class TestSVNFork:'
266 267
267 268 # Not allowed, redirect to the summary
268 269 redirected = response.follow()
269 summary_url = url('summary_home', repo_name=backend.repo_name)
270 summary_url = h.route_path('repo_summary', repo_name=backend.repo_name)
270 271
271 272 # URL adds leading slash and path doesn't have it
272 assert redirected.req.path == summary_url
273 assert redirected.request.path == summary_url
@@ -29,6 +29,7 b' from rhodecode.tests import ('
29 29 no_newline_id_generator)
30 30 from rhodecode.tests.fixture import Fixture
31 31 from rhodecode.lib.auth import check_password
32 from rhodecode.lib import helpers as h
32 33 from rhodecode.model.auth_token import AuthTokenModel
33 34 from rhodecode.model import validators
34 35 from rhodecode.model.db import User, Notification, UserApiKeys
@@ -105,8 +106,9 b' class TestLoginController(object):'
105 106 with fixture.anon_access(False):
106 107 kwargs = {'branch': 'stable'}
107 108 response = self.app.get(
108 url('summary_home', repo_name=HG_REPO, **kwargs))
109 h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs))
109 110 assert response.status == '302 Found'
111
110 112 response_query = urlparse.parse_qsl(response.location)
111 113 assert 'branch=stable' in response_query[0][1]
112 114
@@ -24,13 +24,13 b' from webob.exc import HTTPNotFound'
24 24
25 25 import rhodecode
26 26 from rhodecode.lib.vcs.nodes import FileNode
27 from rhodecode.lib import helpers as h
27 28 from rhodecode.model.changeset_status import ChangesetStatusModel
28 29 from rhodecode.model.db import (
29 30 PullRequest, ChangesetStatus, UserLog, Notification)
30 31 from rhodecode.model.meta import Session
31 32 from rhodecode.model.pull_request import PullRequestModel
32 33 from rhodecode.model.user import UserModel
33 from rhodecode.model.repo import RepoModel
34 34 from rhodecode.tests import (
35 35 assert_session_flash, url, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN)
36 36 from rhodecode.tests.utils import AssertResponse
@@ -38,7 +38,7 b' from rhodecode.tests.utils import Assert'
38 38
39 39 @pytest.mark.usefixtures('app', 'autologin_user')
40 40 @pytest.mark.backends("git", "hg")
41 class TestPullrequestsController:
41 class TestPullrequestsController(object):
42 42
43 43 def test_index(self, backend):
44 44 self.app.get(url(
@@ -47,7 +47,7 b' class TestPullrequestsController:'
47 47
48 48 def test_option_menu_create_pull_request_exists(self, backend):
49 49 repo_name = backend.repo_name
50 response = self.app.get(url('summary_home', repo_name=repo_name))
50 response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
51 51
52 52 create_pr_link = '<a href="%s">Create Pull Request</a>' % url(
53 53 'pullrequest', repo_name=repo_name)
@@ -1074,10 +1074,10 b' def test_redirects_to_repo_summary_for_s'
1074 1074
1075 1075 # Not allowed, redirect to the summary
1076 1076 redirected = response.follow()
1077 summary_url = url('summary_home', repo_name=backend_svn.repo_name)
1077 summary_url = h.route_path('repo_summary', repo_name=backend_svn.repo_name)
1078 1078
1079 1079 # URL adds leading slash and path doesn't have it
1080 assert redirected.req.path == summary_url
1080 assert redirected.request.path == summary_url
1081 1081
1082 1082
1083 1083 def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):
@@ -20,10 +20,10 b''
20 20
21 21 import pytest
22 22 from mock import Mock, patch
23 from pylons import url
24 23
25 24 from rhodecode.lib import base
26 25 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
26 from rhodecode.lib import helpers as h
27 27 from rhodecode.model import db
28 28
29 29
@@ -165,7 +165,7 b' class TestBaseRepoControllerHandleMissin'
165 165 context_mock.repo_name = repo_name
166 166 controller._handle_missing_requirements(error)
167 167
168 expected_url = url('summary_home', repo_name=repo_name)
168 expected_url = h.route_path('repo_summary', repo_name=repo_name)
169 169 if should_redirect:
170 170 redirect_mock.assert_called_once_with(expected_url)
171 171 else:
@@ -1683,6 +1683,15 b' def request_stub():'
1683 1683
1684 1684
1685 1685 @pytest.fixture
1686 def context_stub():
1687 """
1688 Stub context object.
1689 """
1690 context = pyramid.testing.DummyResource()
1691 return context
1692
1693
1694 @pytest.fixture
1686 1695 def config_stub(request, request_stub):
1687 1696 """
1688 1697 Set up pyramid.testing and return the Configurator.
@@ -123,6 +123,7 b' def set_anonymous_access(enabled):'
123 123 user.active = enabled
124 124 Session().add(user)
125 125 Session().commit()
126 time.sleep(1.5) # must sleep for cache (1s to expire)
126 127 log.info('anonymous access is now: %s', enabled)
127 128 assert enabled == User.get_default_user().active, (
128 129 'Cannot set anonymous access')
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now