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 | 210 | ## The list should be "," separated and on a single line. |
|
211 | 211 | ## |
|
212 | 212 | ## Most common views to enable: |
|
213 | # ChangesetController:changeset_patch | |
|
214 | # ChangesetController:changeset_raw | |
|
215 |
# Repo |
|
|
216 |
# RepoFilesView |
|
|
217 |
# RepoFilesView |
|
|
213 | # RepoCommitsView:repo_commit_download | |
|
214 | # RepoCommitsView:repo_commit_patch | |
|
215 | # RepoCommitsView:repo_commit_raw | |
|
216 | # RepoFilesView:repo_files_diff | |
|
217 | # RepoFilesView:repo_archivefile | |
|
218 | # RepoFilesView:repo_file_raw | |
|
218 | 219 | # GistView:* |
|
219 | 220 | api_access_controllers_whitelist = |
|
220 | 221 |
@@ -184,11 +184,12 b' gist_alias_url =' | |||
|
184 | 184 | ## The list should be "," separated and on a single line. |
|
185 | 185 | ## |
|
186 | 186 | ## Most common views to enable: |
|
187 | # ChangesetController:changeset_patch | |
|
188 | # ChangesetController:changeset_raw | |
|
189 |
# Repo |
|
|
190 |
# RepoFilesView |
|
|
191 |
# RepoFilesView |
|
|
187 | # RepoCommitsView:repo_commit_download | |
|
188 | # RepoCommitsView:repo_commit_patch | |
|
189 | # RepoCommitsView:repo_commit_raw | |
|
190 | # RepoFilesView:repo_files_diff | |
|
191 | # RepoFilesView:repo_archivefile | |
|
192 | # RepoFilesView:repo_file_raw | |
|
192 | 193 | # GistView:* |
|
193 | 194 | api_access_controllers_whitelist = |
|
194 | 195 |
@@ -42,7 +42,7 b' archive.' | |||
|
42 | 42 | ## Syntax is <ControllerClass>:<function_pattern>. |
|
43 | 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 | 47 | After this change, a |RCE| view can be accessed without login by adding a |
|
48 | 48 | GET parameter ``?auth_token=<auth_token>`` to a url. For example to |
@@ -172,9 +172,9 b' class HomeView(BaseAppView):' | |||
|
172 | 172 | 'text': entry['commit_id'], |
|
173 | 173 | 'type': 'commit', |
|
174 | 174 | 'obj': {'repo': entry['repository']}, |
|
175 |
'url': h. |
|
|
175 | 'url': h.route_path('repo_commit', | |
|
176 | 176 | repo_name=entry['repository'], |
|
177 |
|
|
|
177 | commit_id=entry['commit_id']) | |
|
178 | 178 | } |
|
179 | 179 | for entry in result['results']] |
|
180 | 180 |
@@ -36,6 +36,8 b' from rhodecode.model.meta import Session' | |||
|
36 | 36 | |
|
37 | 37 | fixture = Fixture() |
|
38 | 38 | |
|
39 | whitelist_view = ['RepoCommitsView:repo_commit_raw'] | |
|
40 | ||
|
39 | 41 | |
|
40 | 42 | def route_path(name, params=None, **kwargs): |
|
41 | 43 | import urllib |
@@ -474,11 +476,10 b' class TestLoginController(object):' | |||
|
474 | 476 | def test_access_whitelisted_page_via_auth_token( |
|
475 | 477 | self, test_name, auth_token, code, user_admin): |
|
476 | 478 | |
|
477 | whitelist_entry = ['ChangesetController:changeset_raw'] | |
|
478 | whitelist = self._get_api_whitelist(whitelist_entry) | |
|
479 | whitelist = self._get_api_whitelist(whitelist_view) | |
|
479 | 480 | |
|
480 | 481 | with mock.patch.dict('rhodecode.CONFIG', whitelist): |
|
481 |
assert whitelist_ |
|
|
482 | assert whitelist_view == whitelist['api_access_controllers_whitelist'] | |
|
482 | 483 | |
|
483 | 484 | if test_name == 'proper_auth_token': |
|
484 | 485 | auth_token = user_admin.api_key |
@@ -492,10 +493,9 b' class TestLoginController(object):' | |||
|
492 | 493 | status=code) |
|
493 | 494 | |
|
494 | 495 | def test_access_page_via_extra_auth_token(self): |
|
495 | whitelist = self._get_api_whitelist( | |
|
496 | ['ChangesetController:changeset_raw']) | |
|
496 | whitelist = self._get_api_whitelist(whitelist_view) | |
|
497 | 497 | with mock.patch.dict('rhodecode.CONFIG', whitelist): |
|
498 |
assert |
|
|
498 | assert whitelist_view == \ | |
|
499 | 499 | whitelist['api_access_controllers_whitelist'] |
|
500 | 500 | |
|
501 | 501 | new_auth_token = AuthTokenModel().create( |
@@ -509,10 +509,9 b' class TestLoginController(object):' | |||
|
509 | 509 | status=200) |
|
510 | 510 | |
|
511 | 511 | def test_access_page_via_expired_auth_token(self): |
|
512 | whitelist = self._get_api_whitelist( | |
|
513 | ['ChangesetController:changeset_raw']) | |
|
512 | whitelist = self._get_api_whitelist(whitelist_view) | |
|
514 | 513 | with mock.patch.dict('rhodecode.CONFIG', whitelist): |
|
515 |
assert |
|
|
514 | assert whitelist_view == \ | |
|
516 | 515 | whitelist['api_access_controllers_whitelist'] |
|
517 | 516 | |
|
518 | 517 | new_auth_token = AuthTokenModel().create( |
@@ -33,10 +33,52 b' def includeme(config):' | |||
|
33 | 33 | pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True) |
|
34 | 34 | |
|
35 | 35 | # repo commits |
|
36 | ||
|
36 | 37 | config.add_route( |
|
37 | 38 | name='repo_commit', |
|
38 | 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 | 82 | # repo files |
|
41 | 83 | config.add_route( |
|
42 | 84 | name='repo_archivefile', |
@@ -180,21 +222,6 b' def includeme(config):' | |||
|
180 | 222 | pattern='/{repo_name:.*?[^/]}/pull-request-data', |
|
181 | 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 | 225 | # Settings |
|
199 | 226 | config.add_route( |
|
200 | 227 | name='edit_repo', |
@@ -18,18 +18,33 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | from pylons.i18n import ungettext | |
|
22 | 21 | import pytest |
|
23 | 22 | |
|
24 |
from rhodecode.tests import |
|
|
23 | from rhodecode.tests import TestController | |
|
24 | ||
|
25 | 25 | from rhodecode.model.db import ( |
|
26 | 26 | ChangesetComment, Notification, UserNotification) |
|
27 | 27 | from rhodecode.model.meta import Session |
|
28 | 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 | 46 | @pytest.mark.backends("git", "hg", "svn") |
|
32 |
class TestCommitComments |
|
|
47 | class TestRepoCommitCommentsView(TestController): | |
|
33 | 48 | |
|
34 | 49 | @pytest.fixture(autouse=True) |
|
35 | 50 | def prepare(self, request, pylonsapp): |
@@ -62,12 +77,13 b' class TestCommitCommentsController(TestC' | |||
|
62 | 77 | params = {'text': text, 'csrf_token': self.csrf_token, |
|
63 | 78 | 'comment_type': comment_type} |
|
64 | 79 | self.app.post( |
|
65 | url(controller='changeset', action='comment', | |
|
66 |
repo_name=backend.repo_name, |
|
|
80 | route_path('repo_commit_comment_create', | |
|
81 | repo_name=backend.repo_name, commit_id=commit_id), | |
|
82 | params=params) | |
|
67 | 83 | |
|
68 | 84 | response = self.app.get( |
|
69 | url(controller='changeset', action='index', | |
|
70 |
repo_name=backend.repo_name, |
|
|
85 | route_path('repo_commit', | |
|
86 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
71 | 87 | |
|
72 | 88 | # test DB |
|
73 | 89 | assert ChangesetComment.query().count() == 1 |
@@ -103,12 +119,13 b' class TestCommitCommentsController(TestC' | |||
|
103 | 119 | 'csrf_token': self.csrf_token} |
|
104 | 120 | |
|
105 | 121 | self.app.post( |
|
106 | url(controller='changeset', action='comment', | |
|
107 |
repo_name=backend.repo_name, |
|
|
122 | route_path('repo_commit_comment_create', | |
|
123 | repo_name=backend.repo_name, commit_id=commit_id), | |
|
124 | params=params) | |
|
108 | 125 | |
|
109 | 126 | response = self.app.get( |
|
110 | url(controller='changeset', action='index', | |
|
111 |
repo_name=backend.repo_name, |
|
|
127 | route_path('repo_commit', | |
|
128 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
112 | 129 | |
|
113 | 130 | # test DB |
|
114 | 131 | assert ChangesetComment.query().count() == 1 |
@@ -153,12 +170,13 b' class TestCommitCommentsController(TestC' | |||
|
153 | 170 | |
|
154 | 171 | params = {'text': text, 'csrf_token': self.csrf_token} |
|
155 | 172 | self.app.post( |
|
156 | url(controller='changeset', action='comment', | |
|
157 |
repo_name=backend.repo_name, |
|
|
173 | route_path('repo_commit_comment_create', | |
|
174 | repo_name=backend.repo_name, commit_id=commit_id), | |
|
175 | params=params) | |
|
158 | 176 | |
|
159 | 177 | response = self.app.get( |
|
160 | url(controller='changeset', action='index', | |
|
161 |
repo_name=backend.repo_name, |
|
|
178 | route_path('repo_commit', | |
|
179 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
162 | 180 | # test DB |
|
163 | 181 | assert ChangesetComment.query().count() == 1 |
|
164 | 182 | assert_comment_links(response, ChangesetComment.query().count(), 0) |
@@ -183,12 +201,14 b' class TestCommitCommentsController(TestC' | |||
|
183 | 201 | 'csrf_token': self.csrf_token} |
|
184 | 202 | |
|
185 | 203 | self.app.post( |
|
186 | url(controller='changeset', action='comment', | |
|
187 | repo_name=backend.repo_name, revision=commit_id), params=params) | |
|
204 | route_path( | |
|
205 | 'repo_commit_comment_create', | |
|
206 | repo_name=backend.repo_name, commit_id=commit_id), | |
|
207 | params=params) | |
|
188 | 208 | |
|
189 | 209 | response = self.app.get( |
|
190 | url(controller='changeset', action='index', | |
|
191 |
repo_name=backend.repo_name, |
|
|
210 | route_path('repo_commit', | |
|
211 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
192 | 212 | |
|
193 | 213 | # test DB |
|
194 | 214 | assert ChangesetComment.query().count() == 1 |
@@ -218,9 +238,9 b' class TestCommitCommentsController(TestC' | |||
|
218 | 238 | |
|
219 | 239 | params = {'text': text, 'csrf_token': self.csrf_token} |
|
220 | 240 | self.app.post( |
|
221 |
|
|
|
222 | controller='changeset', action='comment', | |
|
223 |
repo_name=backend.repo_name, |
|
|
241 | route_path( | |
|
242 | 'repo_commit_comment_create', | |
|
243 | repo_name=backend.repo_name, commit_id=commit_id), | |
|
224 | 244 | params=params) |
|
225 | 245 | |
|
226 | 246 | comments = ChangesetComment.query().all() |
@@ -228,16 +248,18 b' class TestCommitCommentsController(TestC' | |||
|
228 | 248 | comment_id = comments[0].comment_id |
|
229 | 249 | |
|
230 | 250 | self.app.post( |
|
231 | url(controller='changeset', action='delete_comment', | |
|
232 |
repo_name=backend.repo_name, |
|
|
233 | params={'_method': 'delete', 'csrf_token': self.csrf_token}) | |
|
251 | route_path('repo_commit_comment_delete', | |
|
252 | repo_name=backend.repo_name, | |
|
253 | commit_id=commit_id, | |
|
254 | comment_id=comment_id), | |
|
255 | params={'csrf_token': self.csrf_token}) | |
|
234 | 256 | |
|
235 | 257 | comments = ChangesetComment.query().all() |
|
236 | 258 | assert len(comments) == 0 |
|
237 | 259 | |
|
238 | 260 | response = self.app.get( |
|
239 | url(controller='changeset', action='index', | |
|
240 |
repo_name=backend.repo_name, |
|
|
261 | route_path('repo_commit', | |
|
262 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
241 | 263 | assert_comment_links(response, 0, 0) |
|
242 | 264 | |
|
243 | 265 | @pytest.mark.parametrize('renderer, input, output', [ |
@@ -251,36 +273,39 b' class TestCommitCommentsController(TestC' | |||
|
251 | 273 | ('markdown', '**bold**', '<strong>bold</strong>'), |
|
252 | 274 | ], ids=['rst-plain', 'rst-header', 'rst-italics', 'rst-bold', 'md-plain', |
|
253 | 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 | 277 | self.log_user() |
|
256 | 278 | params = { |
|
257 | 279 | 'renderer': renderer, |
|
258 | 280 | 'text': input, |
|
259 | 281 | 'csrf_token': self.csrf_token |
|
260 | 282 | } |
|
261 | environ = { | |
|
262 | 'HTTP_X_PARTIAL_XHR': 'true' | |
|
263 | } | |
|
283 | commit_id = '0' * 16 # fake this for tests | |
|
264 | 284 | response = self.app.post( |
|
265 | url(controller='changeset', | |
|
266 | action='preview_comment', | |
|
267 | repo_name=backend.repo_name), | |
|
285 | route_path('repo_commit_comment_preview', | |
|
286 | repo_name=backend.repo_name, commit_id=commit_id,), | |
|
268 | 287 | params=params, |
|
269 |
extra_environ= |
|
|
288 | extra_environ=xhr_header) | |
|
270 | 289 | |
|
271 | 290 | response.mustcontain(output) |
|
272 | 291 | |
|
273 | 292 | |
|
274 | 293 | def assert_comment_links(response, comments, inline_comments): |
|
275 | comments_text = ungettext("%d Commit comment", | |
|
276 |
|
|
|
294 | if comments == 1: | |
|
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 | 304 | if comments: |
|
278 | 305 | response.mustcontain('<a href="#comments">%s</a>,' % comments_text) |
|
279 | 306 | else: |
|
280 | 307 | response.mustcontain(comments_text) |
|
281 | 308 | |
|
282 | inline_comments_text = ungettext("%d Inline Comment", "%d Inline Comments", | |
|
283 | inline_comments) % inline_comments | |
|
284 | 309 | if inline_comments: |
|
285 | 310 | response.mustcontain( |
|
286 | 311 | 'id="inline-comments-counter">%s</' % inline_comments_text) |
@@ -21,40 +21,56 b'' | |||
|
21 | 21 | import pytest |
|
22 | 22 | |
|
23 | 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 | 45 | @pytest.mark.usefixtures("app") |
|
28 |
class Test |
|
|
46 | class TestRepoCommitView(object): | |
|
29 | 47 | |
|
30 |
def test_ |
|
|
48 | def test_show_commit(self, backend): | |
|
31 | 49 | commit_id = self.commit_id[backend.alias] |
|
32 |
response = self.app.get( |
|
|
33 | controller='changeset', action='index', | |
|
34 | repo_name=backend.repo_name, revision=commit_id)) | |
|
50 | response = self.app.get(route_path( | |
|
51 | 'repo_commit', repo_name=backend.repo_name, commit_id=commit_id)) | |
|
35 | 52 | response.mustcontain('Added a symlink') |
|
36 | 53 | response.mustcontain(commit_id) |
|
37 | 54 | response.mustcontain('No newline at end of file') |
|
38 | 55 | |
|
39 |
def test_ |
|
|
56 | def test_show_raw(self, backend): | |
|
40 | 57 | commit_id = self.commit_id[backend.alias] |
|
41 |
response = self.app.get( |
|
|
42 | controller='changeset', action='changeset_raw', | |
|
43 |
repo_name=backend.repo_name, |
|
|
58 | response = self.app.get(route_path( | |
|
59 | 'repo_commit_raw', | |
|
60 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
44 | 61 | assert response.body == self.diffs[backend.alias] |
|
45 | 62 | |
|
46 |
def test_ |
|
|
47 |
response = self.app.get( |
|
|
48 | controller='changeset', action='changeset_patch', | |
|
49 | repo_name=backend.repo_name, | |
|
50 | revision=self.commit_id[backend.alias])) | |
|
63 | def test_show_raw_patch(self, backend): | |
|
64 | response = self.app.get(route_path( | |
|
65 | 'repo_commit_patch', repo_name=backend.repo_name, | |
|
66 | commit_id=self.commit_id[backend.alias])) | |
|
51 | 67 | assert response.body == self.patches[backend.alias] |
|
52 | 68 | |
|
53 |
def test_i |
|
|
54 |
response = self.app.get( |
|
|
55 | controller='changeset', action='changeset_download', | |
|
69 | def test_commit_download(self, backend): | |
|
70 | response = self.app.get(route_path( | |
|
71 | 'repo_commit_download', | |
|
56 | 72 | repo_name=backend.repo_name, |
|
57 |
|
|
|
73 | commit_id=self.commit_id[backend.alias])) | |
|
58 | 74 | assert response.body == self.diffs[backend.alias] |
|
59 | 75 | |
|
60 | 76 | def test_single_commit_page_different_ops(self, backend): |
@@ -64,9 +80,9 b' class TestChangesetController(object):' | |||
|
64 | 80 | 'svn': '337', |
|
65 | 81 | } |
|
66 | 82 | commit_id = commit_id[backend.alias] |
|
67 |
response = self.app.get( |
|
|
68 | controller='changeset', action='index', | |
|
69 |
repo_name=backend.repo_name, |
|
|
83 | response = self.app.get(route_path( | |
|
84 | 'repo_commit', | |
|
85 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
70 | 86 | |
|
71 | 87 | response.mustcontain(_shorten_commit_id(commit_id)) |
|
72 | 88 | response.mustcontain('21 files changed: 943 inserted, 288 deleted') |
@@ -98,9 +114,9 b' class TestChangesetController(object):' | |||
|
98 | 114 | } |
|
99 | 115 | commit_ids = commit_id_range[backend.alias] |
|
100 | 116 | commit_id = '%s...%s' % (commit_ids[0], commit_ids[1]) |
|
101 |
response = self.app.get( |
|
|
102 | controller='changeset', action='index', | |
|
103 |
repo_name=backend.repo_name, |
|
|
117 | response = self.app.get(route_path( | |
|
118 | 'repo_commit', | |
|
119 | repo_name=backend.repo_name, commit_id=commit_id)) | |
|
104 | 120 | |
|
105 | 121 | response.mustcontain(_shorten_commit_id(commit_ids[0])) |
|
106 | 122 | response.mustcontain(_shorten_commit_id(commit_ids[1])) |
@@ -137,8 +153,8 b' class TestChangesetController(object):' | |||
|
137 | 153 | '337'), |
|
138 | 154 | } |
|
139 | 155 | commit_ids = commit_id_range[backend.alias] |
|
140 |
response = self.app.get( |
|
|
141 | controller='compare', action='compare', | |
|
156 | response = self.app.get(route_path( | |
|
157 | 'repo_compare', | |
|
142 | 158 | repo_name=backend.repo_name, |
|
143 | 159 | source_ref_type='rev', source_ref=commit_ids[0], |
|
144 | 160 | target_ref_type='rev', target_ref=commit_ids[1], )) |
@@ -188,9 +204,10 b' class TestChangesetController(object):' | |||
|
188 | 204 | def _check_changeset_range( |
|
189 | 205 | self, backend, commit_id_ranges, commit_id_range_result): |
|
190 | 206 | response = self.app.get( |
|
191 | url(controller='changeset', action='index', | |
|
207 | route_path('repo_commit', | |
|
192 | 208 | repo_name=backend.repo_name, |
|
193 |
|
|
|
209 | commit_id=commit_id_ranges[backend.alias])) | |
|
210 | ||
|
194 | 211 | expected_result = commit_id_range_result[backend.alias] |
|
195 | 212 | response.mustcontain('{} commits'.format(len(expected_result))) |
|
196 | 213 | for commit_id in expected_result: |
@@ -139,8 +139,8 b' class RepoFeedView(RepoAppView):' | |||
|
139 | 139 | author_name=commit.author, |
|
140 | 140 | description=self._get_description(commit), |
|
141 | 141 | link=h.route_url( |
|
142 |
' |
|
|
143 |
|
|
|
142 | 'repo_commit', repo_name=self.db_repo_name, | |
|
143 | commit_id=commit.raw_id), | |
|
144 | 144 | pubdate=date,) |
|
145 | 145 | |
|
146 | 146 | return feed.mime_type, feed.writeString('utf-8') |
@@ -185,8 +185,8 b' class RepoFeedView(RepoAppView):' | |||
|
185 | 185 | author_name=commit.author, |
|
186 | 186 | description=self._get_description(commit), |
|
187 | 187 | link=h.route_url( |
|
188 |
' |
|
|
189 |
|
|
|
188 | 'repo_commit', repo_name=self.db_repo_name, | |
|
189 | commit_id=commit.raw_id), | |
|
190 | 190 | pubdate=date,) |
|
191 | 191 | |
|
192 | 192 | return feed.mime_type, feed.writeString('utf-8') |
@@ -1043,8 +1043,8 b' class RepoFilesView(RepoAppView):' | |||
|
1043 | 1043 | log.exception('Error during commit operation') |
|
1044 | 1044 | h.flash(_('Error occurred during commit'), category='error') |
|
1045 | 1045 | raise HTTPFound( |
|
1046 |
h.route_path(' |
|
|
1047 |
|
|
|
1046 | h.route_path('repo_commit', repo_name=self.db_repo_name, | |
|
1047 | commit_id='tip')) | |
|
1048 | 1048 | |
|
1049 | 1049 | @LoginRequired() |
|
1050 | 1050 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
@@ -1133,8 +1133,8 b' class RepoFilesView(RepoAppView):' | |||
|
1133 | 1133 | if content == old_content and filename == org_filename: |
|
1134 | 1134 | h.flash(_('No changes'), category='warning') |
|
1135 | 1135 | raise HTTPFound( |
|
1136 |
h.route_path(' |
|
|
1137 |
|
|
|
1136 | h.route_path('repo_commit', repo_name=self.db_repo_name, | |
|
1137 | commit_id='tip')) | |
|
1138 | 1138 | try: |
|
1139 | 1139 | mapping = { |
|
1140 | 1140 | org_f_path: { |
@@ -1161,8 +1161,8 b' class RepoFilesView(RepoAppView):' | |||
|
1161 | 1161 | log.exception('Error occurred during commit') |
|
1162 | 1162 | h.flash(_('Error occurred during commit'), category='error') |
|
1163 | 1163 | raise HTTPFound( |
|
1164 |
h.route_path(' |
|
|
1165 |
|
|
|
1164 | h.route_path('repo_commit', repo_name=self.db_repo_name, | |
|
1165 | commit_id='tip')) | |
|
1166 | 1166 | |
|
1167 | 1167 | @LoginRequired() |
|
1168 | 1168 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
@@ -1222,7 +1222,7 b' class RepoFilesView(RepoAppView):' | |||
|
1222 | 1222 | content = content.file |
|
1223 | 1223 | |
|
1224 | 1224 | default_redirect_url = h.route_path( |
|
1225 |
' |
|
|
1225 | 'repo_commit', repo_name=self.db_repo_name, commit_id='tip') | |
|
1226 | 1226 | |
|
1227 | 1227 | # If there's no commit, redirect to repo summary |
|
1228 | 1228 | if type(c.commit) is EmptyCommit: |
@@ -429,19 +429,6 b' def make_map(config):' | |||
|
429 | 429 | controller='admin/repos', action='repo_check', |
|
430 | 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 | 432 | # repo edit options |
|
446 | 433 | rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', |
|
447 | 434 | controller='admin/repos', action='edit_fields', |
@@ -515,54 +502,6 b' def make_map(config):' | |||
|
515 | 502 | conditions={'method': ['GET', 'POST'], 'function': check_repo}, |
|
516 | 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 | 505 | rmap.connect('compare_home', |
|
567 | 506 | '/{repo_name}/compare', |
|
568 | 507 | controller='compare', action='index', |
@@ -20,7 +20,6 b'' | |||
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | from pylons import url | |
|
24 | 23 | from pylons.i18n.translation import _ |
|
25 | 24 | from webhelpers.html.builder import literal |
|
26 | 25 | from webhelpers.html.tags import link_to |
@@ -201,6 +200,7 b' class ActionParser(object):' | |||
|
201 | 200 | return literal(tmpl % (ico, self.action)) |
|
202 | 201 | |
|
203 | 202 | def get_cs_links(self): |
|
203 | from rhodecode.lib import helpers as h | |
|
204 | 204 | if self.is_deleted(): |
|
205 | 205 | return self.action_params |
|
206 | 206 | |
@@ -223,8 +223,9 b' class ActionParser(object):' | |||
|
223 | 223 | _('Show all combined commits %s->%s') % ( |
|
224 | 224 | commit_ids[0][:12], commit_ids[-1][:12] |
|
225 | 225 | ), |
|
226 | url('changeset_home', repo_name=repo_name, | |
|
227 | revision=commit_id_range), _('compare view') | |
|
226 | h.route_path( | |
|
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 | 277 | def lnk(self, commit_or_id, repo_name): |
|
277 | 278 | from rhodecode.lib.helpers import tooltip |
|
279 | from rhodecode.lib import helpers as h | |
|
278 | 280 | |
|
279 | 281 | if isinstance(commit_or_id, (BaseCommit, AttributeDict)): |
|
280 | 282 | lazy_cs = True |
@@ -292,8 +294,8 b' class ActionParser(object):' | |||
|
292 | 294 | |
|
293 | 295 | else: |
|
294 | 296 | lbl = '%s' % (commit_or_id.short_id[:8]) |
|
295 |
_url = |
|
|
296 |
|
|
|
297 | _url = h.route_path('repo_commit', repo_name=repo_name, | |
|
298 | commit_id=commit_or_id.raw_id) | |
|
297 | 299 | title = tooltip(commit_or_id.message) |
|
298 | 300 | else: |
|
299 | 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( |
|
|
757 | def allowed_auth_token_access(view_name, whitelist=None, auth_token=None): | |
|
758 | 758 | """ |
|
759 | 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 | 768 | auth_token_access_valid = False |
|
769 | 769 | for entry in whitelist: |
|
770 |
if fnmatch.fnmatch( |
|
|
770 | if fnmatch.fnmatch(view_name, entry): | |
|
771 | 771 | auth_token_access_valid = True |
|
772 | 772 | break |
|
773 | 773 | |
|
774 | 774 | if auth_token_access_valid: |
|
775 |
log.debug(' |
|
|
776 |
% ( |
|
|
775 | log.debug('view: `%s` matches entry in whitelist: %s' | |
|
776 | % (view_name, whitelist)) | |
|
777 | 777 | else: |
|
778 |
msg = (' |
|
|
779 |
% ( |
|
|
778 | msg = ('view: `%s` does *NOT* match any entry in whitelist: %s' | |
|
779 | % (view_name, whitelist)) | |
|
780 | 780 | if auth_token: |
|
781 | 781 | # if we use auth token key and don't have access it's a warning |
|
782 | 782 | log.warning(msg) |
@@ -1575,7 +1575,7 b' def urlify_commits(text_, repository):' | |||
|
1575 | 1575 | :param text_: |
|
1576 | 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 | 1579 | URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)') |
|
1580 | 1580 | |
|
1581 | 1581 | def url_func(match_obj): |
@@ -1590,8 +1590,8 b' def urlify_commits(text_, repository):' | |||
|
1590 | 1590 | return tmpl % { |
|
1591 | 1591 | 'pref': pref, |
|
1592 | 1592 | 'cls': 'revision-link', |
|
1593 |
'url': url(' |
|
|
1594 |
|
|
|
1593 | 'url': route_url('repo_commit', repo_name=repository, | |
|
1594 | commit_id=commit_id), | |
|
1595 | 1595 | 'commit_id': commit_id, |
|
1596 | 1596 | 'suf': suf |
|
1597 | 1597 | } |
@@ -15,11 +15,6 b' function registerRCRoutes() {' | |||
|
15 | 15 | pyroutes.register('new_repo', '/_admin/create_repository', []); |
|
16 | 16 | pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); |
|
17 | 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 | 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 | 19 | pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']); |
|
25 | 20 | pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']); |
@@ -111,6 +106,16 b' function registerRCRoutes() {' | |||
|
111 | 106 | pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']); |
|
112 | 107 | pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']); |
|
113 | 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 | 119 | pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']); |
|
115 | 120 | pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']); |
|
116 | 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 | 151 | pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']); |
|
147 | 152 | pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']); |
|
148 | 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 | 154 | pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']); |
|
153 | 155 | pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']); |
|
154 | 156 | pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']); |
@@ -103,8 +103,9 b' var bindToggleButtons = function() {' | |||
|
103 | 103 | this.submitButton = $(this.submitForm).find('input[type="submit"]'); |
|
104 | 104 | this.submitButtonText = this.submitButton.val(); |
|
105 | 105 | |
|
106 |
this.previewUrl = pyroutes.url(' |
|
|
107 |
{'repo_name': templateContext.repo_name |
|
|
106 | this.previewUrl = pyroutes.url('repo_commit_comment_preview', | |
|
107 | {'repo_name': templateContext.repo_name, | |
|
108 | 'commit_id': templateContext.commit_data.commit_id}); | |
|
108 | 109 | |
|
109 | 110 | if (resolvesCommentId){ |
|
110 | 111 | this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId); |
@@ -129,12 +130,12 b' var bindToggleButtons = function() {' | |||
|
129 | 130 | // based on commitId, or pullRequestId decide where do we submit |
|
130 | 131 | // out data |
|
131 | 132 | if (this.commitId){ |
|
132 |
this.submitUrl = pyroutes.url(' |
|
|
133 | this.submitUrl = pyroutes.url('repo_commit_comment_create', | |
|
133 | 134 | {'repo_name': templateContext.repo_name, |
|
134 |
' |
|
|
135 |
this.selfUrl = pyroutes.url(' |
|
|
135 | 'commit_id': this.commitId}); | |
|
136 | this.selfUrl = pyroutes.url('repo_commit', | |
|
136 | 137 | {'repo_name': templateContext.repo_name, |
|
137 |
' |
|
|
138 | 'commit_id': this.commitId}); | |
|
138 | 139 | |
|
139 | 140 | } else if (this.pullRequestId) { |
|
140 | 141 | this.submitUrl = pyroutes.url('pullrequest_comment', |
@@ -5,7 +5,7 b'' | |||
|
5 | 5 | (_('Owner'), lambda:base.gravatar_with_user(c.repo_info.user.email), '', ''), |
|
6 | 6 | (_('Created on'), h.format_date(c.repo_info.created_on), '', ''), |
|
7 | 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. |
|
|
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 | 161 | if (selectedCheckboxes.length>0){ |
|
162 | 162 | var revEnd = selectedCheckboxes[0].name; |
|
163 | 163 | var revStart = selectedCheckboxes[selectedCheckboxes.length-1].name; |
|
164 |
var url = pyroutes.url(' |
|
|
164 | var url = pyroutes.url('repo_commit', | |
|
165 | 165 | {'repo_name': '${c.repo_name}', |
|
166 |
' |
|
|
166 | 'commit_id': revStart+'...'+revEnd}); | |
|
167 | 167 | |
|
168 | 168 | var link = (revStart == revEnd) |
|
169 | 169 | ? _gettext('Show selected commit __S') |
@@ -24,11 +24,11 b'' | |||
|
24 | 24 | <div class="changeset-status-ico"> |
|
25 | 25 | %if c.statuses.get(commit.raw_id)[2]: |
|
26 | 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 |
|
|
27 | <div class="${'flag_status {}'.format(c.statuses.get(commit.raw_id)[0])}"></div> | |
|
28 | 28 | </a> |
|
29 | 29 | %else: |
|
30 |
<a class="tooltip" title="${_('Commit status: |
|
|
31 |
<div class="${'flag_status |
|
|
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 {}'.format(c.statuses.get(commit.raw_id)[0])}"></div> | |
|
32 | 32 | </a> |
|
33 | 33 | %endif |
|
34 | 34 | </div> |
@@ -38,7 +38,7 b'' | |||
|
38 | 38 | </td> |
|
39 | 39 | <td class="td-comments comments-col"> |
|
40 | 40 | %if c.comments.get(commit.raw_id): |
|
41 |
<a title="${_('Commit has comments')}" href="${h. |
|
|
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 | 42 | <i class="icon-comment"></i> ${len(c.comments[commit.raw_id])} |
|
43 | 43 | </a> |
|
44 | 44 | %endif |
@@ -46,7 +46,7 b'' | |||
|
46 | 46 | <td class="td-hash"> |
|
47 | 47 | <code> |
|
48 | 48 | |
|
49 |
<a href="${h. |
|
|
49 | <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=commit.raw_id)}"> | |
|
50 | 50 | <span class="${'commit_hash obsolete' if getattr(commit, 'obsolete', None) else 'commit_hash'}">${h.show_id(commit)}</span> |
|
51 | 51 | </a> |
|
52 | 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 | 15 | <td class="td-message"> |
|
16 | 16 | <div class="log-container"> |
|
17 | 17 | <div class="message_history" title="${h.tooltip(cs.message)}"> |
|
18 |
<a href="${h. |
|
|
18 | <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}"> | |
|
19 | 19 | ${h.shorter(cs.message, 75)} |
|
20 | 20 | </a> |
|
21 | 21 | </div> |
@@ -23,7 +23,7 b'' | |||
|
23 | 23 | </td> |
|
24 | 24 | <td class="td-hash"> |
|
25 | 25 | <code> |
|
26 |
<a href="${h. |
|
|
26 | <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}"> | |
|
27 | 27 | <span>${h.show_id(cs)}</span> |
|
28 | 28 | </a> |
|
29 | 29 | </code> |
@@ -21,7 +21,7 b'' | |||
|
21 | 21 | <%def name="main()"> |
|
22 | 22 | <script> |
|
23 | 23 | // TODO: marcink switch this to pyroutes |
|
24 |
AJAX_COMMENT_DELETE_URL = "${h. |
|
|
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 | 25 | templateContext.commit_data.commit_id = "${c.commit.raw_id}"; |
|
26 | 26 | </script> |
|
27 | 27 | <div class="box"> |
@@ -137,21 +137,21 b'' | |||
|
137 | 137 | </div> |
|
138 | 138 | <div class="right-content"> |
|
139 | 139 | <div class="diff-actions"> |
|
140 |
<a href="${h. |
|
|
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 | 141 | ${_('Raw Diff')} |
|
142 | 142 | </a> |
|
143 | 143 | | |
|
144 |
<a href="${h. |
|
|
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 | 145 | ${_('Patch Diff')} |
|
146 | 146 | </a> |
|
147 | 147 | | |
|
148 |
<a href="${h. |
|
|
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 | 149 | ${_('Download Diff')} |
|
150 | 150 | </a> |
|
151 | 151 | | |
|
152 |
${c.ignorews_url(request |
|
|
152 | ${c.ignorews_url(request)} | |
|
153 | 153 | | |
|
154 |
${c.context_url(request |
|
|
154 | ${c.context_url(request)} | |
|
155 | 155 | </div> |
|
156 | 156 | </div> |
|
157 | 157 | </div> |
@@ -221,7 +221,7 b'' | |||
|
221 | 221 | ${comment.generate_comments(c.comments)} |
|
222 | 222 | |
|
223 | 223 | ## main comment form and it status |
|
224 |
${comment.comments(h. |
|
|
224 | ${comment.comments(h.route_path('repo_commit_comment_create', repo_name=c.repo_name, commit_id=c.commit.raw_id), | |
|
225 | 225 | h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))} |
|
226 | 226 | </div> |
|
227 | 227 | |
@@ -264,14 +264,14 b'' | |||
|
264 | 264 | // >1 links show them to user to choose |
|
265 | 265 | if(!$('#child_link').hasClass('disabled')){ |
|
266 | 266 | $.ajax({ |
|
267 |
url: '${h. |
|
|
267 | url: '${h.route_path('repo_commit_children',repo_name=c.repo_name, commit_id=c.commit.raw_id)}', | |
|
268 | 268 | success: function(data) { |
|
269 | 269 | if(data.results.length === 0){ |
|
270 | 270 | $('#child_link').html("${_('No Child Commits')}").addClass('disabled'); |
|
271 | 271 | } |
|
272 | 272 | if(data.results.length === 1){ |
|
273 | 273 | var commit = data.results[0]; |
|
274 |
window.location = pyroutes.url(' |
|
|
274 | window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id}); | |
|
275 | 275 | } |
|
276 | 276 | else if(data.results.length === 2){ |
|
277 | 277 | $('#child_link').addClass('disabled'); |
@@ -280,12 +280,12 b'' | |||
|
280 | 280 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
281 | 281 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
282 | 282 | .replace('__title__', data.results[0].message) |
|
283 |
.replace('__url__', pyroutes.url(' |
|
|
283 | .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id})); | |
|
284 | 284 | _html +=' | '; |
|
285 | 285 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
286 | 286 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
287 | 287 | .replace('__title__', data.results[1].message) |
|
288 |
.replace('__url__', pyroutes.url(' |
|
|
288 | .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id})); | |
|
289 | 289 | $('#child_link').html(_html); |
|
290 | 290 | } |
|
291 | 291 | } |
@@ -300,14 +300,14 b'' | |||
|
300 | 300 | // >1 links show them to user to choose |
|
301 | 301 | if(!$('#parent_link').hasClass('disabled')){ |
|
302 | 302 | $.ajax({ |
|
303 |
url: '${h. |
|
|
303 | url: '${h.route_path("repo_commit_parents",repo_name=c.repo_name, commit_id=c.commit.raw_id)}', | |
|
304 | 304 | success: function(data) { |
|
305 | 305 | if(data.results.length === 0){ |
|
306 | 306 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); |
|
307 | 307 | } |
|
308 | 308 | if(data.results.length === 1){ |
|
309 | 309 | var commit = data.results[0]; |
|
310 |
window.location = pyroutes.url(' |
|
|
310 | window.location = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': commit.raw_id}); | |
|
311 | 311 | } |
|
312 | 312 | else if(data.results.length === 2){ |
|
313 | 313 | $('#parent_link').addClass('disabled'); |
@@ -316,12 +316,12 b'' | |||
|
316 | 316 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
317 | 317 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
318 | 318 | .replace('__title__', data.results[0].message) |
|
319 |
.replace('__url__', pyroutes.url(' |
|
|
319 | .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[0].raw_id})); | |
|
320 | 320 | _html +=' | '; |
|
321 | 321 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
322 | 322 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
323 | 323 | .replace('__title__', data.results[1].message) |
|
324 |
.replace('__url__', pyroutes.url(' |
|
|
324 | .replace('__url__', pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}','commit_id': data.results[1].raw_id})); | |
|
325 | 325 | $('#parent_link').html(_html); |
|
326 | 326 | } |
|
327 | 327 | } |
@@ -100,7 +100,7 b'' | |||
|
100 | 100 | % endif |
|
101 | 101 | % if inline: |
|
102 | 102 | <div class="pr-version-inline"> |
|
103 |
<a href="${ |
|
|
103 | <a href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}"> | |
|
104 | 104 | % if outdated_at_ver: |
|
105 | 105 | <code class="pr-version-num" title="${_('Outdated comment from pull request version {0}').format(pr_index_ver)}"> |
|
106 | 106 | outdated ${'v{}'.format(pr_index_ver)} | |
@@ -70,15 +70,15 b'' | |||
|
70 | 70 | </div> |
|
71 | 71 | <div class="right-content"> |
|
72 | 72 | <div class="diff-actions"> |
|
73 |
<a href="${h. |
|
|
73 | <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
|
74 | 74 | ${_('Raw Diff')} |
|
75 | 75 | </a> |
|
76 | 76 | | |
|
77 |
<a href="${h. |
|
|
77 | <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |
|
78 | 78 | ${_('Patch Diff')} |
|
79 | 79 | </a> |
|
80 | 80 | | |
|
81 |
<a href="${h. |
|
|
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 | 82 | ${_('Download Diff')} |
|
83 | 83 | </a> |
|
84 | 84 | </div> |
@@ -121,7 +121,7 b' collapse_all = len(diffset.files) > coll' | |||
|
121 | 121 | %endif |
|
122 | 122 | <h2 class="clearinner"> |
|
123 | 123 | %if commit: |
|
124 |
<a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h. |
|
|
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 | 125 | ${h.age_component(commit.date)} - |
|
126 | 126 | %endif |
|
127 | 127 | %if diffset.limited_diff: |
@@ -459,10 +459,10 b' from rhodecode.lib.diffs import NEW_FILE' | |||
|
459 | 459 | |
|
460 | 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 | 461 | %if hasattr(c, 'ignorews_url'): |
|
462 |
${c.ignorews_url(request |
|
|
462 | ${c.ignorews_url(request, h.FID('', filediff.patch['filename']))} | |
|
463 | 463 | %endif |
|
464 | 464 | %if hasattr(c, 'context_url'): |
|
465 |
${c.context_url(request |
|
|
465 | ${c.context_url(request, h.FID('', filediff.patch['filename']))} | |
|
466 | 466 | %endif |
|
467 | 467 | |
|
468 | 468 | %if use_comments: |
@@ -31,7 +31,7 b'' | |||
|
31 | 31 | data-revision="${annotation.revision}" |
|
32 | 32 | onclick="$('[data-revision=${annotation.revision}]').toggleClass('cb-line-fresh')" |
|
33 | 33 | style="background: ${bgcolor}"> |
|
34 |
<a class="cb-annotate" href="${h. |
|
|
34 | <a class="cb-annotate" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=annotation.raw_id)}"> | |
|
35 | 35 | r${annotation.revision} |
|
36 | 36 | </a> |
|
37 | 37 | </td> |
@@ -3,7 +3,7 b'' | |||
|
3 | 3 | |
|
4 | 4 | %if c.ancestor: |
|
5 | 5 | <div class="ancestor">${_('Common Ancestor Commit')}: |
|
6 |
<a href="${h. |
|
|
6 | <a href="${h.route_path('repo_commit', repo_name=c.repo_name, commit_id=c.ancestor)}"> | |
|
7 | 7 | ${h.short_id(c.ancestor)} |
|
8 | 8 | </a>. ${_('Compare was calculated based on this shared commit.')} |
|
9 | 9 | <input id="common_ancestor" type="hidden" name="common_ancestor" value="${c.ancestor}"> |
@@ -34,9 +34,7 b'' | |||
|
34 | 34 | </td> |
|
35 | 35 | <td class="td-hash"> |
|
36 | 36 | <code> |
|
37 | <a href="${h.url('changeset_home', | |
|
38 | repo_name=c.target_repo.repo_name, | |
|
39 | revision=commit.raw_id)}"> | |
|
37 | <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}"> | |
|
40 | 38 | r${commit.revision}:${h.short_id(commit.raw_id)} |
|
41 | 39 | </a> |
|
42 | 40 | ${h.hidden('revisions',commit.raw_id)} |
@@ -137,15 +137,15 b'' | |||
|
137 | 137 | </div> |
|
138 | 138 | <div class="right-content"> |
|
139 | 139 | <div class="diff-actions"> |
|
140 |
<a href="${h. |
|
|
140 | <a href="${h.route_path('repo_commit_raw',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
|
141 | 141 | ${_('Raw Diff')} |
|
142 | 142 | </a> |
|
143 | 143 | | |
|
144 |
<a href="${h. |
|
|
144 | <a href="${h.route_path('repo_commit_patch',repo_name=c.repo_name,commit_id='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |
|
145 | 145 | ${_('Patch Diff')} |
|
146 | 146 | </a> |
|
147 | 147 | | |
|
148 |
<a href="${h. |
|
|
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 | 149 | ${_('Download Diff')} |
|
150 | 150 | </a> |
|
151 | 151 | </div> |
@@ -170,7 +170,7 b'' | |||
|
170 | 170 | return form_inputs |
|
171 | 171 | %> |
|
172 | 172 | <div> |
|
173 |
${comment.comments(h. |
|
|
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 | 174 | </div> |
|
175 | 175 | </div> |
|
176 | 176 | </div> |
@@ -83,7 +83,7 b'' | |||
|
83 | 83 | <%def name="revision(name,rev,tip,author,last_msg)"> |
|
84 | 84 | <div> |
|
85 | 85 | %if rev >= 0: |
|
86 |
<code><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h. |
|
|
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 | 87 | %else: |
|
88 | 88 | ${_('No commits yet')} |
|
89 | 89 | %endif |
@@ -840,7 +840,8 b'' | |||
|
840 | 840 | $('#edit-container').hide(); |
|
841 | 841 | $('#preview-container').show(); |
|
842 | 842 | |
|
843 |
var url = pyroutes.url(' |
|
|
843 | var url = pyroutes.url('repo_commit_comment_preview', | |
|
844 | {'repo_name': 'rhodecode-momentum', 'commit_id': '000000'}); | |
|
844 | 845 | |
|
845 | 846 | ajaxPOST(url, post_data, function(o) { |
|
846 | 847 | previewbox.html(o); |
@@ -17,7 +17,7 b'' | |||
|
17 | 17 | tag: ${tag} <br/> |
|
18 | 18 | % endfor |
|
19 | 19 | |
|
20 |
commit: <a href="${h.url(' |
|
|
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 | 21 | <pre> |
|
22 | 22 | ${h.urlify_commit_message(commit.message)} |
|
23 | 23 |
@@ -23,7 +23,7 b'' | |||
|
23 | 23 | <div class="right-content"> |
|
24 | 24 | <div class="tags"> |
|
25 | 25 | <code> |
|
26 |
<a href="${h. |
|
|
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 | 27 | </code> |
|
28 | 28 | |
|
29 | 29 | ${file_base.refs(c.commit)} |
@@ -217,7 +217,9 b'' | |||
|
217 | 217 | var _renderer = possible_renderer || DEFAULT_RENDERER; |
|
218 | 218 | var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN}; |
|
219 | 219 | $('#editor_preview').html(_gettext('Loading ...')); |
|
220 |
var url = pyroutes.url(' |
|
|
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 | 224 | ajaxPOST(url, post_data, function(o){ |
|
223 | 225 | $('#editor_preview').html(o); |
@@ -21,7 +21,7 b'' | |||
|
21 | 21 | </div> |
|
22 | 22 | <div class="right-content"> |
|
23 | 23 | <div class="tags tags-main"> |
|
24 |
<code><a href="${h. |
|
|
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 | 25 | ${file_base.refs(c.commit)} |
|
26 | 26 | </div> |
|
27 | 27 | </div> |
@@ -33,7 +33,7 b'' | |||
|
33 | 33 | </div> |
|
34 | 34 | <div class="right-content"> |
|
35 | 35 | <div class="tags"> |
|
36 |
<code><a href="${h. |
|
|
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 | 38 | ${file_base.refs(c.file_last_commit)} |
|
39 | 39 | </div> |
@@ -47,7 +47,7 b'' | |||
|
47 | 47 | <div class="code-header"> |
|
48 | 48 | <div class="stats"> |
|
49 | 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. |
|
|
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 | 51 | <span class="item">${h.format_byte_size_binary(c.file.size)}</span> |
|
52 | 52 | <span class="item last">${c.file.mimetype}</span> |
|
53 | 53 | <div class="buttons"> |
@@ -177,8 +177,9 b'' | |||
|
177 | 177 | var _renderer = possible_renderer || DEFAULT_RENDERER; |
|
178 | 178 | var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN}; |
|
179 | 179 | $('#editor_preview').html(_gettext('Loading ...')); |
|
180 |
var url = pyroutes.url(' |
|
|
181 | ||
|
180 | var url = pyroutes.url('repo_commit_comment_preview', | |
|
181 | {'repo_name': '${c.repo_name}', | |
|
182 | 'commit_id': '${c.commit.raw_id}'}); | |
|
182 | 183 | ajaxPOST(url, post_data, function(o){ |
|
183 | 184 | $('#editor_preview').html(o); |
|
184 | 185 | }) |
@@ -86,7 +86,7 b'' | |||
|
86 | 86 | <br/> |
|
87 | 87 | % if c.ancestor_commit: |
|
88 | 88 | ${_('Common ancestor')}: |
|
89 |
<code><a href="${h. |
|
|
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 | 90 | % endif |
|
91 | 91 | </div> |
|
92 | 92 | <div class="pr-pullinfo"> |
@@ -513,7 +513,7 b'' | |||
|
513 | 513 | </td> |
|
514 | 514 | <td class="td-hash"> |
|
515 | 515 | <code> |
|
516 |
<a href="${h. |
|
|
516 | <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}"> | |
|
517 | 517 | r${commit.revision}:${h.short_id(commit.raw_id)} |
|
518 | 518 | </a> |
|
519 | 519 | ${h.hidden('revisions', commit.raw_id)} |
@@ -31,7 +31,7 b'' | |||
|
31 | 31 | </td> |
|
32 | 32 | <td class="td-commit"> |
|
33 | 33 | ${h.link_to(h._shorten_commit_id(entry['commit_id']), |
|
34 |
h. |
|
|
34 | h.route_path('repo_commit',repo_name=entry['repository'],commit_id=entry['commit_id']))} | |
|
35 | 35 | </td> |
|
36 | 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 | 37 | <div class="show_more_col"> |
@@ -19,11 +19,11 b'' | |||
|
19 | 19 | <div class="changeset-status-ico shortlog"> |
|
20 | 20 | %if c.statuses.get(cs.raw_id)[2]: |
|
21 | 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 |
|
|
22 | <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div> | |
|
23 | 23 | </a> |
|
24 | 24 | %else: |
|
25 |
<a class="tooltip" title="${_('Commit status: |
|
|
26 |
<div class="${'flag_status |
|
|
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 {}'.format(c.statuses.get(cs.raw_id)[0])}"></div> | |
|
27 | 27 | </a> |
|
28 | 28 | %endif |
|
29 | 29 | </div> |
@@ -33,13 +33,13 b'' | |||
|
33 | 33 | </td> |
|
34 | 34 | <td class="td-comments"> |
|
35 | 35 | %if c.comments.get(cs.raw_id,[]): |
|
36 |
<a title="${_('Commit has comments')}" href="${h. |
|
|
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 | 37 | <i class="icon-comment"></i> ${len(c.comments[cs.raw_id])} |
|
38 | 38 | </a> |
|
39 | 39 | %endif |
|
40 | 40 | </td> |
|
41 | 41 | <td class="td-commit"> |
|
42 |
<pre><a href="${h. |
|
|
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 | 43 | </td> |
|
44 | 44 | |
|
45 | 45 | <td class="td-description mid"> |
@@ -471,7 +471,7 b' class TestCompareController(object):' | |||
|
471 | 471 | compare_page.contains_change_summary(1, 1, 0) |
|
472 | 472 | |
|
473 | 473 | @pytest.mark.xfail_backends("svn") |
|
474 | def test_compare_commits(self, backend): | |
|
474 | def test_compare_commits(self, backend, xhr_header): | |
|
475 | 475 | commit0 = backend.repo.get_commit(commit_idx=0) |
|
476 | 476 | commit1 = backend.repo.get_commit(commit_idx=1) |
|
477 | 477 | |
@@ -483,7 +483,7 b' class TestCompareController(object):' | |||
|
483 | 483 | target_ref_type="rev", |
|
484 | 484 | target_ref=commit1.raw_id, |
|
485 | 485 | merge='1',), |
|
486 |
extra_environ= |
|
|
486 | extra_environ=xhr_header,) | |
|
487 | 487 | |
|
488 | 488 | # outgoing commits between those commits |
|
489 | 489 | compare_page = ComparePage(response) |
@@ -397,7 +397,7 b' def test_urlify_commits(sample, expected' | |||
|
397 | 397 | |
|
398 | 398 | expected = _quick_url(expected) |
|
399 | 399 | |
|
400 |
with mock.patch(' |
|
|
400 | with mock.patch('rhodecode.lib.helpers.route_url', fake_url): | |
|
401 | 401 | from rhodecode.lib.helpers import urlify_commits |
|
402 | 402 | assert urlify_commits(sample, 'repo_name') == expected |
|
403 | 403 |
@@ -1,7 +1,7 b'' | |||
|
1 | 1 | |
|
2 | 2 | |
|
3 | 3 | ################################################################################ |
|
4 |
## |
|
|
4 | ## RHODECODE COMMUNITY EDITION CONFIGURATION ## | |
|
5 | 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 | 65 | ## GUNICORN WSGI SERVER ## |
|
66 | 66 | ########################## |
|
67 |
## run with gunicorn --log-config |
|
|
67 | ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini | |
|
68 | 68 | |
|
69 | 69 | #use = egg:gunicorn#main |
|
70 | 70 | ## Sets the number of process workers. You must set `instance_id = *` |
@@ -153,8 +153,10 b' asyncore_use_poll = true' | |||
|
153 | 153 | ## prefix middleware for RhodeCode. |
|
154 | 154 | ## recommended when using proxy setup. |
|
155 | 155 | ## allows to set RhodeCode under a prefix in server. |
|
156 |
## eg https://server.com/ |
|
|
157 |
## |
|
|
156 | ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well. | |
|
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 | 160 | [filter:proxy-prefix] |
|
159 | 161 | use = egg:PasteDeploy#prefix |
|
160 | 162 | prefix = / |
@@ -238,27 +240,27 b' rss_items_per_page = 10' | |||
|
238 | 240 | rss_include_diff = false |
|
239 | 241 | |
|
240 | 242 | ## gist URL alias, used to create nicer urls for gist. This should be an |
|
241 |
## url that does rewrites to _admin/gists/ |
|
|
243 | ## url that does rewrites to _admin/gists/{gistid}. | |
|
242 | 244 | ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal |
|
243 |
## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/ |
|
|
245 | ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid} | |
|
244 | 246 | gist_alias_url = |
|
245 | 247 | |
|
246 |
## List of |
|
|
248 | ## List of views (using glob pattern syntax) that AUTH TOKENS could be | |
|
247 | 249 | ## used for access. |
|
248 |
## Adding ?auth_token |
|
|
250 | ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it | |
|
249 | 251 | ## came from the the logged in user who own this authentication token. |
|
250 | 252 | ## |
|
251 | ## Syntax is <ControllerClass>:<function_pattern>. | |
|
252 | ## To enable access to raw_files put `FilesController:raw`. | |
|
253 | ## To enable access to patches add `ChangesetController:changeset_patch`. | |
|
253 | ## list of all views can be found under `_admin/permissions/auth_token_access` | |
|
254 | 254 | ## The list should be "," separated and on a single line. |
|
255 | 255 | ## |
|
256 |
## |
|
|
257 | # ChangesetController:changeset_patch, | |
|
258 | # ChangesetController:changeset_raw, | |
|
259 | # FilesController:raw, | |
|
260 | # FilesController:archivefile, | |
|
261 | # GistsController:*, | |
|
256 | ## Most common views to enable: | |
|
257 | # RepoCommitsView:repo_commit_download | |
|
258 | # RepoCommitsView:repo_commit_patch | |
|
259 | # RepoCommitsView:repo_commit_raw | |
|
260 | # RepoFilesView:repo_files_diff | |
|
261 | # RepoFilesView:repo_archivefile | |
|
262 | # RepoFilesView:repo_file_raw | |
|
263 | # GistView:* | |
|
262 | 264 | api_access_controllers_whitelist = |
|
263 | 265 | |
|
264 | 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 | 424 | ## Secure encrypted cookie. Requires AES and AES python libraries |
|
423 | 425 | ## you must disable beaker.session.secret to use this |
|
424 |
#beaker.session.encrypt_key = |
|
|
425 |
#beaker.session.validate_key = |
|
|
426 | #beaker.session.encrypt_key = key_for_encryption | |
|
427 | #beaker.session.validate_key = validation_key | |
|
426 | 428 | |
|
427 | 429 | ## sets session as invalid(also logging out user) if it haven not been |
|
428 | 430 | ## accessed for given amount of time in seconds |
|
429 | 431 | beaker.session.timeout = 2592000 |
|
430 | 432 | beaker.session.httponly = true |
|
431 | ## Path to use for the cookie. | |
|
432 |
#beaker.session.cookie_path = / |
|
|
433 | ## Path to use for the cookie. Set to prefix if you use prefix middleware | |
|
434 | #beaker.session.cookie_path = /custom_prefix | |
|
433 | 435 | |
|
434 | 436 | ## uncomment for https secure cookie |
|
435 | 437 | beaker.session.secure = false |
@@ -447,8 +449,8 b' beaker.session.auto = false' | |||
|
447 | 449 | ## Full text search indexer is available in rhodecode-tools under |
|
448 | 450 | ## `rhodecode-tools index` command |
|
449 | 451 | |
|
450 | # WHOOSH Backend, doesn't require additional services to run | |
|
451 | # it works good with few dozen repos | |
|
452 | ## WHOOSH Backend, doesn't require additional services to run | |
|
453 | ## it works good with few dozen repos | |
|
452 | 454 | search.module = rhodecode.lib.index.whoosh |
|
453 | 455 | search.location = %(here)s/data/index |
|
454 | 456 | |
@@ -459,15 +461,21 b' search.location = %(here)s/data/index' | |||
|
459 | 461 | ## in the system. It's also used by the chat system |
|
460 | 462 | |
|
461 | 463 | channelstream.enabled = false |
|
462 | # location of channelstream server on the backend | |
|
464 | ||
|
465 | ## server address for channelstream server on the backend | |
|
463 | 466 | channelstream.server = 127.0.0.1:9800 |
|
464 | 467 | ## location of the channelstream server from outside world |
|
465 | ## most likely this would be an http server special backend URL, that handles | |
|
466 | ## websocket connections see nginx example for config | |
|
468 | ## use ws:// for http or wss:// for https. This address needs to be handled | |
|
469 | ## by external HTTP server such as Nginx or Apache | |
|
470 | ## see nginx/apache configuration examples in our docs | |
|
467 | 471 | channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream |
|
468 | 472 | channelstream.secret = secret |
|
469 | 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 | 481 | ## APPENLIGHT CONFIG ## |
@@ -541,19 +549,19 b' set debug = false' | |||
|
541 | 549 | ############## |
|
542 | 550 | debug_style = false |
|
543 | 551 | |
|
544 |
########################################### |
|
|
545 | ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ### | |
|
546 |
########################################### |
|
|
547 | #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db | |
|
552 | ########################################### | |
|
553 | ### MAIN RHODECODE DATABASE CONFIG ### | |
|
554 | ########################################### | |
|
555 | #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30 | |
|
548 | 556 | #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test |
|
549 | 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 | 560 | # see sqlalchemy docs for other advanced settings |
|
553 | 561 | |
|
554 | 562 | ## print the sql statements to output |
|
555 | 563 | sqlalchemy.db1.echo = false |
|
556 |
## recycle the connections after this am |
|
|
564 | ## recycle the connections after this amount of seconds | |
|
557 | 565 | sqlalchemy.db1.pool_recycle = 3600 |
|
558 | 566 | sqlalchemy.db1.convert_unicode = true |
|
559 | 567 | |
@@ -575,7 +583,7 b' vcs.server = localhost:9901' | |||
|
575 | 583 | |
|
576 | 584 | ## Web server connectivity protocol, responsible for web based VCS operatations |
|
577 | 585 | ## Available protocols are: |
|
578 |
## `http` - us |
|
|
586 | ## `http` - use http-rpc backend (default) | |
|
579 | 587 | vcs.server.protocol = http |
|
580 | 588 | |
|
581 | 589 | ## Push/Pull operations protocol, available options are: |
@@ -584,7 +592,7 b' vcs.server.protocol = http' | |||
|
584 | 592 | vcs.scm_app_implementation = http |
|
585 | 593 | |
|
586 | 594 | ## Push/Pull operations hooks protocol, available options are: |
|
587 |
## `http` - us |
|
|
595 | ## `http` - use http-rpc backend (default) | |
|
588 | 596 | vcs.hooks.protocol = http |
|
589 | 597 | |
|
590 | 598 | vcs.server.log_level = debug |
@@ -613,12 +621,19 b' svn.proxy.generate_config = false' | |||
|
613 | 621 | svn.proxy.list_parent_path = true |
|
614 | 622 | ## Set location and file name of generated config file. |
|
615 | 623 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf |
|
616 | ## File system path to the directory containing the repositories served by | |
|
617 | ## RhodeCode. | |
|
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 `/`. | |
|
624 | ## Used as a prefix to the `Location` block in the generated config file. | |
|
625 | ## In most cases it should be set to `/`. | |
|
621 | 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 |
General Comments 0
You need to be logged in to leave comments.
Login now