##// END OF EJS Templates
repo-commits: ported changeset code into pyramid views....
marcink -
r1951:965019b0 default
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (557 lines changed) Show them Hide them
@@ -0,0 +1,557 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-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
22 import logging
23 import collections
24
25 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
26 from pyramid.view import view_config
27 from pyramid.renderers import render
28 from pyramid.response import Response
29
30 from rhodecode.apps._base import RepoAppView
31
32 from rhodecode.lib import diffs, codeblocks
33 from rhodecode.lib.auth import (
34 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired)
35
36 from rhodecode.lib.compat import OrderedDict
37 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
38 import rhodecode.lib.helpers as h
39 from rhodecode.lib.utils2 import safe_unicode, safe_int
40 from rhodecode.lib.vcs.backends.base import EmptyCommit
41 from rhodecode.lib.vcs.exceptions import (
42 RepositoryError, CommitDoesNotExistError, NodeDoesNotExistError)
43 from rhodecode.model.db import ChangesetComment, ChangesetStatus
44 from rhodecode.model.changeset_status import ChangesetStatusModel
45 from rhodecode.model.comment import CommentsModel
46 from rhodecode.model.meta import Session
47
48
49 log = logging.getLogger(__name__)
50
51
52 def _update_with_GET(params, request):
53 for k in ['diff1', 'diff2', 'diff']:
54 params[k] += request.GET.getall(k)
55
56
57 def get_ignore_ws(fid, request):
58 ig_ws_global = request.GET.get('ignorews')
59 ig_ws = filter(lambda k: k.startswith('WS'), request.GET.getall(fid))
60 if ig_ws:
61 try:
62 return int(ig_ws[0].split(':')[-1])
63 except Exception:
64 pass
65 return ig_ws_global
66
67
68 def _ignorews_url(request, fileid=None):
69 _ = request.translate
70 fileid = str(fileid) if fileid else None
71 params = collections.defaultdict(list)
72 _update_with_GET(params, request)
73 label = _('Show whitespace')
74 tooltiplbl = _('Show whitespace for all diffs')
75 ig_ws = get_ignore_ws(fileid, request)
76 ln_ctx = get_line_ctx(fileid, request)
77
78 if ig_ws is None:
79 params['ignorews'] += [1]
80 label = _('Ignore whitespace')
81 tooltiplbl = _('Ignore whitespace for all diffs')
82 ctx_key = 'context'
83 ctx_val = ln_ctx
84
85 # if we have passed in ln_ctx pass it along to our params
86 if ln_ctx:
87 params[ctx_key] += [ctx_val]
88
89 if fileid:
90 params['anchor'] = 'a_' + fileid
91 return h.link_to(label, request.current_route_path(_query=params),
92 title=tooltiplbl, class_='tooltip')
93
94
95 def get_line_ctx(fid, request):
96 ln_ctx_global = request.GET.get('context')
97 if fid:
98 ln_ctx = filter(lambda k: k.startswith('C'), request.GET.getall(fid))
99 else:
100 _ln_ctx = filter(lambda k: k.startswith('C'), request.GET)
101 ln_ctx = request.GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global
102 if ln_ctx:
103 ln_ctx = [ln_ctx]
104
105 if ln_ctx:
106 retval = ln_ctx[0].split(':')[-1]
107 else:
108 retval = ln_ctx_global
109
110 try:
111 return int(retval)
112 except Exception:
113 return 3
114
115
116 def _context_url(request, fileid=None):
117 """
118 Generates a url for context lines.
119
120 :param fileid:
121 """
122
123 _ = request.translate
124 fileid = str(fileid) if fileid else None
125 ig_ws = get_ignore_ws(fileid, request)
126 ln_ctx = (get_line_ctx(fileid, request) or 3) * 2
127
128 params = collections.defaultdict(list)
129 _update_with_GET(params, request)
130
131 if ln_ctx > 0:
132 params['context'] += [ln_ctx]
133
134 if ig_ws:
135 ig_ws_key = 'ignorews'
136 ig_ws_val = 1
137 params[ig_ws_key] += [ig_ws_val]
138
139 lbl = _('Increase context')
140 tooltiplbl = _('Increase context for all diffs')
141
142 if fileid:
143 params['anchor'] = 'a_' + fileid
144 return h.link_to(lbl, request.current_route_path(_query=params),
145 title=tooltiplbl, class_='tooltip')
146
147
148 class RepoCommitsView(RepoAppView):
149 def load_default_context(self):
150 c = self._get_local_tmpl_context(include_app_defaults=True)
151
152 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
153 c.repo_info = self.db_repo
154 c.rhodecode_repo = self.rhodecode_vcs_repo
155
156 self._register_global_c(c)
157 return c
158
159 def _commit(self, commit_id_range, method):
160 _ = self.request.translate
161 c = self.load_default_context()
162 c.ignorews_url = _ignorews_url
163 c.context_url = _context_url
164 c.fulldiff = self.request.GET.get('fulldiff')
165
166 # fetch global flags of ignore ws or context lines
167 context_lcl = get_line_ctx('', self.request)
168 ign_whitespace_lcl = get_ignore_ws('', self.request)
169
170 # diff_limit will cut off the whole diff if the limit is applied
171 # otherwise it will just hide the big files from the front-end
172 diff_limit = c.visual.cut_off_limit_diff
173 file_limit = c.visual.cut_off_limit_file
174
175 # get ranges of commit ids if preset
176 commit_range = commit_id_range.split('...')[:2]
177
178 try:
179 pre_load = ['affected_files', 'author', 'branch', 'date',
180 'message', 'parents']
181
182 if len(commit_range) == 2:
183 commits = self.rhodecode_vcs_repo.get_commits(
184 start_id=commit_range[0], end_id=commit_range[1],
185 pre_load=pre_load)
186 commits = list(commits)
187 else:
188 commits = [self.rhodecode_vcs_repo.get_commit(
189 commit_id=commit_id_range, pre_load=pre_load)]
190
191 c.commit_ranges = commits
192 if not c.commit_ranges:
193 raise RepositoryError(
194 'The commit range returned an empty result')
195 except CommitDoesNotExistError:
196 msg = _('No such commit exists for this repository')
197 h.flash(msg, category='error')
198 raise HTTPNotFound()
199 except Exception:
200 log.exception("General failure")
201 raise HTTPNotFound()
202
203 c.changes = OrderedDict()
204 c.lines_added = 0
205 c.lines_deleted = 0
206
207 # auto collapse if we have more than limit
208 collapse_limit = diffs.DiffProcessor._collapse_commits_over
209 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
210
211 c.commit_statuses = ChangesetStatus.STATUSES
212 c.inline_comments = []
213 c.files = []
214
215 c.statuses = []
216 c.comments = []
217 c.unresolved_comments = []
218 if len(c.commit_ranges) == 1:
219 commit = c.commit_ranges[0]
220 c.comments = CommentsModel().get_comments(
221 self.db_repo.repo_id,
222 revision=commit.raw_id)
223 c.statuses.append(ChangesetStatusModel().get_status(
224 self.db_repo.repo_id, commit.raw_id))
225 # comments from PR
226 statuses = ChangesetStatusModel().get_statuses(
227 self.db_repo.repo_id, commit.raw_id,
228 with_revisions=True)
229 prs = set(st.pull_request for st in statuses
230 if st.pull_request is not None)
231 # from associated statuses, check the pull requests, and
232 # show comments from them
233 for pr in prs:
234 c.comments.extend(pr.comments)
235
236 c.unresolved_comments = CommentsModel()\
237 .get_commit_unresolved_todos(commit.raw_id)
238
239 diff = None
240 # Iterate over ranges (default commit view is always one commit)
241 for commit in c.commit_ranges:
242 c.changes[commit.raw_id] = []
243
244 commit2 = commit
245 commit1 = commit.parents[0] if commit.parents else EmptyCommit()
246
247 _diff = self.rhodecode_vcs_repo.get_diff(
248 commit1, commit2,
249 ignore_whitespace=ign_whitespace_lcl, context=context_lcl)
250 diff_processor = diffs.DiffProcessor(
251 _diff, format='newdiff', diff_limit=diff_limit,
252 file_limit=file_limit, show_full_diff=c.fulldiff)
253
254 commit_changes = OrderedDict()
255 if method == 'show':
256 _parsed = diff_processor.prepare()
257 c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer)
258
259 _parsed = diff_processor.prepare()
260
261 def _node_getter(commit):
262 def get_node(fname):
263 try:
264 return commit.get_node(fname)
265 except NodeDoesNotExistError:
266 return None
267 return get_node
268
269 inline_comments = CommentsModel().get_inline_comments(
270 self.db_repo.repo_id, revision=commit.raw_id)
271 c.inline_cnt = CommentsModel().get_inline_comments_count(
272 inline_comments)
273
274 diffset = codeblocks.DiffSet(
275 repo_name=self.db_repo_name,
276 source_node_getter=_node_getter(commit1),
277 target_node_getter=_node_getter(commit2),
278 comments=inline_comments)
279 diffset = diffset.render_patchset(
280 _parsed, commit1.raw_id, commit2.raw_id)
281
282 c.changes[commit.raw_id] = diffset
283 else:
284 # downloads/raw we only need RAW diff nothing else
285 diff = diff_processor.as_raw()
286 c.changes[commit.raw_id] = [None, None, None, None, diff, None, None]
287
288 # sort comments by how they were generated
289 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
290
291 if len(c.commit_ranges) == 1:
292 c.commit = c.commit_ranges[0]
293 c.parent_tmpl = ''.join(
294 '# Parent %s\n' % x.raw_id for x in c.commit.parents)
295
296 if method == 'download':
297 response = Response(diff)
298 response.content_type = 'text/plain'
299 response.content_disposition = (
300 'attachment; filename=%s.diff' % commit_id_range[:12])
301 return response
302 elif method == 'patch':
303 c.diff = safe_unicode(diff)
304 patch = render(
305 'rhodecode:templates/changeset/patch_changeset.mako',
306 self._get_template_context(c), self.request)
307 response = Response(patch)
308 response.content_type = 'text/plain'
309 return response
310 elif method == 'raw':
311 response = Response(diff)
312 response.content_type = 'text/plain'
313 return response
314 elif method == 'show':
315 if len(c.commit_ranges) == 1:
316 html = render(
317 'rhodecode:templates/changeset/changeset.mako',
318 self._get_template_context(c), self.request)
319 return Response(html)
320 else:
321 c.ancestor = None
322 c.target_repo = self.db_repo
323 html = render(
324 'rhodecode:templates/changeset/changeset_range.mako',
325 self._get_template_context(c), self.request)
326 return Response(html)
327
328 raise HTTPBadRequest()
329
330 @LoginRequired()
331 @HasRepoPermissionAnyDecorator(
332 'repository.read', 'repository.write', 'repository.admin')
333 @view_config(
334 route_name='repo_commit', request_method='GET',
335 renderer=None)
336 def repo_commit_show(self):
337 commit_id = self.request.matchdict['commit_id']
338 return self._commit(commit_id, method='show')
339
340 @LoginRequired()
341 @HasRepoPermissionAnyDecorator(
342 'repository.read', 'repository.write', 'repository.admin')
343 @view_config(
344 route_name='repo_commit_raw', request_method='GET',
345 renderer=None)
346 @view_config(
347 route_name='repo_commit_raw_deprecated', request_method='GET',
348 renderer=None)
349 def repo_commit_raw(self):
350 commit_id = self.request.matchdict['commit_id']
351 return self._commit(commit_id, method='raw')
352
353 @LoginRequired()
354 @HasRepoPermissionAnyDecorator(
355 'repository.read', 'repository.write', 'repository.admin')
356 @view_config(
357 route_name='repo_commit_patch', request_method='GET',
358 renderer=None)
359 def repo_commit_patch(self):
360 commit_id = self.request.matchdict['commit_id']
361 return self._commit(commit_id, method='patch')
362
363 @LoginRequired()
364 @HasRepoPermissionAnyDecorator(
365 'repository.read', 'repository.write', 'repository.admin')
366 @view_config(
367 route_name='repo_commit_download', request_method='GET',
368 renderer=None)
369 def repo_commit_download(self):
370 commit_id = self.request.matchdict['commit_id']
371 return self._commit(commit_id, method='download')
372
373 @LoginRequired()
374 @NotAnonymous()
375 @HasRepoPermissionAnyDecorator(
376 'repository.read', 'repository.write', 'repository.admin')
377 @CSRFRequired()
378 @view_config(
379 route_name='repo_commit_comment_create', request_method='POST',
380 renderer='json_ext')
381 def repo_commit_comment_create(self):
382 _ = self.request.translate
383 commit_id = self.request.matchdict['commit_id']
384
385 c = self.load_default_context()
386 status = self.request.POST.get('changeset_status', None)
387 text = self.request.POST.get('text')
388 comment_type = self.request.POST.get('comment_type')
389 resolves_comment_id = self.request.POST.get('resolves_comment_id', None)
390
391 if status:
392 text = text or (_('Status change %(transition_icon)s %(status)s')
393 % {'transition_icon': '>',
394 'status': ChangesetStatus.get_status_lbl(status)})
395
396 multi_commit_ids = []
397 for _commit_id in self.request.POST.get('commit_ids', '').split(','):
398 if _commit_id not in ['', None, EmptyCommit.raw_id]:
399 if _commit_id not in multi_commit_ids:
400 multi_commit_ids.append(_commit_id)
401
402 commit_ids = multi_commit_ids or [commit_id]
403
404 comment = None
405 for current_id in filter(None, commit_ids):
406 comment = CommentsModel().create(
407 text=text,
408 repo=self.db_repo.repo_id,
409 user=self._rhodecode_db_user.user_id,
410 commit_id=current_id,
411 f_path=self.request.POST.get('f_path'),
412 line_no=self.request.POST.get('line'),
413 status_change=(ChangesetStatus.get_status_lbl(status)
414 if status else None),
415 status_change_type=status,
416 comment_type=comment_type,
417 resolves_comment_id=resolves_comment_id
418 )
419
420 # get status if set !
421 if status:
422 # if latest status was from pull request and it's closed
423 # disallow changing status !
424 # dont_allow_on_closed_pull_request = True !
425
426 try:
427 ChangesetStatusModel().set_status(
428 self.db_repo.repo_id,
429 status,
430 self._rhodecode_db_user.user_id,
431 comment,
432 revision=current_id,
433 dont_allow_on_closed_pull_request=True
434 )
435 except StatusChangeOnClosedPullRequestError:
436 msg = _('Changing the status of a commit associated with '
437 'a closed pull request is not allowed')
438 log.exception(msg)
439 h.flash(msg, category='warning')
440 raise HTTPFound(h.route_path(
441 'repo_commit', repo_name=self.db_repo_name,
442 commit_id=current_id))
443
444 # finalize, commit and redirect
445 Session().commit()
446
447 data = {
448 'target_id': h.safeid(h.safe_unicode(
449 self.request.POST.get('f_path'))),
450 }
451 if comment:
452 c.co = comment
453 rendered_comment = render(
454 'rhodecode:templates/changeset/changeset_comment_block.mako',
455 self._get_template_context(c), self.request)
456
457 data.update(comment.get_dict())
458 data.update({'rendered_text': rendered_comment})
459
460 return data
461
462 @LoginRequired()
463 @NotAnonymous()
464 @HasRepoPermissionAnyDecorator(
465 'repository.read', 'repository.write', 'repository.admin')
466 @CSRFRequired()
467 @view_config(
468 route_name='repo_commit_comment_preview', request_method='POST',
469 renderer='string', xhr=True)
470 def repo_commit_comment_preview(self):
471 # Technically a CSRF token is not needed as no state changes with this
472 # call. However, as this is a POST is better to have it, so automated
473 # tools don't flag it as potential CSRF.
474 # Post is required because the payload could be bigger than the maximum
475 # allowed by GET.
476
477 text = self.request.POST.get('text')
478 renderer = self.request.POST.get('renderer') or 'rst'
479 if text:
480 return h.render(text, renderer=renderer, mentions=True)
481 return ''
482
483 @LoginRequired()
484 @NotAnonymous()
485 @HasRepoPermissionAnyDecorator(
486 'repository.read', 'repository.write', 'repository.admin')
487 @CSRFRequired()
488 @view_config(
489 route_name='repo_commit_comment_delete', request_method='POST',
490 renderer='json_ext')
491 def repo_commit_comment_delete(self):
492 commit_id = self.request.matchdict['commit_id']
493 comment_id = self.request.matchdict['comment_id']
494
495 comment = ChangesetComment.get_or_404(safe_int(comment_id))
496 if not comment:
497 log.debug('Comment with id:%s not found, skipping', comment_id)
498 # comment already deleted in another call probably
499 return True
500
501 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
502 super_admin = h.HasPermissionAny('hg.admin')()
503 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
504 is_repo_comment = comment.repo.repo_name == self.db_repo_name
505 comment_repo_admin = is_repo_admin and is_repo_comment
506
507 if super_admin or comment_owner or comment_repo_admin:
508 CommentsModel().delete(comment=comment, user=self._rhodecode_db_user)
509 Session().commit()
510 return True
511 else:
512 log.warning('No permissions for user %s to delete comment_id: %s',
513 self._rhodecode_db_user, comment_id)
514 raise HTTPNotFound()
515
516 @LoginRequired()
517 @HasRepoPermissionAnyDecorator(
518 'repository.read', 'repository.write', 'repository.admin')
519 @view_config(
520 route_name='repo_commit_data', request_method='GET',
521 renderer='json_ext', xhr=True)
522 def repo_commit_data(self):
523 commit_id = self.request.matchdict['commit_id']
524 self.load_default_context()
525
526 try:
527 return self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
528 except CommitDoesNotExistError as e:
529 return EmptyCommit(message=str(e))
530
531 @LoginRequired()
532 @HasRepoPermissionAnyDecorator(
533 'repository.read', 'repository.write', 'repository.admin')
534 @view_config(
535 route_name='repo_commit_children', request_method='GET',
536 renderer='json_ext', xhr=True)
537 def repo_commit_children(self):
538 commit_id = self.request.matchdict['commit_id']
539 self.load_default_context()
540
541 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
542 result = {"results": commit.children}
543 return result
544
545 @LoginRequired()
546 @HasRepoPermissionAnyDecorator(
547 'repository.read', 'repository.write', 'repository.admin')
548 @view_config(
549 route_name='repo_commit_parents', request_method='GET',
550 renderer='json_ext')
551 def repo_commit_parents(self):
552 commit_id = self.request.matchdict['commit_id']
553 self.load_default_context()
554
555 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
556 result = {"results": commit.parents}
557 return result
@@ -210,11 +210,12 b' gist_alias_url ='
210 ## The list should be "," separated and on a single line.
210 ## The list should be "," separated and on a single line.
211 ##
211 ##
212 ## Most common views to enable:
212 ## Most common views to enable:
213 # ChangesetController:changeset_patch
213 # RepoCommitsView:repo_commit_download
214 # ChangesetController:changeset_raw
214 # RepoCommitsView:repo_commit_patch
215 # RepoFilesView.repo_files_diff
215 # RepoCommitsView:repo_commit_raw
216 # RepoFilesView.repo_archivefile
216 # RepoFilesView:repo_files_diff
217 # RepoFilesView.repo_file_raw
217 # RepoFilesView:repo_archivefile
218 # RepoFilesView:repo_file_raw
218 # GistView:*
219 # GistView:*
219 api_access_controllers_whitelist =
220 api_access_controllers_whitelist =
220
221
@@ -184,11 +184,12 b' gist_alias_url ='
184 ## The list should be "," separated and on a single line.
184 ## The list should be "," separated and on a single line.
185 ##
185 ##
186 ## Most common views to enable:
186 ## Most common views to enable:
187 # ChangesetController:changeset_patch
187 # RepoCommitsView:repo_commit_download
188 # ChangesetController:changeset_raw
188 # RepoCommitsView:repo_commit_patch
189 # RepoFilesView.repo_files_diff
189 # RepoCommitsView:repo_commit_raw
190 # RepoFilesView.repo_archivefile
190 # RepoFilesView:repo_files_diff
191 # RepoFilesView.repo_file_raw
191 # RepoFilesView:repo_archivefile
192 # RepoFilesView:repo_file_raw
192 # GistView:*
193 # GistView:*
193 api_access_controllers_whitelist =
194 api_access_controllers_whitelist =
194
195
@@ -42,7 +42,7 b' archive.'
42 ## Syntax is <ControllerClass>:<function_pattern>.
42 ## Syntax is <ControllerClass>:<function_pattern>.
43 ## The list should be "," separated and on a single line.
43 ## The list should be "," separated and on a single line.
44 ##
44 ##
45 api_access_controllers_whitelist = ChangesetController:changeset_patch,ChangesetController:changeset_raw,ilesController:raw,FilesController:archivefile,
45 api_access_controllers_whitelist = RepoCommitsView:repo_commit_raw,RepoCommitsView:repo_commit_patch,RepoCommitsView:repo_commit_download
46
46
47 After this change, a |RCE| view can be accessed without login by adding a
47 After this change, a |RCE| view can be accessed without login by adding a
48 GET parameter ``?auth_token=<auth_token>`` to a url. For example to
48 GET parameter ``?auth_token=<auth_token>`` to a url. For example to
@@ -172,9 +172,9 b' class HomeView(BaseAppView):'
172 'text': entry['commit_id'],
172 'text': entry['commit_id'],
173 'type': 'commit',
173 'type': 'commit',
174 'obj': {'repo': entry['repository']},
174 'obj': {'repo': entry['repository']},
175 'url': h.url('changeset_home',
175 'url': h.route_path('repo_commit',
176 repo_name=entry['repository'],
176 repo_name=entry['repository'],
177 revision=entry['commit_id'])
177 commit_id=entry['commit_id'])
178 }
178 }
179 for entry in result['results']]
179 for entry in result['results']]
180
180
@@ -36,6 +36,8 b' from rhodecode.model.meta import Session'
36
36
37 fixture = Fixture()
37 fixture = Fixture()
38
38
39 whitelist_view = ['RepoCommitsView:repo_commit_raw']
40
39
41
40 def route_path(name, params=None, **kwargs):
42 def route_path(name, params=None, **kwargs):
41 import urllib
43 import urllib
@@ -474,11 +476,10 b' class TestLoginController(object):'
474 def test_access_whitelisted_page_via_auth_token(
476 def test_access_whitelisted_page_via_auth_token(
475 self, test_name, auth_token, code, user_admin):
477 self, test_name, auth_token, code, user_admin):
476
478
477 whitelist_entry = ['ChangesetController:changeset_raw']
479 whitelist = self._get_api_whitelist(whitelist_view)
478 whitelist = self._get_api_whitelist(whitelist_entry)
479
480
480 with mock.patch.dict('rhodecode.CONFIG', whitelist):
481 with mock.patch.dict('rhodecode.CONFIG', whitelist):
481 assert whitelist_entry == whitelist['api_access_controllers_whitelist']
482 assert whitelist_view == whitelist['api_access_controllers_whitelist']
482
483
483 if test_name == 'proper_auth_token':
484 if test_name == 'proper_auth_token':
484 auth_token = user_admin.api_key
485 auth_token = user_admin.api_key
@@ -492,10 +493,9 b' class TestLoginController(object):'
492 status=code)
493 status=code)
493
494
494 def test_access_page_via_extra_auth_token(self):
495 def test_access_page_via_extra_auth_token(self):
495 whitelist = self._get_api_whitelist(
496 whitelist = self._get_api_whitelist(whitelist_view)
496 ['ChangesetController:changeset_raw'])
497 with mock.patch.dict('rhodecode.CONFIG', whitelist):
497 with mock.patch.dict('rhodecode.CONFIG', whitelist):
498 assert ['ChangesetController:changeset_raw'] == \
498 assert whitelist_view == \
499 whitelist['api_access_controllers_whitelist']
499 whitelist['api_access_controllers_whitelist']
500
500
501 new_auth_token = AuthTokenModel().create(
501 new_auth_token = AuthTokenModel().create(
@@ -509,10 +509,9 b' class TestLoginController(object):'
509 status=200)
509 status=200)
510
510
511 def test_access_page_via_expired_auth_token(self):
511 def test_access_page_via_expired_auth_token(self):
512 whitelist = self._get_api_whitelist(
512 whitelist = self._get_api_whitelist(whitelist_view)
513 ['ChangesetController:changeset_raw'])
514 with mock.patch.dict('rhodecode.CONFIG', whitelist):
513 with mock.patch.dict('rhodecode.CONFIG', whitelist):
515 assert ['ChangesetController:changeset_raw'] == \
514 assert whitelist_view == \
516 whitelist['api_access_controllers_whitelist']
515 whitelist['api_access_controllers_whitelist']
517
516
518 new_auth_token = AuthTokenModel().create(
517 new_auth_token = AuthTokenModel().create(
@@ -33,10 +33,52 b' def includeme(config):'
33 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
33 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
34
34
35 # repo commits
35 # repo commits
36
36 config.add_route(
37 config.add_route(
37 name='repo_commit',
38 name='repo_commit',
38 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
39 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
39
40
41 config.add_route(
42 name='repo_commit_children',
43 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
44
45 config.add_route(
46 name='repo_commit_parents',
47 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
48
49 # still working url for backward compat.
50 config.add_route(
51 name='repo_commit_raw_deprecated',
52 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
53
54 config.add_route(
55 name='repo_commit_raw',
56 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
57
58 config.add_route(
59 name='repo_commit_patch',
60 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
61
62 config.add_route(
63 name='repo_commit_download',
64 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
65
66 config.add_route(
67 name='repo_commit_data',
68 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
69
70 config.add_route(
71 name='repo_commit_comment_create',
72 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
73
74 config.add_route(
75 name='repo_commit_comment_preview',
76 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
77
78 config.add_route(
79 name='repo_commit_comment_delete',
80 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
81
40 # repo files
82 # repo files
41 config.add_route(
83 config.add_route(
42 name='repo_archivefile',
84 name='repo_archivefile',
@@ -180,21 +222,6 b' def includeme(config):'
180 pattern='/{repo_name:.*?[^/]}/pull-request-data',
222 pattern='/{repo_name:.*?[^/]}/pull-request-data',
181 repo_route=True, repo_accepted_types=['hg', 'git'])
223 repo_route=True, repo_accepted_types=['hg', 'git'])
182
224
183 # commits aka changesets
184 # TODO(dan): handle default landing revision ?
185 config.add_route(
186 name='changeset_home',
187 pattern='/{repo_name:.*?[^/]}/changeset/{revision}',
188 repo_route=True)
189 config.add_route(
190 name='changeset_children',
191 pattern='/{repo_name:.*?[^/]}/changeset_children/{revision}',
192 repo_route=True)
193 config.add_route(
194 name='changeset_parents',
195 pattern='/{repo_name:.*?[^/]}/changeset_parents/{revision}',
196 repo_route=True)
197
198 # Settings
225 # Settings
199 config.add_route(
226 config.add_route(
200 name='edit_repo',
227 name='edit_repo',
@@ -18,18 +18,33 b''
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 from pylons.i18n import ungettext
22 import pytest
21 import pytest
23
22
24 from rhodecode.tests import *
23 from rhodecode.tests import TestController
24
25 from rhodecode.model.db import (
25 from rhodecode.model.db import (
26 ChangesetComment, Notification, UserNotification)
26 ChangesetComment, Notification, UserNotification)
27 from rhodecode.model.meta import Session
27 from rhodecode.model.meta import Session
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
29
29
30
30
31 def route_path(name, params=None, **kwargs):
32 import urllib
33
34 base_url = {
35 'repo_commit': '/{repo_name}/changeset/{commit_id}',
36 'repo_commit_comment_create': '/{repo_name}/changeset/{commit_id}/comment/create',
37 'repo_commit_comment_preview': '/{repo_name}/changeset/{commit_id}/comment/preview',
38 'repo_commit_comment_delete': '/{repo_name}/changeset/{commit_id}/comment/{comment_id}/delete',
39 }[name].format(**kwargs)
40
41 if params:
42 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
43 return base_url
44
45
31 @pytest.mark.backends("git", "hg", "svn")
46 @pytest.mark.backends("git", "hg", "svn")
32 class TestCommitCommentsController(TestController):
47 class TestRepoCommitCommentsView(TestController):
33
48
34 @pytest.fixture(autouse=True)
49 @pytest.fixture(autouse=True)
35 def prepare(self, request, pylonsapp):
50 def prepare(self, request, pylonsapp):
@@ -62,12 +77,13 b' class TestCommitCommentsController(TestC'
62 params = {'text': text, 'csrf_token': self.csrf_token,
77 params = {'text': text, 'csrf_token': self.csrf_token,
63 'comment_type': comment_type}
78 'comment_type': comment_type}
64 self.app.post(
79 self.app.post(
65 url(controller='changeset', action='comment',
80 route_path('repo_commit_comment_create',
66 repo_name=backend.repo_name, revision=commit_id), params=params)
81 repo_name=backend.repo_name, commit_id=commit_id),
82 params=params)
67
83
68 response = self.app.get(
84 response = self.app.get(
69 url(controller='changeset', action='index',
85 route_path('repo_commit',
70 repo_name=backend.repo_name, revision=commit_id))
86 repo_name=backend.repo_name, commit_id=commit_id))
71
87
72 # test DB
88 # test DB
73 assert ChangesetComment.query().count() == 1
89 assert ChangesetComment.query().count() == 1
@@ -103,12 +119,13 b' class TestCommitCommentsController(TestC'
103 'csrf_token': self.csrf_token}
119 'csrf_token': self.csrf_token}
104
120
105 self.app.post(
121 self.app.post(
106 url(controller='changeset', action='comment',
122 route_path('repo_commit_comment_create',
107 repo_name=backend.repo_name, revision=commit_id), params=params)
123 repo_name=backend.repo_name, commit_id=commit_id),
124 params=params)
108
125
109 response = self.app.get(
126 response = self.app.get(
110 url(controller='changeset', action='index',
127 route_path('repo_commit',
111 repo_name=backend.repo_name, revision=commit_id))
128 repo_name=backend.repo_name, commit_id=commit_id))
112
129
113 # test DB
130 # test DB
114 assert ChangesetComment.query().count() == 1
131 assert ChangesetComment.query().count() == 1
@@ -153,12 +170,13 b' class TestCommitCommentsController(TestC'
153
170
154 params = {'text': text, 'csrf_token': self.csrf_token}
171 params = {'text': text, 'csrf_token': self.csrf_token}
155 self.app.post(
172 self.app.post(
156 url(controller='changeset', action='comment',
173 route_path('repo_commit_comment_create',
157 repo_name=backend.repo_name, revision=commit_id), params=params)
174 repo_name=backend.repo_name, commit_id=commit_id),
175 params=params)
158
176
159 response = self.app.get(
177 response = self.app.get(
160 url(controller='changeset', action='index',
178 route_path('repo_commit',
161 repo_name=backend.repo_name, revision=commit_id))
179 repo_name=backend.repo_name, commit_id=commit_id))
162 # test DB
180 # test DB
163 assert ChangesetComment.query().count() == 1
181 assert ChangesetComment.query().count() == 1
164 assert_comment_links(response, ChangesetComment.query().count(), 0)
182 assert_comment_links(response, ChangesetComment.query().count(), 0)
@@ -183,12 +201,14 b' class TestCommitCommentsController(TestC'
183 'csrf_token': self.csrf_token}
201 'csrf_token': self.csrf_token}
184
202
185 self.app.post(
203 self.app.post(
186 url(controller='changeset', action='comment',
204 route_path(
187 repo_name=backend.repo_name, revision=commit_id), params=params)
205 'repo_commit_comment_create',
206 repo_name=backend.repo_name, commit_id=commit_id),
207 params=params)
188
208
189 response = self.app.get(
209 response = self.app.get(
190 url(controller='changeset', action='index',
210 route_path('repo_commit',
191 repo_name=backend.repo_name, revision=commit_id))
211 repo_name=backend.repo_name, commit_id=commit_id))
192
212
193 # test DB
213 # test DB
194 assert ChangesetComment.query().count() == 1
214 assert ChangesetComment.query().count() == 1
@@ -218,9 +238,9 b' class TestCommitCommentsController(TestC'
218
238
219 params = {'text': text, 'csrf_token': self.csrf_token}
239 params = {'text': text, 'csrf_token': self.csrf_token}
220 self.app.post(
240 self.app.post(
221 url(
241 route_path(
222 controller='changeset', action='comment',
242 'repo_commit_comment_create',
223 repo_name=backend.repo_name, revision=commit_id),
243 repo_name=backend.repo_name, commit_id=commit_id),
224 params=params)
244 params=params)
225
245
226 comments = ChangesetComment.query().all()
246 comments = ChangesetComment.query().all()
@@ -228,16 +248,18 b' class TestCommitCommentsController(TestC'
228 comment_id = comments[0].comment_id
248 comment_id = comments[0].comment_id
229
249
230 self.app.post(
250 self.app.post(
231 url(controller='changeset', action='delete_comment',
251 route_path('repo_commit_comment_delete',
232 repo_name=backend.repo_name, comment_id=comment_id),
252 repo_name=backend.repo_name,
233 params={'_method': 'delete', 'csrf_token': self.csrf_token})
253 commit_id=commit_id,
254 comment_id=comment_id),
255 params={'csrf_token': self.csrf_token})
234
256
235 comments = ChangesetComment.query().all()
257 comments = ChangesetComment.query().all()
236 assert len(comments) == 0
258 assert len(comments) == 0
237
259
238 response = self.app.get(
260 response = self.app.get(
239 url(controller='changeset', action='index',
261 route_path('repo_commit',
240 repo_name=backend.repo_name, revision=commit_id))
262 repo_name=backend.repo_name, commit_id=commit_id))
241 assert_comment_links(response, 0, 0)
263 assert_comment_links(response, 0, 0)
242
264
243 @pytest.mark.parametrize('renderer, input, output', [
265 @pytest.mark.parametrize('renderer, input, output', [
@@ -251,36 +273,39 b' class TestCommitCommentsController(TestC'
251 ('markdown', '**bold**', '<strong>bold</strong>'),
273 ('markdown', '**bold**', '<strong>bold</strong>'),
252 ], ids=['rst-plain', 'rst-header', 'rst-italics', 'rst-bold', 'md-plain',
274 ], ids=['rst-plain', 'rst-header', 'rst-italics', 'rst-bold', 'md-plain',
253 'md-header', 'md-italics', 'md-bold', ])
275 'md-header', 'md-italics', 'md-bold', ])
254 def test_preview(self, renderer, input, output, backend):
276 def test_preview(self, renderer, input, output, backend, xhr_header):
255 self.log_user()
277 self.log_user()
256 params = {
278 params = {
257 'renderer': renderer,
279 'renderer': renderer,
258 'text': input,
280 'text': input,
259 'csrf_token': self.csrf_token
281 'csrf_token': self.csrf_token
260 }
282 }
261 environ = {
283 commit_id = '0' * 16 # fake this for tests
262 'HTTP_X_PARTIAL_XHR': 'true'
263 }
264 response = self.app.post(
284 response = self.app.post(
265 url(controller='changeset',
285 route_path('repo_commit_comment_preview',
266 action='preview_comment',
286 repo_name=backend.repo_name, commit_id=commit_id,),
267 repo_name=backend.repo_name),
268 params=params,
287 params=params,
269 extra_environ=environ)
288 extra_environ=xhr_header)
270
289
271 response.mustcontain(output)
290 response.mustcontain(output)
272
291
273
292
274 def assert_comment_links(response, comments, inline_comments):
293 def assert_comment_links(response, comments, inline_comments):
275 comments_text = ungettext("%d Commit comment",
294 if comments == 1:
276 "%d Commit comments", comments) % comments
295 comments_text = "%d Commit comment" % comments
296 else:
297 comments_text = "%d Commit comments" % comments
298
299 if inline_comments == 1:
300 inline_comments_text = "%d Inline Comment" % inline_comments
301 else:
302 inline_comments_text = "%d Inline Comments" % inline_comments
303
277 if comments:
304 if comments:
278 response.mustcontain('<a href="#comments">%s</a>,' % comments_text)
305 response.mustcontain('<a href="#comments">%s</a>,' % comments_text)
279 else:
306 else:
280 response.mustcontain(comments_text)
307 response.mustcontain(comments_text)
281
308
282 inline_comments_text = ungettext("%d Inline Comment", "%d Inline Comments",
283 inline_comments) % inline_comments
284 if inline_comments:
309 if inline_comments:
285 response.mustcontain(
310 response.mustcontain(
286 'id="inline-comments-counter">%s</' % inline_comments_text)
311 'id="inline-comments-counter">%s</' % inline_comments_text)
@@ -21,40 +21,56 b''
21 import pytest
21 import pytest
22
22
23 from rhodecode.lib.helpers import _shorten_commit_id
23 from rhodecode.lib.helpers import _shorten_commit_id
24 from rhodecode.tests import url
24
25
26 def route_path(name, params=None, **kwargs):
27 import urllib
28
29 base_url = {
30 'repo_commit': '/{repo_name}/changeset/{commit_id}',
31 'repo_commit_children': '/{repo_name}/changeset_children/{commit_id}',
32 'repo_commit_parents': '/{repo_name}/changeset_parents/{commit_id}',
33 'repo_commit_raw': '/{repo_name}/changeset-diff/{commit_id}',
34 'repo_commit_patch': '/{repo_name}/changeset-patch/{commit_id}',
35 'repo_commit_download': '/{repo_name}/changeset-download/{commit_id}',
36 'repo_commit_data': '/{repo_name}/changeset-data/{commit_id}',
37 'repo_compare': '/{repo_name}/compare/{source_ref_type}@{source_ref}...{target_ref_type}@{target_ref}',
38 }[name].format(**kwargs)
39
40 if params:
41 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
42 return base_url
25
43
26
44
27 @pytest.mark.usefixtures("app")
45 @pytest.mark.usefixtures("app")
28 class TestChangesetController(object):
46 class TestRepoCommitView(object):
29
47
30 def test_index(self, backend):
48 def test_show_commit(self, backend):
31 commit_id = self.commit_id[backend.alias]
49 commit_id = self.commit_id[backend.alias]
32 response = self.app.get(url(
50 response = self.app.get(route_path(
33 controller='changeset', action='index',
51 'repo_commit', repo_name=backend.repo_name, commit_id=commit_id))
34 repo_name=backend.repo_name, revision=commit_id))
35 response.mustcontain('Added a symlink')
52 response.mustcontain('Added a symlink')
36 response.mustcontain(commit_id)
53 response.mustcontain(commit_id)
37 response.mustcontain('No newline at end of file')
54 response.mustcontain('No newline at end of file')
38
55
39 def test_index_raw(self, backend):
56 def test_show_raw(self, backend):
40 commit_id = self.commit_id[backend.alias]
57 commit_id = self.commit_id[backend.alias]
41 response = self.app.get(url(
58 response = self.app.get(route_path(
42 controller='changeset', action='changeset_raw',
59 'repo_commit_raw',
43 repo_name=backend.repo_name, revision=commit_id))
60 repo_name=backend.repo_name, commit_id=commit_id))
44 assert response.body == self.diffs[backend.alias]
61 assert response.body == self.diffs[backend.alias]
45
62
46 def test_index_raw_patch(self, backend):
63 def test_show_raw_patch(self, backend):
47 response = self.app.get(url(
64 response = self.app.get(route_path(
48 controller='changeset', action='changeset_patch',
65 'repo_commit_patch', repo_name=backend.repo_name,
49 repo_name=backend.repo_name,
66 commit_id=self.commit_id[backend.alias]))
50 revision=self.commit_id[backend.alias]))
51 assert response.body == self.patches[backend.alias]
67 assert response.body == self.patches[backend.alias]
52
68
53 def test_index_changeset_download(self, backend):
69 def test_commit_download(self, backend):
54 response = self.app.get(url(
70 response = self.app.get(route_path(
55 controller='changeset', action='changeset_download',
71 'repo_commit_download',
56 repo_name=backend.repo_name,
72 repo_name=backend.repo_name,
57 revision=self.commit_id[backend.alias]))
73 commit_id=self.commit_id[backend.alias]))
58 assert response.body == self.diffs[backend.alias]
74 assert response.body == self.diffs[backend.alias]
59
75
60 def test_single_commit_page_different_ops(self, backend):
76 def test_single_commit_page_different_ops(self, backend):
@@ -64,9 +80,9 b' class TestChangesetController(object):'
64 'svn': '337',
80 'svn': '337',
65 }
81 }
66 commit_id = commit_id[backend.alias]
82 commit_id = commit_id[backend.alias]
67 response = self.app.get(url(
83 response = self.app.get(route_path(
68 controller='changeset', action='index',
84 'repo_commit',
69 repo_name=backend.repo_name, revision=commit_id))
85 repo_name=backend.repo_name, commit_id=commit_id))
70
86
71 response.mustcontain(_shorten_commit_id(commit_id))
87 response.mustcontain(_shorten_commit_id(commit_id))
72 response.mustcontain('21 files changed: 943 inserted, 288 deleted')
88 response.mustcontain('21 files changed: 943 inserted, 288 deleted')
@@ -98,9 +114,9 b' class TestChangesetController(object):'
98 }
114 }
99 commit_ids = commit_id_range[backend.alias]
115 commit_ids = commit_id_range[backend.alias]
100 commit_id = '%s...%s' % (commit_ids[0], commit_ids[1])
116 commit_id = '%s...%s' % (commit_ids[0], commit_ids[1])
101 response = self.app.get(url(
117 response = self.app.get(route_path(
102 controller='changeset', action='index',
118 'repo_commit',
103 repo_name=backend.repo_name, revision=commit_id))
119 repo_name=backend.repo_name, commit_id=commit_id))
104
120
105 response.mustcontain(_shorten_commit_id(commit_ids[0]))
121 response.mustcontain(_shorten_commit_id(commit_ids[0]))
106 response.mustcontain(_shorten_commit_id(commit_ids[1]))
122 response.mustcontain(_shorten_commit_id(commit_ids[1]))
@@ -137,8 +153,8 b' class TestChangesetController(object):'
137 '337'),
153 '337'),
138 }
154 }
139 commit_ids = commit_id_range[backend.alias]
155 commit_ids = commit_id_range[backend.alias]
140 response = self.app.get(url(
156 response = self.app.get(route_path(
141 controller='compare', action='compare',
157 'repo_compare',
142 repo_name=backend.repo_name,
158 repo_name=backend.repo_name,
143 source_ref_type='rev', source_ref=commit_ids[0],
159 source_ref_type='rev', source_ref=commit_ids[0],
144 target_ref_type='rev', target_ref=commit_ids[1], ))
160 target_ref_type='rev', target_ref=commit_ids[1], ))
@@ -188,9 +204,10 b' class TestChangesetController(object):'
188 def _check_changeset_range(
204 def _check_changeset_range(
189 self, backend, commit_id_ranges, commit_id_range_result):
205 self, backend, commit_id_ranges, commit_id_range_result):
190 response = self.app.get(
206 response = self.app.get(
191 url(controller='changeset', action='index',
207 route_path('repo_commit',
192 repo_name=backend.repo_name,
208 repo_name=backend.repo_name,
193 revision=commit_id_ranges[backend.alias]))
209 commit_id=commit_id_ranges[backend.alias]))
210
194 expected_result = commit_id_range_result[backend.alias]
211 expected_result = commit_id_range_result[backend.alias]
195 response.mustcontain('{} commits'.format(len(expected_result)))
212 response.mustcontain('{} commits'.format(len(expected_result)))
196 for commit_id in expected_result:
213 for commit_id in expected_result:
@@ -139,8 +139,8 b' class RepoFeedView(RepoAppView):'
139 author_name=commit.author,
139 author_name=commit.author,
140 description=self._get_description(commit),
140 description=self._get_description(commit),
141 link=h.route_url(
141 link=h.route_url(
142 'changeset_home', repo_name=self.db_repo_name,
142 'repo_commit', repo_name=self.db_repo_name,
143 revision=commit.raw_id),
143 commit_id=commit.raw_id),
144 pubdate=date,)
144 pubdate=date,)
145
145
146 return feed.mime_type, feed.writeString('utf-8')
146 return feed.mime_type, feed.writeString('utf-8')
@@ -185,8 +185,8 b' class RepoFeedView(RepoAppView):'
185 author_name=commit.author,
185 author_name=commit.author,
186 description=self._get_description(commit),
186 description=self._get_description(commit),
187 link=h.route_url(
187 link=h.route_url(
188 'changeset_home', repo_name=self.db_repo_name,
188 'repo_commit', repo_name=self.db_repo_name,
189 revision=commit.raw_id),
189 commit_id=commit.raw_id),
190 pubdate=date,)
190 pubdate=date,)
191
191
192 return feed.mime_type, feed.writeString('utf-8')
192 return feed.mime_type, feed.writeString('utf-8')
@@ -1043,8 +1043,8 b' class RepoFilesView(RepoAppView):'
1043 log.exception('Error during commit operation')
1043 log.exception('Error during commit operation')
1044 h.flash(_('Error occurred during commit'), category='error')
1044 h.flash(_('Error occurred during commit'), category='error')
1045 raise HTTPFound(
1045 raise HTTPFound(
1046 h.route_path('changeset_home', repo_name=self.db_repo_name,
1046 h.route_path('repo_commit', repo_name=self.db_repo_name,
1047 revision='tip'))
1047 commit_id='tip'))
1048
1048
1049 @LoginRequired()
1049 @LoginRequired()
1050 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1050 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
@@ -1133,8 +1133,8 b' class RepoFilesView(RepoAppView):'
1133 if content == old_content and filename == org_filename:
1133 if content == old_content and filename == org_filename:
1134 h.flash(_('No changes'), category='warning')
1134 h.flash(_('No changes'), category='warning')
1135 raise HTTPFound(
1135 raise HTTPFound(
1136 h.route_path('changeset_home', repo_name=self.db_repo_name,
1136 h.route_path('repo_commit', repo_name=self.db_repo_name,
1137 revision='tip'))
1137 commit_id='tip'))
1138 try:
1138 try:
1139 mapping = {
1139 mapping = {
1140 org_f_path: {
1140 org_f_path: {
@@ -1161,8 +1161,8 b' class RepoFilesView(RepoAppView):'
1161 log.exception('Error occurred during commit')
1161 log.exception('Error occurred during commit')
1162 h.flash(_('Error occurred during commit'), category='error')
1162 h.flash(_('Error occurred during commit'), category='error')
1163 raise HTTPFound(
1163 raise HTTPFound(
1164 h.route_path('changeset_home', repo_name=self.db_repo_name,
1164 h.route_path('repo_commit', repo_name=self.db_repo_name,
1165 revision='tip'))
1165 commit_id='tip'))
1166
1166
1167 @LoginRequired()
1167 @LoginRequired()
1168 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1168 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
@@ -1222,7 +1222,7 b' class RepoFilesView(RepoAppView):'
1222 content = content.file
1222 content = content.file
1223
1223
1224 default_redirect_url = h.route_path(
1224 default_redirect_url = h.route_path(
1225 'changeset_home', repo_name=self.db_repo_name, revision='tip')
1225 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1226
1226
1227 # If there's no commit, redirect to repo summary
1227 # If there's no commit, redirect to repo summary
1228 if type(c.commit) is EmptyCommit:
1228 if type(c.commit) is EmptyCommit:
@@ -429,19 +429,6 b' def make_map(config):'
429 controller='admin/repos', action='repo_check',
429 controller='admin/repos', action='repo_check',
430 requirements=URL_NAME_REQUIREMENTS)
430 requirements=URL_NAME_REQUIREMENTS)
431
431
432 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
433 controller='changeset', revision='tip',
434 conditions={'function': check_repo},
435 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
436 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
437 controller='changeset', revision='tip', action='changeset_children',
438 conditions={'function': check_repo},
439 requirements=URL_NAME_REQUIREMENTS)
440 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
441 controller='changeset', revision='tip', action='changeset_parents',
442 conditions={'function': check_repo},
443 requirements=URL_NAME_REQUIREMENTS)
444
445 # repo edit options
432 # repo edit options
446 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
433 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
447 controller='admin/repos', action='edit_fields',
434 controller='admin/repos', action='edit_fields',
@@ -515,54 +502,6 b' def make_map(config):'
515 conditions={'method': ['GET', 'POST'], 'function': check_repo},
502 conditions={'method': ['GET', 'POST'], 'function': check_repo},
516 requirements=URL_NAME_REQUIREMENTS)
503 requirements=URL_NAME_REQUIREMENTS)
517
504
518 # still working url for backward compat.
519 rmap.connect('raw_changeset_home_depraced',
520 '/{repo_name}/raw-changeset/{revision}',
521 controller='changeset', action='changeset_raw',
522 revision='tip', conditions={'function': check_repo},
523 requirements=URL_NAME_REQUIREMENTS)
524
525 # new URLs
526 rmap.connect('changeset_raw_home',
527 '/{repo_name}/changeset-diff/{revision}',
528 controller='changeset', action='changeset_raw',
529 revision='tip', conditions={'function': check_repo},
530 requirements=URL_NAME_REQUIREMENTS)
531
532 rmap.connect('changeset_patch_home',
533 '/{repo_name}/changeset-patch/{revision}',
534 controller='changeset', action='changeset_patch',
535 revision='tip', conditions={'function': check_repo},
536 requirements=URL_NAME_REQUIREMENTS)
537
538 rmap.connect('changeset_download_home',
539 '/{repo_name}/changeset-download/{revision}',
540 controller='changeset', action='changeset_download',
541 revision='tip', conditions={'function': check_repo},
542 requirements=URL_NAME_REQUIREMENTS)
543
544 rmap.connect('changeset_comment',
545 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
546 controller='changeset', revision='tip', action='comment',
547 conditions={'function': check_repo},
548 requirements=URL_NAME_REQUIREMENTS)
549
550 rmap.connect('changeset_comment_preview',
551 '/{repo_name}/changeset/comment/preview', jsroute=True,
552 controller='changeset', action='preview_comment',
553 conditions={'function': check_repo, 'method': ['POST']},
554 requirements=URL_NAME_REQUIREMENTS)
555
556 rmap.connect('changeset_comment_delete',
557 '/{repo_name}/changeset/comment/{comment_id}/delete',
558 controller='changeset', action='delete_comment',
559 conditions={'function': check_repo, 'method': ['DELETE']},
560 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
561
562 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
563 controller='changeset', action='changeset_info',
564 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
565
566 rmap.connect('compare_home',
505 rmap.connect('compare_home',
567 '/{repo_name}/compare',
506 '/{repo_name}/compare',
568 controller='compare', action='index',
507 controller='compare', action='index',
@@ -20,7 +20,6 b''
20
20
21 import logging
21 import logging
22
22
23 from pylons import url
24 from pylons.i18n.translation import _
23 from pylons.i18n.translation import _
25 from webhelpers.html.builder import literal
24 from webhelpers.html.builder import literal
26 from webhelpers.html.tags import link_to
25 from webhelpers.html.tags import link_to
@@ -201,6 +200,7 b' class ActionParser(object):'
201 return literal(tmpl % (ico, self.action))
200 return literal(tmpl % (ico, self.action))
202
201
203 def get_cs_links(self):
202 def get_cs_links(self):
203 from rhodecode.lib import helpers as h
204 if self.is_deleted():
204 if self.is_deleted():
205 return self.action_params
205 return self.action_params
206
206
@@ -223,8 +223,9 b' class ActionParser(object):'
223 _('Show all combined commits %s->%s') % (
223 _('Show all combined commits %s->%s') % (
224 commit_ids[0][:12], commit_ids[-1][:12]
224 commit_ids[0][:12], commit_ids[-1][:12]
225 ),
225 ),
226 url('changeset_home', repo_name=repo_name,
226 h.route_path(
227 revision=commit_id_range), _('compare view')
227 'repo_commit', repo_name=repo_name,
228 commit_id=commit_id_range), _('compare view')
228 )
229 )
229 )
230 )
230
231
@@ -275,6 +276,7 b' class ActionParser(object):'
275
276
276 def lnk(self, commit_or_id, repo_name):
277 def lnk(self, commit_or_id, repo_name):
277 from rhodecode.lib.helpers import tooltip
278 from rhodecode.lib.helpers import tooltip
279 from rhodecode.lib import helpers as h
278
280
279 if isinstance(commit_or_id, (BaseCommit, AttributeDict)):
281 if isinstance(commit_or_id, (BaseCommit, AttributeDict)):
280 lazy_cs = True
282 lazy_cs = True
@@ -292,8 +294,8 b' class ActionParser(object):'
292
294
293 else:
295 else:
294 lbl = '%s' % (commit_or_id.short_id[:8])
296 lbl = '%s' % (commit_or_id.short_id[:8])
295 _url = url('changeset_home', repo_name=repo_name,
297 _url = h.route_path('repo_commit', repo_name=repo_name,
296 revision=commit_or_id.raw_id)
298 commit_id=commit_or_id.raw_id)
297 title = tooltip(commit_or_id.message)
299 title = tooltip(commit_or_id.message)
298 else:
300 else:
299 # commit cannot be found/striped/removed etc.
301 # commit cannot be found/striped/removed etc.
@@ -754,7 +754,7 b' class PermissionCalculator(object):'
754 }
754 }
755
755
756
756
757 def allowed_auth_token_access(controller_name, whitelist=None, auth_token=None):
757 def allowed_auth_token_access(view_name, whitelist=None, auth_token=None):
758 """
758 """
759 Check if given controller_name is in whitelist of auth token access
759 Check if given controller_name is in whitelist of auth token access
760 """
760 """
@@ -767,16 +767,16 b' def allowed_auth_token_access(controller'
767
767
768 auth_token_access_valid = False
768 auth_token_access_valid = False
769 for entry in whitelist:
769 for entry in whitelist:
770 if fnmatch.fnmatch(controller_name, entry):
770 if fnmatch.fnmatch(view_name, entry):
771 auth_token_access_valid = True
771 auth_token_access_valid = True
772 break
772 break
773
773
774 if auth_token_access_valid:
774 if auth_token_access_valid:
775 log.debug('controller:%s matches entry in whitelist'
775 log.debug('view: `%s` matches entry in whitelist: %s'
776 % (controller_name,))
776 % (view_name, whitelist))
777 else:
777 else:
778 msg = ('controller: %s does *NOT* match any entry in whitelist'
778 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
779 % (controller_name,))
779 % (view_name, whitelist))
780 if auth_token:
780 if auth_token:
781 # if we use auth token key and don't have access it's a warning
781 # if we use auth token key and don't have access it's a warning
782 log.warning(msg)
782 log.warning(msg)
@@ -1575,7 +1575,7 b' def urlify_commits(text_, repository):'
1575 :param text_:
1575 :param text_:
1576 :param repository: repo name to build the URL with
1576 :param repository: repo name to build the URL with
1577 """
1577 """
1578 from pylons import url # doh, we need to re-import url to mock it later
1578
1579 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1579 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1580
1580
1581 def url_func(match_obj):
1581 def url_func(match_obj):
@@ -1590,8 +1590,8 b' def urlify_commits(text_, repository):'
1590 return tmpl % {
1590 return tmpl % {
1591 'pref': pref,
1591 'pref': pref,
1592 'cls': 'revision-link',
1592 'cls': 'revision-link',
1593 'url': url('changeset_home', repo_name=repository,
1593 'url': route_url('repo_commit', repo_name=repository,
1594 revision=commit_id, qualified=True),
1594 commit_id=commit_id),
1595 'commit_id': commit_id,
1595 'commit_id': commit_id,
1596 'suf': suf
1596 'suf': suf
1597 }
1597 }
@@ -15,11 +15,6 b' function registerRCRoutes() {'
15 pyroutes.register('new_repo', '/_admin/create_repository', []);
15 pyroutes.register('new_repo', '/_admin/create_repository', []);
16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
16 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
18 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
19 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
20 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
21 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
22 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
23 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
18 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
24 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
19 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
25 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
20 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
@@ -111,6 +106,16 b' function registerRCRoutes() {'
111 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
106 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
112 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
107 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
113 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
108 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
109 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
110 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
111 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
112 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
113 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
114 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
115 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
116 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
117 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
118 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
114 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
119 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
115 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
120 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
116 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
121 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
@@ -146,9 +151,6 b' function registerRCRoutes() {'
146 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
151 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
147 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
152 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
148 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
153 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
149 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
150 pyroutes.register('changeset_children', '/%(repo_name)s/changeset_children/%(revision)s', ['repo_name', 'revision']);
151 pyroutes.register('changeset_parents', '/%(repo_name)s/changeset_parents/%(revision)s', ['repo_name', 'revision']);
152 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
154 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
153 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
155 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
154 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
156 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
@@ -103,8 +103,9 b' var bindToggleButtons = function() {'
103 this.submitButton = $(this.submitForm).find('input[type="submit"]');
103 this.submitButton = $(this.submitForm).find('input[type="submit"]');
104 this.submitButtonText = this.submitButton.val();
104 this.submitButtonText = this.submitButton.val();
105
105
106 this.previewUrl = pyroutes.url('changeset_comment_preview',
106 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
107 {'repo_name': templateContext.repo_name});
107 {'repo_name': templateContext.repo_name,
108 'commit_id': templateContext.commit_data.commit_id});
108
109
109 if (resolvesCommentId){
110 if (resolvesCommentId){
110 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
111 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
@@ -129,12 +130,12 b' var bindToggleButtons = function() {'
129 // based on commitId, or pullRequestId decide where do we submit
130 // based on commitId, or pullRequestId decide where do we submit
130 // out data
131 // out data
131 if (this.commitId){
132 if (this.commitId){
132 this.submitUrl = pyroutes.url('changeset_comment',
133 this.submitUrl = pyroutes.url('repo_commit_comment_create',
133 {'repo_name': templateContext.repo_name,
134 {'repo_name': templateContext.repo_name,
134 'revision': this.commitId});
135 'commit_id': this.commitId});
135 this.selfUrl = pyroutes.url('changeset_home',
136 this.selfUrl = pyroutes.url('repo_commit',
136 {'repo_name': templateContext.repo_name,
137 {'repo_name': templateContext.repo_name,
137 'revision': this.commitId});
138 'commit_id': this.commitId});
138
139
139 } else if (this.pullRequestId) {
140 } else if (this.pullRequestId) {
140 this.submitUrl = pyroutes.url('pullrequest_comment',
141 this.submitUrl = pyroutes.url('pullrequest_comment',
@@ -5,7 +5,7 b''
5 (_('Owner'), lambda:base.gravatar_with_user(c.repo_info.user.email), '', ''),
5 (_('Owner'), lambda:base.gravatar_with_user(c.repo_info.user.email), '', ''),
6 (_('Created on'), h.format_date(c.repo_info.created_on), '', ''),
6 (_('Created on'), h.format_date(c.repo_info.created_on), '', ''),
7 (_('Updated on'), h.format_date(c.repo_info.updated_on), '', ''),
7 (_('Updated on'), h.format_date(c.repo_info.updated_on), '', ''),
8 (_('Cached Commit id'), lambda: h.link_to(c.repo_info.changeset_cache.get('short_id'), h.url('changeset_home',repo_name=c.repo_name,revision=c.repo_info.changeset_cache.get('raw_id'))), '', ''),
8 (_('Cached Commit id'), lambda: h.link_to(c.repo_info.changeset_cache.get('short_id'), h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.repo_info.changeset_cache.get('raw_id'))), '', ''),
9 ]
9 ]
10 %>
10 %>
11
11
@@ -161,9 +161,9 b''
161 if (selectedCheckboxes.length>0){
161 if (selectedCheckboxes.length>0){
162 var revEnd = selectedCheckboxes[0].name;
162 var revEnd = selectedCheckboxes[0].name;
163 var revStart = selectedCheckboxes[selectedCheckboxes.length-1].name;
163 var revStart = selectedCheckboxes[selectedCheckboxes.length-1].name;
164 var url = pyroutes.url('changeset_home',
164 var url = pyroutes.url('repo_commit',
165 {'repo_name': '${c.repo_name}',
165 {'repo_name': '${c.repo_name}',
166 'revision': revStart+'...'+revEnd});
166 'commit_id': revStart+'...'+revEnd});
167
167
168 var link = (revStart == revEnd)
168 var link = (revStart == revEnd)
169 ? _gettext('Show selected commit __S')
169 ? _gettext('Show selected commit __S')
@@ -24,11 +24,11 b''
24 <div class="changeset-status-ico">
24 <div class="changeset-status-ico">
25 %if c.statuses.get(commit.raw_id)[2]:
25 %if c.statuses.get(commit.raw_id)[2]:
26 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.route_path('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
26 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.route_path('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
27 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
27 <div class="${'flag_status {}'.format(c.statuses.get(commit.raw_id)[0])}"></div>
28 </a>
28 </a>
29 %else:
29 %else:
30 <a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(commit.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
30 <a class="tooltip" title="${_('Commit status: {}').format(h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]))}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id,_anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
31 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
31 <div class="${'flag_status {}'.format(c.statuses.get(commit.raw_id)[0])}"></div>
32 </a>
32 </a>
33 %endif
33 %endif
34 </div>
34 </div>
@@ -38,7 +38,7 b''
38 </td>
38 </td>
39 <td class="td-comments comments-col">
39 <td class="td-comments comments-col">
40 %if c.comments.get(commit.raw_id):
40 %if c.comments.get(commit.raw_id):
41 <a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
41 <a title="${_('Commit has comments')}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id,_anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
42 <i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
42 <i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
43 </a>
43 </a>
44 %endif
44 %endif
@@ -46,7 +46,7 b''
46 <td class="td-hash">
46 <td class="td-hash">
47 <code>
47 <code>
48
48
49 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">
49 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id)}">
50 <span class="${'commit_hash obsolete' if getattr(commit, 'obsolete', None) else 'commit_hash'}">${h.show_id(commit)}</span>
50 <span class="${'commit_hash obsolete' if getattr(commit, 'obsolete', None) else 'commit_hash'}">${h.show_id(commit)}</span>
51 </a>
51 </a>
52 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
52 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${commit.raw_id}" title="${_('Copy the full commit id')}"></i>
@@ -15,7 +15,7 b''
15 <td class="td-message">
15 <td class="td-message">
16 <div class="log-container">
16 <div class="log-container">
17 <div class="message_history" title="${h.tooltip(cs.message)}">
17 <div class="message_history" title="${h.tooltip(cs.message)}">
18 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
18 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}">
19 ${h.shorter(cs.message, 75)}
19 ${h.shorter(cs.message, 75)}
20 </a>
20 </a>
21 </div>
21 </div>
@@ -23,7 +23,7 b''
23 </td>
23 </td>
24 <td class="td-hash">
24 <td class="td-hash">
25 <code>
25 <code>
26 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
26 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}">
27 <span>${h.show_id(cs)}</span>
27 <span>${h.show_id(cs)}</span>
28 </a>
28 </a>
29 </code>
29 </code>
@@ -21,7 +21,7 b''
21 <%def name="main()">
21 <%def name="main()">
22 <script>
22 <script>
23 // TODO: marcink switch this to pyroutes
23 // TODO: marcink switch this to pyroutes
24 AJAX_COMMENT_DELETE_URL = "${h.url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
24 AJAX_COMMENT_DELETE_URL = "${h.route_path('repo_commit_comment_delete',repo_name=c.repo_name,commit_id=c.commit.raw_id,comment_id='__COMMENT_ID__')}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
26 </script>
26 </script>
27 <div class="box">
27 <div class="box">
@@ -137,21 +137,21 b''
137 </div>
137 </div>
138 <div class="right-content">
138 <div class="right-content">
139 <div class="diff-actions">
139 <div class="diff-actions">
140 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
140 <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
141 ${_('Raw Diff')}
141 ${_('Raw Diff')}
142 </a>
142 </a>
143 |
143 |
144 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
144 <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
145 ${_('Patch Diff')}
145 ${_('Patch Diff')}
146 </a>
146 </a>
147 |
147 |
148 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
148 <a href="${h.route_path('repo_commit_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,_query=dict(diff='download'))}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
149 ${_('Download Diff')}
149 ${_('Download Diff')}
150 </a>
150 </a>
151 |
151 |
152 ${c.ignorews_url(request.GET)}
152 ${c.ignorews_url(request)}
153 |
153 |
154 ${c.context_url(request.GET)}
154 ${c.context_url(request)}
155 </div>
155 </div>
156 </div>
156 </div>
157 </div>
157 </div>
@@ -221,7 +221,7 b''
221 ${comment.generate_comments(c.comments)}
221 ${comment.generate_comments(c.comments)}
222
222
223 ## main comment form and it status
223 ## main comment form and it status
224 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id),
224 ${comment.comments(h.route_path('repo_commit_comment_create', repo_name=c.repo_name, commit_id=c.commit.raw_id),
225 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
225 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
226 </div>
226 </div>
227
227
@@ -264,14 +264,14 b''
264 // >1 links show them to user to choose
264 // >1 links show them to user to choose
265 if(!$('#child_link').hasClass('disabled')){
265 if(!$('#child_link').hasClass('disabled')){
266 $.ajax({
266 $.ajax({
267 url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}',
267 url: '${h.route_path('repo_commit_children',repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
268 success: function(data) {
268 success: function(data) {
269 if(data.results.length === 0){
269 if(data.results.length === 0){
270 $('#child_link').html("${_('No Child Commits')}").addClass('disabled');
270 $('#child_link').html("${_('No Child Commits')}").addClass('disabled');
271 }
271 }
272 if(data.results.length === 1){
272 if(data.results.length === 1){
273 var commit = data.results[0];
273 var commit = data.results[0];
274 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
274 window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
275 }
275 }
276 else if(data.results.length === 2){
276 else if(data.results.length === 2){
277 $('#child_link').addClass('disabled');
277 $('#child_link').addClass('disabled');
@@ -280,12 +280,12 b''
280 _html +='<a title="__title__" href="__url__">__rev__</a> '
280 _html +='<a title="__title__" href="__url__">__rev__</a> '
281 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
281 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
282 .replace('__title__', data.results[0].message)
282 .replace('__title__', data.results[0].message)
283 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
283 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
284 _html +=' | ';
284 _html +=' | ';
285 _html +='<a title="__title__" href="__url__">__rev__</a> '
285 _html +='<a title="__title__" href="__url__">__rev__</a> '
286 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
286 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
287 .replace('__title__', data.results[1].message)
287 .replace('__title__', data.results[1].message)
288 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
288 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
289 $('#child_link').html(_html);
289 $('#child_link').html(_html);
290 }
290 }
291 }
291 }
@@ -300,14 +300,14 b''
300 // >1 links show them to user to choose
300 // >1 links show them to user to choose
301 if(!$('#parent_link').hasClass('disabled')){
301 if(!$('#parent_link').hasClass('disabled')){
302 $.ajax({
302 $.ajax({
303 url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}',
303 url: '${h.route_path("repo_commit_parents",repo_name=c.repo_name, commit_id=c.commit.raw_id)}',
304 success: function(data) {
304 success: function(data) {
305 if(data.results.length === 0){
305 if(data.results.length === 0){
306 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
306 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
307 }
307 }
308 if(data.results.length === 1){
308 if(data.results.length === 1){
309 var commit = data.results[0];
309 var commit = data.results[0];
310 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
310 window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id});
311 }
311 }
312 else if(data.results.length === 2){
312 else if(data.results.length === 2){
313 $('#parent_link').addClass('disabled');
313 $('#parent_link').addClass('disabled');
@@ -316,12 +316,12 b''
316 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
316 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
317 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
317 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
318 .replace('__title__', data.results[0].message)
318 .replace('__title__', data.results[0].message)
319 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
319 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id}));
320 _html +=' | ';
320 _html +=' | ';
321 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
321 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
322 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
322 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
323 .replace('__title__', data.results[1].message)
323 .replace('__title__', data.results[1].message)
324 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
324 .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id}));
325 $('#parent_link').html(_html);
325 $('#parent_link').html(_html);
326 }
326 }
327 }
327 }
@@ -100,7 +100,7 b''
100 % endif
100 % endif
101 % if inline:
101 % if inline:
102 <div class="pr-version-inline">
102 <div class="pr-version-inline">
103 <a href="${h.url.current(version=comment.pull_request_version_id, anchor='comment-{}'.format(comment.comment_id))}">
103 <a href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}">
104 % if outdated_at_ver:
104 % if outdated_at_ver:
105 <code class="pr-version-num" title="${_('Outdated comment from pull request version {0}').format(pr_index_ver)}">
105 <code class="pr-version-num" title="${_('Outdated comment from pull request version {0}').format(pr_index_ver)}">
106 outdated ${'v{}'.format(pr_index_ver)} |
106 outdated ${'v{}'.format(pr_index_ver)} |
@@ -70,15 +70,15 b''
70 </div>
70 </div>
71 <div class="right-content">
71 <div class="right-content">
72 <div class="diff-actions">
72 <div class="diff-actions">
73 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
73 <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
74 ${_('Raw Diff')}
74 ${_('Raw Diff')}
75 </a>
75 </a>
76 |
76 |
77 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
77 <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
78 ${_('Patch Diff')}
78 ${_('Patch Diff')}
79 </a>
79 </a>
80 |
80 |
81 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
81 <a href="${h.route_path('repo_commit_download',repo_name=c.repo_name,commit_id='?',_query=dict(diff='download'))}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
82 ${_('Download Diff')}
82 ${_('Download Diff')}
83 </a>
83 </a>
84 </div>
84 </div>
@@ -121,7 +121,7 b' collapse_all = len(diffset.files) > coll'
121 %endif
121 %endif
122 <h2 class="clearinner">
122 <h2 class="clearinner">
123 %if commit:
123 %if commit:
124 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> -
124 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> -
125 ${h.age_component(commit.date)} -
125 ${h.age_component(commit.date)} -
126 %endif
126 %endif
127 %if diffset.limited_diff:
127 %if diffset.limited_diff:
@@ -459,10 +459,10 b' from rhodecode.lib.diffs import NEW_FILE'
459
459
460 ## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks)
460 ## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks)
461 %if hasattr(c, 'ignorews_url'):
461 %if hasattr(c, 'ignorews_url'):
462 ${c.ignorews_url(request.GET, h.FID('', filediff.patch['filename']))}
462 ${c.ignorews_url(request, h.FID('', filediff.patch['filename']))}
463 %endif
463 %endif
464 %if hasattr(c, 'context_url'):
464 %if hasattr(c, 'context_url'):
465 ${c.context_url(request.GET, h.FID('', filediff.patch['filename']))}
465 ${c.context_url(request, h.FID('', filediff.patch['filename']))}
466 %endif
466 %endif
467
467
468 %if use_comments:
468 %if use_comments:
@@ -31,7 +31,7 b''
31 data-revision="${annotation.revision}"
31 data-revision="${annotation.revision}"
32 onclick="$('[data-revision=${annotation.revision}]').toggleClass('cb-line-fresh')"
32 onclick="$('[data-revision=${annotation.revision}]').toggleClass('cb-line-fresh')"
33 style="background: ${bgcolor}">
33 style="background: ${bgcolor}">
34 <a class="cb-annotate" href="${h.url('changeset_home',repo_name=c.repo_name,revision=annotation.raw_id)}">
34 <a class="cb-annotate" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=annotation.raw_id)}">
35 r${annotation.revision}
35 r${annotation.revision}
36 </a>
36 </a>
37 </td>
37 </td>
@@ -3,7 +3,7 b''
3
3
4 %if c.ancestor:
4 %if c.ancestor:
5 <div class="ancestor">${_('Common Ancestor Commit')}:
5 <div class="ancestor">${_('Common Ancestor Commit')}:
6 <a href="${h.url('changeset_home', repo_name=c.repo_name, revision=c.ancestor)}">
6 <a href="${h.route_path('repo_commit', repo_name=c.repo_name, commit_id=c.ancestor)}">
7 ${h.short_id(c.ancestor)}
7 ${h.short_id(c.ancestor)}
8 </a>. ${_('Compare was calculated based on this shared commit.')}
8 </a>. ${_('Compare was calculated based on this shared commit.')}
9 <input id="common_ancestor" type="hidden" name="common_ancestor" value="${c.ancestor}">
9 <input id="common_ancestor" type="hidden" name="common_ancestor" value="${c.ancestor}">
@@ -34,9 +34,7 b''
34 </td>
34 </td>
35 <td class="td-hash">
35 <td class="td-hash">
36 <code>
36 <code>
37 <a href="${h.url('changeset_home',
37 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
38 repo_name=c.target_repo.repo_name,
39 revision=commit.raw_id)}">
40 r${commit.revision}:${h.short_id(commit.raw_id)}
38 r${commit.revision}:${h.short_id(commit.raw_id)}
41 </a>
39 </a>
42 ${h.hidden('revisions',commit.raw_id)}
40 ${h.hidden('revisions',commit.raw_id)}
@@ -137,15 +137,15 b''
137 </div>
137 </div>
138 <div class="right-content">
138 <div class="right-content">
139 <div class="diff-actions">
139 <div class="diff-actions">
140 <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
140 <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}">
141 ${_('Raw Diff')}
141 ${_('Raw Diff')}
142 </a>
142 </a>
143 |
143 |
144 <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
144 <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}">
145 ${_('Patch Diff')}
145 ${_('Patch Diff')}
146 </a>
146 </a>
147 |
147 |
148 <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
148 <a href="${h.route_path('repo_commit_download',repo_name=c.repo_name,commit_id='?',_query=dict(diff='download'))}" class="tooltip" title="${h.tooltip(_('Download diff'))}">
149 ${_('Download Diff')}
149 ${_('Download Diff')}
150 </a>
150 </a>
151 </div>
151 </div>
@@ -170,7 +170,7 b''
170 return form_inputs
170 return form_inputs
171 %>
171 %>
172 <div>
172 <div>
173 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision='0'*16), None, is_compare=True, form_extras=revs(c.commit_ranges))}
173 ${comment.comments(h.route_path('repo_commit_comment_create', repo_name=c.repo_name, commit_id='0'*16), None, is_compare=True, form_extras=revs(c.commit_ranges))}
174 </div>
174 </div>
175 </div>
175 </div>
176 </div>
176 </div>
@@ -83,7 +83,7 b''
83 <%def name="revision(name,rev,tip,author,last_msg)">
83 <%def name="revision(name,rev,tip,author,last_msg)">
84 <div>
84 <div>
85 %if rev >= 0:
85 %if rev >= 0:
86 <code><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></code>
86 <code><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.route_path('repo_commit',repo_name=name,commit_id=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></code>
87 %else:
87 %else:
88 ${_('No commits yet')}
88 ${_('No commits yet')}
89 %endif
89 %endif
@@ -840,7 +840,8 b''
840 $('#edit-container').hide();
840 $('#edit-container').hide();
841 $('#preview-container').show();
841 $('#preview-container').show();
842
842
843 var url = pyroutes.url('changeset_comment_preview', {'repo_name': 'rhodecode-momentum'});
843 var url = pyroutes.url('repo_commit_comment_preview',
844 {'repo_name': 'rhodecode-momentum', 'commit_id': '000000'});
844
845
845 ajaxPOST(url, post_data, function(o) {
846 ajaxPOST(url, post_data, function(o) {
846 previewbox.html(o);
847 previewbox.html(o);
@@ -17,7 +17,7 b''
17 tag: ${tag} <br/>
17 tag: ${tag} <br/>
18 % endfor
18 % endfor
19
19
20 commit: <a href="${h.url('changeset_home', repo_name=c.rhodecode_db_repo.repo_name, revision=commit.raw_id, qualified=True)}">${h.show_id(commit)}</a>
20 commit: <a href="${h.route_url('repo_commit', repo_name=c.rhodecode_db_repo.repo_name, commit_id=commit.raw_id)}">${h.show_id(commit)}</a>
21 <pre>
21 <pre>
22 ${h.urlify_commit_message(commit.message)}
22 ${h.urlify_commit_message(commit.message)}
23
23
@@ -23,7 +23,7 b''
23 <div class="right-content">
23 <div class="right-content">
24 <div class="tags">
24 <div class="tags">
25 <code>
25 <code>
26 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.commit.raw_id)}">${h.show_id(c.commit)}</a>
26 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">${h.show_id(c.commit)}</a>
27 </code>
27 </code>
28
28
29 ${file_base.refs(c.commit)}
29 ${file_base.refs(c.commit)}
@@ -217,7 +217,9 b''
217 var _renderer = possible_renderer || DEFAULT_RENDERER;
217 var _renderer = possible_renderer || DEFAULT_RENDERER;
218 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
218 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
219 $('#editor_preview').html(_gettext('Loading ...'));
219 $('#editor_preview').html(_gettext('Loading ...'));
220 var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
220 var url = pyroutes.url('repo_commit_comment_preview',
221 {'repo_name': '${c.repo_name}',
222 'commit_id': '${c.commit.raw_id}'});
221
223
222 ajaxPOST(url, post_data, function(o){
224 ajaxPOST(url, post_data, function(o){
223 $('#editor_preview').html(o);
225 $('#editor_preview').html(o);
@@ -21,7 +21,7 b''
21 </div>
21 </div>
22 <div class="right-content">
22 <div class="right-content">
23 <div class="tags tags-main">
23 <div class="tags tags-main">
24 <code><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.commit.raw_id)}">${h.show_id(c.commit)}</a></code>
24 <code><a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">${h.show_id(c.commit)}</a></code>
25 ${file_base.refs(c.commit)}
25 ${file_base.refs(c.commit)}
26 </div>
26 </div>
27 </div>
27 </div>
@@ -33,7 +33,7 b''
33 </div>
33 </div>
34 <div class="right-content">
34 <div class="right-content">
35 <div class="tags">
35 <div class="tags">
36 <code><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.file_last_commit.raw_id)}">${h.show_id(c.file_last_commit)}</a></code>
36 <code><a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.file_last_commit.raw_id)}">${h.show_id(c.file_last_commit)}</a></code>
37
37
38 ${file_base.refs(c.file_last_commit)}
38 ${file_base.refs(c.file_last_commit)}
39 </div>
39 </div>
@@ -47,7 +47,7 b''
47 <div class="code-header">
47 <div class="code-header">
48 <div class="stats">
48 <div class="stats">
49 <i class="icon-file"></i>
49 <i class="icon-file"></i>
50 <span class="item">${h.link_to("r%s:%s" % (c.file.commit.idx,h.short_id(c.file.commit.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.commit.raw_id))}</span>
50 <span class="item">${h.link_to("r%s:%s" % (c.file.commit.idx,h.short_id(c.file.commit.raw_id)),h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.file.commit.raw_id))}</span>
51 <span class="item">${h.format_byte_size_binary(c.file.size)}</span>
51 <span class="item">${h.format_byte_size_binary(c.file.size)}</span>
52 <span class="item last">${c.file.mimetype}</span>
52 <span class="item last">${c.file.mimetype}</span>
53 <div class="buttons">
53 <div class="buttons">
@@ -177,8 +177,9 b''
177 var _renderer = possible_renderer || DEFAULT_RENDERER;
177 var _renderer = possible_renderer || DEFAULT_RENDERER;
178 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
178 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
179 $('#editor_preview').html(_gettext('Loading ...'));
179 $('#editor_preview').html(_gettext('Loading ...'));
180 var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
180 var url = pyroutes.url('repo_commit_comment_preview',
181
181 {'repo_name': '${c.repo_name}',
182 'commit_id': '${c.commit.raw_id}'});
182 ajaxPOST(url, post_data, function(o){
183 ajaxPOST(url, post_data, function(o){
183 $('#editor_preview').html(o);
184 $('#editor_preview').html(o);
184 })
185 })
@@ -86,7 +86,7 b''
86 <br/>
86 <br/>
87 % if c.ancestor_commit:
87 % if c.ancestor_commit:
88 ${_('Common ancestor')}:
88 ${_('Common ancestor')}:
89 <code><a href="${h.url('changeset_home', repo_name=c.target_repo.repo_name, revision=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a></code>
89 <code><a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a></code>
90 % endif
90 % endif
91 </div>
91 </div>
92 <div class="pr-pullinfo">
92 <div class="pr-pullinfo">
@@ -513,7 +513,7 b''
513 </td>
513 </td>
514 <td class="td-hash">
514 <td class="td-hash">
515 <code>
515 <code>
516 <a href="${h.url('changeset_home', repo_name=c.target_repo.repo_name, revision=commit.raw_id)}">
516 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
517 r${commit.revision}:${h.short_id(commit.raw_id)}
517 r${commit.revision}:${h.short_id(commit.raw_id)}
518 </a>
518 </a>
519 ${h.hidden('revisions', commit.raw_id)}
519 ${h.hidden('revisions', commit.raw_id)}
@@ -31,7 +31,7 b''
31 </td>
31 </td>
32 <td class="td-commit">
32 <td class="td-commit">
33 ${h.link_to(h._shorten_commit_id(entry['commit_id']),
33 ${h.link_to(h._shorten_commit_id(entry['commit_id']),
34 h.url('changeset_home',repo_name=entry['repository'],revision=entry['commit_id']))}
34 h.route_path('repo_commit',repo_name=entry['repository'],commit_id=entry['commit_id']))}
35 </td>
35 </td>
36 <td class="td-message expand_commit search open" data-commit-id="${h.md5_safe(entry['repository'])+entry['commit_id']}" id="t-${h.md5_safe(entry['repository'])+entry['commit_id']}" title="${_('Expand commit message')}">
36 <td class="td-message expand_commit search open" data-commit-id="${h.md5_safe(entry['repository'])+entry['commit_id']}" id="t-${h.md5_safe(entry['repository'])+entry['commit_id']}" title="${_('Expand commit message')}">
37 <div class="show_more_col">
37 <div class="show_more_col">
@@ -19,11 +19,11 b''
19 <div class="changeset-status-ico shortlog">
19 <div class="changeset-status-ico shortlog">
20 %if c.statuses.get(cs.raw_id)[2]:
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.route_path('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=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.route_path('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>
22 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
23 </a>
23 </a>
24 %else:
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)}">
25 <a class="tooltip" title="${_('Commit status: {}').format(h.commit_status_lbl(c.statuses.get(cs.raw_id)[0]))}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=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>
26 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
27 </a>
27 </a>
28 %endif
28 %endif
29 </div>
29 </div>
@@ -33,13 +33,13 b''
33 </td>
33 </td>
34 <td class="td-comments">
34 <td class="td-comments">
35 %if c.comments.get(cs.raw_id,[]):
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)}">
36 <a title="${_('Commit has comments')}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=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])}
37 <i class="icon-comment"></i> ${len(c.comments[cs.raw_id])}
38 </a>
38 </a>
39 %endif
39 %endif
40 </td>
40 </td>
41 <td class="td-commit">
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>
42 <pre><a href="${h.route_path('repo_commit', repo_name=c.repo_name, commit_id=cs.raw_id)}">${h.show_id(cs)}</a></pre>
43 </td>
43 </td>
44
44
45 <td class="td-description mid">
45 <td class="td-description mid">
@@ -471,7 +471,7 b' class TestCompareController(object):'
471 compare_page.contains_change_summary(1, 1, 0)
471 compare_page.contains_change_summary(1, 1, 0)
472
472
473 @pytest.mark.xfail_backends("svn")
473 @pytest.mark.xfail_backends("svn")
474 def test_compare_commits(self, backend):
474 def test_compare_commits(self, backend, xhr_header):
475 commit0 = backend.repo.get_commit(commit_idx=0)
475 commit0 = backend.repo.get_commit(commit_idx=0)
476 commit1 = backend.repo.get_commit(commit_idx=1)
476 commit1 = backend.repo.get_commit(commit_idx=1)
477
477
@@ -483,7 +483,7 b' class TestCompareController(object):'
483 target_ref_type="rev",
483 target_ref_type="rev",
484 target_ref=commit1.raw_id,
484 target_ref=commit1.raw_id,
485 merge='1',),
485 merge='1',),
486 extra_environ={'HTTP_X_PARTIAL_XHR': '1'},)
486 extra_environ=xhr_header,)
487
487
488 # outgoing commits between those commits
488 # outgoing commits between those commits
489 compare_page = ComparePage(response)
489 compare_page = ComparePage(response)
@@ -397,7 +397,7 b' def test_urlify_commits(sample, expected'
397
397
398 expected = _quick_url(expected)
398 expected = _quick_url(expected)
399
399
400 with mock.patch('pylons.url', fake_url):
400 with mock.patch('rhodecode.lib.helpers.route_url', fake_url):
401 from rhodecode.lib.helpers import urlify_commits
401 from rhodecode.lib.helpers import urlify_commits
402 assert urlify_commits(sample, 'repo_name') == expected
402 assert urlify_commits(sample, 'repo_name') == expected
403
403
@@ -1,7 +1,7 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE ENTERPRISE CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
@@ -64,7 +64,7 b' asyncore_use_poll = true'
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config <inifile.ini> --paste <inifile.ini>
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
@@ -153,8 +153,10 b' asyncore_use_poll = true'
153 ## prefix middleware for RhodeCode.
153 ## prefix middleware for RhodeCode.
154 ## recommended when using proxy setup.
154 ## recommended when using proxy setup.
155 ## allows to set RhodeCode under a prefix in server.
155 ## allows to set RhodeCode under a prefix in server.
156 ## eg https://server.com/<prefix>. Enable `filter-with =` option below as well.
156 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
157 ## optionally set prefix like: `prefix = /<your-prefix>`
157 ## And set your prefix like: `prefix = /custom_prefix`
158 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
159 ## to make your cookies only work on prefix url
158 [filter:proxy-prefix]
160 [filter:proxy-prefix]
159 use = egg:PasteDeploy#prefix
161 use = egg:PasteDeploy#prefix
160 prefix = /
162 prefix = /
@@ -238,27 +240,27 b' rss_items_per_page = 10'
238 rss_include_diff = false
240 rss_include_diff = false
239
241
240 ## gist URL alias, used to create nicer urls for gist. This should be an
242 ## gist URL alias, used to create nicer urls for gist. This should be an
241 ## url that does rewrites to _admin/gists/<gistid>.
243 ## url that does rewrites to _admin/gists/{gistid}.
242 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
244 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
243 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/<gistid>
245 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
244 gist_alias_url =
246 gist_alias_url =
245
247
246 ## List of controllers (using glob pattern syntax) that AUTH TOKENS could be
248 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
247 ## used for access.
249 ## used for access.
248 ## Adding ?auth_token = <token> to the url authenticates this request as if it
250 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
249 ## came from the the logged in user who own this authentication token.
251 ## came from the the logged in user who own this authentication token.
250 ##
252 ##
251 ## Syntax is <ControllerClass>:<function_pattern>.
253 ## list of all views can be found under `_admin/permissions/auth_token_access`
252 ## To enable access to raw_files put `FilesController:raw`.
253 ## To enable access to patches add `ChangesetController:changeset_patch`.
254 ## The list should be "," separated and on a single line.
254 ## The list should be "," separated and on a single line.
255 ##
255 ##
256 ## Recommended controllers to enable:
256 ## Most common views to enable:
257 # ChangesetController:changeset_patch,
257 # RepoCommitsView:repo_commit_download
258 # ChangesetController:changeset_raw,
258 # RepoCommitsView:repo_commit_patch
259 # FilesController:raw,
259 # RepoCommitsView:repo_commit_raw
260 # FilesController:archivefile,
260 # RepoFilesView:repo_files_diff
261 # GistsController:*,
261 # RepoFilesView:repo_archivefile
262 # RepoFilesView:repo_file_raw
263 # GistView:*
262 api_access_controllers_whitelist =
264 api_access_controllers_whitelist =
263
265
264 ## default encoding used to convert from and to unicode
266 ## default encoding used to convert from and to unicode
@@ -421,15 +423,15 b' beaker.session.lock_dir = %(here)s/rc/da'
421
423
422 ## Secure encrypted cookie. Requires AES and AES python libraries
424 ## Secure encrypted cookie. Requires AES and AES python libraries
423 ## you must disable beaker.session.secret to use this
425 ## you must disable beaker.session.secret to use this
424 #beaker.session.encrypt_key = <key_for_encryption>
426 #beaker.session.encrypt_key = key_for_encryption
425 #beaker.session.validate_key = <validation_key>
427 #beaker.session.validate_key = validation_key
426
428
427 ## sets session as invalid(also logging out user) if it haven not been
429 ## sets session as invalid(also logging out user) if it haven not been
428 ## accessed for given amount of time in seconds
430 ## accessed for given amount of time in seconds
429 beaker.session.timeout = 2592000
431 beaker.session.timeout = 2592000
430 beaker.session.httponly = true
432 beaker.session.httponly = true
431 ## Path to use for the cookie.
433 ## Path to use for the cookie. Set to prefix if you use prefix middleware
432 #beaker.session.cookie_path = /<your-prefix>
434 #beaker.session.cookie_path = /custom_prefix
433
435
434 ## uncomment for https secure cookie
436 ## uncomment for https secure cookie
435 beaker.session.secure = false
437 beaker.session.secure = false
@@ -447,8 +449,8 b' beaker.session.auto = false'
447 ## Full text search indexer is available in rhodecode-tools under
449 ## Full text search indexer is available in rhodecode-tools under
448 ## `rhodecode-tools index` command
450 ## `rhodecode-tools index` command
449
451
450 # WHOOSH Backend, doesn't require additional services to run
452 ## WHOOSH Backend, doesn't require additional services to run
451 # it works good with few dozen repos
453 ## it works good with few dozen repos
452 search.module = rhodecode.lib.index.whoosh
454 search.module = rhodecode.lib.index.whoosh
453 search.location = %(here)s/data/index
455 search.location = %(here)s/data/index
454
456
@@ -459,15 +461,21 b' search.location = %(here)s/data/index'
459 ## in the system. It's also used by the chat system
461 ## in the system. It's also used by the chat system
460
462
461 channelstream.enabled = false
463 channelstream.enabled = false
462 # location of channelstream server on the backend
464
465 ## server address for channelstream server on the backend
463 channelstream.server = 127.0.0.1:9800
466 channelstream.server = 127.0.0.1:9800
464 ## location of the channelstream server from outside world
467 ## location of the channelstream server from outside world
465 ## most likely this would be an http server special backend URL, that handles
468 ## use ws:// for http or wss:// for https. This address needs to be handled
466 ## websocket connections see nginx example for config
469 ## by external HTTP server such as Nginx or Apache
470 ## see nginx/apache configuration examples in our docs
467 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
471 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
468 channelstream.secret = secret
472 channelstream.secret = secret
469 channelstream.history.location = %(here)s/channelstream_history
473 channelstream.history.location = %(here)s/channelstream_history
470
474
475 ## Internal application path that Javascript uses to connect into.
476 ## If you use proxy-prefix the prefix should be added before /_channelstream
477 channelstream.proxy_path = /_channelstream
478
471
479
472 ###################################
480 ###################################
473 ## APPENLIGHT CONFIG ##
481 ## APPENLIGHT CONFIG ##
@@ -541,19 +549,19 b' set debug = false'
541 ##############
549 ##############
542 debug_style = false
550 debug_style = false
543
551
544 #########################################################
552 ###########################################
545 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
553 ### MAIN RHODECODE DATABASE CONFIG ###
546 #########################################################
554 ###########################################
547 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db
555 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
548 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
556 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
549 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
557 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
550 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db
558 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
551
559
552 # see sqlalchemy docs for other advanced settings
560 # see sqlalchemy docs for other advanced settings
553
561
554 ## print the sql statements to output
562 ## print the sql statements to output
555 sqlalchemy.db1.echo = false
563 sqlalchemy.db1.echo = false
556 ## recycle the connections after this ammount of seconds
564 ## recycle the connections after this amount of seconds
557 sqlalchemy.db1.pool_recycle = 3600
565 sqlalchemy.db1.pool_recycle = 3600
558 sqlalchemy.db1.convert_unicode = true
566 sqlalchemy.db1.convert_unicode = true
559
567
@@ -575,7 +583,7 b' vcs.server = localhost:9901'
575
583
576 ## Web server connectivity protocol, responsible for web based VCS operatations
584 ## Web server connectivity protocol, responsible for web based VCS operatations
577 ## Available protocols are:
585 ## Available protocols are:
578 ## `http` - using http-rpc backend
586 ## `http` - use http-rpc backend (default)
579 vcs.server.protocol = http
587 vcs.server.protocol = http
580
588
581 ## Push/Pull operations protocol, available options are:
589 ## Push/Pull operations protocol, available options are:
@@ -584,7 +592,7 b' vcs.server.protocol = http'
584 vcs.scm_app_implementation = http
592 vcs.scm_app_implementation = http
585
593
586 ## Push/Pull operations hooks protocol, available options are:
594 ## Push/Pull operations hooks protocol, available options are:
587 ## `http` - using http-rpc backend
595 ## `http` - use http-rpc backend (default)
588 vcs.hooks.protocol = http
596 vcs.hooks.protocol = http
589
597
590 vcs.server.log_level = debug
598 vcs.server.log_level = debug
@@ -613,12 +621,19 b' svn.proxy.generate_config = false'
613 svn.proxy.list_parent_path = true
621 svn.proxy.list_parent_path = true
614 ## Set location and file name of generated config file.
622 ## Set location and file name of generated config file.
615 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
623 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
616 ## File system path to the directory containing the repositories served by
624 ## Used as a prefix to the `Location` block in the generated config file.
617 ## RhodeCode.
625 ## In most cases it should be set to `/`.
618 svn.proxy.parent_path_root = /path/to/repo_store
619 ## Used as a prefix to the <Location> block in the generated config file. In
620 ## most cases it should be set to `/`.
621 svn.proxy.location_root = /
626 svn.proxy.location_root = /
627 ## Command to reload the mod dav svn configuration on change.
628 ## Example: `/etc/init.d/apache2 reload`
629 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
630 ## If the timeout expires before the reload command finishes, the command will
631 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
632 #svn.proxy.reload_timeout = 10
633
634 ## Dummy marker to add new entries after.
635 ## Add any custom entries below. Please don't remove.
636 custom.conf = 1
622
637
623
638
624 ################################
639 ################################
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now