##// END OF EJS Templates
comments-history: fixed fetching of history for comments
super-admin -
r4717:39aa18a6 default
parent child Browse files
Show More
@@ -1,1227 +1,1227 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 from rhodecode.apps._base import add_route_with_slash
20 from rhodecode.apps._base import add_route_with_slash
21
21
22
22
23 def includeme(config):
23 def includeme(config):
24 from rhodecode.apps.repository.views.repo_artifacts import RepoArtifactsView
24 from rhodecode.apps.repository.views.repo_artifacts import RepoArtifactsView
25 from rhodecode.apps.repository.views.repo_audit_logs import AuditLogsView
25 from rhodecode.apps.repository.views.repo_audit_logs import AuditLogsView
26 from rhodecode.apps.repository.views.repo_automation import RepoAutomationView
26 from rhodecode.apps.repository.views.repo_automation import RepoAutomationView
27 from rhodecode.apps.repository.views.repo_bookmarks import RepoBookmarksView
27 from rhodecode.apps.repository.views.repo_bookmarks import RepoBookmarksView
28 from rhodecode.apps.repository.views.repo_branch_permissions import RepoSettingsBranchPermissionsView
28 from rhodecode.apps.repository.views.repo_branch_permissions import RepoSettingsBranchPermissionsView
29 from rhodecode.apps.repository.views.repo_branches import RepoBranchesView
29 from rhodecode.apps.repository.views.repo_branches import RepoBranchesView
30 from rhodecode.apps.repository.views.repo_caches import RepoCachesView
30 from rhodecode.apps.repository.views.repo_caches import RepoCachesView
31 from rhodecode.apps.repository.views.repo_changelog import RepoChangelogView
31 from rhodecode.apps.repository.views.repo_changelog import RepoChangelogView
32 from rhodecode.apps.repository.views.repo_checks import RepoChecksView
32 from rhodecode.apps.repository.views.repo_checks import RepoChecksView
33 from rhodecode.apps.repository.views.repo_commits import RepoCommitsView
33 from rhodecode.apps.repository.views.repo_commits import RepoCommitsView
34 from rhodecode.apps.repository.views.repo_compare import RepoCompareView
34 from rhodecode.apps.repository.views.repo_compare import RepoCompareView
35 from rhodecode.apps.repository.views.repo_feed import RepoFeedView
35 from rhodecode.apps.repository.views.repo_feed import RepoFeedView
36 from rhodecode.apps.repository.views.repo_files import RepoFilesView
36 from rhodecode.apps.repository.views.repo_files import RepoFilesView
37 from rhodecode.apps.repository.views.repo_forks import RepoForksView
37 from rhodecode.apps.repository.views.repo_forks import RepoForksView
38 from rhodecode.apps.repository.views.repo_maintainance import RepoMaintenanceView
38 from rhodecode.apps.repository.views.repo_maintainance import RepoMaintenanceView
39 from rhodecode.apps.repository.views.repo_permissions import RepoSettingsPermissionsView
39 from rhodecode.apps.repository.views.repo_permissions import RepoSettingsPermissionsView
40 from rhodecode.apps.repository.views.repo_pull_requests import RepoPullRequestsView
40 from rhodecode.apps.repository.views.repo_pull_requests import RepoPullRequestsView
41 from rhodecode.apps.repository.views.repo_review_rules import RepoReviewRulesView
41 from rhodecode.apps.repository.views.repo_review_rules import RepoReviewRulesView
42 from rhodecode.apps.repository.views.repo_settings import RepoSettingsView
42 from rhodecode.apps.repository.views.repo_settings import RepoSettingsView
43 from rhodecode.apps.repository.views.repo_settings_advanced import RepoSettingsAdvancedView
43 from rhodecode.apps.repository.views.repo_settings_advanced import RepoSettingsAdvancedView
44 from rhodecode.apps.repository.views.repo_settings_fields import RepoSettingsFieldsView
44 from rhodecode.apps.repository.views.repo_settings_fields import RepoSettingsFieldsView
45 from rhodecode.apps.repository.views.repo_settings_issue_trackers import RepoSettingsIssueTrackersView
45 from rhodecode.apps.repository.views.repo_settings_issue_trackers import RepoSettingsIssueTrackersView
46 from rhodecode.apps.repository.views.repo_settings_remote import RepoSettingsRemoteView
46 from rhodecode.apps.repository.views.repo_settings_remote import RepoSettingsRemoteView
47 from rhodecode.apps.repository.views.repo_settings_vcs import RepoSettingsVcsView
47 from rhodecode.apps.repository.views.repo_settings_vcs import RepoSettingsVcsView
48 from rhodecode.apps.repository.views.repo_strip import RepoStripView
48 from rhodecode.apps.repository.views.repo_strip import RepoStripView
49 from rhodecode.apps.repository.views.repo_summary import RepoSummaryView
49 from rhodecode.apps.repository.views.repo_summary import RepoSummaryView
50 from rhodecode.apps.repository.views.repo_tags import RepoTagsView
50 from rhodecode.apps.repository.views.repo_tags import RepoTagsView
51
51
52 # repo creating checks, special cases that aren't repo routes
52 # repo creating checks, special cases that aren't repo routes
53 config.add_route(
53 config.add_route(
54 name='repo_creating',
54 name='repo_creating',
55 pattern='/{repo_name:.*?[^/]}/repo_creating')
55 pattern='/{repo_name:.*?[^/]}/repo_creating')
56 config.add_view(
56 config.add_view(
57 RepoChecksView,
57 RepoChecksView,
58 attr='repo_creating',
58 attr='repo_creating',
59 route_name='repo_creating', request_method='GET',
59 route_name='repo_creating', request_method='GET',
60 renderer='rhodecode:templates/admin/repos/repo_creating.mako')
60 renderer='rhodecode:templates/admin/repos/repo_creating.mako')
61
61
62 config.add_route(
62 config.add_route(
63 name='repo_creating_check',
63 name='repo_creating_check',
64 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
64 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
65 config.add_view(
65 config.add_view(
66 RepoChecksView,
66 RepoChecksView,
67 attr='repo_creating_check',
67 attr='repo_creating_check',
68 route_name='repo_creating_check', request_method='GET',
68 route_name='repo_creating_check', request_method='GET',
69 renderer='json_ext')
69 renderer='json_ext')
70
70
71 # Summary
71 # Summary
72 # NOTE(marcink): one additional route is defined in very bottom, catch
72 # NOTE(marcink): one additional route is defined in very bottom, catch
73 # all pattern
73 # all pattern
74 config.add_route(
74 config.add_route(
75 name='repo_summary_explicit',
75 name='repo_summary_explicit',
76 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
76 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
77 config.add_view(
77 config.add_view(
78 RepoSummaryView,
78 RepoSummaryView,
79 attr='summary',
79 attr='summary',
80 route_name='repo_summary_explicit', request_method='GET',
80 route_name='repo_summary_explicit', request_method='GET',
81 renderer='rhodecode:templates/summary/summary.mako')
81 renderer='rhodecode:templates/summary/summary.mako')
82
82
83 config.add_route(
83 config.add_route(
84 name='repo_summary_commits',
84 name='repo_summary_commits',
85 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
85 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
86 config.add_view(
86 config.add_view(
87 RepoSummaryView,
87 RepoSummaryView,
88 attr='summary_commits',
88 attr='summary_commits',
89 route_name='repo_summary_commits', request_method='GET',
89 route_name='repo_summary_commits', request_method='GET',
90 renderer='rhodecode:templates/summary/summary_commits.mako')
90 renderer='rhodecode:templates/summary/summary_commits.mako')
91
91
92 # Commits
92 # Commits
93 config.add_route(
93 config.add_route(
94 name='repo_commit',
94 name='repo_commit',
95 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
95 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
96 config.add_view(
96 config.add_view(
97 RepoCommitsView,
97 RepoCommitsView,
98 attr='repo_commit_show',
98 attr='repo_commit_show',
99 route_name='repo_commit', request_method='GET',
99 route_name='repo_commit', request_method='GET',
100 renderer=None)
100 renderer=None)
101
101
102 config.add_route(
102 config.add_route(
103 name='repo_commit_children',
103 name='repo_commit_children',
104 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
104 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
105 config.add_view(
105 config.add_view(
106 RepoCommitsView,
106 RepoCommitsView,
107 attr='repo_commit_children',
107 attr='repo_commit_children',
108 route_name='repo_commit_children', request_method='GET',
108 route_name='repo_commit_children', request_method='GET',
109 renderer='json_ext', xhr=True)
109 renderer='json_ext', xhr=True)
110
110
111 config.add_route(
111 config.add_route(
112 name='repo_commit_parents',
112 name='repo_commit_parents',
113 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
113 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
114 config.add_view(
114 config.add_view(
115 RepoCommitsView,
115 RepoCommitsView,
116 attr='repo_commit_parents',
116 attr='repo_commit_parents',
117 route_name='repo_commit_parents', request_method='GET',
117 route_name='repo_commit_parents', request_method='GET',
118 renderer='json_ext')
118 renderer='json_ext')
119
119
120 config.add_route(
120 config.add_route(
121 name='repo_commit_raw',
121 name='repo_commit_raw',
122 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
122 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
123 config.add_view(
123 config.add_view(
124 RepoCommitsView,
124 RepoCommitsView,
125 attr='repo_commit_raw',
125 attr='repo_commit_raw',
126 route_name='repo_commit_raw', request_method='GET',
126 route_name='repo_commit_raw', request_method='GET',
127 renderer=None)
127 renderer=None)
128
128
129 config.add_route(
129 config.add_route(
130 name='repo_commit_patch',
130 name='repo_commit_patch',
131 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
131 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
132 config.add_view(
132 config.add_view(
133 RepoCommitsView,
133 RepoCommitsView,
134 attr='repo_commit_patch',
134 attr='repo_commit_patch',
135 route_name='repo_commit_patch', request_method='GET',
135 route_name='repo_commit_patch', request_method='GET',
136 renderer=None)
136 renderer=None)
137
137
138 config.add_route(
138 config.add_route(
139 name='repo_commit_download',
139 name='repo_commit_download',
140 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
140 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
141 config.add_view(
141 config.add_view(
142 RepoCommitsView,
142 RepoCommitsView,
143 attr='repo_commit_download',
143 attr='repo_commit_download',
144 route_name='repo_commit_download', request_method='GET',
144 route_name='repo_commit_download', request_method='GET',
145 renderer=None)
145 renderer=None)
146
146
147 config.add_route(
147 config.add_route(
148 name='repo_commit_data',
148 name='repo_commit_data',
149 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
149 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
150 config.add_view(
150 config.add_view(
151 RepoCommitsView,
151 RepoCommitsView,
152 attr='repo_commit_data',
152 attr='repo_commit_data',
153 route_name='repo_commit_data', request_method='GET',
153 route_name='repo_commit_data', request_method='GET',
154 renderer='json_ext', xhr=True)
154 renderer='json_ext', xhr=True)
155
155
156 config.add_route(
156 config.add_route(
157 name='repo_commit_comment_create',
157 name='repo_commit_comment_create',
158 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
158 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
159 config.add_view(
159 config.add_view(
160 RepoCommitsView,
160 RepoCommitsView,
161 attr='repo_commit_comment_create',
161 attr='repo_commit_comment_create',
162 route_name='repo_commit_comment_create', request_method='POST',
162 route_name='repo_commit_comment_create', request_method='POST',
163 renderer='json_ext')
163 renderer='json_ext')
164
164
165 config.add_route(
165 config.add_route(
166 name='repo_commit_comment_preview',
166 name='repo_commit_comment_preview',
167 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
167 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
168 config.add_view(
168 config.add_view(
169 RepoCommitsView,
169 RepoCommitsView,
170 attr='repo_commit_comment_preview',
170 attr='repo_commit_comment_preview',
171 route_name='repo_commit_comment_preview', request_method='POST',
171 route_name='repo_commit_comment_preview', request_method='POST',
172 renderer='string', xhr=True)
172 renderer='string', xhr=True)
173
173
174 config.add_route(
174 config.add_route(
175 name='repo_commit_comment_history_view',
175 name='repo_commit_comment_history_view',
176 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_history_id}/history_view', repo_route=True)
176 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/history_view/{comment_history_id}', repo_route=True)
177 config.add_view(
177 config.add_view(
178 RepoCommitsView,
178 RepoCommitsView,
179 attr='repo_commit_comment_history_view',
179 attr='repo_commit_comment_history_view',
180 route_name='repo_commit_comment_history_view', request_method='POST',
180 route_name='repo_commit_comment_history_view', request_method='POST',
181 renderer='string', xhr=True)
181 renderer='string', xhr=True)
182
182
183 config.add_route(
183 config.add_route(
184 name='repo_commit_comment_attachment_upload',
184 name='repo_commit_comment_attachment_upload',
185 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/attachment_upload', repo_route=True)
185 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/attachment_upload', repo_route=True)
186 config.add_view(
186 config.add_view(
187 RepoCommitsView,
187 RepoCommitsView,
188 attr='repo_commit_comment_attachment_upload',
188 attr='repo_commit_comment_attachment_upload',
189 route_name='repo_commit_comment_attachment_upload', request_method='POST',
189 route_name='repo_commit_comment_attachment_upload', request_method='POST',
190 renderer='json_ext', xhr=True)
190 renderer='json_ext', xhr=True)
191
191
192 config.add_route(
192 config.add_route(
193 name='repo_commit_comment_delete',
193 name='repo_commit_comment_delete',
194 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
194 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
195 config.add_view(
195 config.add_view(
196 RepoCommitsView,
196 RepoCommitsView,
197 attr='repo_commit_comment_delete',
197 attr='repo_commit_comment_delete',
198 route_name='repo_commit_comment_delete', request_method='POST',
198 route_name='repo_commit_comment_delete', request_method='POST',
199 renderer='json_ext')
199 renderer='json_ext')
200
200
201 config.add_route(
201 config.add_route(
202 name='repo_commit_comment_edit',
202 name='repo_commit_comment_edit',
203 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/edit', repo_route=True)
203 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/edit', repo_route=True)
204 config.add_view(
204 config.add_view(
205 RepoCommitsView,
205 RepoCommitsView,
206 attr='repo_commit_comment_edit',
206 attr='repo_commit_comment_edit',
207 route_name='repo_commit_comment_edit', request_method='POST',
207 route_name='repo_commit_comment_edit', request_method='POST',
208 renderer='json_ext')
208 renderer='json_ext')
209
209
210 # still working url for backward compat.
210 # still working url for backward compat.
211 config.add_route(
211 config.add_route(
212 name='repo_commit_raw_deprecated',
212 name='repo_commit_raw_deprecated',
213 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
213 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
214 config.add_view(
214 config.add_view(
215 RepoCommitsView,
215 RepoCommitsView,
216 attr='repo_commit_raw',
216 attr='repo_commit_raw',
217 route_name='repo_commit_raw_deprecated', request_method='GET',
217 route_name='repo_commit_raw_deprecated', request_method='GET',
218 renderer=None)
218 renderer=None)
219
219
220 # Files
220 # Files
221 config.add_route(
221 config.add_route(
222 name='repo_archivefile',
222 name='repo_archivefile',
223 pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True)
223 pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True)
224 config.add_view(
224 config.add_view(
225 RepoFilesView,
225 RepoFilesView,
226 attr='repo_archivefile',
226 attr='repo_archivefile',
227 route_name='repo_archivefile', request_method='GET',
227 route_name='repo_archivefile', request_method='GET',
228 renderer=None)
228 renderer=None)
229
229
230 config.add_route(
230 config.add_route(
231 name='repo_files_diff',
231 name='repo_files_diff',
232 pattern='/{repo_name:.*?[^/]}/diff/{f_path:.*}', repo_route=True)
232 pattern='/{repo_name:.*?[^/]}/diff/{f_path:.*}', repo_route=True)
233 config.add_view(
233 config.add_view(
234 RepoFilesView,
234 RepoFilesView,
235 attr='repo_files_diff',
235 attr='repo_files_diff',
236 route_name='repo_files_diff', request_method='GET',
236 route_name='repo_files_diff', request_method='GET',
237 renderer=None)
237 renderer=None)
238
238
239 config.add_route( # legacy route to make old links work
239 config.add_route( # legacy route to make old links work
240 name='repo_files_diff_2way_redirect',
240 name='repo_files_diff_2way_redirect',
241 pattern='/{repo_name:.*?[^/]}/diff-2way/{f_path:.*}', repo_route=True)
241 pattern='/{repo_name:.*?[^/]}/diff-2way/{f_path:.*}', repo_route=True)
242 config.add_view(
242 config.add_view(
243 RepoFilesView,
243 RepoFilesView,
244 attr='repo_files_diff_2way_redirect',
244 attr='repo_files_diff_2way_redirect',
245 route_name='repo_files_diff_2way_redirect', request_method='GET',
245 route_name='repo_files_diff_2way_redirect', request_method='GET',
246 renderer=None)
246 renderer=None)
247
247
248 config.add_route(
248 config.add_route(
249 name='repo_files',
249 name='repo_files',
250 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/{f_path:.*}', repo_route=True)
250 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/{f_path:.*}', repo_route=True)
251 config.add_view(
251 config.add_view(
252 RepoFilesView,
252 RepoFilesView,
253 attr='repo_files',
253 attr='repo_files',
254 route_name='repo_files', request_method='GET',
254 route_name='repo_files', request_method='GET',
255 renderer=None)
255 renderer=None)
256
256
257 config.add_route(
257 config.add_route(
258 name='repo_files:default_path',
258 name='repo_files:default_path',
259 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/', repo_route=True)
259 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/', repo_route=True)
260 config.add_view(
260 config.add_view(
261 RepoFilesView,
261 RepoFilesView,
262 attr='repo_files',
262 attr='repo_files',
263 route_name='repo_files:default_path', request_method='GET',
263 route_name='repo_files:default_path', request_method='GET',
264 renderer=None)
264 renderer=None)
265
265
266 config.add_route(
266 config.add_route(
267 name='repo_files:default_commit',
267 name='repo_files:default_commit',
268 pattern='/{repo_name:.*?[^/]}/files', repo_route=True)
268 pattern='/{repo_name:.*?[^/]}/files', repo_route=True)
269 config.add_view(
269 config.add_view(
270 RepoFilesView,
270 RepoFilesView,
271 attr='repo_files',
271 attr='repo_files',
272 route_name='repo_files:default_commit', request_method='GET',
272 route_name='repo_files:default_commit', request_method='GET',
273 renderer=None)
273 renderer=None)
274
274
275 config.add_route(
275 config.add_route(
276 name='repo_files:rendered',
276 name='repo_files:rendered',
277 pattern='/{repo_name:.*?[^/]}/render/{commit_id}/{f_path:.*}', repo_route=True)
277 pattern='/{repo_name:.*?[^/]}/render/{commit_id}/{f_path:.*}', repo_route=True)
278 config.add_view(
278 config.add_view(
279 RepoFilesView,
279 RepoFilesView,
280 attr='repo_files',
280 attr='repo_files',
281 route_name='repo_files:rendered', request_method='GET',
281 route_name='repo_files:rendered', request_method='GET',
282 renderer=None)
282 renderer=None)
283
283
284 config.add_route(
284 config.add_route(
285 name='repo_files:annotated',
285 name='repo_files:annotated',
286 pattern='/{repo_name:.*?[^/]}/annotate/{commit_id}/{f_path:.*}', repo_route=True)
286 pattern='/{repo_name:.*?[^/]}/annotate/{commit_id}/{f_path:.*}', repo_route=True)
287 config.add_view(
287 config.add_view(
288 RepoFilesView,
288 RepoFilesView,
289 attr='repo_files',
289 attr='repo_files',
290 route_name='repo_files:annotated', request_method='GET',
290 route_name='repo_files:annotated', request_method='GET',
291 renderer=None)
291 renderer=None)
292
292
293 config.add_route(
293 config.add_route(
294 name='repo_files:annotated_previous',
294 name='repo_files:annotated_previous',
295 pattern='/{repo_name:.*?[^/]}/annotate-previous/{commit_id}/{f_path:.*}', repo_route=True)
295 pattern='/{repo_name:.*?[^/]}/annotate-previous/{commit_id}/{f_path:.*}', repo_route=True)
296 config.add_view(
296 config.add_view(
297 RepoFilesView,
297 RepoFilesView,
298 attr='repo_files_annotated_previous',
298 attr='repo_files_annotated_previous',
299 route_name='repo_files:annotated_previous', request_method='GET',
299 route_name='repo_files:annotated_previous', request_method='GET',
300 renderer=None)
300 renderer=None)
301
301
302 config.add_route(
302 config.add_route(
303 name='repo_nodetree_full',
303 name='repo_nodetree_full',
304 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/{f_path:.*}', repo_route=True)
304 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/{f_path:.*}', repo_route=True)
305 config.add_view(
305 config.add_view(
306 RepoFilesView,
306 RepoFilesView,
307 attr='repo_nodetree_full',
307 attr='repo_nodetree_full',
308 route_name='repo_nodetree_full', request_method='GET',
308 route_name='repo_nodetree_full', request_method='GET',
309 renderer=None, xhr=True)
309 renderer=None, xhr=True)
310
310
311 config.add_route(
311 config.add_route(
312 name='repo_nodetree_full:default_path',
312 name='repo_nodetree_full:default_path',
313 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/', repo_route=True)
313 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/', repo_route=True)
314 config.add_view(
314 config.add_view(
315 RepoFilesView,
315 RepoFilesView,
316 attr='repo_nodetree_full',
316 attr='repo_nodetree_full',
317 route_name='repo_nodetree_full:default_path', request_method='GET',
317 route_name='repo_nodetree_full:default_path', request_method='GET',
318 renderer=None, xhr=True)
318 renderer=None, xhr=True)
319
319
320 config.add_route(
320 config.add_route(
321 name='repo_files_nodelist',
321 name='repo_files_nodelist',
322 pattern='/{repo_name:.*?[^/]}/nodelist/{commit_id}/{f_path:.*}', repo_route=True)
322 pattern='/{repo_name:.*?[^/]}/nodelist/{commit_id}/{f_path:.*}', repo_route=True)
323 config.add_view(
323 config.add_view(
324 RepoFilesView,
324 RepoFilesView,
325 attr='repo_nodelist',
325 attr='repo_nodelist',
326 route_name='repo_files_nodelist', request_method='GET',
326 route_name='repo_files_nodelist', request_method='GET',
327 renderer='json_ext', xhr=True)
327 renderer='json_ext', xhr=True)
328
328
329 config.add_route(
329 config.add_route(
330 name='repo_file_raw',
330 name='repo_file_raw',
331 pattern='/{repo_name:.*?[^/]}/raw/{commit_id}/{f_path:.*}', repo_route=True)
331 pattern='/{repo_name:.*?[^/]}/raw/{commit_id}/{f_path:.*}', repo_route=True)
332 config.add_view(
332 config.add_view(
333 RepoFilesView,
333 RepoFilesView,
334 attr='repo_file_raw',
334 attr='repo_file_raw',
335 route_name='repo_file_raw', request_method='GET',
335 route_name='repo_file_raw', request_method='GET',
336 renderer=None)
336 renderer=None)
337
337
338 config.add_route(
338 config.add_route(
339 name='repo_file_download',
339 name='repo_file_download',
340 pattern='/{repo_name:.*?[^/]}/download/{commit_id}/{f_path:.*}', repo_route=True)
340 pattern='/{repo_name:.*?[^/]}/download/{commit_id}/{f_path:.*}', repo_route=True)
341 config.add_view(
341 config.add_view(
342 RepoFilesView,
342 RepoFilesView,
343 attr='repo_file_download',
343 attr='repo_file_download',
344 route_name='repo_file_download', request_method='GET',
344 route_name='repo_file_download', request_method='GET',
345 renderer=None)
345 renderer=None)
346
346
347 config.add_route( # backward compat to keep old links working
347 config.add_route( # backward compat to keep old links working
348 name='repo_file_download:legacy',
348 name='repo_file_download:legacy',
349 pattern='/{repo_name:.*?[^/]}/rawfile/{commit_id}/{f_path:.*}',
349 pattern='/{repo_name:.*?[^/]}/rawfile/{commit_id}/{f_path:.*}',
350 repo_route=True)
350 repo_route=True)
351 config.add_view(
351 config.add_view(
352 RepoFilesView,
352 RepoFilesView,
353 attr='repo_file_download',
353 attr='repo_file_download',
354 route_name='repo_file_download:legacy', request_method='GET',
354 route_name='repo_file_download:legacy', request_method='GET',
355 renderer=None)
355 renderer=None)
356
356
357 config.add_route(
357 config.add_route(
358 name='repo_file_history',
358 name='repo_file_history',
359 pattern='/{repo_name:.*?[^/]}/history/{commit_id}/{f_path:.*}', repo_route=True)
359 pattern='/{repo_name:.*?[^/]}/history/{commit_id}/{f_path:.*}', repo_route=True)
360 config.add_view(
360 config.add_view(
361 RepoFilesView,
361 RepoFilesView,
362 attr='repo_file_history',
362 attr='repo_file_history',
363 route_name='repo_file_history', request_method='GET',
363 route_name='repo_file_history', request_method='GET',
364 renderer='json_ext')
364 renderer='json_ext')
365
365
366 config.add_route(
366 config.add_route(
367 name='repo_file_authors',
367 name='repo_file_authors',
368 pattern='/{repo_name:.*?[^/]}/authors/{commit_id}/{f_path:.*}', repo_route=True)
368 pattern='/{repo_name:.*?[^/]}/authors/{commit_id}/{f_path:.*}', repo_route=True)
369 config.add_view(
369 config.add_view(
370 RepoFilesView,
370 RepoFilesView,
371 attr='repo_file_authors',
371 attr='repo_file_authors',
372 route_name='repo_file_authors', request_method='GET',
372 route_name='repo_file_authors', request_method='GET',
373 renderer='rhodecode:templates/files/file_authors_box.mako')
373 renderer='rhodecode:templates/files/file_authors_box.mako')
374
374
375 config.add_route(
375 config.add_route(
376 name='repo_files_check_head',
376 name='repo_files_check_head',
377 pattern='/{repo_name:.*?[^/]}/check_head/{commit_id}/{f_path:.*}',
377 pattern='/{repo_name:.*?[^/]}/check_head/{commit_id}/{f_path:.*}',
378 repo_route=True)
378 repo_route=True)
379 config.add_view(
379 config.add_view(
380 RepoFilesView,
380 RepoFilesView,
381 attr='repo_files_check_head',
381 attr='repo_files_check_head',
382 route_name='repo_files_check_head', request_method='POST',
382 route_name='repo_files_check_head', request_method='POST',
383 renderer='json_ext', xhr=True)
383 renderer='json_ext', xhr=True)
384
384
385 config.add_route(
385 config.add_route(
386 name='repo_files_remove_file',
386 name='repo_files_remove_file',
387 pattern='/{repo_name:.*?[^/]}/remove_file/{commit_id}/{f_path:.*}',
387 pattern='/{repo_name:.*?[^/]}/remove_file/{commit_id}/{f_path:.*}',
388 repo_route=True)
388 repo_route=True)
389 config.add_view(
389 config.add_view(
390 RepoFilesView,
390 RepoFilesView,
391 attr='repo_files_remove_file',
391 attr='repo_files_remove_file',
392 route_name='repo_files_remove_file', request_method='GET',
392 route_name='repo_files_remove_file', request_method='GET',
393 renderer='rhodecode:templates/files/files_delete.mako')
393 renderer='rhodecode:templates/files/files_delete.mako')
394
394
395 config.add_route(
395 config.add_route(
396 name='repo_files_delete_file',
396 name='repo_files_delete_file',
397 pattern='/{repo_name:.*?[^/]}/delete_file/{commit_id}/{f_path:.*}',
397 pattern='/{repo_name:.*?[^/]}/delete_file/{commit_id}/{f_path:.*}',
398 repo_route=True)
398 repo_route=True)
399 config.add_view(
399 config.add_view(
400 RepoFilesView,
400 RepoFilesView,
401 attr='repo_files_delete_file',
401 attr='repo_files_delete_file',
402 route_name='repo_files_delete_file', request_method='POST',
402 route_name='repo_files_delete_file', request_method='POST',
403 renderer=None)
403 renderer=None)
404
404
405 config.add_route(
405 config.add_route(
406 name='repo_files_edit_file',
406 name='repo_files_edit_file',
407 pattern='/{repo_name:.*?[^/]}/edit_file/{commit_id}/{f_path:.*}',
407 pattern='/{repo_name:.*?[^/]}/edit_file/{commit_id}/{f_path:.*}',
408 repo_route=True)
408 repo_route=True)
409 config.add_view(
409 config.add_view(
410 RepoFilesView,
410 RepoFilesView,
411 attr='repo_files_edit_file',
411 attr='repo_files_edit_file',
412 route_name='repo_files_edit_file', request_method='GET',
412 route_name='repo_files_edit_file', request_method='GET',
413 renderer='rhodecode:templates/files/files_edit.mako')
413 renderer='rhodecode:templates/files/files_edit.mako')
414
414
415 config.add_route(
415 config.add_route(
416 name='repo_files_update_file',
416 name='repo_files_update_file',
417 pattern='/{repo_name:.*?[^/]}/update_file/{commit_id}/{f_path:.*}',
417 pattern='/{repo_name:.*?[^/]}/update_file/{commit_id}/{f_path:.*}',
418 repo_route=True)
418 repo_route=True)
419 config.add_view(
419 config.add_view(
420 RepoFilesView,
420 RepoFilesView,
421 attr='repo_files_update_file',
421 attr='repo_files_update_file',
422 route_name='repo_files_update_file', request_method='POST',
422 route_name='repo_files_update_file', request_method='POST',
423 renderer=None)
423 renderer=None)
424
424
425 config.add_route(
425 config.add_route(
426 name='repo_files_add_file',
426 name='repo_files_add_file',
427 pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}',
427 pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}',
428 repo_route=True)
428 repo_route=True)
429 config.add_view(
429 config.add_view(
430 RepoFilesView,
430 RepoFilesView,
431 attr='repo_files_add_file',
431 attr='repo_files_add_file',
432 route_name='repo_files_add_file', request_method='GET',
432 route_name='repo_files_add_file', request_method='GET',
433 renderer='rhodecode:templates/files/files_add.mako')
433 renderer='rhodecode:templates/files/files_add.mako')
434
434
435 config.add_route(
435 config.add_route(
436 name='repo_files_upload_file',
436 name='repo_files_upload_file',
437 pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}',
437 pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}',
438 repo_route=True)
438 repo_route=True)
439 config.add_view(
439 config.add_view(
440 RepoFilesView,
440 RepoFilesView,
441 attr='repo_files_add_file',
441 attr='repo_files_add_file',
442 route_name='repo_files_upload_file', request_method='GET',
442 route_name='repo_files_upload_file', request_method='GET',
443 renderer='rhodecode:templates/files/files_upload.mako')
443 renderer='rhodecode:templates/files/files_upload.mako')
444 config.add_view( # POST creates
444 config.add_view( # POST creates
445 RepoFilesView,
445 RepoFilesView,
446 attr='repo_files_upload_file',
446 attr='repo_files_upload_file',
447 route_name='repo_files_upload_file', request_method='POST',
447 route_name='repo_files_upload_file', request_method='POST',
448 renderer='json_ext')
448 renderer='json_ext')
449
449
450 config.add_route(
450 config.add_route(
451 name='repo_files_create_file',
451 name='repo_files_create_file',
452 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
452 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
453 repo_route=True)
453 repo_route=True)
454 config.add_view( # POST creates
454 config.add_view( # POST creates
455 RepoFilesView,
455 RepoFilesView,
456 attr='repo_files_create_file',
456 attr='repo_files_create_file',
457 route_name='repo_files_create_file', request_method='POST',
457 route_name='repo_files_create_file', request_method='POST',
458 renderer=None)
458 renderer=None)
459
459
460 # Refs data
460 # Refs data
461 config.add_route(
461 config.add_route(
462 name='repo_refs_data',
462 name='repo_refs_data',
463 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
463 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
464 config.add_view(
464 config.add_view(
465 RepoSummaryView,
465 RepoSummaryView,
466 attr='repo_refs_data',
466 attr='repo_refs_data',
467 route_name='repo_refs_data', request_method='GET',
467 route_name='repo_refs_data', request_method='GET',
468 renderer='json_ext')
468 renderer='json_ext')
469
469
470 config.add_route(
470 config.add_route(
471 name='repo_refs_changelog_data',
471 name='repo_refs_changelog_data',
472 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
472 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
473 config.add_view(
473 config.add_view(
474 RepoSummaryView,
474 RepoSummaryView,
475 attr='repo_refs_changelog_data',
475 attr='repo_refs_changelog_data',
476 route_name='repo_refs_changelog_data', request_method='GET',
476 route_name='repo_refs_changelog_data', request_method='GET',
477 renderer='json_ext')
477 renderer='json_ext')
478
478
479 config.add_route(
479 config.add_route(
480 name='repo_stats',
480 name='repo_stats',
481 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
481 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
482 config.add_view(
482 config.add_view(
483 RepoSummaryView,
483 RepoSummaryView,
484 attr='repo_stats',
484 attr='repo_stats',
485 route_name='repo_stats', request_method='GET',
485 route_name='repo_stats', request_method='GET',
486 renderer='json_ext')
486 renderer='json_ext')
487
487
488 # Commits
488 # Commits
489 config.add_route(
489 config.add_route(
490 name='repo_commits',
490 name='repo_commits',
491 pattern='/{repo_name:.*?[^/]}/commits', repo_route=True)
491 pattern='/{repo_name:.*?[^/]}/commits', repo_route=True)
492 config.add_view(
492 config.add_view(
493 RepoChangelogView,
493 RepoChangelogView,
494 attr='repo_changelog',
494 attr='repo_changelog',
495 route_name='repo_commits', request_method='GET',
495 route_name='repo_commits', request_method='GET',
496 renderer='rhodecode:templates/commits/changelog.mako')
496 renderer='rhodecode:templates/commits/changelog.mako')
497 # old routes for backward compat
497 # old routes for backward compat
498 config.add_view(
498 config.add_view(
499 RepoChangelogView,
499 RepoChangelogView,
500 attr='repo_changelog',
500 attr='repo_changelog',
501 route_name='repo_changelog', request_method='GET',
501 route_name='repo_changelog', request_method='GET',
502 renderer='rhodecode:templates/commits/changelog.mako')
502 renderer='rhodecode:templates/commits/changelog.mako')
503
503
504 config.add_route(
504 config.add_route(
505 name='repo_commits_elements',
505 name='repo_commits_elements',
506 pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True)
506 pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True)
507 config.add_view(
507 config.add_view(
508 RepoChangelogView,
508 RepoChangelogView,
509 attr='repo_commits_elements',
509 attr='repo_commits_elements',
510 route_name='repo_commits_elements', request_method=('GET', 'POST'),
510 route_name='repo_commits_elements', request_method=('GET', 'POST'),
511 renderer='rhodecode:templates/commits/changelog_elements.mako',
511 renderer='rhodecode:templates/commits/changelog_elements.mako',
512 xhr=True)
512 xhr=True)
513
513
514 config.add_route(
514 config.add_route(
515 name='repo_commits_elements_file',
515 name='repo_commits_elements_file',
516 pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True)
516 pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True)
517 config.add_view(
517 config.add_view(
518 RepoChangelogView,
518 RepoChangelogView,
519 attr='repo_commits_elements',
519 attr='repo_commits_elements',
520 route_name='repo_commits_elements_file', request_method=('GET', 'POST'),
520 route_name='repo_commits_elements_file', request_method=('GET', 'POST'),
521 renderer='rhodecode:templates/commits/changelog_elements.mako',
521 renderer='rhodecode:templates/commits/changelog_elements.mako',
522 xhr=True)
522 xhr=True)
523
523
524 config.add_route(
524 config.add_route(
525 name='repo_commits_file',
525 name='repo_commits_file',
526 pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True)
526 pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True)
527 config.add_view(
527 config.add_view(
528 RepoChangelogView,
528 RepoChangelogView,
529 attr='repo_changelog',
529 attr='repo_changelog',
530 route_name='repo_commits_file', request_method='GET',
530 route_name='repo_commits_file', request_method='GET',
531 renderer='rhodecode:templates/commits/changelog.mako')
531 renderer='rhodecode:templates/commits/changelog.mako')
532 # old routes for backward compat
532 # old routes for backward compat
533 config.add_view(
533 config.add_view(
534 RepoChangelogView,
534 RepoChangelogView,
535 attr='repo_changelog',
535 attr='repo_changelog',
536 route_name='repo_changelog_file', request_method='GET',
536 route_name='repo_changelog_file', request_method='GET',
537 renderer='rhodecode:templates/commits/changelog.mako')
537 renderer='rhodecode:templates/commits/changelog.mako')
538
538
539 # Changelog (old deprecated name for commits page)
539 # Changelog (old deprecated name for commits page)
540 config.add_route(
540 config.add_route(
541 name='repo_changelog',
541 name='repo_changelog',
542 pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True)
542 pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True)
543 config.add_route(
543 config.add_route(
544 name='repo_changelog_file',
544 name='repo_changelog_file',
545 pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True)
545 pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True)
546
546
547 # Compare
547 # Compare
548 config.add_route(
548 config.add_route(
549 name='repo_compare_select',
549 name='repo_compare_select',
550 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
550 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
551 config.add_view(
551 config.add_view(
552 RepoCompareView,
552 RepoCompareView,
553 attr='compare_select',
553 attr='compare_select',
554 route_name='repo_compare_select', request_method='GET',
554 route_name='repo_compare_select', request_method='GET',
555 renderer='rhodecode:templates/compare/compare_diff.mako')
555 renderer='rhodecode:templates/compare/compare_diff.mako')
556
556
557 config.add_route(
557 config.add_route(
558 name='repo_compare',
558 name='repo_compare',
559 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
559 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
560 config.add_view(
560 config.add_view(
561 RepoCompareView,
561 RepoCompareView,
562 attr='compare',
562 attr='compare',
563 route_name='repo_compare', request_method='GET',
563 route_name='repo_compare', request_method='GET',
564 renderer=None)
564 renderer=None)
565
565
566 # Tags
566 # Tags
567 config.add_route(
567 config.add_route(
568 name='tags_home',
568 name='tags_home',
569 pattern='/{repo_name:.*?[^/]}/tags', repo_route=True)
569 pattern='/{repo_name:.*?[^/]}/tags', repo_route=True)
570 config.add_view(
570 config.add_view(
571 RepoTagsView,
571 RepoTagsView,
572 attr='tags',
572 attr='tags',
573 route_name='tags_home', request_method='GET',
573 route_name='tags_home', request_method='GET',
574 renderer='rhodecode:templates/tags/tags.mako')
574 renderer='rhodecode:templates/tags/tags.mako')
575
575
576 # Branches
576 # Branches
577 config.add_route(
577 config.add_route(
578 name='branches_home',
578 name='branches_home',
579 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
579 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
580 config.add_view(
580 config.add_view(
581 RepoBranchesView,
581 RepoBranchesView,
582 attr='branches',
582 attr='branches',
583 route_name='branches_home', request_method='GET',
583 route_name='branches_home', request_method='GET',
584 renderer='rhodecode:templates/branches/branches.mako')
584 renderer='rhodecode:templates/branches/branches.mako')
585
585
586 # Bookmarks
586 # Bookmarks
587 config.add_route(
587 config.add_route(
588 name='bookmarks_home',
588 name='bookmarks_home',
589 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
589 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
590 config.add_view(
590 config.add_view(
591 RepoBookmarksView,
591 RepoBookmarksView,
592 attr='bookmarks',
592 attr='bookmarks',
593 route_name='bookmarks_home', request_method='GET',
593 route_name='bookmarks_home', request_method='GET',
594 renderer='rhodecode:templates/bookmarks/bookmarks.mako')
594 renderer='rhodecode:templates/bookmarks/bookmarks.mako')
595
595
596 # Forks
596 # Forks
597 config.add_route(
597 config.add_route(
598 name='repo_fork_new',
598 name='repo_fork_new',
599 pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
599 pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
600 repo_forbid_when_archived=True,
600 repo_forbid_when_archived=True,
601 repo_accepted_types=['hg', 'git'])
601 repo_accepted_types=['hg', 'git'])
602 config.add_view(
602 config.add_view(
603 RepoForksView,
603 RepoForksView,
604 attr='repo_fork_new',
604 attr='repo_fork_new',
605 route_name='repo_fork_new', request_method='GET',
605 route_name='repo_fork_new', request_method='GET',
606 renderer='rhodecode:templates/forks/forks.mako')
606 renderer='rhodecode:templates/forks/forks.mako')
607
607
608 config.add_route(
608 config.add_route(
609 name='repo_fork_create',
609 name='repo_fork_create',
610 pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
610 pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
611 repo_forbid_when_archived=True,
611 repo_forbid_when_archived=True,
612 repo_accepted_types=['hg', 'git'])
612 repo_accepted_types=['hg', 'git'])
613 config.add_view(
613 config.add_view(
614 RepoForksView,
614 RepoForksView,
615 attr='repo_fork_create',
615 attr='repo_fork_create',
616 route_name='repo_fork_create', request_method='POST',
616 route_name='repo_fork_create', request_method='POST',
617 renderer='rhodecode:templates/forks/fork.mako')
617 renderer='rhodecode:templates/forks/fork.mako')
618
618
619 config.add_route(
619 config.add_route(
620 name='repo_forks_show_all',
620 name='repo_forks_show_all',
621 pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
621 pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
622 repo_accepted_types=['hg', 'git'])
622 repo_accepted_types=['hg', 'git'])
623 config.add_view(
623 config.add_view(
624 RepoForksView,
624 RepoForksView,
625 attr='repo_forks_show_all',
625 attr='repo_forks_show_all',
626 route_name='repo_forks_show_all', request_method='GET',
626 route_name='repo_forks_show_all', request_method='GET',
627 renderer='rhodecode:templates/forks/forks.mako')
627 renderer='rhodecode:templates/forks/forks.mako')
628
628
629 config.add_route(
629 config.add_route(
630 name='repo_forks_data',
630 name='repo_forks_data',
631 pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
631 pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
632 repo_accepted_types=['hg', 'git'])
632 repo_accepted_types=['hg', 'git'])
633 config.add_view(
633 config.add_view(
634 RepoForksView,
634 RepoForksView,
635 attr='repo_forks_data',
635 attr='repo_forks_data',
636 route_name='repo_forks_data', request_method='GET',
636 route_name='repo_forks_data', request_method='GET',
637 renderer='json_ext', xhr=True)
637 renderer='json_ext', xhr=True)
638
638
639 # Pull Requests
639 # Pull Requests
640 config.add_route(
640 config.add_route(
641 name='pullrequest_show',
641 name='pullrequest_show',
642 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}',
642 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}',
643 repo_route=True)
643 repo_route=True)
644 config.add_view(
644 config.add_view(
645 RepoPullRequestsView,
645 RepoPullRequestsView,
646 attr='pull_request_show',
646 attr='pull_request_show',
647 route_name='pullrequest_show', request_method='GET',
647 route_name='pullrequest_show', request_method='GET',
648 renderer='rhodecode:templates/pullrequests/pullrequest_show.mako')
648 renderer='rhodecode:templates/pullrequests/pullrequest_show.mako')
649
649
650 config.add_route(
650 config.add_route(
651 name='pullrequest_show_all',
651 name='pullrequest_show_all',
652 pattern='/{repo_name:.*?[^/]}/pull-request',
652 pattern='/{repo_name:.*?[^/]}/pull-request',
653 repo_route=True, repo_accepted_types=['hg', 'git'])
653 repo_route=True, repo_accepted_types=['hg', 'git'])
654 config.add_view(
654 config.add_view(
655 RepoPullRequestsView,
655 RepoPullRequestsView,
656 attr='pull_request_list',
656 attr='pull_request_list',
657 route_name='pullrequest_show_all', request_method='GET',
657 route_name='pullrequest_show_all', request_method='GET',
658 renderer='rhodecode:templates/pullrequests/pullrequests.mako')
658 renderer='rhodecode:templates/pullrequests/pullrequests.mako')
659
659
660 config.add_route(
660 config.add_route(
661 name='pullrequest_show_all_data',
661 name='pullrequest_show_all_data',
662 pattern='/{repo_name:.*?[^/]}/pull-request-data',
662 pattern='/{repo_name:.*?[^/]}/pull-request-data',
663 repo_route=True, repo_accepted_types=['hg', 'git'])
663 repo_route=True, repo_accepted_types=['hg', 'git'])
664 config.add_view(
664 config.add_view(
665 RepoPullRequestsView,
665 RepoPullRequestsView,
666 attr='pull_request_list_data',
666 attr='pull_request_list_data',
667 route_name='pullrequest_show_all_data', request_method='GET',
667 route_name='pullrequest_show_all_data', request_method='GET',
668 renderer='json_ext', xhr=True)
668 renderer='json_ext', xhr=True)
669
669
670 config.add_route(
670 config.add_route(
671 name='pullrequest_repo_refs',
671 name='pullrequest_repo_refs',
672 pattern='/{repo_name:.*?[^/]}/pull-request/refs/{target_repo_name:.*?[^/]}',
672 pattern='/{repo_name:.*?[^/]}/pull-request/refs/{target_repo_name:.*?[^/]}',
673 repo_route=True)
673 repo_route=True)
674 config.add_view(
674 config.add_view(
675 RepoPullRequestsView,
675 RepoPullRequestsView,
676 attr='pull_request_repo_refs',
676 attr='pull_request_repo_refs',
677 route_name='pullrequest_repo_refs', request_method='GET',
677 route_name='pullrequest_repo_refs', request_method='GET',
678 renderer='json_ext', xhr=True)
678 renderer='json_ext', xhr=True)
679
679
680 config.add_route(
680 config.add_route(
681 name='pullrequest_repo_targets',
681 name='pullrequest_repo_targets',
682 pattern='/{repo_name:.*?[^/]}/pull-request/repo-targets',
682 pattern='/{repo_name:.*?[^/]}/pull-request/repo-targets',
683 repo_route=True)
683 repo_route=True)
684 config.add_view(
684 config.add_view(
685 RepoPullRequestsView,
685 RepoPullRequestsView,
686 attr='pullrequest_repo_targets',
686 attr='pullrequest_repo_targets',
687 route_name='pullrequest_repo_targets', request_method='GET',
687 route_name='pullrequest_repo_targets', request_method='GET',
688 renderer='json_ext', xhr=True)
688 renderer='json_ext', xhr=True)
689
689
690 config.add_route(
690 config.add_route(
691 name='pullrequest_new',
691 name='pullrequest_new',
692 pattern='/{repo_name:.*?[^/]}/pull-request/new',
692 pattern='/{repo_name:.*?[^/]}/pull-request/new',
693 repo_route=True, repo_accepted_types=['hg', 'git'],
693 repo_route=True, repo_accepted_types=['hg', 'git'],
694 repo_forbid_when_archived=True)
694 repo_forbid_when_archived=True)
695 config.add_view(
695 config.add_view(
696 RepoPullRequestsView,
696 RepoPullRequestsView,
697 attr='pull_request_new',
697 attr='pull_request_new',
698 route_name='pullrequest_new', request_method='GET',
698 route_name='pullrequest_new', request_method='GET',
699 renderer='rhodecode:templates/pullrequests/pullrequest.mako')
699 renderer='rhodecode:templates/pullrequests/pullrequest.mako')
700
700
701 config.add_route(
701 config.add_route(
702 name='pullrequest_create',
702 name='pullrequest_create',
703 pattern='/{repo_name:.*?[^/]}/pull-request/create',
703 pattern='/{repo_name:.*?[^/]}/pull-request/create',
704 repo_route=True, repo_accepted_types=['hg', 'git'],
704 repo_route=True, repo_accepted_types=['hg', 'git'],
705 repo_forbid_when_archived=True)
705 repo_forbid_when_archived=True)
706 config.add_view(
706 config.add_view(
707 RepoPullRequestsView,
707 RepoPullRequestsView,
708 attr='pull_request_create',
708 attr='pull_request_create',
709 route_name='pullrequest_create', request_method='POST',
709 route_name='pullrequest_create', request_method='POST',
710 renderer=None)
710 renderer=None)
711
711
712 config.add_route(
712 config.add_route(
713 name='pullrequest_update',
713 name='pullrequest_update',
714 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/update',
714 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/update',
715 repo_route=True, repo_forbid_when_archived=True)
715 repo_route=True, repo_forbid_when_archived=True)
716 config.add_view(
716 config.add_view(
717 RepoPullRequestsView,
717 RepoPullRequestsView,
718 attr='pull_request_update',
718 attr='pull_request_update',
719 route_name='pullrequest_update', request_method='POST',
719 route_name='pullrequest_update', request_method='POST',
720 renderer='json_ext')
720 renderer='json_ext')
721
721
722 config.add_route(
722 config.add_route(
723 name='pullrequest_merge',
723 name='pullrequest_merge',
724 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/merge',
724 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/merge',
725 repo_route=True, repo_forbid_when_archived=True)
725 repo_route=True, repo_forbid_when_archived=True)
726 config.add_view(
726 config.add_view(
727 RepoPullRequestsView,
727 RepoPullRequestsView,
728 attr='pull_request_merge',
728 attr='pull_request_merge',
729 route_name='pullrequest_merge', request_method='POST',
729 route_name='pullrequest_merge', request_method='POST',
730 renderer='json_ext')
730 renderer='json_ext')
731
731
732 config.add_route(
732 config.add_route(
733 name='pullrequest_delete',
733 name='pullrequest_delete',
734 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/delete',
734 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/delete',
735 repo_route=True, repo_forbid_when_archived=True)
735 repo_route=True, repo_forbid_when_archived=True)
736 config.add_view(
736 config.add_view(
737 RepoPullRequestsView,
737 RepoPullRequestsView,
738 attr='pull_request_delete',
738 attr='pull_request_delete',
739 route_name='pullrequest_delete', request_method='POST',
739 route_name='pullrequest_delete', request_method='POST',
740 renderer='json_ext')
740 renderer='json_ext')
741
741
742 config.add_route(
742 config.add_route(
743 name='pullrequest_comment_create',
743 name='pullrequest_comment_create',
744 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment',
744 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment',
745 repo_route=True)
745 repo_route=True)
746 config.add_view(
746 config.add_view(
747 RepoPullRequestsView,
747 RepoPullRequestsView,
748 attr='pull_request_comment_create',
748 attr='pull_request_comment_create',
749 route_name='pullrequest_comment_create', request_method='POST',
749 route_name='pullrequest_comment_create', request_method='POST',
750 renderer='json_ext')
750 renderer='json_ext')
751
751
752 config.add_route(
752 config.add_route(
753 name='pullrequest_comment_edit',
753 name='pullrequest_comment_edit',
754 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/edit',
754 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/edit',
755 repo_route=True, repo_accepted_types=['hg', 'git'])
755 repo_route=True, repo_accepted_types=['hg', 'git'])
756 config.add_view(
756 config.add_view(
757 RepoPullRequestsView,
757 RepoPullRequestsView,
758 attr='pull_request_comment_edit',
758 attr='pull_request_comment_edit',
759 route_name='pullrequest_comment_edit', request_method='POST',
759 route_name='pullrequest_comment_edit', request_method='POST',
760 renderer='json_ext')
760 renderer='json_ext')
761
761
762 config.add_route(
762 config.add_route(
763 name='pullrequest_comment_delete',
763 name='pullrequest_comment_delete',
764 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
764 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
765 repo_route=True, repo_accepted_types=['hg', 'git'])
765 repo_route=True, repo_accepted_types=['hg', 'git'])
766 config.add_view(
766 config.add_view(
767 RepoPullRequestsView,
767 RepoPullRequestsView,
768 attr='pull_request_comment_delete',
768 attr='pull_request_comment_delete',
769 route_name='pullrequest_comment_delete', request_method='POST',
769 route_name='pullrequest_comment_delete', request_method='POST',
770 renderer='json_ext')
770 renderer='json_ext')
771
771
772 config.add_route(
772 config.add_route(
773 name='pullrequest_comments',
773 name='pullrequest_comments',
774 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comments',
774 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comments',
775 repo_route=True)
775 repo_route=True)
776 config.add_view(
776 config.add_view(
777 RepoPullRequestsView,
777 RepoPullRequestsView,
778 attr='pullrequest_comments',
778 attr='pullrequest_comments',
779 route_name='pullrequest_comments', request_method='POST',
779 route_name='pullrequest_comments', request_method='POST',
780 renderer='string_html', xhr=True)
780 renderer='string_html', xhr=True)
781
781
782 config.add_route(
782 config.add_route(
783 name='pullrequest_todos',
783 name='pullrequest_todos',
784 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos',
784 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/todos',
785 repo_route=True)
785 repo_route=True)
786 config.add_view(
786 config.add_view(
787 RepoPullRequestsView,
787 RepoPullRequestsView,
788 attr='pullrequest_todos',
788 attr='pullrequest_todos',
789 route_name='pullrequest_todos', request_method='POST',
789 route_name='pullrequest_todos', request_method='POST',
790 renderer='string_html', xhr=True)
790 renderer='string_html', xhr=True)
791
791
792 config.add_route(
792 config.add_route(
793 name='pullrequest_drafts',
793 name='pullrequest_drafts',
794 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/drafts',
794 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/drafts',
795 repo_route=True)
795 repo_route=True)
796 config.add_view(
796 config.add_view(
797 RepoPullRequestsView,
797 RepoPullRequestsView,
798 attr='pullrequest_drafts',
798 attr='pullrequest_drafts',
799 route_name='pullrequest_drafts', request_method='POST',
799 route_name='pullrequest_drafts', request_method='POST',
800 renderer='string_html', xhr=True)
800 renderer='string_html', xhr=True)
801
801
802 # Artifacts, (EE feature)
802 # Artifacts, (EE feature)
803 config.add_route(
803 config.add_route(
804 name='repo_artifacts_list',
804 name='repo_artifacts_list',
805 pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True)
805 pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True)
806 config.add_view(
806 config.add_view(
807 RepoArtifactsView,
807 RepoArtifactsView,
808 attr='repo_artifacts',
808 attr='repo_artifacts',
809 route_name='repo_artifacts_list', request_method='GET',
809 route_name='repo_artifacts_list', request_method='GET',
810 renderer='rhodecode:templates/artifacts/artifact_list.mako')
810 renderer='rhodecode:templates/artifacts/artifact_list.mako')
811
811
812 # Settings
812 # Settings
813 config.add_route(
813 config.add_route(
814 name='edit_repo',
814 name='edit_repo',
815 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
815 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
816 config.add_view(
816 config.add_view(
817 RepoSettingsView,
817 RepoSettingsView,
818 attr='edit_settings',
818 attr='edit_settings',
819 route_name='edit_repo', request_method='GET',
819 route_name='edit_repo', request_method='GET',
820 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
820 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
821 # update is POST on edit_repo
821 # update is POST on edit_repo
822 config.add_view(
822 config.add_view(
823 RepoSettingsView,
823 RepoSettingsView,
824 attr='edit_settings_update',
824 attr='edit_settings_update',
825 route_name='edit_repo', request_method='POST',
825 route_name='edit_repo', request_method='POST',
826 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
826 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
827
827
828 # Settings advanced
828 # Settings advanced
829 config.add_route(
829 config.add_route(
830 name='edit_repo_advanced',
830 name='edit_repo_advanced',
831 pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
831 pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
832 config.add_view(
832 config.add_view(
833 RepoSettingsAdvancedView,
833 RepoSettingsAdvancedView,
834 attr='edit_advanced',
834 attr='edit_advanced',
835 route_name='edit_repo_advanced', request_method='GET',
835 route_name='edit_repo_advanced', request_method='GET',
836 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
836 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
837
837
838 config.add_route(
838 config.add_route(
839 name='edit_repo_advanced_archive',
839 name='edit_repo_advanced_archive',
840 pattern='/{repo_name:.*?[^/]}/settings/advanced/archive', repo_route=True)
840 pattern='/{repo_name:.*?[^/]}/settings/advanced/archive', repo_route=True)
841 config.add_view(
841 config.add_view(
842 RepoSettingsAdvancedView,
842 RepoSettingsAdvancedView,
843 attr='edit_advanced_archive',
843 attr='edit_advanced_archive',
844 route_name='edit_repo_advanced_archive', request_method='POST',
844 route_name='edit_repo_advanced_archive', request_method='POST',
845 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
845 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
846
846
847 config.add_route(
847 config.add_route(
848 name='edit_repo_advanced_delete',
848 name='edit_repo_advanced_delete',
849 pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
849 pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
850 config.add_view(
850 config.add_view(
851 RepoSettingsAdvancedView,
851 RepoSettingsAdvancedView,
852 attr='edit_advanced_delete',
852 attr='edit_advanced_delete',
853 route_name='edit_repo_advanced_delete', request_method='POST',
853 route_name='edit_repo_advanced_delete', request_method='POST',
854 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
854 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
855
855
856 config.add_route(
856 config.add_route(
857 name='edit_repo_advanced_locking',
857 name='edit_repo_advanced_locking',
858 pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
858 pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
859 config.add_view(
859 config.add_view(
860 RepoSettingsAdvancedView,
860 RepoSettingsAdvancedView,
861 attr='edit_advanced_toggle_locking',
861 attr='edit_advanced_toggle_locking',
862 route_name='edit_repo_advanced_locking', request_method='POST',
862 route_name='edit_repo_advanced_locking', request_method='POST',
863 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
863 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
864
864
865 config.add_route(
865 config.add_route(
866 name='edit_repo_advanced_journal',
866 name='edit_repo_advanced_journal',
867 pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
867 pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
868 config.add_view(
868 config.add_view(
869 RepoSettingsAdvancedView,
869 RepoSettingsAdvancedView,
870 attr='edit_advanced_journal',
870 attr='edit_advanced_journal',
871 route_name='edit_repo_advanced_journal', request_method='POST',
871 route_name='edit_repo_advanced_journal', request_method='POST',
872 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
872 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
873
873
874 config.add_route(
874 config.add_route(
875 name='edit_repo_advanced_fork',
875 name='edit_repo_advanced_fork',
876 pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
876 pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
877 config.add_view(
877 config.add_view(
878 RepoSettingsAdvancedView,
878 RepoSettingsAdvancedView,
879 attr='edit_advanced_fork',
879 attr='edit_advanced_fork',
880 route_name='edit_repo_advanced_fork', request_method='POST',
880 route_name='edit_repo_advanced_fork', request_method='POST',
881 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
881 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
882
882
883 config.add_route(
883 config.add_route(
884 name='edit_repo_advanced_hooks',
884 name='edit_repo_advanced_hooks',
885 pattern='/{repo_name:.*?[^/]}/settings/advanced/hooks', repo_route=True)
885 pattern='/{repo_name:.*?[^/]}/settings/advanced/hooks', repo_route=True)
886 config.add_view(
886 config.add_view(
887 RepoSettingsAdvancedView,
887 RepoSettingsAdvancedView,
888 attr='edit_advanced_install_hooks',
888 attr='edit_advanced_install_hooks',
889 route_name='edit_repo_advanced_hooks', request_method='GET',
889 route_name='edit_repo_advanced_hooks', request_method='GET',
890 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
890 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
891
891
892 # Caches
892 # Caches
893 config.add_route(
893 config.add_route(
894 name='edit_repo_caches',
894 name='edit_repo_caches',
895 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
895 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
896 config.add_view(
896 config.add_view(
897 RepoCachesView,
897 RepoCachesView,
898 attr='repo_caches',
898 attr='repo_caches',
899 route_name='edit_repo_caches', request_method='GET',
899 route_name='edit_repo_caches', request_method='GET',
900 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
900 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
901 config.add_view(
901 config.add_view(
902 RepoCachesView,
902 RepoCachesView,
903 attr='repo_caches_purge',
903 attr='repo_caches_purge',
904 route_name='edit_repo_caches', request_method='POST')
904 route_name='edit_repo_caches', request_method='POST')
905
905
906 # Permissions
906 # Permissions
907 config.add_route(
907 config.add_route(
908 name='edit_repo_perms',
908 name='edit_repo_perms',
909 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
909 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
910 config.add_view(
910 config.add_view(
911 RepoSettingsPermissionsView,
911 RepoSettingsPermissionsView,
912 attr='edit_permissions',
912 attr='edit_permissions',
913 route_name='edit_repo_perms', request_method='GET',
913 route_name='edit_repo_perms', request_method='GET',
914 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
914 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
915 config.add_view(
915 config.add_view(
916 RepoSettingsPermissionsView,
916 RepoSettingsPermissionsView,
917 attr='edit_permissions_update',
917 attr='edit_permissions_update',
918 route_name='edit_repo_perms', request_method='POST',
918 route_name='edit_repo_perms', request_method='POST',
919 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
919 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
920
920
921 config.add_route(
921 config.add_route(
922 name='edit_repo_perms_set_private',
922 name='edit_repo_perms_set_private',
923 pattern='/{repo_name:.*?[^/]}/settings/permissions/set_private', repo_route=True)
923 pattern='/{repo_name:.*?[^/]}/settings/permissions/set_private', repo_route=True)
924 config.add_view(
924 config.add_view(
925 RepoSettingsPermissionsView,
925 RepoSettingsPermissionsView,
926 attr='edit_permissions_set_private_repo',
926 attr='edit_permissions_set_private_repo',
927 route_name='edit_repo_perms_set_private', request_method='POST',
927 route_name='edit_repo_perms_set_private', request_method='POST',
928 renderer='json_ext')
928 renderer='json_ext')
929
929
930 # Permissions Branch (EE feature)
930 # Permissions Branch (EE feature)
931 config.add_route(
931 config.add_route(
932 name='edit_repo_perms_branch',
932 name='edit_repo_perms_branch',
933 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
933 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
934 config.add_view(
934 config.add_view(
935 RepoSettingsBranchPermissionsView,
935 RepoSettingsBranchPermissionsView,
936 attr='branch_permissions',
936 attr='branch_permissions',
937 route_name='edit_repo_perms_branch', request_method='GET',
937 route_name='edit_repo_perms_branch', request_method='GET',
938 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
938 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
939
939
940 config.add_route(
940 config.add_route(
941 name='edit_repo_perms_branch_delete',
941 name='edit_repo_perms_branch_delete',
942 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
942 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
943 repo_route=True)
943 repo_route=True)
944 ## Only implemented in EE
944 ## Only implemented in EE
945
945
946 # Maintenance
946 # Maintenance
947 config.add_route(
947 config.add_route(
948 name='edit_repo_maintenance',
948 name='edit_repo_maintenance',
949 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
949 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
950 config.add_view(
950 config.add_view(
951 RepoMaintenanceView,
951 RepoMaintenanceView,
952 attr='repo_maintenance',
952 attr='repo_maintenance',
953 route_name='edit_repo_maintenance', request_method='GET',
953 route_name='edit_repo_maintenance', request_method='GET',
954 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
954 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
955
955
956 config.add_route(
956 config.add_route(
957 name='edit_repo_maintenance_execute',
957 name='edit_repo_maintenance_execute',
958 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
958 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
959 config.add_view(
959 config.add_view(
960 RepoMaintenanceView,
960 RepoMaintenanceView,
961 attr='repo_maintenance_execute',
961 attr='repo_maintenance_execute',
962 route_name='edit_repo_maintenance_execute', request_method='GET',
962 route_name='edit_repo_maintenance_execute', request_method='GET',
963 renderer='json', xhr=True)
963 renderer='json', xhr=True)
964
964
965 # Fields
965 # Fields
966 config.add_route(
966 config.add_route(
967 name='edit_repo_fields',
967 name='edit_repo_fields',
968 pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True)
968 pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True)
969 config.add_view(
969 config.add_view(
970 RepoSettingsFieldsView,
970 RepoSettingsFieldsView,
971 attr='repo_field_edit',
971 attr='repo_field_edit',
972 route_name='edit_repo_fields', request_method='GET',
972 route_name='edit_repo_fields', request_method='GET',
973 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
973 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
974
974
975 config.add_route(
975 config.add_route(
976 name='edit_repo_fields_create',
976 name='edit_repo_fields_create',
977 pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True)
977 pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True)
978 config.add_view(
978 config.add_view(
979 RepoSettingsFieldsView,
979 RepoSettingsFieldsView,
980 attr='repo_field_create',
980 attr='repo_field_create',
981 route_name='edit_repo_fields_create', request_method='POST',
981 route_name='edit_repo_fields_create', request_method='POST',
982 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
982 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
983
983
984 config.add_route(
984 config.add_route(
985 name='edit_repo_fields_delete',
985 name='edit_repo_fields_delete',
986 pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True)
986 pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True)
987 config.add_view(
987 config.add_view(
988 RepoSettingsFieldsView,
988 RepoSettingsFieldsView,
989 attr='repo_field_delete',
989 attr='repo_field_delete',
990 route_name='edit_repo_fields_delete', request_method='POST',
990 route_name='edit_repo_fields_delete', request_method='POST',
991 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
991 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
992
992
993 # Locking
993 # Locking
994 config.add_route(
994 config.add_route(
995 name='repo_edit_toggle_locking',
995 name='repo_edit_toggle_locking',
996 pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True)
996 pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True)
997 config.add_view(
997 config.add_view(
998 RepoSettingsView,
998 RepoSettingsView,
999 attr='edit_advanced_toggle_locking',
999 attr='edit_advanced_toggle_locking',
1000 route_name='repo_edit_toggle_locking', request_method='GET',
1000 route_name='repo_edit_toggle_locking', request_method='GET',
1001 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1001 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1002
1002
1003 # Remote
1003 # Remote
1004 config.add_route(
1004 config.add_route(
1005 name='edit_repo_remote',
1005 name='edit_repo_remote',
1006 pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True)
1006 pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True)
1007 config.add_view(
1007 config.add_view(
1008 RepoSettingsRemoteView,
1008 RepoSettingsRemoteView,
1009 attr='repo_remote_edit_form',
1009 attr='repo_remote_edit_form',
1010 route_name='edit_repo_remote', request_method='GET',
1010 route_name='edit_repo_remote', request_method='GET',
1011 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1011 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1012
1012
1013 config.add_route(
1013 config.add_route(
1014 name='edit_repo_remote_pull',
1014 name='edit_repo_remote_pull',
1015 pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
1015 pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
1016 config.add_view(
1016 config.add_view(
1017 RepoSettingsRemoteView,
1017 RepoSettingsRemoteView,
1018 attr='repo_remote_pull_changes',
1018 attr='repo_remote_pull_changes',
1019 route_name='edit_repo_remote_pull', request_method='POST',
1019 route_name='edit_repo_remote_pull', request_method='POST',
1020 renderer=None)
1020 renderer=None)
1021
1021
1022 config.add_route(
1022 config.add_route(
1023 name='edit_repo_remote_push',
1023 name='edit_repo_remote_push',
1024 pattern='/{repo_name:.*?[^/]}/settings/remote/push', repo_route=True)
1024 pattern='/{repo_name:.*?[^/]}/settings/remote/push', repo_route=True)
1025
1025
1026 # Statistics
1026 # Statistics
1027 config.add_route(
1027 config.add_route(
1028 name='edit_repo_statistics',
1028 name='edit_repo_statistics',
1029 pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True)
1029 pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True)
1030 config.add_view(
1030 config.add_view(
1031 RepoSettingsView,
1031 RepoSettingsView,
1032 attr='edit_statistics_form',
1032 attr='edit_statistics_form',
1033 route_name='edit_repo_statistics', request_method='GET',
1033 route_name='edit_repo_statistics', request_method='GET',
1034 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1034 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1035
1035
1036 config.add_route(
1036 config.add_route(
1037 name='edit_repo_statistics_reset',
1037 name='edit_repo_statistics_reset',
1038 pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True)
1038 pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True)
1039 config.add_view(
1039 config.add_view(
1040 RepoSettingsView,
1040 RepoSettingsView,
1041 attr='repo_statistics_reset',
1041 attr='repo_statistics_reset',
1042 route_name='edit_repo_statistics_reset', request_method='POST',
1042 route_name='edit_repo_statistics_reset', request_method='POST',
1043 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1043 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1044
1044
1045 # Issue trackers
1045 # Issue trackers
1046 config.add_route(
1046 config.add_route(
1047 name='edit_repo_issuetracker',
1047 name='edit_repo_issuetracker',
1048 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True)
1048 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True)
1049 config.add_view(
1049 config.add_view(
1050 RepoSettingsIssueTrackersView,
1050 RepoSettingsIssueTrackersView,
1051 attr='repo_issuetracker',
1051 attr='repo_issuetracker',
1052 route_name='edit_repo_issuetracker', request_method='GET',
1052 route_name='edit_repo_issuetracker', request_method='GET',
1053 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1053 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1054
1054
1055 config.add_route(
1055 config.add_route(
1056 name='edit_repo_issuetracker_test',
1056 name='edit_repo_issuetracker_test',
1057 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True)
1057 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True)
1058 config.add_view(
1058 config.add_view(
1059 RepoSettingsIssueTrackersView,
1059 RepoSettingsIssueTrackersView,
1060 attr='repo_issuetracker_test',
1060 attr='repo_issuetracker_test',
1061 route_name='edit_repo_issuetracker_test', request_method='POST',
1061 route_name='edit_repo_issuetracker_test', request_method='POST',
1062 renderer='string', xhr=True)
1062 renderer='string', xhr=True)
1063
1063
1064 config.add_route(
1064 config.add_route(
1065 name='edit_repo_issuetracker_delete',
1065 name='edit_repo_issuetracker_delete',
1066 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True)
1066 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True)
1067 config.add_view(
1067 config.add_view(
1068 RepoSettingsIssueTrackersView,
1068 RepoSettingsIssueTrackersView,
1069 attr='repo_issuetracker_delete',
1069 attr='repo_issuetracker_delete',
1070 route_name='edit_repo_issuetracker_delete', request_method='POST',
1070 route_name='edit_repo_issuetracker_delete', request_method='POST',
1071 renderer='json_ext', xhr=True)
1071 renderer='json_ext', xhr=True)
1072
1072
1073 config.add_route(
1073 config.add_route(
1074 name='edit_repo_issuetracker_update',
1074 name='edit_repo_issuetracker_update',
1075 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True)
1075 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True)
1076 config.add_view(
1076 config.add_view(
1077 RepoSettingsIssueTrackersView,
1077 RepoSettingsIssueTrackersView,
1078 attr='repo_issuetracker_update',
1078 attr='repo_issuetracker_update',
1079 route_name='edit_repo_issuetracker_update', request_method='POST',
1079 route_name='edit_repo_issuetracker_update', request_method='POST',
1080 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1080 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1081
1081
1082 # VCS Settings
1082 # VCS Settings
1083 config.add_route(
1083 config.add_route(
1084 name='edit_repo_vcs',
1084 name='edit_repo_vcs',
1085 pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True)
1085 pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True)
1086 config.add_view(
1086 config.add_view(
1087 RepoSettingsVcsView,
1087 RepoSettingsVcsView,
1088 attr='repo_vcs_settings',
1088 attr='repo_vcs_settings',
1089 route_name='edit_repo_vcs', request_method='GET',
1089 route_name='edit_repo_vcs', request_method='GET',
1090 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1090 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1091
1091
1092 config.add_route(
1092 config.add_route(
1093 name='edit_repo_vcs_update',
1093 name='edit_repo_vcs_update',
1094 pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True)
1094 pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True)
1095 config.add_view(
1095 config.add_view(
1096 RepoSettingsVcsView,
1096 RepoSettingsVcsView,
1097 attr='repo_settings_vcs_update',
1097 attr='repo_settings_vcs_update',
1098 route_name='edit_repo_vcs_update', request_method='POST',
1098 route_name='edit_repo_vcs_update', request_method='POST',
1099 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1099 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1100
1100
1101 # svn pattern
1101 # svn pattern
1102 config.add_route(
1102 config.add_route(
1103 name='edit_repo_vcs_svn_pattern_delete',
1103 name='edit_repo_vcs_svn_pattern_delete',
1104 pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True)
1104 pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True)
1105 config.add_view(
1105 config.add_view(
1106 RepoSettingsVcsView,
1106 RepoSettingsVcsView,
1107 attr='repo_settings_delete_svn_pattern',
1107 attr='repo_settings_delete_svn_pattern',
1108 route_name='edit_repo_vcs_svn_pattern_delete', request_method='POST',
1108 route_name='edit_repo_vcs_svn_pattern_delete', request_method='POST',
1109 renderer='json_ext', xhr=True)
1109 renderer='json_ext', xhr=True)
1110
1110
1111 # Repo Review Rules (EE feature)
1111 # Repo Review Rules (EE feature)
1112 config.add_route(
1112 config.add_route(
1113 name='repo_reviewers',
1113 name='repo_reviewers',
1114 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
1114 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
1115 config.add_view(
1115 config.add_view(
1116 RepoReviewRulesView,
1116 RepoReviewRulesView,
1117 attr='repo_review_rules',
1117 attr='repo_review_rules',
1118 route_name='repo_reviewers', request_method='GET',
1118 route_name='repo_reviewers', request_method='GET',
1119 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1119 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1120
1120
1121 config.add_route(
1121 config.add_route(
1122 name='repo_default_reviewers_data',
1122 name='repo_default_reviewers_data',
1123 pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True)
1123 pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True)
1124 config.add_view(
1124 config.add_view(
1125 RepoReviewRulesView,
1125 RepoReviewRulesView,
1126 attr='repo_default_reviewers_data',
1126 attr='repo_default_reviewers_data',
1127 route_name='repo_default_reviewers_data', request_method='GET',
1127 route_name='repo_default_reviewers_data', request_method='GET',
1128 renderer='json_ext')
1128 renderer='json_ext')
1129
1129
1130 # Repo Automation (EE feature)
1130 # Repo Automation (EE feature)
1131 config.add_route(
1131 config.add_route(
1132 name='repo_automation',
1132 name='repo_automation',
1133 pattern='/{repo_name:.*?[^/]}/settings/automation', repo_route=True)
1133 pattern='/{repo_name:.*?[^/]}/settings/automation', repo_route=True)
1134 config.add_view(
1134 config.add_view(
1135 RepoAutomationView,
1135 RepoAutomationView,
1136 attr='repo_automation',
1136 attr='repo_automation',
1137 route_name='repo_automation', request_method='GET',
1137 route_name='repo_automation', request_method='GET',
1138 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1138 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1139
1139
1140 # Strip
1140 # Strip
1141 config.add_route(
1141 config.add_route(
1142 name='edit_repo_strip',
1142 name='edit_repo_strip',
1143 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
1143 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
1144 config.add_view(
1144 config.add_view(
1145 RepoStripView,
1145 RepoStripView,
1146 attr='strip',
1146 attr='strip',
1147 route_name='edit_repo_strip', request_method='GET',
1147 route_name='edit_repo_strip', request_method='GET',
1148 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1148 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1149
1149
1150 config.add_route(
1150 config.add_route(
1151 name='strip_check',
1151 name='strip_check',
1152 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
1152 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
1153 config.add_view(
1153 config.add_view(
1154 RepoStripView,
1154 RepoStripView,
1155 attr='strip_check',
1155 attr='strip_check',
1156 route_name='strip_check', request_method='POST',
1156 route_name='strip_check', request_method='POST',
1157 renderer='json', xhr=True)
1157 renderer='json', xhr=True)
1158
1158
1159 config.add_route(
1159 config.add_route(
1160 name='strip_execute',
1160 name='strip_execute',
1161 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
1161 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
1162 config.add_view(
1162 config.add_view(
1163 RepoStripView,
1163 RepoStripView,
1164 attr='strip_execute',
1164 attr='strip_execute',
1165 route_name='strip_execute', request_method='POST',
1165 route_name='strip_execute', request_method='POST',
1166 renderer='json', xhr=True)
1166 renderer='json', xhr=True)
1167
1167
1168 # Audit logs
1168 # Audit logs
1169 config.add_route(
1169 config.add_route(
1170 name='edit_repo_audit_logs',
1170 name='edit_repo_audit_logs',
1171 pattern='/{repo_name:.*?[^/]}/settings/audit_logs', repo_route=True)
1171 pattern='/{repo_name:.*?[^/]}/settings/audit_logs', repo_route=True)
1172 config.add_view(
1172 config.add_view(
1173 AuditLogsView,
1173 AuditLogsView,
1174 attr='repo_audit_logs',
1174 attr='repo_audit_logs',
1175 route_name='edit_repo_audit_logs', request_method='GET',
1175 route_name='edit_repo_audit_logs', request_method='GET',
1176 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1176 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
1177
1177
1178 # ATOM/RSS Feed, shouldn't contain slashes for outlook compatibility
1178 # ATOM/RSS Feed, shouldn't contain slashes for outlook compatibility
1179 config.add_route(
1179 config.add_route(
1180 name='rss_feed_home',
1180 name='rss_feed_home',
1181 pattern='/{repo_name:.*?[^/]}/feed-rss', repo_route=True)
1181 pattern='/{repo_name:.*?[^/]}/feed-rss', repo_route=True)
1182 config.add_view(
1182 config.add_view(
1183 RepoFeedView,
1183 RepoFeedView,
1184 attr='rss',
1184 attr='rss',
1185 route_name='rss_feed_home', request_method='GET', renderer=None)
1185 route_name='rss_feed_home', request_method='GET', renderer=None)
1186
1186
1187 config.add_route(
1187 config.add_route(
1188 name='rss_feed_home_old',
1188 name='rss_feed_home_old',
1189 pattern='/{repo_name:.*?[^/]}/feed/rss', repo_route=True)
1189 pattern='/{repo_name:.*?[^/]}/feed/rss', repo_route=True)
1190 config.add_view(
1190 config.add_view(
1191 RepoFeedView,
1191 RepoFeedView,
1192 attr='rss',
1192 attr='rss',
1193 route_name='rss_feed_home_old', request_method='GET', renderer=None)
1193 route_name='rss_feed_home_old', request_method='GET', renderer=None)
1194
1194
1195 config.add_route(
1195 config.add_route(
1196 name='atom_feed_home',
1196 name='atom_feed_home',
1197 pattern='/{repo_name:.*?[^/]}/feed-atom', repo_route=True)
1197 pattern='/{repo_name:.*?[^/]}/feed-atom', repo_route=True)
1198 config.add_view(
1198 config.add_view(
1199 RepoFeedView,
1199 RepoFeedView,
1200 attr='atom',
1200 attr='atom',
1201 route_name='atom_feed_home', request_method='GET', renderer=None)
1201 route_name='atom_feed_home', request_method='GET', renderer=None)
1202
1202
1203 config.add_route(
1203 config.add_route(
1204 name='atom_feed_home_old',
1204 name='atom_feed_home_old',
1205 pattern='/{repo_name:.*?[^/]}/feed/atom', repo_route=True)
1205 pattern='/{repo_name:.*?[^/]}/feed/atom', repo_route=True)
1206 config.add_view(
1206 config.add_view(
1207 RepoFeedView,
1207 RepoFeedView,
1208 attr='atom',
1208 attr='atom',
1209 route_name='atom_feed_home_old', request_method='GET', renderer=None)
1209 route_name='atom_feed_home_old', request_method='GET', renderer=None)
1210
1210
1211 # NOTE(marcink): needs to be at the end for catch-all
1211 # NOTE(marcink): needs to be at the end for catch-all
1212 add_route_with_slash(
1212 add_route_with_slash(
1213 config,
1213 config,
1214 name='repo_summary',
1214 name='repo_summary',
1215 pattern='/{repo_name:.*?[^/]}', repo_route=True)
1215 pattern='/{repo_name:.*?[^/]}', repo_route=True)
1216 config.add_view(
1216 config.add_view(
1217 RepoSummaryView,
1217 RepoSummaryView,
1218 attr='summary',
1218 attr='summary',
1219 route_name='repo_summary', request_method='GET',
1219 route_name='repo_summary', request_method='GET',
1220 renderer='rhodecode:templates/summary/summary.mako')
1220 renderer='rhodecode:templates/summary/summary.mako')
1221
1221
1222 # TODO(marcink): there's no such route??
1222 # TODO(marcink): there's no such route??
1223 config.add_view(
1223 config.add_view(
1224 RepoSummaryView,
1224 RepoSummaryView,
1225 attr='summary',
1225 attr='summary',
1226 route_name='repo_summary_slash', request_method='GET',
1226 route_name='repo_summary_slash', request_method='GET',
1227 renderer='rhodecode:templates/summary/summary.mako') No newline at end of file
1227 renderer='rhodecode:templates/summary/summary.mako')
@@ -1,818 +1,819 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import collections
22 import collections
23
23
24 from pyramid.httpexceptions import (
24 from pyramid.httpexceptions import (
25 HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden, HTTPConflict)
25 HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden, HTTPConflict)
26 from pyramid.renderers import render
26 from pyramid.renderers import render
27 from pyramid.response import Response
27 from pyramid.response import Response
28
28
29 from rhodecode.apps._base import RepoAppView
29 from rhodecode.apps._base import RepoAppView
30 from rhodecode.apps.file_store import utils as store_utils
30 from rhodecode.apps.file_store import utils as store_utils
31 from rhodecode.apps.file_store.exceptions import FileNotAllowedException, FileOverSizeException
31 from rhodecode.apps.file_store.exceptions import FileNotAllowedException, FileOverSizeException
32
32
33 from rhodecode.lib import diffs, codeblocks, channelstream
33 from rhodecode.lib import diffs, codeblocks, channelstream
34 from rhodecode.lib.auth import (
34 from rhodecode.lib.auth import (
35 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired)
35 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, CSRFRequired)
36 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.compat import OrderedDict
37 from rhodecode.lib.compat import OrderedDict
38 from rhodecode.lib.diffs import (
38 from rhodecode.lib.diffs import (
39 cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
39 cache_diff, load_cached_diff, diff_cache_exist, get_diff_context,
40 get_diff_whitespace_flag)
40 get_diff_whitespace_flag)
41 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError, CommentVersionMismatch
41 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError, CommentVersionMismatch
42 import rhodecode.lib.helpers as h
42 import rhodecode.lib.helpers as h
43 from rhodecode.lib.utils2 import safe_unicode, str2bool, StrictAttributeDict, safe_str
43 from rhodecode.lib.utils2 import safe_unicode, str2bool, StrictAttributeDict, safe_str
44 from rhodecode.lib.vcs.backends.base import EmptyCommit
44 from rhodecode.lib.vcs.backends.base import EmptyCommit
45 from rhodecode.lib.vcs.exceptions import (
45 from rhodecode.lib.vcs.exceptions import (
46 RepositoryError, CommitDoesNotExistError)
46 RepositoryError, CommitDoesNotExistError)
47 from rhodecode.model.db import ChangesetComment, ChangesetStatus, FileStore, \
47 from rhodecode.model.db import ChangesetComment, ChangesetStatus, FileStore, \
48 ChangesetCommentHistory
48 ChangesetCommentHistory
49 from rhodecode.model.changeset_status import ChangesetStatusModel
49 from rhodecode.model.changeset_status import ChangesetStatusModel
50 from rhodecode.model.comment import CommentsModel
50 from rhodecode.model.comment import CommentsModel
51 from rhodecode.model.meta import Session
51 from rhodecode.model.meta import Session
52 from rhodecode.model.settings import VcsSettingsModel
52 from rhodecode.model.settings import VcsSettingsModel
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 def _update_with_GET(params, request):
57 def _update_with_GET(params, request):
58 for k in ['diff1', 'diff2', 'diff']:
58 for k in ['diff1', 'diff2', 'diff']:
59 params[k] += request.GET.getall(k)
59 params[k] += request.GET.getall(k)
60
60
61
61
62 class RepoCommitsView(RepoAppView):
62 class RepoCommitsView(RepoAppView):
63 def load_default_context(self):
63 def load_default_context(self):
64 c = self._get_local_tmpl_context(include_app_defaults=True)
64 c = self._get_local_tmpl_context(include_app_defaults=True)
65 c.rhodecode_repo = self.rhodecode_vcs_repo
65 c.rhodecode_repo = self.rhodecode_vcs_repo
66
66
67 return c
67 return c
68
68
69 def _is_diff_cache_enabled(self, target_repo):
69 def _is_diff_cache_enabled(self, target_repo):
70 caching_enabled = self._get_general_setting(
70 caching_enabled = self._get_general_setting(
71 target_repo, 'rhodecode_diff_cache')
71 target_repo, 'rhodecode_diff_cache')
72 log.debug('Diff caching enabled: %s', caching_enabled)
72 log.debug('Diff caching enabled: %s', caching_enabled)
73 return caching_enabled
73 return caching_enabled
74
74
75 def _commit(self, commit_id_range, method):
75 def _commit(self, commit_id_range, method):
76 _ = self.request.translate
76 _ = self.request.translate
77 c = self.load_default_context()
77 c = self.load_default_context()
78 c.fulldiff = self.request.GET.get('fulldiff')
78 c.fulldiff = self.request.GET.get('fulldiff')
79 redirect_to_combined = str2bool(self.request.GET.get('redirect_combined'))
79 redirect_to_combined = str2bool(self.request.GET.get('redirect_combined'))
80
80
81 # fetch global flags of ignore ws or context lines
81 # fetch global flags of ignore ws or context lines
82 diff_context = get_diff_context(self.request)
82 diff_context = get_diff_context(self.request)
83 hide_whitespace_changes = get_diff_whitespace_flag(self.request)
83 hide_whitespace_changes = get_diff_whitespace_flag(self.request)
84
84
85 # diff_limit will cut off the whole diff if the limit is applied
85 # diff_limit will cut off the whole diff if the limit is applied
86 # otherwise it will just hide the big files from the front-end
86 # otherwise it will just hide the big files from the front-end
87 diff_limit = c.visual.cut_off_limit_diff
87 diff_limit = c.visual.cut_off_limit_diff
88 file_limit = c.visual.cut_off_limit_file
88 file_limit = c.visual.cut_off_limit_file
89
89
90 # get ranges of commit ids if preset
90 # get ranges of commit ids if preset
91 commit_range = commit_id_range.split('...')[:2]
91 commit_range = commit_id_range.split('...')[:2]
92
92
93 try:
93 try:
94 pre_load = ['affected_files', 'author', 'branch', 'date',
94 pre_load = ['affected_files', 'author', 'branch', 'date',
95 'message', 'parents']
95 'message', 'parents']
96 if self.rhodecode_vcs_repo.alias == 'hg':
96 if self.rhodecode_vcs_repo.alias == 'hg':
97 pre_load += ['hidden', 'obsolete', 'phase']
97 pre_load += ['hidden', 'obsolete', 'phase']
98
98
99 if len(commit_range) == 2:
99 if len(commit_range) == 2:
100 commits = self.rhodecode_vcs_repo.get_commits(
100 commits = self.rhodecode_vcs_repo.get_commits(
101 start_id=commit_range[0], end_id=commit_range[1],
101 start_id=commit_range[0], end_id=commit_range[1],
102 pre_load=pre_load, translate_tags=False)
102 pre_load=pre_load, translate_tags=False)
103 commits = list(commits)
103 commits = list(commits)
104 else:
104 else:
105 commits = [self.rhodecode_vcs_repo.get_commit(
105 commits = [self.rhodecode_vcs_repo.get_commit(
106 commit_id=commit_id_range, pre_load=pre_load)]
106 commit_id=commit_id_range, pre_load=pre_load)]
107
107
108 c.commit_ranges = commits
108 c.commit_ranges = commits
109 if not c.commit_ranges:
109 if not c.commit_ranges:
110 raise RepositoryError('The commit range returned an empty result')
110 raise RepositoryError('The commit range returned an empty result')
111 except CommitDoesNotExistError as e:
111 except CommitDoesNotExistError as e:
112 msg = _('No such commit exists. Org exception: `{}`').format(safe_str(e))
112 msg = _('No such commit exists. Org exception: `{}`').format(safe_str(e))
113 h.flash(msg, category='error')
113 h.flash(msg, category='error')
114 raise HTTPNotFound()
114 raise HTTPNotFound()
115 except Exception:
115 except Exception:
116 log.exception("General failure")
116 log.exception("General failure")
117 raise HTTPNotFound()
117 raise HTTPNotFound()
118 single_commit = len(c.commit_ranges) == 1
118 single_commit = len(c.commit_ranges) == 1
119
119
120 if redirect_to_combined and not single_commit:
120 if redirect_to_combined and not single_commit:
121 source_ref = getattr(c.commit_ranges[0].parents[0]
121 source_ref = getattr(c.commit_ranges[0].parents[0]
122 if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id')
122 if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id')
123 target_ref = c.commit_ranges[-1].raw_id
123 target_ref = c.commit_ranges[-1].raw_id
124 next_url = h.route_path(
124 next_url = h.route_path(
125 'repo_compare',
125 'repo_compare',
126 repo_name=c.repo_name,
126 repo_name=c.repo_name,
127 source_ref_type='rev',
127 source_ref_type='rev',
128 source_ref=source_ref,
128 source_ref=source_ref,
129 target_ref_type='rev',
129 target_ref_type='rev',
130 target_ref=target_ref)
130 target_ref=target_ref)
131 raise HTTPFound(next_url)
131 raise HTTPFound(next_url)
132
132
133 c.changes = OrderedDict()
133 c.changes = OrderedDict()
134 c.lines_added = 0
134 c.lines_added = 0
135 c.lines_deleted = 0
135 c.lines_deleted = 0
136
136
137 # auto collapse if we have more than limit
137 # auto collapse if we have more than limit
138 collapse_limit = diffs.DiffProcessor._collapse_commits_over
138 collapse_limit = diffs.DiffProcessor._collapse_commits_over
139 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
139 c.collapse_all_commits = len(c.commit_ranges) > collapse_limit
140
140
141 c.commit_statuses = ChangesetStatus.STATUSES
141 c.commit_statuses = ChangesetStatus.STATUSES
142 c.inline_comments = []
142 c.inline_comments = []
143 c.files = []
143 c.files = []
144
144
145 c.comments = []
145 c.comments = []
146 c.unresolved_comments = []
146 c.unresolved_comments = []
147 c.resolved_comments = []
147 c.resolved_comments = []
148
148
149 # Single commit
149 # Single commit
150 if single_commit:
150 if single_commit:
151 commit = c.commit_ranges[0]
151 commit = c.commit_ranges[0]
152 c.comments = CommentsModel().get_comments(
152 c.comments = CommentsModel().get_comments(
153 self.db_repo.repo_id,
153 self.db_repo.repo_id,
154 revision=commit.raw_id)
154 revision=commit.raw_id)
155
155
156 # comments from PR
156 # comments from PR
157 statuses = ChangesetStatusModel().get_statuses(
157 statuses = ChangesetStatusModel().get_statuses(
158 self.db_repo.repo_id, commit.raw_id,
158 self.db_repo.repo_id, commit.raw_id,
159 with_revisions=True)
159 with_revisions=True)
160
160
161 prs = set()
161 prs = set()
162 reviewers = list()
162 reviewers = list()
163 reviewers_duplicates = set() # to not have duplicates from multiple votes
163 reviewers_duplicates = set() # to not have duplicates from multiple votes
164 for c_status in statuses:
164 for c_status in statuses:
165
165
166 # extract associated pull-requests from votes
166 # extract associated pull-requests from votes
167 if c_status.pull_request:
167 if c_status.pull_request:
168 prs.add(c_status.pull_request)
168 prs.add(c_status.pull_request)
169
169
170 # extract reviewers
170 # extract reviewers
171 _user_id = c_status.author.user_id
171 _user_id = c_status.author.user_id
172 if _user_id not in reviewers_duplicates:
172 if _user_id not in reviewers_duplicates:
173 reviewers.append(
173 reviewers.append(
174 StrictAttributeDict({
174 StrictAttributeDict({
175 'user': c_status.author,
175 'user': c_status.author,
176
176
177 # fake attributed for commit, page that we don't have
177 # fake attributed for commit, page that we don't have
178 # but we share the display with PR page
178 # but we share the display with PR page
179 'mandatory': False,
179 'mandatory': False,
180 'reasons': [],
180 'reasons': [],
181 'rule_user_group_data': lambda: None
181 'rule_user_group_data': lambda: None
182 })
182 })
183 )
183 )
184 reviewers_duplicates.add(_user_id)
184 reviewers_duplicates.add(_user_id)
185
185
186 c.reviewers_count = len(reviewers)
186 c.reviewers_count = len(reviewers)
187 c.observers_count = 0
187 c.observers_count = 0
188
188
189 # from associated statuses, check the pull requests, and
189 # from associated statuses, check the pull requests, and
190 # show comments from them
190 # show comments from them
191 for pr in prs:
191 for pr in prs:
192 c.comments.extend(pr.comments)
192 c.comments.extend(pr.comments)
193
193
194 c.unresolved_comments = CommentsModel()\
194 c.unresolved_comments = CommentsModel()\
195 .get_commit_unresolved_todos(commit.raw_id)
195 .get_commit_unresolved_todos(commit.raw_id)
196 c.resolved_comments = CommentsModel()\
196 c.resolved_comments = CommentsModel()\
197 .get_commit_resolved_todos(commit.raw_id)
197 .get_commit_resolved_todos(commit.raw_id)
198
198
199 c.inline_comments_flat = CommentsModel()\
199 c.inline_comments_flat = CommentsModel()\
200 .get_commit_inline_comments(commit.raw_id)
200 .get_commit_inline_comments(commit.raw_id)
201
201
202 review_statuses = ChangesetStatusModel().aggregate_votes_by_user(
202 review_statuses = ChangesetStatusModel().aggregate_votes_by_user(
203 statuses, reviewers)
203 statuses, reviewers)
204
204
205 c.commit_review_status = ChangesetStatus.STATUS_NOT_REVIEWED
205 c.commit_review_status = ChangesetStatus.STATUS_NOT_REVIEWED
206
206
207 c.commit_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
207 c.commit_set_reviewers_data_json = collections.OrderedDict({'reviewers': []})
208
208
209 for review_obj, member, reasons, mandatory, status in review_statuses:
209 for review_obj, member, reasons, mandatory, status in review_statuses:
210 member_reviewer = h.reviewer_as_json(
210 member_reviewer = h.reviewer_as_json(
211 member, reasons=reasons, mandatory=mandatory, role=None,
211 member, reasons=reasons, mandatory=mandatory, role=None,
212 user_group=None
212 user_group=None
213 )
213 )
214
214
215 current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED
215 current_review_status = status[0][1].status if status else ChangesetStatus.STATUS_NOT_REVIEWED
216 member_reviewer['review_status'] = current_review_status
216 member_reviewer['review_status'] = current_review_status
217 member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status)
217 member_reviewer['review_status_label'] = h.commit_status_lbl(current_review_status)
218 member_reviewer['allowed_to_update'] = False
218 member_reviewer['allowed_to_update'] = False
219 c.commit_set_reviewers_data_json['reviewers'].append(member_reviewer)
219 c.commit_set_reviewers_data_json['reviewers'].append(member_reviewer)
220
220
221 c.commit_set_reviewers_data_json = json.dumps(c.commit_set_reviewers_data_json)
221 c.commit_set_reviewers_data_json = json.dumps(c.commit_set_reviewers_data_json)
222
222
223 # NOTE(marcink): this uses the same voting logic as in pull-requests
223 # NOTE(marcink): this uses the same voting logic as in pull-requests
224 c.commit_review_status = ChangesetStatusModel().calculate_status(review_statuses)
224 c.commit_review_status = ChangesetStatusModel().calculate_status(review_statuses)
225 c.commit_broadcast_channel = channelstream.comment_channel(c.repo_name, commit_obj=commit)
225 c.commit_broadcast_channel = channelstream.comment_channel(c.repo_name, commit_obj=commit)
226
226
227 diff = None
227 diff = None
228 # Iterate over ranges (default commit view is always one commit)
228 # Iterate over ranges (default commit view is always one commit)
229 for commit in c.commit_ranges:
229 for commit in c.commit_ranges:
230 c.changes[commit.raw_id] = []
230 c.changes[commit.raw_id] = []
231
231
232 commit2 = commit
232 commit2 = commit
233 commit1 = commit.first_parent
233 commit1 = commit.first_parent
234
234
235 if method == 'show':
235 if method == 'show':
236 inline_comments = CommentsModel().get_inline_comments(
236 inline_comments = CommentsModel().get_inline_comments(
237 self.db_repo.repo_id, revision=commit.raw_id)
237 self.db_repo.repo_id, revision=commit.raw_id)
238 c.inline_cnt = len(CommentsModel().get_inline_comments_as_list(
238 c.inline_cnt = len(CommentsModel().get_inline_comments_as_list(
239 inline_comments))
239 inline_comments))
240 c.inline_comments = inline_comments
240 c.inline_comments = inline_comments
241
241
242 cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(
242 cache_path = self.rhodecode_vcs_repo.get_create_shadow_cache_pr_path(
243 self.db_repo)
243 self.db_repo)
244 cache_file_path = diff_cache_exist(
244 cache_file_path = diff_cache_exist(
245 cache_path, 'diff', commit.raw_id,
245 cache_path, 'diff', commit.raw_id,
246 hide_whitespace_changes, diff_context, c.fulldiff)
246 hide_whitespace_changes, diff_context, c.fulldiff)
247
247
248 caching_enabled = self._is_diff_cache_enabled(self.db_repo)
248 caching_enabled = self._is_diff_cache_enabled(self.db_repo)
249 force_recache = str2bool(self.request.GET.get('force_recache'))
249 force_recache = str2bool(self.request.GET.get('force_recache'))
250
250
251 cached_diff = None
251 cached_diff = None
252 if caching_enabled:
252 if caching_enabled:
253 cached_diff = load_cached_diff(cache_file_path)
253 cached_diff = load_cached_diff(cache_file_path)
254
254
255 has_proper_diff_cache = cached_diff and cached_diff.get('diff')
255 has_proper_diff_cache = cached_diff and cached_diff.get('diff')
256 if not force_recache and has_proper_diff_cache:
256 if not force_recache and has_proper_diff_cache:
257 diffset = cached_diff['diff']
257 diffset = cached_diff['diff']
258 else:
258 else:
259 vcs_diff = self.rhodecode_vcs_repo.get_diff(
259 vcs_diff = self.rhodecode_vcs_repo.get_diff(
260 commit1, commit2,
260 commit1, commit2,
261 ignore_whitespace=hide_whitespace_changes,
261 ignore_whitespace=hide_whitespace_changes,
262 context=diff_context)
262 context=diff_context)
263
263
264 diff_processor = diffs.DiffProcessor(
264 diff_processor = diffs.DiffProcessor(
265 vcs_diff, format='newdiff', diff_limit=diff_limit,
265 vcs_diff, format='newdiff', diff_limit=diff_limit,
266 file_limit=file_limit, show_full_diff=c.fulldiff)
266 file_limit=file_limit, show_full_diff=c.fulldiff)
267
267
268 _parsed = diff_processor.prepare()
268 _parsed = diff_processor.prepare()
269
269
270 diffset = codeblocks.DiffSet(
270 diffset = codeblocks.DiffSet(
271 repo_name=self.db_repo_name,
271 repo_name=self.db_repo_name,
272 source_node_getter=codeblocks.diffset_node_getter(commit1),
272 source_node_getter=codeblocks.diffset_node_getter(commit1),
273 target_node_getter=codeblocks.diffset_node_getter(commit2))
273 target_node_getter=codeblocks.diffset_node_getter(commit2))
274
274
275 diffset = self.path_filter.render_patchset_filtered(
275 diffset = self.path_filter.render_patchset_filtered(
276 diffset, _parsed, commit1.raw_id, commit2.raw_id)
276 diffset, _parsed, commit1.raw_id, commit2.raw_id)
277
277
278 # save cached diff
278 # save cached diff
279 if caching_enabled:
279 if caching_enabled:
280 cache_diff(cache_file_path, diffset, None)
280 cache_diff(cache_file_path, diffset, None)
281
281
282 c.limited_diff = diffset.limited_diff
282 c.limited_diff = diffset.limited_diff
283 c.changes[commit.raw_id] = diffset
283 c.changes[commit.raw_id] = diffset
284 else:
284 else:
285 # TODO(marcink): no cache usage here...
285 # TODO(marcink): no cache usage here...
286 _diff = self.rhodecode_vcs_repo.get_diff(
286 _diff = self.rhodecode_vcs_repo.get_diff(
287 commit1, commit2,
287 commit1, commit2,
288 ignore_whitespace=hide_whitespace_changes, context=diff_context)
288 ignore_whitespace=hide_whitespace_changes, context=diff_context)
289 diff_processor = diffs.DiffProcessor(
289 diff_processor = diffs.DiffProcessor(
290 _diff, format='newdiff', diff_limit=diff_limit,
290 _diff, format='newdiff', diff_limit=diff_limit,
291 file_limit=file_limit, show_full_diff=c.fulldiff)
291 file_limit=file_limit, show_full_diff=c.fulldiff)
292 # downloads/raw we only need RAW diff nothing else
292 # downloads/raw we only need RAW diff nothing else
293 diff = self.path_filter.get_raw_patch(diff_processor)
293 diff = self.path_filter.get_raw_patch(diff_processor)
294 c.changes[commit.raw_id] = [None, None, None, None, diff, None, None]
294 c.changes[commit.raw_id] = [None, None, None, None, diff, None, None]
295
295
296 # sort comments by how they were generated
296 # sort comments by how they were generated
297 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
297 c.comments = sorted(c.comments, key=lambda x: x.comment_id)
298 c.at_version_num = None
298 c.at_version_num = None
299
299
300 if len(c.commit_ranges) == 1:
300 if len(c.commit_ranges) == 1:
301 c.commit = c.commit_ranges[0]
301 c.commit = c.commit_ranges[0]
302 c.parent_tmpl = ''.join(
302 c.parent_tmpl = ''.join(
303 '# Parent %s\n' % x.raw_id for x in c.commit.parents)
303 '# Parent %s\n' % x.raw_id for x in c.commit.parents)
304
304
305 if method == 'download':
305 if method == 'download':
306 response = Response(diff)
306 response = Response(diff)
307 response.content_type = 'text/plain'
307 response.content_type = 'text/plain'
308 response.content_disposition = (
308 response.content_disposition = (
309 'attachment; filename=%s.diff' % commit_id_range[:12])
309 'attachment; filename=%s.diff' % commit_id_range[:12])
310 return response
310 return response
311 elif method == 'patch':
311 elif method == 'patch':
312 c.diff = safe_unicode(diff)
312 c.diff = safe_unicode(diff)
313 patch = render(
313 patch = render(
314 'rhodecode:templates/changeset/patch_changeset.mako',
314 'rhodecode:templates/changeset/patch_changeset.mako',
315 self._get_template_context(c), self.request)
315 self._get_template_context(c), self.request)
316 response = Response(patch)
316 response = Response(patch)
317 response.content_type = 'text/plain'
317 response.content_type = 'text/plain'
318 return response
318 return response
319 elif method == 'raw':
319 elif method == 'raw':
320 response = Response(diff)
320 response = Response(diff)
321 response.content_type = 'text/plain'
321 response.content_type = 'text/plain'
322 return response
322 return response
323 elif method == 'show':
323 elif method == 'show':
324 if len(c.commit_ranges) == 1:
324 if len(c.commit_ranges) == 1:
325 html = render(
325 html = render(
326 'rhodecode:templates/changeset/changeset.mako',
326 'rhodecode:templates/changeset/changeset.mako',
327 self._get_template_context(c), self.request)
327 self._get_template_context(c), self.request)
328 return Response(html)
328 return Response(html)
329 else:
329 else:
330 c.ancestor = None
330 c.ancestor = None
331 c.target_repo = self.db_repo
331 c.target_repo = self.db_repo
332 html = render(
332 html = render(
333 'rhodecode:templates/changeset/changeset_range.mako',
333 'rhodecode:templates/changeset/changeset_range.mako',
334 self._get_template_context(c), self.request)
334 self._get_template_context(c), self.request)
335 return Response(html)
335 return Response(html)
336
336
337 raise HTTPBadRequest()
337 raise HTTPBadRequest()
338
338
339 @LoginRequired()
339 @LoginRequired()
340 @HasRepoPermissionAnyDecorator(
340 @HasRepoPermissionAnyDecorator(
341 'repository.read', 'repository.write', 'repository.admin')
341 'repository.read', 'repository.write', 'repository.admin')
342 def repo_commit_show(self):
342 def repo_commit_show(self):
343 commit_id = self.request.matchdict['commit_id']
343 commit_id = self.request.matchdict['commit_id']
344 return self._commit(commit_id, method='show')
344 return self._commit(commit_id, method='show')
345
345
346 @LoginRequired()
346 @LoginRequired()
347 @HasRepoPermissionAnyDecorator(
347 @HasRepoPermissionAnyDecorator(
348 'repository.read', 'repository.write', 'repository.admin')
348 'repository.read', 'repository.write', 'repository.admin')
349 def repo_commit_raw(self):
349 def repo_commit_raw(self):
350 commit_id = self.request.matchdict['commit_id']
350 commit_id = self.request.matchdict['commit_id']
351 return self._commit(commit_id, method='raw')
351 return self._commit(commit_id, method='raw')
352
352
353 @LoginRequired()
353 @LoginRequired()
354 @HasRepoPermissionAnyDecorator(
354 @HasRepoPermissionAnyDecorator(
355 'repository.read', 'repository.write', 'repository.admin')
355 'repository.read', 'repository.write', 'repository.admin')
356 def repo_commit_patch(self):
356 def repo_commit_patch(self):
357 commit_id = self.request.matchdict['commit_id']
357 commit_id = self.request.matchdict['commit_id']
358 return self._commit(commit_id, method='patch')
358 return self._commit(commit_id, method='patch')
359
359
360 @LoginRequired()
360 @LoginRequired()
361 @HasRepoPermissionAnyDecorator(
361 @HasRepoPermissionAnyDecorator(
362 'repository.read', 'repository.write', 'repository.admin')
362 'repository.read', 'repository.write', 'repository.admin')
363 def repo_commit_download(self):
363 def repo_commit_download(self):
364 commit_id = self.request.matchdict['commit_id']
364 commit_id = self.request.matchdict['commit_id']
365 return self._commit(commit_id, method='download')
365 return self._commit(commit_id, method='download')
366
366
367 def _commit_comments_create(self, commit_id, comments):
367 def _commit_comments_create(self, commit_id, comments):
368 _ = self.request.translate
368 _ = self.request.translate
369 data = {}
369 data = {}
370 if not comments:
370 if not comments:
371 return
371 return
372
372
373 commit = self.db_repo.get_commit(commit_id)
373 commit = self.db_repo.get_commit(commit_id)
374
374
375 all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments)
375 all_drafts = len([x for x in comments if str2bool(x['is_draft'])]) == len(comments)
376 for entry in comments:
376 for entry in comments:
377 c = self.load_default_context()
377 c = self.load_default_context()
378 comment_type = entry['comment_type']
378 comment_type = entry['comment_type']
379 text = entry['text']
379 text = entry['text']
380 status = entry['status']
380 status = entry['status']
381 is_draft = str2bool(entry['is_draft'])
381 is_draft = str2bool(entry['is_draft'])
382 resolves_comment_id = entry['resolves_comment_id']
382 resolves_comment_id = entry['resolves_comment_id']
383 f_path = entry['f_path']
383 f_path = entry['f_path']
384 line_no = entry['line']
384 line_no = entry['line']
385 target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path)))
385 target_elem_id = 'file-{}'.format(h.safeid(h.safe_unicode(f_path)))
386
386
387 if status:
387 if status:
388 text = text or (_('Status change %(transition_icon)s %(status)s')
388 text = text or (_('Status change %(transition_icon)s %(status)s')
389 % {'transition_icon': '>',
389 % {'transition_icon': '>',
390 'status': ChangesetStatus.get_status_lbl(status)})
390 'status': ChangesetStatus.get_status_lbl(status)})
391
391
392 comment = CommentsModel().create(
392 comment = CommentsModel().create(
393 text=text,
393 text=text,
394 repo=self.db_repo.repo_id,
394 repo=self.db_repo.repo_id,
395 user=self._rhodecode_db_user.user_id,
395 user=self._rhodecode_db_user.user_id,
396 commit_id=commit_id,
396 commit_id=commit_id,
397 f_path=f_path,
397 f_path=f_path,
398 line_no=line_no,
398 line_no=line_no,
399 status_change=(ChangesetStatus.get_status_lbl(status)
399 status_change=(ChangesetStatus.get_status_lbl(status)
400 if status else None),
400 if status else None),
401 status_change_type=status,
401 status_change_type=status,
402 comment_type=comment_type,
402 comment_type=comment_type,
403 is_draft=is_draft,
403 is_draft=is_draft,
404 resolves_comment_id=resolves_comment_id,
404 resolves_comment_id=resolves_comment_id,
405 auth_user=self._rhodecode_user,
405 auth_user=self._rhodecode_user,
406 send_email=not is_draft, # skip notification for draft comments
406 send_email=not is_draft, # skip notification for draft comments
407 )
407 )
408 is_inline = comment.is_inline
408 is_inline = comment.is_inline
409
409
410 # get status if set !
410 # get status if set !
411 if status:
411 if status:
412 # `dont_allow_on_closed_pull_request = True` means
412 # `dont_allow_on_closed_pull_request = True` means
413 # if latest status was from pull request and it's closed
413 # if latest status was from pull request and it's closed
414 # disallow changing status !
414 # disallow changing status !
415
415
416 try:
416 try:
417 ChangesetStatusModel().set_status(
417 ChangesetStatusModel().set_status(
418 self.db_repo.repo_id,
418 self.db_repo.repo_id,
419 status,
419 status,
420 self._rhodecode_db_user.user_id,
420 self._rhodecode_db_user.user_id,
421 comment,
421 comment,
422 revision=commit_id,
422 revision=commit_id,
423 dont_allow_on_closed_pull_request=True
423 dont_allow_on_closed_pull_request=True
424 )
424 )
425 except StatusChangeOnClosedPullRequestError:
425 except StatusChangeOnClosedPullRequestError:
426 msg = _('Changing the status of a commit associated with '
426 msg = _('Changing the status of a commit associated with '
427 'a closed pull request is not allowed')
427 'a closed pull request is not allowed')
428 log.exception(msg)
428 log.exception(msg)
429 h.flash(msg, category='warning')
429 h.flash(msg, category='warning')
430 raise HTTPFound(h.route_path(
430 raise HTTPFound(h.route_path(
431 'repo_commit', repo_name=self.db_repo_name,
431 'repo_commit', repo_name=self.db_repo_name,
432 commit_id=commit_id))
432 commit_id=commit_id))
433
433
434 Session().flush()
434 Session().flush()
435 # this is somehow required to get access to some relationship
435 # this is somehow required to get access to some relationship
436 # loaded on comment
436 # loaded on comment
437 Session().refresh(comment)
437 Session().refresh(comment)
438
438
439 # skip notifications for drafts
439 # skip notifications for drafts
440 if not is_draft:
440 if not is_draft:
441 CommentsModel().trigger_commit_comment_hook(
441 CommentsModel().trigger_commit_comment_hook(
442 self.db_repo, self._rhodecode_user, 'create',
442 self.db_repo, self._rhodecode_user, 'create',
443 data={'comment': comment, 'commit': commit})
443 data={'comment': comment, 'commit': commit})
444
444
445 comment_id = comment.comment_id
445 comment_id = comment.comment_id
446 data[comment_id] = {
446 data[comment_id] = {
447 'target_id': target_elem_id
447 'target_id': target_elem_id
448 }
448 }
449 Session().flush()
449 Session().flush()
450
450
451 c.co = comment
451 c.co = comment
452 c.at_version_num = 0
452 c.at_version_num = 0
453 c.is_new = True
453 c.is_new = True
454 rendered_comment = render(
454 rendered_comment = render(
455 'rhodecode:templates/changeset/changeset_comment_block.mako',
455 'rhodecode:templates/changeset/changeset_comment_block.mako',
456 self._get_template_context(c), self.request)
456 self._get_template_context(c), self.request)
457
457
458 data[comment_id].update(comment.get_dict())
458 data[comment_id].update(comment.get_dict())
459 data[comment_id].update({'rendered_text': rendered_comment})
459 data[comment_id].update({'rendered_text': rendered_comment})
460
460
461 # finalize, commit and redirect
461 # finalize, commit and redirect
462 Session().commit()
462 Session().commit()
463
463
464 # skip channelstream for draft comments
464 # skip channelstream for draft comments
465 if not all_drafts:
465 if not all_drafts:
466 comment_broadcast_channel = channelstream.comment_channel(
466 comment_broadcast_channel = channelstream.comment_channel(
467 self.db_repo_name, commit_obj=commit)
467 self.db_repo_name, commit_obj=commit)
468
468
469 comment_data = data
469 comment_data = data
470 posted_comment_type = 'inline' if is_inline else 'general'
470 posted_comment_type = 'inline' if is_inline else 'general'
471 if len(data) == 1:
471 if len(data) == 1:
472 msg = _('posted {} new {} comment').format(len(data), posted_comment_type)
472 msg = _('posted {} new {} comment').format(len(data), posted_comment_type)
473 else:
473 else:
474 msg = _('posted {} new {} comments').format(len(data), posted_comment_type)
474 msg = _('posted {} new {} comments').format(len(data), posted_comment_type)
475
475
476 channelstream.comment_channelstream_push(
476 channelstream.comment_channelstream_push(
477 self.request, comment_broadcast_channel, self._rhodecode_user, msg,
477 self.request, comment_broadcast_channel, self._rhodecode_user, msg,
478 comment_data=comment_data)
478 comment_data=comment_data)
479
479
480 return data
480 return data
481
481
482 @LoginRequired()
482 @LoginRequired()
483 @NotAnonymous()
483 @NotAnonymous()
484 @HasRepoPermissionAnyDecorator(
484 @HasRepoPermissionAnyDecorator(
485 'repository.read', 'repository.write', 'repository.admin')
485 'repository.read', 'repository.write', 'repository.admin')
486 @CSRFRequired()
486 @CSRFRequired()
487 def repo_commit_comment_create(self):
487 def repo_commit_comment_create(self):
488 _ = self.request.translate
488 _ = self.request.translate
489 commit_id = self.request.matchdict['commit_id']
489 commit_id = self.request.matchdict['commit_id']
490
490
491 multi_commit_ids = []
491 multi_commit_ids = []
492 for _commit_id in self.request.POST.get('commit_ids', '').split(','):
492 for _commit_id in self.request.POST.get('commit_ids', '').split(','):
493 if _commit_id not in ['', None, EmptyCommit.raw_id]:
493 if _commit_id not in ['', None, EmptyCommit.raw_id]:
494 if _commit_id not in multi_commit_ids:
494 if _commit_id not in multi_commit_ids:
495 multi_commit_ids.append(_commit_id)
495 multi_commit_ids.append(_commit_id)
496
496
497 commit_ids = multi_commit_ids or [commit_id]
497 commit_ids = multi_commit_ids or [commit_id]
498
498
499 data = []
499 data = []
500 # Multiple comments for each passed commit id
500 # Multiple comments for each passed commit id
501 for current_id in filter(None, commit_ids):
501 for current_id in filter(None, commit_ids):
502 comment_data = {
502 comment_data = {
503 'comment_type': self.request.POST.get('comment_type'),
503 'comment_type': self.request.POST.get('comment_type'),
504 'text': self.request.POST.get('text'),
504 'text': self.request.POST.get('text'),
505 'status': self.request.POST.get('changeset_status', None),
505 'status': self.request.POST.get('changeset_status', None),
506 'is_draft': self.request.POST.get('draft'),
506 'is_draft': self.request.POST.get('draft'),
507 'resolves_comment_id': self.request.POST.get('resolves_comment_id', None),
507 'resolves_comment_id': self.request.POST.get('resolves_comment_id', None),
508 'close_pull_request': self.request.POST.get('close_pull_request'),
508 'close_pull_request': self.request.POST.get('close_pull_request'),
509 'f_path': self.request.POST.get('f_path'),
509 'f_path': self.request.POST.get('f_path'),
510 'line': self.request.POST.get('line'),
510 'line': self.request.POST.get('line'),
511 }
511 }
512 comment = self._commit_comments_create(commit_id=current_id, comments=[comment_data])
512 comment = self._commit_comments_create(commit_id=current_id, comments=[comment_data])
513 data.append(comment)
513 data.append(comment)
514
514
515 return data if len(data) > 1 else data[0]
515 return data if len(data) > 1 else data[0]
516
516
517 @LoginRequired()
517 @LoginRequired()
518 @NotAnonymous()
518 @NotAnonymous()
519 @HasRepoPermissionAnyDecorator(
519 @HasRepoPermissionAnyDecorator(
520 'repository.read', 'repository.write', 'repository.admin')
520 'repository.read', 'repository.write', 'repository.admin')
521 @CSRFRequired()
521 @CSRFRequired()
522 def repo_commit_comment_preview(self):
522 def repo_commit_comment_preview(self):
523 # Technically a CSRF token is not needed as no state changes with this
523 # Technically a CSRF token is not needed as no state changes with this
524 # call. However, as this is a POST is better to have it, so automated
524 # call. However, as this is a POST is better to have it, so automated
525 # tools don't flag it as potential CSRF.
525 # tools don't flag it as potential CSRF.
526 # Post is required because the payload could be bigger than the maximum
526 # Post is required because the payload could be bigger than the maximum
527 # allowed by GET.
527 # allowed by GET.
528
528
529 text = self.request.POST.get('text')
529 text = self.request.POST.get('text')
530 renderer = self.request.POST.get('renderer') or 'rst'
530 renderer = self.request.POST.get('renderer') or 'rst'
531 if text:
531 if text:
532 return h.render(text, renderer=renderer, mentions=True,
532 return h.render(text, renderer=renderer, mentions=True,
533 repo_name=self.db_repo_name)
533 repo_name=self.db_repo_name)
534 return ''
534 return ''
535
535
536 @LoginRequired()
536 @LoginRequired()
537 @HasRepoPermissionAnyDecorator(
537 @HasRepoPermissionAnyDecorator(
538 'repository.read', 'repository.write', 'repository.admin')
538 'repository.read', 'repository.write', 'repository.admin')
539 @CSRFRequired()
539 @CSRFRequired()
540 def repo_commit_comment_history_view(self):
540 def repo_commit_comment_history_view(self):
541 c = self.load_default_context()
541 c = self.load_default_context()
542 comment_id = self.request.matchdict['comment_id']
542 comment_history_id = self.request.matchdict['comment_history_id']
543 comment_history_id = self.request.matchdict['comment_history_id']
543
544
544 comment = ChangesetComment.get_or_404(comment_history_id)
545 comment = ChangesetComment.get_or_404(comment_id)
545 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
546 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
546 if comment.draft and not comment_owner:
547 if comment.draft and not comment_owner:
547 # if we see draft comments history, we only allow this for owner
548 # if we see draft comments history, we only allow this for owner
548 raise HTTPNotFound()
549 raise HTTPNotFound()
549
550
550 comment_history = ChangesetCommentHistory.get_or_404(comment_history_id)
551 comment_history = ChangesetCommentHistory.get_or_404(comment_history_id)
551 is_repo_comment = comment_history.comment.repo.repo_id == self.db_repo.repo_id
552 is_repo_comment = comment_history.comment.repo.repo_id == self.db_repo.repo_id
552
553
553 if is_repo_comment:
554 if is_repo_comment:
554 c.comment_history = comment_history
555 c.comment_history = comment_history
555
556
556 rendered_comment = render(
557 rendered_comment = render(
557 'rhodecode:templates/changeset/comment_history.mako',
558 'rhodecode:templates/changeset/comment_history.mako',
558 self._get_template_context(c), self.request)
559 self._get_template_context(c), self.request)
559 return rendered_comment
560 return rendered_comment
560 else:
561 else:
561 log.warning('No permissions for user %s to show comment_history_id: %s',
562 log.warning('No permissions for user %s to show comment_history_id: %s',
562 self._rhodecode_db_user, comment_history_id)
563 self._rhodecode_db_user, comment_history_id)
563 raise HTTPNotFound()
564 raise HTTPNotFound()
564
565
565 @LoginRequired()
566 @LoginRequired()
566 @NotAnonymous()
567 @NotAnonymous()
567 @HasRepoPermissionAnyDecorator(
568 @HasRepoPermissionAnyDecorator(
568 'repository.read', 'repository.write', 'repository.admin')
569 'repository.read', 'repository.write', 'repository.admin')
569 @CSRFRequired()
570 @CSRFRequired()
570 def repo_commit_comment_attachment_upload(self):
571 def repo_commit_comment_attachment_upload(self):
571 c = self.load_default_context()
572 c = self.load_default_context()
572 upload_key = 'attachment'
573 upload_key = 'attachment'
573
574
574 file_obj = self.request.POST.get(upload_key)
575 file_obj = self.request.POST.get(upload_key)
575
576
576 if file_obj is None:
577 if file_obj is None:
577 self.request.response.status = 400
578 self.request.response.status = 400
578 return {'store_fid': None,
579 return {'store_fid': None,
579 'access_path': None,
580 'access_path': None,
580 'error': '{} data field is missing'.format(upload_key)}
581 'error': '{} data field is missing'.format(upload_key)}
581
582
582 if not hasattr(file_obj, 'filename'):
583 if not hasattr(file_obj, 'filename'):
583 self.request.response.status = 400
584 self.request.response.status = 400
584 return {'store_fid': None,
585 return {'store_fid': None,
585 'access_path': None,
586 'access_path': None,
586 'error': 'filename cannot be read from the data field'}
587 'error': 'filename cannot be read from the data field'}
587
588
588 filename = file_obj.filename
589 filename = file_obj.filename
589 file_display_name = filename
590 file_display_name = filename
590
591
591 metadata = {
592 metadata = {
592 'user_uploaded': {'username': self._rhodecode_user.username,
593 'user_uploaded': {'username': self._rhodecode_user.username,
593 'user_id': self._rhodecode_user.user_id,
594 'user_id': self._rhodecode_user.user_id,
594 'ip': self._rhodecode_user.ip_addr}}
595 'ip': self._rhodecode_user.ip_addr}}
595
596
596 # TODO(marcink): allow .ini configuration for allowed_extensions, and file-size
597 # TODO(marcink): allow .ini configuration for allowed_extensions, and file-size
597 allowed_extensions = [
598 allowed_extensions = [
598 'gif', '.jpeg', '.jpg', '.png', '.docx', '.gz', '.log', '.pdf',
599 'gif', '.jpeg', '.jpg', '.png', '.docx', '.gz', '.log', '.pdf',
599 '.pptx', '.txt', '.xlsx', '.zip']
600 '.pptx', '.txt', '.xlsx', '.zip']
600 max_file_size = 10 * 1024 * 1024 # 10MB, also validated via dropzone.js
601 max_file_size = 10 * 1024 * 1024 # 10MB, also validated via dropzone.js
601
602
602 try:
603 try:
603 storage = store_utils.get_file_storage(self.request.registry.settings)
604 storage = store_utils.get_file_storage(self.request.registry.settings)
604 store_uid, metadata = storage.save_file(
605 store_uid, metadata = storage.save_file(
605 file_obj.file, filename, extra_metadata=metadata,
606 file_obj.file, filename, extra_metadata=metadata,
606 extensions=allowed_extensions, max_filesize=max_file_size)
607 extensions=allowed_extensions, max_filesize=max_file_size)
607 except FileNotAllowedException:
608 except FileNotAllowedException:
608 self.request.response.status = 400
609 self.request.response.status = 400
609 permitted_extensions = ', '.join(allowed_extensions)
610 permitted_extensions = ', '.join(allowed_extensions)
610 error_msg = 'File `{}` is not allowed. ' \
611 error_msg = 'File `{}` is not allowed. ' \
611 'Only following extensions are permitted: {}'.format(
612 'Only following extensions are permitted: {}'.format(
612 filename, permitted_extensions)
613 filename, permitted_extensions)
613 return {'store_fid': None,
614 return {'store_fid': None,
614 'access_path': None,
615 'access_path': None,
615 'error': error_msg}
616 'error': error_msg}
616 except FileOverSizeException:
617 except FileOverSizeException:
617 self.request.response.status = 400
618 self.request.response.status = 400
618 limit_mb = h.format_byte_size_binary(max_file_size)
619 limit_mb = h.format_byte_size_binary(max_file_size)
619 return {'store_fid': None,
620 return {'store_fid': None,
620 'access_path': None,
621 'access_path': None,
621 'error': 'File {} is exceeding allowed limit of {}.'.format(
622 'error': 'File {} is exceeding allowed limit of {}.'.format(
622 filename, limit_mb)}
623 filename, limit_mb)}
623
624
624 try:
625 try:
625 entry = FileStore.create(
626 entry = FileStore.create(
626 file_uid=store_uid, filename=metadata["filename"],
627 file_uid=store_uid, filename=metadata["filename"],
627 file_hash=metadata["sha256"], file_size=metadata["size"],
628 file_hash=metadata["sha256"], file_size=metadata["size"],
628 file_display_name=file_display_name,
629 file_display_name=file_display_name,
629 file_description=u'comment attachment `{}`'.format(safe_unicode(filename)),
630 file_description=u'comment attachment `{}`'.format(safe_unicode(filename)),
630 hidden=True, check_acl=True, user_id=self._rhodecode_user.user_id,
631 hidden=True, check_acl=True, user_id=self._rhodecode_user.user_id,
631 scope_repo_id=self.db_repo.repo_id
632 scope_repo_id=self.db_repo.repo_id
632 )
633 )
633 Session().add(entry)
634 Session().add(entry)
634 Session().commit()
635 Session().commit()
635 log.debug('Stored upload in DB as %s', entry)
636 log.debug('Stored upload in DB as %s', entry)
636 except Exception:
637 except Exception:
637 log.exception('Failed to store file %s', filename)
638 log.exception('Failed to store file %s', filename)
638 self.request.response.status = 400
639 self.request.response.status = 400
639 return {'store_fid': None,
640 return {'store_fid': None,
640 'access_path': None,
641 'access_path': None,
641 'error': 'File {} failed to store in DB.'.format(filename)}
642 'error': 'File {} failed to store in DB.'.format(filename)}
642
643
643 Session().commit()
644 Session().commit()
644
645
645 return {
646 return {
646 'store_fid': store_uid,
647 'store_fid': store_uid,
647 'access_path': h.route_path(
648 'access_path': h.route_path(
648 'download_file', fid=store_uid),
649 'download_file', fid=store_uid),
649 'fqn_access_path': h.route_url(
650 'fqn_access_path': h.route_url(
650 'download_file', fid=store_uid),
651 'download_file', fid=store_uid),
651 'repo_access_path': h.route_path(
652 'repo_access_path': h.route_path(
652 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
653 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
653 'repo_fqn_access_path': h.route_url(
654 'repo_fqn_access_path': h.route_url(
654 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
655 'repo_artifacts_get', repo_name=self.db_repo_name, uid=store_uid),
655 }
656 }
656
657
657 @LoginRequired()
658 @LoginRequired()
658 @NotAnonymous()
659 @NotAnonymous()
659 @HasRepoPermissionAnyDecorator(
660 @HasRepoPermissionAnyDecorator(
660 'repository.read', 'repository.write', 'repository.admin')
661 'repository.read', 'repository.write', 'repository.admin')
661 @CSRFRequired()
662 @CSRFRequired()
662 def repo_commit_comment_delete(self):
663 def repo_commit_comment_delete(self):
663 commit_id = self.request.matchdict['commit_id']
664 commit_id = self.request.matchdict['commit_id']
664 comment_id = self.request.matchdict['comment_id']
665 comment_id = self.request.matchdict['comment_id']
665
666
666 comment = ChangesetComment.get_or_404(comment_id)
667 comment = ChangesetComment.get_or_404(comment_id)
667 if not comment:
668 if not comment:
668 log.debug('Comment with id:%s not found, skipping', comment_id)
669 log.debug('Comment with id:%s not found, skipping', comment_id)
669 # comment already deleted in another call probably
670 # comment already deleted in another call probably
670 return True
671 return True
671
672
672 if comment.immutable:
673 if comment.immutable:
673 # don't allow deleting comments that are immutable
674 # don't allow deleting comments that are immutable
674 raise HTTPForbidden()
675 raise HTTPForbidden()
675
676
676 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
677 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
677 super_admin = h.HasPermissionAny('hg.admin')()
678 super_admin = h.HasPermissionAny('hg.admin')()
678 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
679 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
679 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
680 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
680 comment_repo_admin = is_repo_admin and is_repo_comment
681 comment_repo_admin = is_repo_admin and is_repo_comment
681
682
682 if comment.draft and not comment_owner:
683 if comment.draft and not comment_owner:
683 # We never allow to delete draft comments for other than owners
684 # We never allow to delete draft comments for other than owners
684 raise HTTPNotFound()
685 raise HTTPNotFound()
685
686
686 if super_admin or comment_owner or comment_repo_admin:
687 if super_admin or comment_owner or comment_repo_admin:
687 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
688 CommentsModel().delete(comment=comment, auth_user=self._rhodecode_user)
688 Session().commit()
689 Session().commit()
689 return True
690 return True
690 else:
691 else:
691 log.warning('No permissions for user %s to delete comment_id: %s',
692 log.warning('No permissions for user %s to delete comment_id: %s',
692 self._rhodecode_db_user, comment_id)
693 self._rhodecode_db_user, comment_id)
693 raise HTTPNotFound()
694 raise HTTPNotFound()
694
695
695 @LoginRequired()
696 @LoginRequired()
696 @NotAnonymous()
697 @NotAnonymous()
697 @HasRepoPermissionAnyDecorator(
698 @HasRepoPermissionAnyDecorator(
698 'repository.read', 'repository.write', 'repository.admin')
699 'repository.read', 'repository.write', 'repository.admin')
699 @CSRFRequired()
700 @CSRFRequired()
700 def repo_commit_comment_edit(self):
701 def repo_commit_comment_edit(self):
701 self.load_default_context()
702 self.load_default_context()
702
703
703 commit_id = self.request.matchdict['commit_id']
704 commit_id = self.request.matchdict['commit_id']
704 comment_id = self.request.matchdict['comment_id']
705 comment_id = self.request.matchdict['comment_id']
705 comment = ChangesetComment.get_or_404(comment_id)
706 comment = ChangesetComment.get_or_404(comment_id)
706
707
707 if comment.immutable:
708 if comment.immutable:
708 # don't allow deleting comments that are immutable
709 # don't allow deleting comments that are immutable
709 raise HTTPForbidden()
710 raise HTTPForbidden()
710
711
711 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
712 is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
712 super_admin = h.HasPermissionAny('hg.admin')()
713 super_admin = h.HasPermissionAny('hg.admin')()
713 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
714 comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
714 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
715 is_repo_comment = comment.repo.repo_id == self.db_repo.repo_id
715 comment_repo_admin = is_repo_admin and is_repo_comment
716 comment_repo_admin = is_repo_admin and is_repo_comment
716
717
717 if super_admin or comment_owner or comment_repo_admin:
718 if super_admin or comment_owner or comment_repo_admin:
718 text = self.request.POST.get('text')
719 text = self.request.POST.get('text')
719 version = self.request.POST.get('version')
720 version = self.request.POST.get('version')
720 if text == comment.text:
721 if text == comment.text:
721 log.warning(
722 log.warning(
722 'Comment(repo): '
723 'Comment(repo): '
723 'Trying to create new version '
724 'Trying to create new version '
724 'with the same comment body {}'.format(
725 'with the same comment body {}'.format(
725 comment_id,
726 comment_id,
726 )
727 )
727 )
728 )
728 raise HTTPNotFound()
729 raise HTTPNotFound()
729
730
730 if version.isdigit():
731 if version.isdigit():
731 version = int(version)
732 version = int(version)
732 else:
733 else:
733 log.warning(
734 log.warning(
734 'Comment(repo): Wrong version type {} {} '
735 'Comment(repo): Wrong version type {} {} '
735 'for comment {}'.format(
736 'for comment {}'.format(
736 version,
737 version,
737 type(version),
738 type(version),
738 comment_id,
739 comment_id,
739 )
740 )
740 )
741 )
741 raise HTTPNotFound()
742 raise HTTPNotFound()
742
743
743 try:
744 try:
744 comment_history = CommentsModel().edit(
745 comment_history = CommentsModel().edit(
745 comment_id=comment_id,
746 comment_id=comment_id,
746 text=text,
747 text=text,
747 auth_user=self._rhodecode_user,
748 auth_user=self._rhodecode_user,
748 version=version,
749 version=version,
749 )
750 )
750 except CommentVersionMismatch:
751 except CommentVersionMismatch:
751 raise HTTPConflict()
752 raise HTTPConflict()
752
753
753 if not comment_history:
754 if not comment_history:
754 raise HTTPNotFound()
755 raise HTTPNotFound()
755
756
756 if not comment.draft:
757 if not comment.draft:
757 commit = self.db_repo.get_commit(commit_id)
758 commit = self.db_repo.get_commit(commit_id)
758 CommentsModel().trigger_commit_comment_hook(
759 CommentsModel().trigger_commit_comment_hook(
759 self.db_repo, self._rhodecode_user, 'edit',
760 self.db_repo, self._rhodecode_user, 'edit',
760 data={'comment': comment, 'commit': commit})
761 data={'comment': comment, 'commit': commit})
761
762
762 Session().commit()
763 Session().commit()
763 return {
764 return {
764 'comment_history_id': comment_history.comment_history_id,
765 'comment_history_id': comment_history.comment_history_id,
765 'comment_id': comment.comment_id,
766 'comment_id': comment.comment_id,
766 'comment_version': comment_history.version,
767 'comment_version': comment_history.version,
767 'comment_author_username': comment_history.author.username,
768 'comment_author_username': comment_history.author.username,
768 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16),
769 'comment_author_gravatar': h.gravatar_url(comment_history.author.email, 16),
769 'comment_created_on': h.age_component(comment_history.created_on,
770 'comment_created_on': h.age_component(comment_history.created_on,
770 time_is_local=True),
771 time_is_local=True),
771 }
772 }
772 else:
773 else:
773 log.warning('No permissions for user %s to edit comment_id: %s',
774 log.warning('No permissions for user %s to edit comment_id: %s',
774 self._rhodecode_db_user, comment_id)
775 self._rhodecode_db_user, comment_id)
775 raise HTTPNotFound()
776 raise HTTPNotFound()
776
777
777 @LoginRequired()
778 @LoginRequired()
778 @HasRepoPermissionAnyDecorator(
779 @HasRepoPermissionAnyDecorator(
779 'repository.read', 'repository.write', 'repository.admin')
780 'repository.read', 'repository.write', 'repository.admin')
780 def repo_commit_data(self):
781 def repo_commit_data(self):
781 commit_id = self.request.matchdict['commit_id']
782 commit_id = self.request.matchdict['commit_id']
782 self.load_default_context()
783 self.load_default_context()
783
784
784 try:
785 try:
785 return self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
786 return self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
786 except CommitDoesNotExistError as e:
787 except CommitDoesNotExistError as e:
787 return EmptyCommit(message=str(e))
788 return EmptyCommit(message=str(e))
788
789
789 @LoginRequired()
790 @LoginRequired()
790 @HasRepoPermissionAnyDecorator(
791 @HasRepoPermissionAnyDecorator(
791 'repository.read', 'repository.write', 'repository.admin')
792 'repository.read', 'repository.write', 'repository.admin')
792 def repo_commit_children(self):
793 def repo_commit_children(self):
793 commit_id = self.request.matchdict['commit_id']
794 commit_id = self.request.matchdict['commit_id']
794 self.load_default_context()
795 self.load_default_context()
795
796
796 try:
797 try:
797 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
798 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
798 children = commit.children
799 children = commit.children
799 except CommitDoesNotExistError:
800 except CommitDoesNotExistError:
800 children = []
801 children = []
801
802
802 result = {"results": children}
803 result = {"results": children}
803 return result
804 return result
804
805
805 @LoginRequired()
806 @LoginRequired()
806 @HasRepoPermissionAnyDecorator(
807 @HasRepoPermissionAnyDecorator(
807 'repository.read', 'repository.write', 'repository.admin')
808 'repository.read', 'repository.write', 'repository.admin')
808 def repo_commit_parents(self):
809 def repo_commit_parents(self):
809 commit_id = self.request.matchdict['commit_id']
810 commit_id = self.request.matchdict['commit_id']
810 self.load_default_context()
811 self.load_default_context()
811
812
812 try:
813 try:
813 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
814 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
814 parents = commit.parents
815 parents = commit.parents
815 except CommitDoesNotExistError:
816 except CommitDoesNotExistError:
816 parents = []
817 parents = []
817 result = {"results": parents}
818 result = {"results": parents}
818 return result
819 return result
@@ -1,411 +1,411 b''
1
1
2 /******************************************************************************
2 /******************************************************************************
3 * *
3 * *
4 * DO NOT CHANGE THIS FILE MANUALLY *
4 * DO NOT CHANGE THIS FILE MANUALLY *
5 * *
5 * *
6 * *
6 * *
7 * This file is automatically generated when the app starts up with *
7 * This file is automatically generated when the app starts up with *
8 * generate_js_files = true *
8 * generate_js_files = true *
9 * *
9 * *
10 * To add a route here pass jsroute=True to the route definition in the app *
10 * To add a route here pass jsroute=True to the route definition in the app *
11 * *
11 * *
12 ******************************************************************************/
12 ******************************************************************************/
13 function registerRCRoutes() {
13 function registerRCRoutes() {
14 // routes registration
14 // routes registration
15 pyroutes.register('admin_artifacts', '/_admin/artifacts', []);
15 pyroutes.register('admin_artifacts', '/_admin/artifacts', []);
16 pyroutes.register('admin_artifacts_data', '/_admin/artifacts-data', []);
16 pyroutes.register('admin_artifacts_data', '/_admin/artifacts-data', []);
17 pyroutes.register('admin_artifacts_delete', '/_admin/artifacts/%(uid)s/delete', ['uid']);
17 pyroutes.register('admin_artifacts_delete', '/_admin/artifacts/%(uid)s/delete', ['uid']);
18 pyroutes.register('admin_artifacts_show_all', '/_admin/artifacts', []);
18 pyroutes.register('admin_artifacts_show_all', '/_admin/artifacts', []);
19 pyroutes.register('admin_artifacts_show_info', '/_admin/artifacts/%(uid)s', ['uid']);
19 pyroutes.register('admin_artifacts_show_info', '/_admin/artifacts/%(uid)s', ['uid']);
20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
23 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
23 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
24 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
24 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
25 pyroutes.register('admin_home', '/_admin', []);
25 pyroutes.register('admin_home', '/_admin', []);
26 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
26 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
27 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
27 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
28 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
28 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
29 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
29 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
30 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
30 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
31 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
31 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
32 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
32 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
33 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
33 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
34 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
34 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
35 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
35 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
36 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
36 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
37 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
37 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
38 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
38 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
39 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
39 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
40 pyroutes.register('admin_settings', '/_admin/settings', []);
40 pyroutes.register('admin_settings', '/_admin/settings', []);
41 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
41 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
42 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
42 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
43 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
43 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
44 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
44 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
45 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
45 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
46 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
46 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
47 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []);
47 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []);
48 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
48 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
49 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
49 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
50 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
50 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
51 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
51 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
52 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
52 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
53 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
53 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
54 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
54 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
55 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
55 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
56 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
56 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
57 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
57 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
58 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
58 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
59 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
59 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
60 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
60 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
61 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
61 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
62 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
62 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
63 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
63 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
64 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
64 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
65 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
65 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
66 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
66 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
67 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
67 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
68 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
68 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
69 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
69 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
70 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
70 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
71 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
71 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
72 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
72 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
73 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
73 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
74 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
74 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
75 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
75 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
80 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
80 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
81 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
81 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
82 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
82 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
83 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
83 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
84 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
84 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
85 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
85 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
86 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
86 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
87 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
87 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
88 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
88 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
89 pyroutes.register('apiv2', '/_admin/api', []);
89 pyroutes.register('apiv2', '/_admin/api', []);
90 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
90 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
91 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
91 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
92 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
92 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
93 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
93 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
94 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
94 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
95 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
95 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
96 pyroutes.register('channelstream_proxy', '/_channelstream', []);
96 pyroutes.register('channelstream_proxy', '/_channelstream', []);
97 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
97 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
98 pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']);
98 pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']);
99 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
99 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
100 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
100 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
101 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
101 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
102 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
102 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
103 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
103 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
104 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
104 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
105 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
105 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
106 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
106 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
107 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
107 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
108 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
108 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
109 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
109 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
110 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
110 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
111 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
111 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
112 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
112 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
113 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
113 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
114 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
114 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
115 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
115 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
116 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
116 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
117 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
117 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
118 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
118 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
119 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
119 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
120 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
120 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
121 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
121 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
122 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
122 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
123 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
123 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
124 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
124 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
125 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
125 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
126 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
126 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
127 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
127 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
128 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
128 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
129 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
129 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
130 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
130 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
131 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
131 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
132 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
132 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
133 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
133 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
134 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
134 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
135 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
135 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
136 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
136 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
137 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
137 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
138 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
138 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
139 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
139 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
140 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
140 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
141 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
141 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
142 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
142 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
143 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
143 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
144 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
144 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
145 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
145 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
146 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
146 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
147 pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']);
147 pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']);
148 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
148 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
149 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
149 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
150 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
150 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
151 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
151 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
152 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
152 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
153 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
153 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
154 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
154 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
155 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
155 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
156 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
156 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
157 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
157 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
158 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
158 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
159 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
159 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
160 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
160 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
161 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
161 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
162 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
162 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
163 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
163 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
164 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
164 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
165 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
165 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
166 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
166 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
167 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
167 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
168 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
168 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
169 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
169 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
170 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
170 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
171 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
171 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
172 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
172 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
173 pyroutes.register('favicon', '/favicon.ico', []);
173 pyroutes.register('favicon', '/favicon.ico', []);
174 pyroutes.register('file_preview', '/_file_preview', []);
174 pyroutes.register('file_preview', '/_file_preview', []);
175 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
175 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
176 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
176 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
177 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
177 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
178 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
178 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
179 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
179 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
180 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
180 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
181 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']);
181 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']);
182 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
182 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
183 pyroutes.register('gists_create', '/_admin/gists/create', []);
183 pyroutes.register('gists_create', '/_admin/gists/create', []);
184 pyroutes.register('gists_new', '/_admin/gists/new', []);
184 pyroutes.register('gists_new', '/_admin/gists/new', []);
185 pyroutes.register('gists_show', '/_admin/gists', []);
185 pyroutes.register('gists_show', '/_admin/gists', []);
186 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
186 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
187 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
187 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
188 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
188 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
189 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
189 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
190 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
190 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
191 pyroutes.register('goto_switcher_data', '/_goto_data', []);
191 pyroutes.register('goto_switcher_data', '/_goto_data', []);
192 pyroutes.register('home', '/', []);
192 pyroutes.register('home', '/', []);
193 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
193 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
194 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
194 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
195 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
195 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
196 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
196 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
197 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
197 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
198 pyroutes.register('journal', '/_admin/journal', []);
198 pyroutes.register('journal', '/_admin/journal', []);
199 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
199 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
200 pyroutes.register('journal_public', '/_admin/public_journal', []);
200 pyroutes.register('journal_public', '/_admin/public_journal', []);
201 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
201 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
202 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
202 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
203 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
203 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
204 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
204 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
205 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
205 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
206 pyroutes.register('login', '/_admin/login', []);
206 pyroutes.register('login', '/_admin/login', []);
207 pyroutes.register('logout', '/_admin/logout', []);
207 pyroutes.register('logout', '/_admin/logout', []);
208 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
208 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
209 pyroutes.register('main_page_repos_data', '/_home_repos', []);
209 pyroutes.register('main_page_repos_data', '/_home_repos', []);
210 pyroutes.register('markup_preview', '/_markup_preview', []);
210 pyroutes.register('markup_preview', '/_markup_preview', []);
211 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
211 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
212 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
212 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
213 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
213 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
214 pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []);
214 pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []);
215 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
215 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
216 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
216 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
217 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
217 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
218 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
218 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
219 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
219 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
220 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
220 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
221 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
221 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
222 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
222 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
223 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
223 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
224 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
224 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
225 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
225 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
226 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
226 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
227 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
227 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
228 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
228 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
229 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
229 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
230 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
230 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
231 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
231 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
232 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
232 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
233 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
233 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
234 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
234 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
235 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
235 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
236 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
236 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
237 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
237 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
238 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
238 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
239 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
239 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
240 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
240 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
241 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
241 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
242 pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []);
242 pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []);
243 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
243 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
244 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
244 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
245 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
245 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
246 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
246 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
247 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
247 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
248 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
248 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
249 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
249 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
250 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
250 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
251 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
251 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
252 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
252 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
253 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
253 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
254 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
254 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
255 pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']);
255 pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']);
256 pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']);
256 pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']);
257 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
257 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
258 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
258 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
259 pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']);
259 pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']);
260 pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']);
260 pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']);
261 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
261 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
262 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
262 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
263 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
263 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
264 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
264 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
265 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
265 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
266 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
266 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
267 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
267 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
268 pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']);
268 pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']);
269 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
269 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
270 pyroutes.register('register', '/_admin/register', []);
270 pyroutes.register('register', '/_admin/register', []);
271 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
271 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
272 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
272 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
273 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
273 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
274 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
274 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
275 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
275 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
276 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
276 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
277 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
277 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
278 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
278 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
279 pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []);
279 pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []);
280 pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []);
280 pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []);
281 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
281 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
282 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
282 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
283 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
283 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
284 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
284 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
285 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
285 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
286 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
286 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
287 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
287 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
288 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
288 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
289 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
289 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
290 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
290 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
291 pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']);
291 pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']);
292 pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_history_id)s/history_view', ['repo_name', 'commit_id', 'comment_history_id']);
292 pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/history_view/%(comment_history_id)s', ['repo_name', 'commit_id', 'comment_id', 'comment_history_id']);
293 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
293 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
294 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
294 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
295 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
295 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
296 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
296 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
297 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
297 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
298 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
298 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
299 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
299 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
300 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
300 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
301 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
301 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
302 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
302 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
303 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
303 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
304 pyroutes.register('repo_compare', '/%(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']);
304 pyroutes.register('repo_compare', '/%(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']);
305 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
305 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
306 pyroutes.register('repo_create', '/_admin/repos/create', []);
306 pyroutes.register('repo_create', '/_admin/repos/create', []);
307 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
307 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
308 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
308 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
309 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
309 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
310 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
310 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
311 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
311 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
312 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
312 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
314 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
314 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
315 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
315 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
316 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
316 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
317 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
317 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
318 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
318 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
319 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
319 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
320 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
320 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
321 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
321 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
322 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
322 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
323 pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
323 pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
324 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
324 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
325 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
325 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
326 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
326 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
327 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
327 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
328 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
328 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
329 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
329 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
330 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
330 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
331 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
331 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
332 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
332 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
333 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
333 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
334 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
334 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
335 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
335 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
336 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
336 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
337 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
337 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
338 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
338 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
339 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
339 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
340 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
340 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
341 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
341 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
342 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
342 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
343 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
343 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
344 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
344 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
345 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
345 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
346 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
346 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
347 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
347 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
348 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
348 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
349 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
349 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
350 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
350 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
351 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
351 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
352 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
352 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
353 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
353 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
354 pyroutes.register('repo_list_data', '/_repos', []);
354 pyroutes.register('repo_list_data', '/_repos', []);
355 pyroutes.register('repo_new', '/_admin/repos/new', []);
355 pyroutes.register('repo_new', '/_admin/repos/new', []);
356 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
356 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
357 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
357 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
358 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
358 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
359 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
359 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
360 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
360 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
362 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
362 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
363 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
363 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
364 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
364 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
365 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
365 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
366 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
366 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
367 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
367 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
368 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
368 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
369 pyroutes.register('repos', '/_admin/repos', []);
369 pyroutes.register('repos', '/_admin/repos', []);
370 pyroutes.register('repos_data', '/_admin/repos_data', []);
370 pyroutes.register('repos_data', '/_admin/repos_data', []);
371 pyroutes.register('reset_password', '/_admin/password_reset', []);
371 pyroutes.register('reset_password', '/_admin/password_reset', []);
372 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
372 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
373 pyroutes.register('robots', '/robots.txt', []);
373 pyroutes.register('robots', '/robots.txt', []);
374 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
374 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
375 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
375 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
376 pyroutes.register('search', '/_admin/search', []);
376 pyroutes.register('search', '/_admin/search', []);
377 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
377 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
378 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
378 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
379 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
379 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
380 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
380 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
381 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
381 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
382 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
382 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
383 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
383 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
384 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
384 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
385 pyroutes.register('upload_file', '/_file_store/upload', []);
385 pyroutes.register('upload_file', '/_file_store/upload', []);
386 pyroutes.register('user_autocomplete_data', '/_users', []);
386 pyroutes.register('user_autocomplete_data', '/_users', []);
387 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
387 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
388 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
388 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
389 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
389 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
390 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
390 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
391 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
391 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
392 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
392 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
393 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
393 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
394 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
394 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
395 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
395 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
396 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
396 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
397 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
397 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
398 pyroutes.register('user_groups', '/_admin/user_groups', []);
398 pyroutes.register('user_groups', '/_admin/user_groups', []);
399 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
399 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
400 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
400 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
401 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
401 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
402 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
402 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
403 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
403 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
404 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
404 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
405 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
405 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
406 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
406 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
407 pyroutes.register('users', '/_admin/users', []);
407 pyroutes.register('users', '/_admin/users', []);
408 pyroutes.register('users_create', '/_admin/users/create', []);
408 pyroutes.register('users_create', '/_admin/users/create', []);
409 pyroutes.register('users_data', '/_admin/users_data', []);
409 pyroutes.register('users_data', '/_admin/users_data', []);
410 pyroutes.register('users_new', '/_admin/users/new', []);
410 pyroutes.register('users_new', '/_admin/users/new', []);
411 }
411 }
@@ -1,1644 +1,1645 b''
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
1 // # Copyright (C) 2010-2020 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 var firefoxAnchorFix = function() {
19 var firefoxAnchorFix = function() {
20 // hack to make anchor links behave properly on firefox, in our inline
20 // hack to make anchor links behave properly on firefox, in our inline
21 // comments generation when comments are injected firefox is misbehaving
21 // comments generation when comments are injected firefox is misbehaving
22 // when jumping to anchor links
22 // when jumping to anchor links
23 if (location.href.indexOf('#') > -1) {
23 if (location.href.indexOf('#') > -1) {
24 location.href += '';
24 location.href += '';
25 }
25 }
26 };
26 };
27
27
28
28
29 var linkifyComments = function(comments) {
29 var linkifyComments = function(comments) {
30 var firstCommentId = null;
30 var firstCommentId = null;
31 if (comments) {
31 if (comments) {
32 firstCommentId = $(comments[0]).data('comment-id');
32 firstCommentId = $(comments[0]).data('comment-id');
33 }
33 }
34
34
35 if (firstCommentId){
35 if (firstCommentId){
36 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
36 $('#inline-comments-counter').attr('href', '#comment-' + firstCommentId);
37 }
37 }
38 };
38 };
39
39
40
40
41 var bindToggleButtons = function() {
41 var bindToggleButtons = function() {
42 $('.comment-toggle').on('click', function() {
42 $('.comment-toggle').on('click', function() {
43 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
43 $(this).parent().nextUntil('tr.line').toggle('inline-comments');
44 });
44 });
45 };
45 };
46
46
47
47
48 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
48 var _submitAjaxPOST = function(url, postData, successHandler, failHandler) {
49 failHandler = failHandler || function() {};
49 failHandler = failHandler || function() {};
50 postData = toQueryString(postData);
50 postData = toQueryString(postData);
51 var request = $.ajax({
51 var request = $.ajax({
52 url: url,
52 url: url,
53 type: 'POST',
53 type: 'POST',
54 data: postData,
54 data: postData,
55 headers: {'X-PARTIAL-XHR': true}
55 headers: {'X-PARTIAL-XHR': true}
56 })
56 })
57 .done(function (data) {
57 .done(function (data) {
58 successHandler(data);
58 successHandler(data);
59 })
59 })
60 .fail(function (data, textStatus, errorThrown) {
60 .fail(function (data, textStatus, errorThrown) {
61 failHandler(data, textStatus, errorThrown)
61 failHandler(data, textStatus, errorThrown)
62 });
62 });
63 return request;
63 return request;
64 };
64 };
65
65
66
66
67 /* Comment form for main and inline comments */
67 /* Comment form for main and inline comments */
68 (function(mod) {
68 (function(mod) {
69
69
70 if (typeof exports == "object" && typeof module == "object") {
70 if (typeof exports == "object" && typeof module == "object") {
71 // CommonJS
71 // CommonJS
72 module.exports = mod();
72 module.exports = mod();
73 }
73 }
74 else {
74 else {
75 // Plain browser env
75 // Plain browser env
76 (this || window).CommentForm = mod();
76 (this || window).CommentForm = mod();
77 }
77 }
78
78
79 })(function() {
79 })(function() {
80 "use strict";
80 "use strict";
81
81
82 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id) {
82 function CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id) {
83
83
84 if (!(this instanceof CommentForm)) {
84 if (!(this instanceof CommentForm)) {
85 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id);
85 return new CommentForm(formElement, commitId, pullRequestId, lineNo, initAutocompleteActions, resolvesCommentId, edit, comment_id);
86 }
86 }
87
87
88 // bind the element instance to our Form
88 // bind the element instance to our Form
89 $(formElement).get(0).CommentForm = this;
89 $(formElement).get(0).CommentForm = this;
90
90
91 this.withLineNo = function(selector) {
91 this.withLineNo = function(selector) {
92 var lineNo = this.lineNo;
92 var lineNo = this.lineNo;
93 if (lineNo === undefined) {
93 if (lineNo === undefined) {
94 return selector
94 return selector
95 } else {
95 } else {
96 return selector + '_' + lineNo;
96 return selector + '_' + lineNo;
97 }
97 }
98 };
98 };
99
99
100 this.commitId = commitId;
100 this.commitId = commitId;
101 this.pullRequestId = pullRequestId;
101 this.pullRequestId = pullRequestId;
102 this.lineNo = lineNo;
102 this.lineNo = lineNo;
103 this.initAutocompleteActions = initAutocompleteActions;
103 this.initAutocompleteActions = initAutocompleteActions;
104
104
105 this.previewButton = this.withLineNo('#preview-btn');
105 this.previewButton = this.withLineNo('#preview-btn');
106 this.previewContainer = this.withLineNo('#preview-container');
106 this.previewContainer = this.withLineNo('#preview-container');
107
107
108 this.previewBoxSelector = this.withLineNo('#preview-box');
108 this.previewBoxSelector = this.withLineNo('#preview-box');
109
109
110 this.editButton = this.withLineNo('#edit-btn');
110 this.editButton = this.withLineNo('#edit-btn');
111 this.editContainer = this.withLineNo('#edit-container');
111 this.editContainer = this.withLineNo('#edit-container');
112 this.cancelButton = this.withLineNo('#cancel-btn');
112 this.cancelButton = this.withLineNo('#cancel-btn');
113 this.commentType = this.withLineNo('#comment_type');
113 this.commentType = this.withLineNo('#comment_type');
114
114
115 this.resolvesId = null;
115 this.resolvesId = null;
116 this.resolvesActionId = null;
116 this.resolvesActionId = null;
117
117
118 this.closesPr = '#close_pull_request';
118 this.closesPr = '#close_pull_request';
119
119
120 this.cmBox = this.withLineNo('#text');
120 this.cmBox = this.withLineNo('#text');
121 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
121 this.cm = initCommentBoxCodeMirror(this, this.cmBox, this.initAutocompleteActions);
122
122
123 this.statusChange = this.withLineNo('#change_status');
123 this.statusChange = this.withLineNo('#change_status');
124
124
125 this.submitForm = formElement;
125 this.submitForm = formElement;
126
126
127 this.submitButton = $(this.submitForm).find('.submit-comment-action');
127 this.submitButton = $(this.submitForm).find('.submit-comment-action');
128 this.submitButtonText = this.submitButton.val();
128 this.submitButtonText = this.submitButton.val();
129
129
130 this.submitDraftButton = $(this.submitForm).find('.submit-draft-action');
130 this.submitDraftButton = $(this.submitForm).find('.submit-draft-action');
131 this.submitDraftButtonText = this.submitDraftButton.val();
131 this.submitDraftButtonText = this.submitDraftButton.val();
132
132
133 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
133 this.previewUrl = pyroutes.url('repo_commit_comment_preview',
134 {'repo_name': templateContext.repo_name,
134 {'repo_name': templateContext.repo_name,
135 'commit_id': templateContext.commit_data.commit_id});
135 'commit_id': templateContext.commit_data.commit_id});
136
136
137 if (edit){
137 if (edit){
138 this.submitDraftButton.hide();
138 this.submitDraftButton.hide();
139 this.submitButtonText = _gettext('Update Comment');
139 this.submitButtonText = _gettext('Update Comment');
140 $(this.commentType).prop('disabled', true);
140 $(this.commentType).prop('disabled', true);
141 $(this.commentType).addClass('disabled');
141 $(this.commentType).addClass('disabled');
142 var editInfo =
142 var editInfo =
143 '';
143 '';
144 $(editInfo).insertBefore($(this.editButton).parent());
144 $(editInfo).insertBefore($(this.editButton).parent());
145 }
145 }
146
146
147 if (resolvesCommentId){
147 if (resolvesCommentId){
148 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
148 this.resolvesId = '#resolve_comment_{0}'.format(resolvesCommentId);
149 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
149 this.resolvesActionId = '#resolve_comment_action_{0}'.format(resolvesCommentId);
150 $(this.commentType).prop('disabled', true);
150 $(this.commentType).prop('disabled', true);
151 $(this.commentType).addClass('disabled');
151 $(this.commentType).addClass('disabled');
152
152
153 // disable select
153 // disable select
154 setTimeout(function() {
154 setTimeout(function() {
155 $(self.statusChange).select2('readonly', true);
155 $(self.statusChange).select2('readonly', true);
156 }, 10);
156 }, 10);
157
157
158 var resolvedInfo = (
158 var resolvedInfo = (
159 '<li class="resolve-action">' +
159 '<li class="resolve-action">' +
160 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
160 '<input type="hidden" id="resolve_comment_{0}" name="resolve_comment_{0}" value="{0}">' +
161 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
161 '<button id="resolve_comment_action_{0}" class="resolve-text btn btn-sm" onclick="return Rhodecode.comments.submitResolution({0})">{1} #{0}</button>' +
162 '</li>'
162 '</li>'
163 ).format(resolvesCommentId, _gettext('resolve comment'));
163 ).format(resolvesCommentId, _gettext('resolve comment'));
164 $(resolvedInfo).insertAfter($(this.commentType).parent());
164 $(resolvedInfo).insertAfter($(this.commentType).parent());
165 }
165 }
166
166
167 // based on commitId, or pullRequestId decide where do we submit
167 // based on commitId, or pullRequestId decide where do we submit
168 // out data
168 // out data
169 if (this.commitId){
169 if (this.commitId){
170 var pyurl = 'repo_commit_comment_create';
170 var pyurl = 'repo_commit_comment_create';
171 if(edit){
171 if(edit){
172 pyurl = 'repo_commit_comment_edit';
172 pyurl = 'repo_commit_comment_edit';
173 }
173 }
174 this.submitUrl = pyroutes.url(pyurl,
174 this.submitUrl = pyroutes.url(pyurl,
175 {'repo_name': templateContext.repo_name,
175 {'repo_name': templateContext.repo_name,
176 'commit_id': this.commitId,
176 'commit_id': this.commitId,
177 'comment_id': comment_id});
177 'comment_id': comment_id});
178 this.selfUrl = pyroutes.url('repo_commit',
178 this.selfUrl = pyroutes.url('repo_commit',
179 {'repo_name': templateContext.repo_name,
179 {'repo_name': templateContext.repo_name,
180 'commit_id': this.commitId});
180 'commit_id': this.commitId});
181
181
182 } else if (this.pullRequestId) {
182 } else if (this.pullRequestId) {
183 var pyurl = 'pullrequest_comment_create';
183 var pyurl = 'pullrequest_comment_create';
184 if(edit){
184 if(edit){
185 pyurl = 'pullrequest_comment_edit';
185 pyurl = 'pullrequest_comment_edit';
186 }
186 }
187 this.submitUrl = pyroutes.url(pyurl,
187 this.submitUrl = pyroutes.url(pyurl,
188 {'repo_name': templateContext.repo_name,
188 {'repo_name': templateContext.repo_name,
189 'pull_request_id': this.pullRequestId,
189 'pull_request_id': this.pullRequestId,
190 'comment_id': comment_id});
190 'comment_id': comment_id});
191 this.selfUrl = pyroutes.url('pullrequest_show',
191 this.selfUrl = pyroutes.url('pullrequest_show',
192 {'repo_name': templateContext.repo_name,
192 {'repo_name': templateContext.repo_name,
193 'pull_request_id': this.pullRequestId});
193 'pull_request_id': this.pullRequestId});
194
194
195 } else {
195 } else {
196 throw new Error(
196 throw new Error(
197 'CommentForm requires pullRequestId, or commitId to be specified.')
197 'CommentForm requires pullRequestId, or commitId to be specified.')
198 }
198 }
199
199
200 // FUNCTIONS and helpers
200 // FUNCTIONS and helpers
201 var self = this;
201 var self = this;
202
202
203 this.isInline = function(){
203 this.isInline = function(){
204 return this.lineNo && this.lineNo != 'general';
204 return this.lineNo && this.lineNo != 'general';
205 };
205 };
206
206
207 this.getCmInstance = function(){
207 this.getCmInstance = function(){
208 return this.cm
208 return this.cm
209 };
209 };
210
210
211 this.setPlaceholder = function(placeholder) {
211 this.setPlaceholder = function(placeholder) {
212 var cm = this.getCmInstance();
212 var cm = this.getCmInstance();
213 if (cm){
213 if (cm){
214 cm.setOption('placeholder', placeholder);
214 cm.setOption('placeholder', placeholder);
215 }
215 }
216 };
216 };
217
217
218 this.getCommentStatus = function() {
218 this.getCommentStatus = function() {
219 return $(this.submitForm).find(this.statusChange).val();
219 return $(this.submitForm).find(this.statusChange).val();
220 };
220 };
221
221
222 this.getCommentType = function() {
222 this.getCommentType = function() {
223 return $(this.submitForm).find(this.commentType).val();
223 return $(this.submitForm).find(this.commentType).val();
224 };
224 };
225
225
226 this.getDraftState = function () {
226 this.getDraftState = function () {
227 var submitterElem = $(this.submitForm).find('input[type="submit"].submitter');
227 var submitterElem = $(this.submitForm).find('input[type="submit"].submitter');
228 var data = $(submitterElem).data('isDraft');
228 var data = $(submitterElem).data('isDraft');
229 return data
229 return data
230 }
230 }
231
231
232 this.getResolvesId = function() {
232 this.getResolvesId = function() {
233 return $(this.submitForm).find(this.resolvesId).val() || null;
233 return $(this.submitForm).find(this.resolvesId).val() || null;
234 };
234 };
235
235
236 this.getClosePr = function() {
236 this.getClosePr = function() {
237 return $(this.submitForm).find(this.closesPr).val() || null;
237 return $(this.submitForm).find(this.closesPr).val() || null;
238 };
238 };
239
239
240 this.markCommentResolved = function(resolvedCommentId){
240 this.markCommentResolved = function(resolvedCommentId){
241 Rhodecode.comments.markCommentResolved(resolvedCommentId)
241 Rhodecode.comments.markCommentResolved(resolvedCommentId)
242 };
242 };
243
243
244 this.isAllowedToSubmit = function() {
244 this.isAllowedToSubmit = function() {
245 var commentDisabled = $(this.submitButton).prop('disabled');
245 var commentDisabled = $(this.submitButton).prop('disabled');
246 var draftDisabled = $(this.submitDraftButton).prop('disabled');
246 var draftDisabled = $(this.submitDraftButton).prop('disabled');
247 return !commentDisabled && !draftDisabled;
247 return !commentDisabled && !draftDisabled;
248 };
248 };
249
249
250 this.initStatusChangeSelector = function(){
250 this.initStatusChangeSelector = function(){
251 var formatChangeStatus = function(state, escapeMarkup) {
251 var formatChangeStatus = function(state, escapeMarkup) {
252 var originalOption = state.element;
252 var originalOption = state.element;
253 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
253 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
254 return tmpl
254 return tmpl
255 };
255 };
256 var formatResult = function(result, container, query, escapeMarkup) {
256 var formatResult = function(result, container, query, escapeMarkup) {
257 return formatChangeStatus(result, escapeMarkup);
257 return formatChangeStatus(result, escapeMarkup);
258 };
258 };
259
259
260 var formatSelection = function(data, container, escapeMarkup) {
260 var formatSelection = function(data, container, escapeMarkup) {
261 return formatChangeStatus(data, escapeMarkup);
261 return formatChangeStatus(data, escapeMarkup);
262 };
262 };
263
263
264 $(this.submitForm).find(this.statusChange).select2({
264 $(this.submitForm).find(this.statusChange).select2({
265 placeholder: _gettext('Status Review'),
265 placeholder: _gettext('Status Review'),
266 formatResult: formatResult,
266 formatResult: formatResult,
267 formatSelection: formatSelection,
267 formatSelection: formatSelection,
268 containerCssClass: "drop-menu status_box_menu",
268 containerCssClass: "drop-menu status_box_menu",
269 dropdownCssClass: "drop-menu-dropdown",
269 dropdownCssClass: "drop-menu-dropdown",
270 dropdownAutoWidth: true,
270 dropdownAutoWidth: true,
271 minimumResultsForSearch: -1
271 minimumResultsForSearch: -1
272 });
272 });
273
273
274 $(this.submitForm).find(this.statusChange).on('change', function() {
274 $(this.submitForm).find(this.statusChange).on('change', function() {
275 var status = self.getCommentStatus();
275 var status = self.getCommentStatus();
276
276
277 if (status && !self.isInline()) {
277 if (status && !self.isInline()) {
278 $(self.submitButton).prop('disabled', false);
278 $(self.submitButton).prop('disabled', false);
279 $(self.submitDraftButton).prop('disabled', false);
279 $(self.submitDraftButton).prop('disabled', false);
280 }
280 }
281
281
282 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
282 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
283 self.setPlaceholder(placeholderText)
283 self.setPlaceholder(placeholderText)
284 })
284 })
285 };
285 };
286
286
287 // reset the comment form into it's original state
287 // reset the comment form into it's original state
288 this.resetCommentFormState = function(content) {
288 this.resetCommentFormState = function(content) {
289 content = content || '';
289 content = content || '';
290
290
291 $(this.editContainer).show();
291 $(this.editContainer).show();
292 $(this.editButton).parent().addClass('active');
292 $(this.editButton).parent().addClass('active');
293
293
294 $(this.previewContainer).hide();
294 $(this.previewContainer).hide();
295 $(this.previewButton).parent().removeClass('active');
295 $(this.previewButton).parent().removeClass('active');
296
296
297 this.setActionButtonsDisabled(true);
297 this.setActionButtonsDisabled(true);
298 self.cm.setValue(content);
298 self.cm.setValue(content);
299 self.cm.setOption("readOnly", false);
299 self.cm.setOption("readOnly", false);
300
300
301 if (this.resolvesId) {
301 if (this.resolvesId) {
302 // destroy the resolve action
302 // destroy the resolve action
303 $(this.resolvesId).parent().remove();
303 $(this.resolvesId).parent().remove();
304 }
304 }
305 // reset closingPR flag
305 // reset closingPR flag
306 $('.close-pr-input').remove();
306 $('.close-pr-input').remove();
307
307
308 $(this.statusChange).select2('readonly', false);
308 $(this.statusChange).select2('readonly', false);
309 };
309 };
310
310
311 this.globalSubmitSuccessCallback = function(comment){
311 this.globalSubmitSuccessCallback = function(comment){
312 // default behaviour is to call GLOBAL hook, if it's registered.
312 // default behaviour is to call GLOBAL hook, if it's registered.
313 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
313 if (window.commentFormGlobalSubmitSuccessCallback !== undefined){
314 commentFormGlobalSubmitSuccessCallback(comment);
314 commentFormGlobalSubmitSuccessCallback(comment);
315 }
315 }
316 };
316 };
317
317
318 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
318 this.submitAjaxPOST = function(url, postData, successHandler, failHandler) {
319 return _submitAjaxPOST(url, postData, successHandler, failHandler);
319 return _submitAjaxPOST(url, postData, successHandler, failHandler);
320 };
320 };
321
321
322 // overwrite a submitHandler, we need to do it for inline comments
322 // overwrite a submitHandler, we need to do it for inline comments
323 this.setHandleFormSubmit = function(callback) {
323 this.setHandleFormSubmit = function(callback) {
324 this.handleFormSubmit = callback;
324 this.handleFormSubmit = callback;
325 };
325 };
326
326
327 // overwrite a submitSuccessHandler
327 // overwrite a submitSuccessHandler
328 this.setGlobalSubmitSuccessCallback = function(callback) {
328 this.setGlobalSubmitSuccessCallback = function(callback) {
329 this.globalSubmitSuccessCallback = callback;
329 this.globalSubmitSuccessCallback = callback;
330 };
330 };
331
331
332 // default handler for for submit for main comments
332 // default handler for for submit for main comments
333 this.handleFormSubmit = function() {
333 this.handleFormSubmit = function() {
334 var text = self.cm.getValue();
334 var text = self.cm.getValue();
335 var status = self.getCommentStatus();
335 var status = self.getCommentStatus();
336 var commentType = self.getCommentType();
336 var commentType = self.getCommentType();
337 var isDraft = self.getDraftState();
337 var isDraft = self.getDraftState();
338 var resolvesCommentId = self.getResolvesId();
338 var resolvesCommentId = self.getResolvesId();
339 var closePullRequest = self.getClosePr();
339 var closePullRequest = self.getClosePr();
340
340
341 if (text === "" && !status) {
341 if (text === "" && !status) {
342 return;
342 return;
343 }
343 }
344
344
345 var excludeCancelBtn = false;
345 var excludeCancelBtn = false;
346 var submitEvent = true;
346 var submitEvent = true;
347 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
347 self.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
348 self.cm.setOption("readOnly", true);
348 self.cm.setOption("readOnly", true);
349
349
350 var postData = {
350 var postData = {
351 'text': text,
351 'text': text,
352 'changeset_status': status,
352 'changeset_status': status,
353 'comment_type': commentType,
353 'comment_type': commentType,
354 'csrf_token': CSRF_TOKEN
354 'csrf_token': CSRF_TOKEN
355 };
355 };
356
356
357 if (resolvesCommentId) {
357 if (resolvesCommentId) {
358 postData['resolves_comment_id'] = resolvesCommentId;
358 postData['resolves_comment_id'] = resolvesCommentId;
359 }
359 }
360
360
361 if (closePullRequest) {
361 if (closePullRequest) {
362 postData['close_pull_request'] = true;
362 postData['close_pull_request'] = true;
363 }
363 }
364
364
365 // submitSuccess for general comments
365 // submitSuccess for general comments
366 var submitSuccessCallback = function(json_data) {
366 var submitSuccessCallback = function(json_data) {
367 // reload page if we change status for single commit.
367 // reload page if we change status for single commit.
368 if (status && self.commitId) {
368 if (status && self.commitId) {
369 location.reload(true);
369 location.reload(true);
370 } else {
370 } else {
371 // inject newly created comments, json_data is {<comment_id>: {}}
371 // inject newly created comments, json_data is {<comment_id>: {}}
372 Rhodecode.comments.attachGeneralComment(json_data)
372 Rhodecode.comments.attachGeneralComment(json_data)
373
373
374 self.resetCommentFormState();
374 self.resetCommentFormState();
375 timeagoActivate();
375 timeagoActivate();
376 tooltipActivate();
376 tooltipActivate();
377
377
378 // mark visually which comment was resolved
378 // mark visually which comment was resolved
379 if (resolvesCommentId) {
379 if (resolvesCommentId) {
380 self.markCommentResolved(resolvesCommentId);
380 self.markCommentResolved(resolvesCommentId);
381 }
381 }
382 }
382 }
383
383
384 // run global callback on submit
384 // run global callback on submit
385 self.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
385 self.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
386
386
387 };
387 };
388 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
388 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
389 var prefix = "Error while submitting comment.\n"
389 var prefix = "Error while submitting comment.\n"
390 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
390 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
391 ajaxErrorSwal(message);
391 ajaxErrorSwal(message);
392 self.resetCommentFormState(text);
392 self.resetCommentFormState(text);
393 };
393 };
394 self.submitAjaxPOST(
394 self.submitAjaxPOST(
395 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
395 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
396 };
396 };
397
397
398 this.previewSuccessCallback = function(o) {
398 this.previewSuccessCallback = function(o) {
399 $(self.previewBoxSelector).html(o);
399 $(self.previewBoxSelector).html(o);
400 $(self.previewBoxSelector).removeClass('unloaded');
400 $(self.previewBoxSelector).removeClass('unloaded');
401
401
402 // swap buttons, making preview active
402 // swap buttons, making preview active
403 $(self.previewButton).parent().addClass('active');
403 $(self.previewButton).parent().addClass('active');
404 $(self.editButton).parent().removeClass('active');
404 $(self.editButton).parent().removeClass('active');
405
405
406 // unlock buttons
406 // unlock buttons
407 self.setActionButtonsDisabled(false);
407 self.setActionButtonsDisabled(false);
408 };
408 };
409
409
410 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
410 this.setActionButtonsDisabled = function(state, excludeCancelBtn, submitEvent) {
411 excludeCancelBtn = excludeCancelBtn || false;
411 excludeCancelBtn = excludeCancelBtn || false;
412 submitEvent = submitEvent || false;
412 submitEvent = submitEvent || false;
413
413
414 $(this.editButton).prop('disabled', state);
414 $(this.editButton).prop('disabled', state);
415 $(this.previewButton).prop('disabled', state);
415 $(this.previewButton).prop('disabled', state);
416
416
417 if (!excludeCancelBtn) {
417 if (!excludeCancelBtn) {
418 $(this.cancelButton).prop('disabled', state);
418 $(this.cancelButton).prop('disabled', state);
419 }
419 }
420
420
421 var submitState = state;
421 var submitState = state;
422 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
422 if (!submitEvent && this.getCommentStatus() && !self.isInline()) {
423 // if the value of commit review status is set, we allow
423 // if the value of commit review status is set, we allow
424 // submit button, but only on Main form, isInline means inline
424 // submit button, but only on Main form, isInline means inline
425 submitState = false
425 submitState = false
426 }
426 }
427
427
428 $(this.submitButton).prop('disabled', submitState);
428 $(this.submitButton).prop('disabled', submitState);
429 $(this.submitDraftButton).prop('disabled', submitState);
429 $(this.submitDraftButton).prop('disabled', submitState);
430
430
431 if (submitEvent) {
431 if (submitEvent) {
432 var isDraft = self.getDraftState();
432 var isDraft = self.getDraftState();
433
433
434 if (isDraft) {
434 if (isDraft) {
435 $(this.submitDraftButton).val(_gettext('Saving Draft...'));
435 $(this.submitDraftButton).val(_gettext('Saving Draft...'));
436 } else {
436 } else {
437 $(this.submitButton).val(_gettext('Submitting...'));
437 $(this.submitButton).val(_gettext('Submitting...'));
438 }
438 }
439
439
440 } else {
440 } else {
441 $(this.submitButton).val(this.submitButtonText);
441 $(this.submitButton).val(this.submitButtonText);
442 $(this.submitDraftButton).val(this.submitDraftButtonText);
442 $(this.submitDraftButton).val(this.submitDraftButtonText);
443 }
443 }
444
444
445 };
445 };
446
446
447 // lock preview/edit/submit buttons on load, but exclude cancel button
447 // lock preview/edit/submit buttons on load, but exclude cancel button
448 var excludeCancelBtn = true;
448 var excludeCancelBtn = true;
449 this.setActionButtonsDisabled(true, excludeCancelBtn);
449 this.setActionButtonsDisabled(true, excludeCancelBtn);
450
450
451 // anonymous users don't have access to initialized CM instance
451 // anonymous users don't have access to initialized CM instance
452 if (this.cm !== undefined){
452 if (this.cm !== undefined){
453 this.cm.on('change', function(cMirror) {
453 this.cm.on('change', function(cMirror) {
454 if (cMirror.getValue() === "") {
454 if (cMirror.getValue() === "") {
455 self.setActionButtonsDisabled(true, excludeCancelBtn)
455 self.setActionButtonsDisabled(true, excludeCancelBtn)
456 } else {
456 } else {
457 self.setActionButtonsDisabled(false, excludeCancelBtn)
457 self.setActionButtonsDisabled(false, excludeCancelBtn)
458 }
458 }
459 });
459 });
460 }
460 }
461
461
462 $(this.editButton).on('click', function(e) {
462 $(this.editButton).on('click', function(e) {
463 e.preventDefault();
463 e.preventDefault();
464
464
465 $(self.previewButton).parent().removeClass('active');
465 $(self.previewButton).parent().removeClass('active');
466 $(self.previewContainer).hide();
466 $(self.previewContainer).hide();
467
467
468 $(self.editButton).parent().addClass('active');
468 $(self.editButton).parent().addClass('active');
469 $(self.editContainer).show();
469 $(self.editContainer).show();
470
470
471 });
471 });
472
472
473 $(this.previewButton).on('click', function(e) {
473 $(this.previewButton).on('click', function(e) {
474 e.preventDefault();
474 e.preventDefault();
475 var text = self.cm.getValue();
475 var text = self.cm.getValue();
476
476
477 if (text === "") {
477 if (text === "") {
478 return;
478 return;
479 }
479 }
480
480
481 var postData = {
481 var postData = {
482 'text': text,
482 'text': text,
483 'renderer': templateContext.visual.default_renderer,
483 'renderer': templateContext.visual.default_renderer,
484 'csrf_token': CSRF_TOKEN
484 'csrf_token': CSRF_TOKEN
485 };
485 };
486
486
487 // lock ALL buttons on preview
487 // lock ALL buttons on preview
488 self.setActionButtonsDisabled(true);
488 self.setActionButtonsDisabled(true);
489
489
490 $(self.previewBoxSelector).addClass('unloaded');
490 $(self.previewBoxSelector).addClass('unloaded');
491 $(self.previewBoxSelector).html(_gettext('Loading ...'));
491 $(self.previewBoxSelector).html(_gettext('Loading ...'));
492
492
493 $(self.editContainer).hide();
493 $(self.editContainer).hide();
494 $(self.previewContainer).show();
494 $(self.previewContainer).show();
495
495
496 // by default we reset state of comment preserving the text
496 // by default we reset state of comment preserving the text
497 var previewFailCallback = function(jqXHR, textStatus, errorThrown) {
497 var previewFailCallback = function(jqXHR, textStatus, errorThrown) {
498 var prefix = "Error while preview of comment.\n"
498 var prefix = "Error while preview of comment.\n"
499 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
499 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
500 ajaxErrorSwal(message);
500 ajaxErrorSwal(message);
501
501
502 self.resetCommentFormState(text)
502 self.resetCommentFormState(text)
503 };
503 };
504 self.submitAjaxPOST(
504 self.submitAjaxPOST(
505 self.previewUrl, postData, self.previewSuccessCallback,
505 self.previewUrl, postData, self.previewSuccessCallback,
506 previewFailCallback);
506 previewFailCallback);
507
507
508 $(self.previewButton).parent().addClass('active');
508 $(self.previewButton).parent().addClass('active');
509 $(self.editButton).parent().removeClass('active');
509 $(self.editButton).parent().removeClass('active');
510 });
510 });
511
511
512 $(this.submitForm).submit(function(e) {
512 $(this.submitForm).submit(function(e) {
513 e.preventDefault();
513 e.preventDefault();
514 var allowedToSubmit = self.isAllowedToSubmit();
514 var allowedToSubmit = self.isAllowedToSubmit();
515 if (!allowedToSubmit){
515 if (!allowedToSubmit){
516 return false;
516 return false;
517 }
517 }
518
518
519 self.handleFormSubmit();
519 self.handleFormSubmit();
520 });
520 });
521
521
522 }
522 }
523
523
524 return CommentForm;
524 return CommentForm;
525 });
525 });
526
526
527 /* selector for comment versions */
527 /* selector for comment versions */
528 var initVersionSelector = function(selector, initialData) {
528 var initVersionSelector = function(selector, initialData) {
529
529
530 var formatResult = function(result, container, query, escapeMarkup) {
530 var formatResult = function(result, container, query, escapeMarkup) {
531
531
532 return renderTemplate('commentVersion', {
532 return renderTemplate('commentVersion', {
533 show_disabled: true,
533 show_disabled: true,
534 version: result.comment_version,
534 version: result.comment_version,
535 user_name: result.comment_author_username,
535 user_name: result.comment_author_username,
536 gravatar_url: result.comment_author_gravatar,
536 gravatar_url: result.comment_author_gravatar,
537 size: 16,
537 size: 16,
538 timeago_component: result.comment_created_on,
538 timeago_component: result.comment_created_on,
539 })
539 })
540 };
540 };
541
541
542 $(selector).select2({
542 $(selector).select2({
543 placeholder: "Edited",
543 placeholder: "Edited",
544 containerCssClass: "drop-menu-comment-history",
544 containerCssClass: "drop-menu-comment-history",
545 dropdownCssClass: "drop-menu-dropdown",
545 dropdownCssClass: "drop-menu-dropdown",
546 dropdownAutoWidth: true,
546 dropdownAutoWidth: true,
547 minimumResultsForSearch: -1,
547 minimumResultsForSearch: -1,
548 data: initialData,
548 data: initialData,
549 formatResult: formatResult,
549 formatResult: formatResult,
550 });
550 });
551
551
552 $(selector).on('select2-selecting', function (e) {
552 $(selector).on('select2-selecting', function (e) {
553 // hide the mast as we later do preventDefault()
553 // hide the mast as we later do preventDefault()
554 $("#select2-drop-mask").click();
554 $("#select2-drop-mask").click();
555 e.preventDefault();
555 e.preventDefault();
556 e.choice.action();
556 e.choice.action();
557 });
557 });
558
558
559 $(selector).on("select2-open", function() {
559 $(selector).on("select2-open", function() {
560 timeagoActivate();
560 timeagoActivate();
561 });
561 });
562 };
562 };
563
563
564 /* comments controller */
564 /* comments controller */
565 var CommentsController = function() {
565 var CommentsController = function() {
566 var mainComment = '#text';
566 var mainComment = '#text';
567 var self = this;
567 var self = this;
568
568
569 this.showVersion = function (comment_id, comment_history_id) {
569 this.showVersion = function (comment_id, comment_history_id) {
570
570
571 var historyViewUrl = pyroutes.url(
571 var historyViewUrl = pyroutes.url(
572 'repo_commit_comment_history_view',
572 'repo_commit_comment_history_view',
573 {
573 {
574 'repo_name': templateContext.repo_name,
574 'repo_name': templateContext.repo_name,
575 'commit_id': comment_id,
575 'commit_id': null, // We don't need to check the commit data here...
576 'comment_id': comment_id,
576 'comment_history_id': comment_history_id,
577 'comment_history_id': comment_history_id,
577 }
578 }
578 );
579 );
579 successRenderCommit = function (data) {
580 successRenderCommit = function (data) {
580 SwalNoAnimation.fire({
581 SwalNoAnimation.fire({
581 html: data,
582 html: data,
582 title: '',
583 title: '',
583 });
584 });
584 };
585 };
585 failRenderCommit = function () {
586 failRenderCommit = function () {
586 SwalNoAnimation.fire({
587 SwalNoAnimation.fire({
587 html: 'Error while loading comment history',
588 html: 'Error while loading comment history',
588 title: '',
589 title: '',
589 });
590 });
590 };
591 };
591 _submitAjaxPOST(
592 _submitAjaxPOST(
592 historyViewUrl, {'csrf_token': CSRF_TOKEN},
593 historyViewUrl, {'csrf_token': CSRF_TOKEN},
593 successRenderCommit,
594 successRenderCommit,
594 failRenderCommit
595 failRenderCommit
595 );
596 );
596 };
597 };
597
598
598 this.getLineNumber = function(node) {
599 this.getLineNumber = function(node) {
599 var $node = $(node);
600 var $node = $(node);
600 var lineNo = $node.closest('td').attr('data-line-no');
601 var lineNo = $node.closest('td').attr('data-line-no');
601 if (lineNo === undefined && $node.data('commentInline')){
602 if (lineNo === undefined && $node.data('commentInline')){
602 lineNo = $node.data('commentLineNo')
603 lineNo = $node.data('commentLineNo')
603 }
604 }
604
605
605 return lineNo
606 return lineNo
606 };
607 };
607
608
608 this.scrollToComment = function(node, offset, outdated) {
609 this.scrollToComment = function(node, offset, outdated) {
609 if (offset === undefined) {
610 if (offset === undefined) {
610 offset = 0;
611 offset = 0;
611 }
612 }
612 var outdated = outdated || false;
613 var outdated = outdated || false;
613 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
614 var klass = outdated ? 'div.comment-outdated' : 'div.comment-current';
614
615
615 if (!node) {
616 if (!node) {
616 node = $('.comment-selected');
617 node = $('.comment-selected');
617 if (!node.length) {
618 if (!node.length) {
618 node = $('comment-current')
619 node = $('comment-current')
619 }
620 }
620 }
621 }
621
622
622 $wrapper = $(node).closest('div.comment');
623 $wrapper = $(node).closest('div.comment');
623
624
624 // show hidden comment when referenced.
625 // show hidden comment when referenced.
625 if (!$wrapper.is(':visible')){
626 if (!$wrapper.is(':visible')){
626 $wrapper.show();
627 $wrapper.show();
627 }
628 }
628
629
629 $comment = $(node).closest(klass);
630 $comment = $(node).closest(klass);
630 $comments = $(klass);
631 $comments = $(klass);
631
632
632 $('.comment-selected').removeClass('comment-selected');
633 $('.comment-selected').removeClass('comment-selected');
633
634
634 var nextIdx = $(klass).index($comment) + offset;
635 var nextIdx = $(klass).index($comment) + offset;
635 if (nextIdx >= $comments.length) {
636 if (nextIdx >= $comments.length) {
636 nextIdx = 0;
637 nextIdx = 0;
637 }
638 }
638 var $next = $(klass).eq(nextIdx);
639 var $next = $(klass).eq(nextIdx);
639
640
640 var $cb = $next.closest('.cb');
641 var $cb = $next.closest('.cb');
641 $cb.removeClass('cb-collapsed');
642 $cb.removeClass('cb-collapsed');
642
643
643 var $filediffCollapseState = $cb.closest('.filediff').prev();
644 var $filediffCollapseState = $cb.closest('.filediff').prev();
644 $filediffCollapseState.prop('checked', false);
645 $filediffCollapseState.prop('checked', false);
645 $next.addClass('comment-selected');
646 $next.addClass('comment-selected');
646 scrollToElement($next);
647 scrollToElement($next);
647 return false;
648 return false;
648 };
649 };
649
650
650 this.nextComment = function(node) {
651 this.nextComment = function(node) {
651 return self.scrollToComment(node, 1);
652 return self.scrollToComment(node, 1);
652 };
653 };
653
654
654 this.prevComment = function(node) {
655 this.prevComment = function(node) {
655 return self.scrollToComment(node, -1);
656 return self.scrollToComment(node, -1);
656 };
657 };
657
658
658 this.nextOutdatedComment = function(node) {
659 this.nextOutdatedComment = function(node) {
659 return self.scrollToComment(node, 1, true);
660 return self.scrollToComment(node, 1, true);
660 };
661 };
661
662
662 this.prevOutdatedComment = function(node) {
663 this.prevOutdatedComment = function(node) {
663 return self.scrollToComment(node, -1, true);
664 return self.scrollToComment(node, -1, true);
664 };
665 };
665
666
666 this.cancelComment = function (node) {
667 this.cancelComment = function (node) {
667 var $node = $(node);
668 var $node = $(node);
668 var edit = $(this).attr('edit');
669 var edit = $(this).attr('edit');
669 var $inlineComments = $node.closest('div.inline-comments');
670 var $inlineComments = $node.closest('div.inline-comments');
670
671
671 if (edit) {
672 if (edit) {
672 var $general_comments = null;
673 var $general_comments = null;
673 if (!$inlineComments.length) {
674 if (!$inlineComments.length) {
674 $general_comments = $('#comments');
675 $general_comments = $('#comments');
675 var $comment = $general_comments.parent().find('div.comment:hidden');
676 var $comment = $general_comments.parent().find('div.comment:hidden');
676 // show hidden general comment form
677 // show hidden general comment form
677 $('#cb-comment-general-form-placeholder').show();
678 $('#cb-comment-general-form-placeholder').show();
678 } else {
679 } else {
679 var $comment = $inlineComments.find('div.comment:hidden');
680 var $comment = $inlineComments.find('div.comment:hidden');
680 }
681 }
681 $comment.show();
682 $comment.show();
682 }
683 }
683 var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper')
684 var $replyWrapper = $node.closest('.comment-inline-form').closest('.reply-thread-container-wrapper')
684 $replyWrapper.removeClass('comment-form-active');
685 $replyWrapper.removeClass('comment-form-active');
685
686
686 var lastComment = $inlineComments.find('.comment-inline').last();
687 var lastComment = $inlineComments.find('.comment-inline').last();
687 if ($(lastComment).hasClass('comment-outdated')) {
688 if ($(lastComment).hasClass('comment-outdated')) {
688 $replyWrapper.hide();
689 $replyWrapper.hide();
689 }
690 }
690
691
691 $node.closest('.comment-inline-form').remove();
692 $node.closest('.comment-inline-form').remove();
692 return false;
693 return false;
693 };
694 };
694
695
695 this._deleteComment = function(node) {
696 this._deleteComment = function(node) {
696 var $node = $(node);
697 var $node = $(node);
697 var $td = $node.closest('td');
698 var $td = $node.closest('td');
698 var $comment = $node.closest('.comment');
699 var $comment = $node.closest('.comment');
699 var comment_id = $($comment).data('commentId');
700 var comment_id = $($comment).data('commentId');
700 var isDraft = $($comment).data('commentDraft');
701 var isDraft = $($comment).data('commentDraft');
701
702
702 var pullRequestId = templateContext.pull_request_data.pull_request_id;
703 var pullRequestId = templateContext.pull_request_data.pull_request_id;
703 var commitId = templateContext.commit_data.commit_id;
704 var commitId = templateContext.commit_data.commit_id;
704
705
705 if (pullRequestId) {
706 if (pullRequestId) {
706 var url = pyroutes.url('pullrequest_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
707 var url = pyroutes.url('pullrequest_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
707 } else if (commitId) {
708 } else if (commitId) {
708 var url = pyroutes.url('repo_commit_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "commit_id": commitId})
709 var url = pyroutes.url('repo_commit_comment_delete', {"comment_id": comment_id, "repo_name": templateContext.repo_name, "commit_id": commitId})
709 }
710 }
710
711
711 var postData = {
712 var postData = {
712 'csrf_token': CSRF_TOKEN
713 'csrf_token': CSRF_TOKEN
713 };
714 };
714
715
715 $comment.addClass('comment-deleting');
716 $comment.addClass('comment-deleting');
716 $comment.hide('fast');
717 $comment.hide('fast');
717
718
718 var success = function(response) {
719 var success = function(response) {
719 $comment.remove();
720 $comment.remove();
720
721
721 if (window.updateSticky !== undefined) {
722 if (window.updateSticky !== undefined) {
722 // potentially our comments change the active window size, so we
723 // potentially our comments change the active window size, so we
723 // notify sticky elements
724 // notify sticky elements
724 updateSticky()
725 updateSticky()
725 }
726 }
726
727
727 if (window.refreshAllComments !== undefined && !isDraft) {
728 if (window.refreshAllComments !== undefined && !isDraft) {
728 // if we have this handler, run it, and refresh all comments boxes
729 // if we have this handler, run it, and refresh all comments boxes
729 refreshAllComments()
730 refreshAllComments()
730 }
731 }
731 else if (window.refreshDraftComments !== undefined && isDraft) {
732 else if (window.refreshDraftComments !== undefined && isDraft) {
732 // if we have this handler, run it, and refresh all comments boxes
733 // if we have this handler, run it, and refresh all comments boxes
733 refreshDraftComments();
734 refreshDraftComments();
734 }
735 }
735 return false;
736 return false;
736 };
737 };
737
738
738 var failure = function(jqXHR, textStatus, errorThrown) {
739 var failure = function(jqXHR, textStatus, errorThrown) {
739 var prefix = "Error while deleting this comment.\n"
740 var prefix = "Error while deleting this comment.\n"
740 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
741 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
741 ajaxErrorSwal(message);
742 ajaxErrorSwal(message);
742
743
743 $comment.show('fast');
744 $comment.show('fast');
744 $comment.removeClass('comment-deleting');
745 $comment.removeClass('comment-deleting');
745 return false;
746 return false;
746 };
747 };
747 ajaxPOST(url, postData, success, failure);
748 ajaxPOST(url, postData, success, failure);
748
749
749 }
750 }
750
751
751 this.deleteComment = function(node) {
752 this.deleteComment = function(node) {
752 var $comment = $(node).closest('.comment');
753 var $comment = $(node).closest('.comment');
753 var comment_id = $comment.attr('data-comment-id');
754 var comment_id = $comment.attr('data-comment-id');
754
755
755 SwalNoAnimation.fire({
756 SwalNoAnimation.fire({
756 title: 'Delete this comment?',
757 title: 'Delete this comment?',
757 icon: 'warning',
758 icon: 'warning',
758 showCancelButton: true,
759 showCancelButton: true,
759 confirmButtonText: _gettext('Yes, delete comment #{0}!').format(comment_id),
760 confirmButtonText: _gettext('Yes, delete comment #{0}!').format(comment_id),
760
761
761 }).then(function(result) {
762 }).then(function(result) {
762 if (result.value) {
763 if (result.value) {
763 self._deleteComment(node);
764 self._deleteComment(node);
764 }
765 }
765 })
766 })
766 };
767 };
767
768
768 this._finalizeDrafts = function(commentIds) {
769 this._finalizeDrafts = function(commentIds) {
769
770
770 var pullRequestId = templateContext.pull_request_data.pull_request_id;
771 var pullRequestId = templateContext.pull_request_data.pull_request_id;
771 var commitId = templateContext.commit_data.commit_id;
772 var commitId = templateContext.commit_data.commit_id;
772
773
773 if (pullRequestId) {
774 if (pullRequestId) {
774 var url = pyroutes.url('pullrequest_draft_comments_submit', {"repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
775 var url = pyroutes.url('pullrequest_draft_comments_submit', {"repo_name": templateContext.repo_name, "pull_request_id": pullRequestId})
775 } else if (commitId) {
776 } else if (commitId) {
776 var url = pyroutes.url('commit_draft_comments_submit', {"repo_name": templateContext.repo_name, "commit_id": commitId})
777 var url = pyroutes.url('commit_draft_comments_submit', {"repo_name": templateContext.repo_name, "commit_id": commitId})
777 }
778 }
778
779
779 // remove the drafts so we can lock them before submit.
780 // remove the drafts so we can lock them before submit.
780 $.each(commentIds, function(idx, val){
781 $.each(commentIds, function(idx, val){
781 $('#comment-{0}'.format(val)).remove();
782 $('#comment-{0}'.format(val)).remove();
782 })
783 })
783
784
784 var postData = {'comments': commentIds, 'csrf_token': CSRF_TOKEN};
785 var postData = {'comments': commentIds, 'csrf_token': CSRF_TOKEN};
785
786
786 var submitSuccessCallback = function(json_data) {
787 var submitSuccessCallback = function(json_data) {
787 self.attachInlineComment(json_data);
788 self.attachInlineComment(json_data);
788
789
789 if (window.refreshDraftComments !== undefined) {
790 if (window.refreshDraftComments !== undefined) {
790 // if we have this handler, run it, and refresh all comments boxes
791 // if we have this handler, run it, and refresh all comments boxes
791 refreshDraftComments()
792 refreshDraftComments()
792 }
793 }
793
794
794 if (window.refreshAllComments !== undefined) {
795 if (window.refreshAllComments !== undefined) {
795 // if we have this handler, run it, and refresh all comments boxes
796 // if we have this handler, run it, and refresh all comments boxes
796 refreshAllComments()
797 refreshAllComments()
797 }
798 }
798
799
799 return false;
800 return false;
800 };
801 };
801
802
802 ajaxPOST(url, postData, submitSuccessCallback)
803 ajaxPOST(url, postData, submitSuccessCallback)
803
804
804 }
805 }
805
806
806 this.finalizeDrafts = function(commentIds, callback) {
807 this.finalizeDrafts = function(commentIds, callback) {
807
808
808 SwalNoAnimation.fire({
809 SwalNoAnimation.fire({
809 title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
810 title: _ngettext('Submit {0} draft comment.', 'Submit {0} draft comments.', commentIds.length).format(commentIds.length),
810 icon: 'warning',
811 icon: 'warning',
811 showCancelButton: true,
812 showCancelButton: true,
812 confirmButtonText: _gettext('Yes'),
813 confirmButtonText: _gettext('Yes'),
813
814
814 }).then(function(result) {
815 }).then(function(result) {
815 if (result.value) {
816 if (result.value) {
816 if (callback !== undefined) {
817 if (callback !== undefined) {
817 callback(result)
818 callback(result)
818 }
819 }
819 self._finalizeDrafts(commentIds);
820 self._finalizeDrafts(commentIds);
820 }
821 }
821 })
822 })
822 };
823 };
823
824
824 this.toggleWideMode = function (node) {
825 this.toggleWideMode = function (node) {
825
826
826 if ($('#content').hasClass('wrapper')) {
827 if ($('#content').hasClass('wrapper')) {
827 $('#content').removeClass("wrapper");
828 $('#content').removeClass("wrapper");
828 $('#content').addClass("wide-mode-wrapper");
829 $('#content').addClass("wide-mode-wrapper");
829 $(node).addClass('btn-success');
830 $(node).addClass('btn-success');
830 return true
831 return true
831 } else {
832 } else {
832 $('#content').removeClass("wide-mode-wrapper");
833 $('#content').removeClass("wide-mode-wrapper");
833 $('#content').addClass("wrapper");
834 $('#content').addClass("wrapper");
834 $(node).removeClass('btn-success');
835 $(node).removeClass('btn-success');
835 return false
836 return false
836 }
837 }
837
838
838 };
839 };
839
840
840 /**
841 /**
841 * Turn off/on all comments in file diff
842 * Turn off/on all comments in file diff
842 */
843 */
843 this.toggleDiffComments = function(node) {
844 this.toggleDiffComments = function(node) {
844 // Find closes filediff container
845 // Find closes filediff container
845 var $filediff = $(node).closest('.filediff');
846 var $filediff = $(node).closest('.filediff');
846 if ($(node).hasClass('toggle-on')) {
847 if ($(node).hasClass('toggle-on')) {
847 var show = false;
848 var show = false;
848 } else if ($(node).hasClass('toggle-off')) {
849 } else if ($(node).hasClass('toggle-off')) {
849 var show = true;
850 var show = true;
850 }
851 }
851
852
852 // Toggle each individual comment block, so we can un-toggle single ones
853 // Toggle each individual comment block, so we can un-toggle single ones
853 $.each($filediff.find('.toggle-comment-action'), function(idx, val) {
854 $.each($filediff.find('.toggle-comment-action'), function(idx, val) {
854 self.toggleLineComments($(val), show)
855 self.toggleLineComments($(val), show)
855 })
856 })
856
857
857 // since we change the height of the diff container that has anchor points for upper
858 // since we change the height of the diff container that has anchor points for upper
858 // sticky header, we need to tell it to re-calculate those
859 // sticky header, we need to tell it to re-calculate those
859 if (window.updateSticky !== undefined) {
860 if (window.updateSticky !== undefined) {
860 // potentially our comments change the active window size, so we
861 // potentially our comments change the active window size, so we
861 // notify sticky elements
862 // notify sticky elements
862 updateSticky()
863 updateSticky()
863 }
864 }
864
865
865 return false;
866 return false;
866 }
867 }
867
868
868 this.toggleLineComments = function(node, show) {
869 this.toggleLineComments = function(node, show) {
869
870
870 var trElem = $(node).closest('tr')
871 var trElem = $(node).closest('tr')
871
872
872 if (show === true) {
873 if (show === true) {
873 // mark outdated comments as visible before the toggle;
874 // mark outdated comments as visible before the toggle;
874 $(trElem).find('.comment-outdated').show();
875 $(trElem).find('.comment-outdated').show();
875 $(trElem).removeClass('hide-line-comments');
876 $(trElem).removeClass('hide-line-comments');
876 } else if (show === false) {
877 } else if (show === false) {
877 $(trElem).find('.comment-outdated').hide();
878 $(trElem).find('.comment-outdated').hide();
878 $(trElem).addClass('hide-line-comments');
879 $(trElem).addClass('hide-line-comments');
879 } else {
880 } else {
880 // mark outdated comments as visible before the toggle;
881 // mark outdated comments as visible before the toggle;
881 $(trElem).find('.comment-outdated').show();
882 $(trElem).find('.comment-outdated').show();
882 $(trElem).toggleClass('hide-line-comments');
883 $(trElem).toggleClass('hide-line-comments');
883 }
884 }
884
885
885 // since we change the height of the diff container that has anchor points for upper
886 // since we change the height of the diff container that has anchor points for upper
886 // sticky header, we need to tell it to re-calculate those
887 // sticky header, we need to tell it to re-calculate those
887 if (window.updateSticky !== undefined) {
888 if (window.updateSticky !== undefined) {
888 // potentially our comments change the active window size, so we
889 // potentially our comments change the active window size, so we
889 // notify sticky elements
890 // notify sticky elements
890 updateSticky()
891 updateSticky()
891 }
892 }
892
893
893 };
894 };
894
895
895 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){
896 this.createCommentForm = function(formElement, lineno, placeholderText, initAutocompleteActions, resolvesCommentId, edit, comment_id){
896 var pullRequestId = templateContext.pull_request_data.pull_request_id;
897 var pullRequestId = templateContext.pull_request_data.pull_request_id;
897 var commitId = templateContext.commit_data.commit_id;
898 var commitId = templateContext.commit_data.commit_id;
898
899
899 var commentForm = new CommentForm(
900 var commentForm = new CommentForm(
900 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId, edit, comment_id);
901 formElement, commitId, pullRequestId, lineno, initAutocompleteActions, resolvesCommentId, edit, comment_id);
901 var cm = commentForm.getCmInstance();
902 var cm = commentForm.getCmInstance();
902
903
903 if (resolvesCommentId){
904 if (resolvesCommentId){
904 placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
905 placeholderText = _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}').format(resolvesCommentId);
905 }
906 }
906
907
907 setTimeout(function() {
908 setTimeout(function() {
908 // callbacks
909 // callbacks
909 if (cm !== undefined) {
910 if (cm !== undefined) {
910 commentForm.setPlaceholder(placeholderText);
911 commentForm.setPlaceholder(placeholderText);
911 if (commentForm.isInline()) {
912 if (commentForm.isInline()) {
912 cm.focus();
913 cm.focus();
913 cm.refresh();
914 cm.refresh();
914 }
915 }
915 }
916 }
916 }, 10);
917 }, 10);
917
918
918 // trigger scrolldown to the resolve comment, since it might be away
919 // trigger scrolldown to the resolve comment, since it might be away
919 // from the clicked
920 // from the clicked
920 if (resolvesCommentId){
921 if (resolvesCommentId){
921 var actionNode = $(commentForm.resolvesActionId).offset();
922 var actionNode = $(commentForm.resolvesActionId).offset();
922
923
923 setTimeout(function() {
924 setTimeout(function() {
924 if (actionNode) {
925 if (actionNode) {
925 $('body, html').animate({scrollTop: actionNode.top}, 10);
926 $('body, html').animate({scrollTop: actionNode.top}, 10);
926 }
927 }
927 }, 100);
928 }, 100);
928 }
929 }
929
930
930 // add dropzone support
931 // add dropzone support
931 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
932 var insertAttachmentText = function (cm, attachmentName, attachmentStoreUrl, isRendered) {
932 var renderer = templateContext.visual.default_renderer;
933 var renderer = templateContext.visual.default_renderer;
933 if (renderer == 'rst') {
934 if (renderer == 'rst') {
934 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
935 var attachmentUrl = '`#{0} <{1}>`_'.format(attachmentName, attachmentStoreUrl);
935 if (isRendered){
936 if (isRendered){
936 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
937 attachmentUrl = '\n.. image:: {0}'.format(attachmentStoreUrl);
937 }
938 }
938 } else if (renderer == 'markdown') {
939 } else if (renderer == 'markdown') {
939 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
940 var attachmentUrl = '[{0}]({1})'.format(attachmentName, attachmentStoreUrl);
940 if (isRendered){
941 if (isRendered){
941 attachmentUrl = '!' + attachmentUrl;
942 attachmentUrl = '!' + attachmentUrl;
942 }
943 }
943 } else {
944 } else {
944 var attachmentUrl = '{}'.format(attachmentStoreUrl);
945 var attachmentUrl = '{}'.format(attachmentStoreUrl);
945 }
946 }
946 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
947 cm.replaceRange(attachmentUrl+'\n', CodeMirror.Pos(cm.lastLine()));
947
948
948 return false;
949 return false;
949 };
950 };
950
951
951 //see: https://www.dropzonejs.com/#configuration
952 //see: https://www.dropzonejs.com/#configuration
952 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
953 var storeUrl = pyroutes.url('repo_commit_comment_attachment_upload',
953 {'repo_name': templateContext.repo_name,
954 {'repo_name': templateContext.repo_name,
954 'commit_id': templateContext.commit_data.commit_id})
955 'commit_id': templateContext.commit_data.commit_id})
955
956
956 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
957 var previewTmpl = $(formElement).find('.comment-attachment-uploader-template').get(0);
957 if (previewTmpl !== undefined){
958 if (previewTmpl !== undefined){
958 var selectLink = $(formElement).find('.pick-attachment').get(0);
959 var selectLink = $(formElement).find('.pick-attachment').get(0);
959 $(formElement).find('.comment-attachment-uploader').dropzone({
960 $(formElement).find('.comment-attachment-uploader').dropzone({
960 url: storeUrl,
961 url: storeUrl,
961 headers: {"X-CSRF-Token": CSRF_TOKEN},
962 headers: {"X-CSRF-Token": CSRF_TOKEN},
962 paramName: function () {
963 paramName: function () {
963 return "attachment"
964 return "attachment"
964 }, // The name that will be used to transfer the file
965 }, // The name that will be used to transfer the file
965 clickable: selectLink,
966 clickable: selectLink,
966 parallelUploads: 1,
967 parallelUploads: 1,
967 maxFiles: 10,
968 maxFiles: 10,
968 maxFilesize: templateContext.attachment_store.max_file_size_mb,
969 maxFilesize: templateContext.attachment_store.max_file_size_mb,
969 uploadMultiple: false,
970 uploadMultiple: false,
970 autoProcessQueue: true, // if false queue will not be processed automatically.
971 autoProcessQueue: true, // if false queue will not be processed automatically.
971 createImageThumbnails: false,
972 createImageThumbnails: false,
972 previewTemplate: previewTmpl.innerHTML,
973 previewTemplate: previewTmpl.innerHTML,
973
974
974 accept: function (file, done) {
975 accept: function (file, done) {
975 done();
976 done();
976 },
977 },
977 init: function () {
978 init: function () {
978
979
979 this.on("sending", function (file, xhr, formData) {
980 this.on("sending", function (file, xhr, formData) {
980 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
981 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').hide();
981 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
982 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').show();
982 });
983 });
983
984
984 this.on("success", function (file, response) {
985 this.on("success", function (file, response) {
985 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
986 $(formElement).find('.comment-attachment-uploader').find('.dropzone-text').show();
986 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
987 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
987
988
988 var isRendered = false;
989 var isRendered = false;
989 var ext = file.name.split('.').pop();
990 var ext = file.name.split('.').pop();
990 var imageExts = templateContext.attachment_store.image_ext;
991 var imageExts = templateContext.attachment_store.image_ext;
991 if (imageExts.indexOf(ext) !== -1){
992 if (imageExts.indexOf(ext) !== -1){
992 isRendered = true;
993 isRendered = true;
993 }
994 }
994
995
995 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
996 insertAttachmentText(cm, file.name, response.repo_fqn_access_path, isRendered)
996 });
997 });
997
998
998 this.on("error", function (file, errorMessage, xhr) {
999 this.on("error", function (file, errorMessage, xhr) {
999 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
1000 $(formElement).find('.comment-attachment-uploader').find('.dropzone-upload').hide();
1000
1001
1001 var error = null;
1002 var error = null;
1002
1003
1003 if (xhr !== undefined){
1004 if (xhr !== undefined){
1004 var httpStatus = xhr.status + " " + xhr.statusText;
1005 var httpStatus = xhr.status + " " + xhr.statusText;
1005 if (xhr !== undefined && xhr.status >= 500) {
1006 if (xhr !== undefined && xhr.status >= 500) {
1006 error = httpStatus;
1007 error = httpStatus;
1007 }
1008 }
1008 }
1009 }
1009
1010
1010 if (error === null) {
1011 if (error === null) {
1011 error = errorMessage.error || errorMessage || httpStatus;
1012 error = errorMessage.error || errorMessage || httpStatus;
1012 }
1013 }
1013 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
1014 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
1014
1015
1015 });
1016 });
1016 }
1017 }
1017 });
1018 });
1018 }
1019 }
1019 return commentForm;
1020 return commentForm;
1020 };
1021 };
1021
1022
1022 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
1023 this.createGeneralComment = function (lineNo, placeholderText, resolvesCommentId) {
1023
1024
1024 var tmpl = $('#cb-comment-general-form-template').html();
1025 var tmpl = $('#cb-comment-general-form-template').html();
1025 tmpl = tmpl.format(null, 'general');
1026 tmpl = tmpl.format(null, 'general');
1026 var $form = $(tmpl);
1027 var $form = $(tmpl);
1027
1028
1028 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
1029 var $formPlaceholder = $('#cb-comment-general-form-placeholder');
1029 var curForm = $formPlaceholder.find('form');
1030 var curForm = $formPlaceholder.find('form');
1030 if (curForm){
1031 if (curForm){
1031 curForm.remove();
1032 curForm.remove();
1032 }
1033 }
1033 $formPlaceholder.append($form);
1034 $formPlaceholder.append($form);
1034
1035
1035 var _form = $($form[0]);
1036 var _form = $($form[0]);
1036 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
1037 var autocompleteActions = ['approve', 'reject', 'as_note', 'as_todo'];
1037 var edit = false;
1038 var edit = false;
1038 var comment_id = null;
1039 var comment_id = null;
1039 var commentForm = this.createCommentForm(
1040 var commentForm = this.createCommentForm(
1040 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId, edit, comment_id);
1041 _form, lineNo, placeholderText, autocompleteActions, resolvesCommentId, edit, comment_id);
1041 commentForm.initStatusChangeSelector();
1042 commentForm.initStatusChangeSelector();
1042
1043
1043 return commentForm;
1044 return commentForm;
1044 };
1045 };
1045
1046
1046 this.editComment = function(node, line_no, f_path) {
1047 this.editComment = function(node, line_no, f_path) {
1047 self.edit = true;
1048 self.edit = true;
1048 var $node = $(node);
1049 var $node = $(node);
1049 var $td = $node.closest('td');
1050 var $td = $node.closest('td');
1050
1051
1051 var $comment = $(node).closest('.comment');
1052 var $comment = $(node).closest('.comment');
1052 var comment_id = $($comment).data('commentId');
1053 var comment_id = $($comment).data('commentId');
1053 var isDraft = $($comment).data('commentDraft');
1054 var isDraft = $($comment).data('commentDraft');
1054 var $editForm = null
1055 var $editForm = null
1055
1056
1056 var $comments = $node.closest('div.inline-comments');
1057 var $comments = $node.closest('div.inline-comments');
1057 var $general_comments = null;
1058 var $general_comments = null;
1058
1059
1059 if($comments.length){
1060 if($comments.length){
1060 // inline comments setup
1061 // inline comments setup
1061 $editForm = $comments.find('.comment-inline-form');
1062 $editForm = $comments.find('.comment-inline-form');
1062 line_no = self.getLineNumber(node)
1063 line_no = self.getLineNumber(node)
1063 }
1064 }
1064 else{
1065 else{
1065 // general comments setup
1066 // general comments setup
1066 $comments = $('#comments');
1067 $comments = $('#comments');
1067 $editForm = $comments.find('.comment-inline-form');
1068 $editForm = $comments.find('.comment-inline-form');
1068 line_no = $comment[0].id
1069 line_no = $comment[0].id
1069 $('#cb-comment-general-form-placeholder').hide();
1070 $('#cb-comment-general-form-placeholder').hide();
1070 }
1071 }
1071
1072
1072 if ($editForm.length === 0) {
1073 if ($editForm.length === 0) {
1073
1074
1074 // unhide all comments if they are hidden for a proper REPLY mode
1075 // unhide all comments if they are hidden for a proper REPLY mode
1075 var $filediff = $node.closest('.filediff');
1076 var $filediff = $node.closest('.filediff');
1076 $filediff.removeClass('hide-comments');
1077 $filediff.removeClass('hide-comments');
1077
1078
1078 $editForm = self.createNewFormWrapper(f_path, line_no);
1079 $editForm = self.createNewFormWrapper(f_path, line_no);
1079 if(f_path && line_no) {
1080 if(f_path && line_no) {
1080 $editForm.addClass('comment-inline-form-edit')
1081 $editForm.addClass('comment-inline-form-edit')
1081 }
1082 }
1082
1083
1083 $comment.after($editForm)
1084 $comment.after($editForm)
1084
1085
1085 var _form = $($editForm[0]).find('form');
1086 var _form = $($editForm[0]).find('form');
1086 var autocompleteActions = ['as_note',];
1087 var autocompleteActions = ['as_note',];
1087 var commentForm = this.createCommentForm(
1088 var commentForm = this.createCommentForm(
1088 _form, line_no, '', autocompleteActions, resolvesCommentId,
1089 _form, line_no, '', autocompleteActions, resolvesCommentId,
1089 this.edit, comment_id);
1090 this.edit, comment_id);
1090 var old_comment_text_binary = $comment.attr('data-comment-text');
1091 var old_comment_text_binary = $comment.attr('data-comment-text');
1091 var old_comment_text = b64DecodeUnicode(old_comment_text_binary);
1092 var old_comment_text = b64DecodeUnicode(old_comment_text_binary);
1092 commentForm.cm.setValue(old_comment_text);
1093 commentForm.cm.setValue(old_comment_text);
1093 $comment.hide();
1094 $comment.hide();
1094 tooltipActivate();
1095 tooltipActivate();
1095
1096
1096 // set a CUSTOM submit handler for inline comment edit action.
1097 // set a CUSTOM submit handler for inline comment edit action.
1097 commentForm.setHandleFormSubmit(function(o) {
1098 commentForm.setHandleFormSubmit(function(o) {
1098 var text = commentForm.cm.getValue();
1099 var text = commentForm.cm.getValue();
1099 var commentType = commentForm.getCommentType();
1100 var commentType = commentForm.getCommentType();
1100
1101
1101 if (text === "") {
1102 if (text === "") {
1102 return;
1103 return;
1103 }
1104 }
1104
1105
1105 if (old_comment_text == text) {
1106 if (old_comment_text == text) {
1106 SwalNoAnimation.fire({
1107 SwalNoAnimation.fire({
1107 title: 'Unable to edit comment',
1108 title: 'Unable to edit comment',
1108 html: _gettext('Comment body was not changed.'),
1109 html: _gettext('Comment body was not changed.'),
1109 });
1110 });
1110 return;
1111 return;
1111 }
1112 }
1112 var excludeCancelBtn = false;
1113 var excludeCancelBtn = false;
1113 var submitEvent = true;
1114 var submitEvent = true;
1114 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1115 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1115 commentForm.cm.setOption("readOnly", true);
1116 commentForm.cm.setOption("readOnly", true);
1116
1117
1117 // Read last version known
1118 // Read last version known
1118 var versionSelector = $('#comment_versions_{0}'.format(comment_id));
1119 var versionSelector = $('#comment_versions_{0}'.format(comment_id));
1119 var version = versionSelector.data('lastVersion');
1120 var version = versionSelector.data('lastVersion');
1120
1121
1121 if (!version) {
1122 if (!version) {
1122 version = 0;
1123 version = 0;
1123 }
1124 }
1124
1125
1125 var postData = {
1126 var postData = {
1126 'text': text,
1127 'text': text,
1127 'f_path': f_path,
1128 'f_path': f_path,
1128 'line': line_no,
1129 'line': line_no,
1129 'comment_type': commentType,
1130 'comment_type': commentType,
1130 'draft': isDraft,
1131 'draft': isDraft,
1131 'version': version,
1132 'version': version,
1132 'csrf_token': CSRF_TOKEN
1133 'csrf_token': CSRF_TOKEN
1133 };
1134 };
1134
1135
1135 var submitSuccessCallback = function(json_data) {
1136 var submitSuccessCallback = function(json_data) {
1136 $editForm.remove();
1137 $editForm.remove();
1137 $comment.show();
1138 $comment.show();
1138 var postData = {
1139 var postData = {
1139 'text': text,
1140 'text': text,
1140 'renderer': $comment.attr('data-comment-renderer'),
1141 'renderer': $comment.attr('data-comment-renderer'),
1141 'csrf_token': CSRF_TOKEN
1142 'csrf_token': CSRF_TOKEN
1142 };
1143 };
1143
1144
1144 /* Inject new edited version selector */
1145 /* Inject new edited version selector */
1145 var updateCommentVersionDropDown = function () {
1146 var updateCommentVersionDropDown = function () {
1146 var versionSelectId = '#comment_versions_'+comment_id;
1147 var versionSelectId = '#comment_versions_'+comment_id;
1147 var preLoadVersionData = [
1148 var preLoadVersionData = [
1148 {
1149 {
1149 id: json_data['comment_version'],
1150 id: json_data['comment_version'],
1150 text: "v{0}".format(json_data['comment_version']),
1151 text: "v{0}".format(json_data['comment_version']),
1151 action: function () {
1152 action: function () {
1152 Rhodecode.comments.showVersion(
1153 Rhodecode.comments.showVersion(
1153 json_data['comment_id'],
1154 json_data['comment_id'],
1154 json_data['comment_history_id']
1155 json_data['comment_history_id']
1155 )
1156 )
1156 },
1157 },
1157 comment_version: json_data['comment_version'],
1158 comment_version: json_data['comment_version'],
1158 comment_author_username: json_data['comment_author_username'],
1159 comment_author_username: json_data['comment_author_username'],
1159 comment_author_gravatar: json_data['comment_author_gravatar'],
1160 comment_author_gravatar: json_data['comment_author_gravatar'],
1160 comment_created_on: json_data['comment_created_on'],
1161 comment_created_on: json_data['comment_created_on'],
1161 },
1162 },
1162 ]
1163 ]
1163
1164
1164
1165
1165 if ($(versionSelectId).data('select2')) {
1166 if ($(versionSelectId).data('select2')) {
1166 var oldData = $(versionSelectId).data('select2').opts.data.results;
1167 var oldData = $(versionSelectId).data('select2').opts.data.results;
1167 $(versionSelectId).select2("destroy");
1168 $(versionSelectId).select2("destroy");
1168 preLoadVersionData = oldData.concat(preLoadVersionData)
1169 preLoadVersionData = oldData.concat(preLoadVersionData)
1169 }
1170 }
1170
1171
1171 initVersionSelector(versionSelectId, {results: preLoadVersionData});
1172 initVersionSelector(versionSelectId, {results: preLoadVersionData});
1172
1173
1173 $comment.attr('data-comment-text', utf8ToB64(text));
1174 $comment.attr('data-comment-text', utf8ToB64(text));
1174
1175
1175 var versionSelector = $('#comment_versions_'+comment_id);
1176 var versionSelector = $('#comment_versions_'+comment_id);
1176
1177
1177 // set lastVersion so we know our last edit version
1178 // set lastVersion so we know our last edit version
1178 versionSelector.data('lastVersion', json_data['comment_version'])
1179 versionSelector.data('lastVersion', json_data['comment_version'])
1179 versionSelector.parent().show();
1180 versionSelector.parent().show();
1180 }
1181 }
1181 updateCommentVersionDropDown();
1182 updateCommentVersionDropDown();
1182
1183
1183 // by default we reset state of comment preserving the text
1184 // by default we reset state of comment preserving the text
1184 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
1185 var failRenderCommit = function(jqXHR, textStatus, errorThrown) {
1185 var prefix = "Error while editing this comment.\n"
1186 var prefix = "Error while editing this comment.\n"
1186 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1187 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1187 ajaxErrorSwal(message);
1188 ajaxErrorSwal(message);
1188 };
1189 };
1189
1190
1190 var successRenderCommit = function(o){
1191 var successRenderCommit = function(o){
1191 $comment.show();
1192 $comment.show();
1192 $comment[0].lastElementChild.innerHTML = o;
1193 $comment[0].lastElementChild.innerHTML = o;
1193 };
1194 };
1194
1195
1195 var previewUrl = pyroutes.url(
1196 var previewUrl = pyroutes.url(
1196 'repo_commit_comment_preview',
1197 'repo_commit_comment_preview',
1197 {'repo_name': templateContext.repo_name,
1198 {'repo_name': templateContext.repo_name,
1198 'commit_id': templateContext.commit_data.commit_id});
1199 'commit_id': templateContext.commit_data.commit_id});
1199
1200
1200 _submitAjaxPOST(
1201 _submitAjaxPOST(
1201 previewUrl, postData, successRenderCommit, failRenderCommit
1202 previewUrl, postData, successRenderCommit, failRenderCommit
1202 );
1203 );
1203
1204
1204 try {
1205 try {
1205 var html = json_data.rendered_text;
1206 var html = json_data.rendered_text;
1206 var lineno = json_data.line_no;
1207 var lineno = json_data.line_no;
1207 var target_id = json_data.target_id;
1208 var target_id = json_data.target_id;
1208
1209
1209 $comments.find('.cb-comment-add-button').before(html);
1210 $comments.find('.cb-comment-add-button').before(html);
1210
1211
1211 // run global callback on submit
1212 // run global callback on submit
1212 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1213 commentForm.globalSubmitSuccessCallback({draft: isDraft, comment_id: comment_id});
1213
1214
1214 } catch (e) {
1215 } catch (e) {
1215 console.error(e);
1216 console.error(e);
1216 }
1217 }
1217
1218
1218 // re trigger the linkification of next/prev navigation
1219 // re trigger the linkification of next/prev navigation
1219 linkifyComments($('.inline-comment-injected'));
1220 linkifyComments($('.inline-comment-injected'));
1220 timeagoActivate();
1221 timeagoActivate();
1221 tooltipActivate();
1222 tooltipActivate();
1222
1223
1223 if (window.updateSticky !== undefined) {
1224 if (window.updateSticky !== undefined) {
1224 // potentially our comments change the active window size, so we
1225 // potentially our comments change the active window size, so we
1225 // notify sticky elements
1226 // notify sticky elements
1226 updateSticky()
1227 updateSticky()
1227 }
1228 }
1228
1229
1229 if (window.refreshAllComments !== undefined && !isDraft) {
1230 if (window.refreshAllComments !== undefined && !isDraft) {
1230 // if we have this handler, run it, and refresh all comments boxes
1231 // if we have this handler, run it, and refresh all comments boxes
1231 refreshAllComments()
1232 refreshAllComments()
1232 }
1233 }
1233 else if (window.refreshDraftComments !== undefined && isDraft) {
1234 else if (window.refreshDraftComments !== undefined && isDraft) {
1234 // if we have this handler, run it, and refresh all comments boxes
1235 // if we have this handler, run it, and refresh all comments boxes
1235 refreshDraftComments();
1236 refreshDraftComments();
1236 }
1237 }
1237
1238
1238 commentForm.setActionButtonsDisabled(false);
1239 commentForm.setActionButtonsDisabled(false);
1239
1240
1240 };
1241 };
1241
1242
1242 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1243 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1243 var prefix = "Error while editing comment.\n"
1244 var prefix = "Error while editing comment.\n"
1244 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1245 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1245 if (jqXHR.status == 409){
1246 if (jqXHR.status == 409){
1246 message = 'This comment was probably changed somewhere else. Please reload the content of this comment.'
1247 message = 'This comment was probably changed somewhere else. Please reload the content of this comment.'
1247 ajaxErrorSwal(message, 'Comment version mismatch.');
1248 ajaxErrorSwal(message, 'Comment version mismatch.');
1248 } else {
1249 } else {
1249 ajaxErrorSwal(message);
1250 ajaxErrorSwal(message);
1250 }
1251 }
1251
1252
1252 commentForm.resetCommentFormState(text)
1253 commentForm.resetCommentFormState(text)
1253 };
1254 };
1254 commentForm.submitAjaxPOST(
1255 commentForm.submitAjaxPOST(
1255 commentForm.submitUrl, postData,
1256 commentForm.submitUrl, postData,
1256 submitSuccessCallback,
1257 submitSuccessCallback,
1257 submitFailCallback);
1258 submitFailCallback);
1258 });
1259 });
1259 }
1260 }
1260
1261
1261 $editForm.addClass('comment-inline-form-open');
1262 $editForm.addClass('comment-inline-form-open');
1262 };
1263 };
1263
1264
1264 this.attachComment = function(json_data) {
1265 this.attachComment = function(json_data) {
1265 var self = this;
1266 var self = this;
1266 $.each(json_data, function(idx, val) {
1267 $.each(json_data, function(idx, val) {
1267 var json_data_elem = [val]
1268 var json_data_elem = [val]
1268 var isInline = val.comment_f_path && val.comment_lineno
1269 var isInline = val.comment_f_path && val.comment_lineno
1269
1270
1270 if (isInline) {
1271 if (isInline) {
1271 self.attachInlineComment(json_data_elem)
1272 self.attachInlineComment(json_data_elem)
1272 } else {
1273 } else {
1273 self.attachGeneralComment(json_data_elem)
1274 self.attachGeneralComment(json_data_elem)
1274 }
1275 }
1275 })
1276 })
1276
1277
1277 }
1278 }
1278
1279
1279 this.attachGeneralComment = function(json_data) {
1280 this.attachGeneralComment = function(json_data) {
1280 $.each(json_data, function(idx, val) {
1281 $.each(json_data, function(idx, val) {
1281 $('#injected_page_comments').append(val.rendered_text);
1282 $('#injected_page_comments').append(val.rendered_text);
1282 })
1283 })
1283 }
1284 }
1284
1285
1285 this.attachInlineComment = function(json_data) {
1286 this.attachInlineComment = function(json_data) {
1286
1287
1287 $.each(json_data, function (idx, val) {
1288 $.each(json_data, function (idx, val) {
1288 var line_qry = '*[data-line-no="{0}"]'.format(val.line_no);
1289 var line_qry = '*[data-line-no="{0}"]'.format(val.line_no);
1289 var html = val.rendered_text;
1290 var html = val.rendered_text;
1290 var $inlineComments = $('#' + val.target_id)
1291 var $inlineComments = $('#' + val.target_id)
1291 .find(line_qry)
1292 .find(line_qry)
1292 .find('.inline-comments');
1293 .find('.inline-comments');
1293
1294
1294 var lastComment = $inlineComments.find('.comment-inline').last();
1295 var lastComment = $inlineComments.find('.comment-inline').last();
1295
1296
1296 if (lastComment.length === 0) {
1297 if (lastComment.length === 0) {
1297 // first comment, we append simply
1298 // first comment, we append simply
1298 $inlineComments.find('.reply-thread-container-wrapper').before(html);
1299 $inlineComments.find('.reply-thread-container-wrapper').before(html);
1299 } else {
1300 } else {
1300 $(lastComment).after(html)
1301 $(lastComment).after(html)
1301 }
1302 }
1302
1303
1303 })
1304 })
1304
1305
1305 };
1306 };
1306
1307
1307 this.createNewFormWrapper = function(f_path, line_no) {
1308 this.createNewFormWrapper = function(f_path, line_no) {
1308 // create a new reply HTML form from template
1309 // create a new reply HTML form from template
1309 var tmpl = $('#cb-comment-inline-form-template').html();
1310 var tmpl = $('#cb-comment-inline-form-template').html();
1310 tmpl = tmpl.format(escapeHtml(f_path), line_no);
1311 tmpl = tmpl.format(escapeHtml(f_path), line_no);
1311 return $(tmpl);
1312 return $(tmpl);
1312 }
1313 }
1313
1314
1314 this.markCommentResolved = function(commentId) {
1315 this.markCommentResolved = function(commentId) {
1315 $('#comment-label-{0}'.format(commentId)).find('.resolved').show();
1316 $('#comment-label-{0}'.format(commentId)).find('.resolved').show();
1316 $('#comment-label-{0}'.format(commentId)).find('.resolve').hide();
1317 $('#comment-label-{0}'.format(commentId)).find('.resolve').hide();
1317 };
1318 };
1318
1319
1319 this.createComment = function(node, f_path, line_no, resolutionComment) {
1320 this.createComment = function(node, f_path, line_no, resolutionComment) {
1320 self.edit = false;
1321 self.edit = false;
1321 var $node = $(node);
1322 var $node = $(node);
1322 var $td = $node.closest('td');
1323 var $td = $node.closest('td');
1323 var resolvesCommentId = resolutionComment || null;
1324 var resolvesCommentId = resolutionComment || null;
1324
1325
1325 var $replyForm = $td.find('.comment-inline-form');
1326 var $replyForm = $td.find('.comment-inline-form');
1326
1327
1327 // if form isn't existing, we're generating a new one and injecting it.
1328 // if form isn't existing, we're generating a new one and injecting it.
1328 if ($replyForm.length === 0) {
1329 if ($replyForm.length === 0) {
1329
1330
1330 // unhide/expand all comments if they are hidden for a proper REPLY mode
1331 // unhide/expand all comments if they are hidden for a proper REPLY mode
1331 self.toggleLineComments($node, true);
1332 self.toggleLineComments($node, true);
1332
1333
1333 $replyForm = self.createNewFormWrapper(f_path, line_no);
1334 $replyForm = self.createNewFormWrapper(f_path, line_no);
1334
1335
1335 var $comments = $td.find('.inline-comments');
1336 var $comments = $td.find('.inline-comments');
1336
1337
1337 // There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first
1338 // There aren't any comments, we init the `.inline-comments` with `reply-thread-container` first
1338 if ($comments.length===0) {
1339 if ($comments.length===0) {
1339 var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(escapeHtml(f_path), line_no)
1340 var replBtn = '<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, \'{0}\', \'{1}\', null)">Reply...</button>'.format(escapeHtml(f_path), line_no)
1340 var $reply_container = $('#cb-comments-inline-container-template')
1341 var $reply_container = $('#cb-comments-inline-container-template')
1341 $reply_container.find('button.cb-comment-add-button').replaceWith(replBtn);
1342 $reply_container.find('button.cb-comment-add-button').replaceWith(replBtn);
1342 $td.append($($reply_container).html());
1343 $td.append($($reply_container).html());
1343 }
1344 }
1344
1345
1345 // default comment button exists, so we prepend the form for leaving initial comment
1346 // default comment button exists, so we prepend the form for leaving initial comment
1346 $td.find('.cb-comment-add-button').before($replyForm);
1347 $td.find('.cb-comment-add-button').before($replyForm);
1347 // set marker, that we have a open form
1348 // set marker, that we have a open form
1348 var $replyWrapper = $td.find('.reply-thread-container-wrapper')
1349 var $replyWrapper = $td.find('.reply-thread-container-wrapper')
1349 $replyWrapper.addClass('comment-form-active');
1350 $replyWrapper.addClass('comment-form-active');
1350
1351
1351 var lastComment = $comments.find('.comment-inline').last();
1352 var lastComment = $comments.find('.comment-inline').last();
1352 if ($(lastComment).hasClass('comment-outdated')) {
1353 if ($(lastComment).hasClass('comment-outdated')) {
1353 $replyWrapper.show();
1354 $replyWrapper.show();
1354 }
1355 }
1355
1356
1356 var _form = $($replyForm[0]).find('form');
1357 var _form = $($replyForm[0]).find('form');
1357 var autocompleteActions = ['as_note', 'as_todo'];
1358 var autocompleteActions = ['as_note', 'as_todo'];
1358 var comment_id=null;
1359 var comment_id=null;
1359 var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no);
1360 var placeholderText = _gettext('Leave a comment on file {0} line {1}.').format(f_path, line_no);
1360 var commentForm = self.createCommentForm(
1361 var commentForm = self.createCommentForm(
1361 _form, line_no, placeholderText, autocompleteActions, resolvesCommentId,
1362 _form, line_no, placeholderText, autocompleteActions, resolvesCommentId,
1362 self.edit, comment_id);
1363 self.edit, comment_id);
1363
1364
1364 // set a CUSTOM submit handler for inline comments.
1365 // set a CUSTOM submit handler for inline comments.
1365 commentForm.setHandleFormSubmit(function(o) {
1366 commentForm.setHandleFormSubmit(function(o) {
1366 var text = commentForm.cm.getValue();
1367 var text = commentForm.cm.getValue();
1367 var commentType = commentForm.getCommentType();
1368 var commentType = commentForm.getCommentType();
1368 var resolvesCommentId = commentForm.getResolvesId();
1369 var resolvesCommentId = commentForm.getResolvesId();
1369 var isDraft = commentForm.getDraftState();
1370 var isDraft = commentForm.getDraftState();
1370
1371
1371 if (text === "") {
1372 if (text === "") {
1372 return;
1373 return;
1373 }
1374 }
1374
1375
1375 if (line_no === undefined) {
1376 if (line_no === undefined) {
1376 alert('Error: unable to fetch line number for this inline comment !');
1377 alert('Error: unable to fetch line number for this inline comment !');
1377 return;
1378 return;
1378 }
1379 }
1379
1380
1380 if (f_path === undefined) {
1381 if (f_path === undefined) {
1381 alert('Error: unable to fetch file path for this inline comment !');
1382 alert('Error: unable to fetch file path for this inline comment !');
1382 return;
1383 return;
1383 }
1384 }
1384
1385
1385 var excludeCancelBtn = false;
1386 var excludeCancelBtn = false;
1386 var submitEvent = true;
1387 var submitEvent = true;
1387 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1388 commentForm.setActionButtonsDisabled(true, excludeCancelBtn, submitEvent);
1388 commentForm.cm.setOption("readOnly", true);
1389 commentForm.cm.setOption("readOnly", true);
1389 var postData = {
1390 var postData = {
1390 'text': text,
1391 'text': text,
1391 'f_path': f_path,
1392 'f_path': f_path,
1392 'line': line_no,
1393 'line': line_no,
1393 'comment_type': commentType,
1394 'comment_type': commentType,
1394 'draft': isDraft,
1395 'draft': isDraft,
1395 'csrf_token': CSRF_TOKEN
1396 'csrf_token': CSRF_TOKEN
1396 };
1397 };
1397 if (resolvesCommentId){
1398 if (resolvesCommentId){
1398 postData['resolves_comment_id'] = resolvesCommentId;
1399 postData['resolves_comment_id'] = resolvesCommentId;
1399 }
1400 }
1400
1401
1401 // submitSuccess for inline commits
1402 // submitSuccess for inline commits
1402 var submitSuccessCallback = function(json_data) {
1403 var submitSuccessCallback = function(json_data) {
1403
1404
1404 $replyForm.remove();
1405 $replyForm.remove();
1405 $td.find('.reply-thread-container-wrapper').removeClass('comment-form-active');
1406 $td.find('.reply-thread-container-wrapper').removeClass('comment-form-active');
1406
1407
1407 try {
1408 try {
1408
1409
1409 // inject newly created comments, json_data is {<comment_id>: {}}
1410 // inject newly created comments, json_data is {<comment_id>: {}}
1410 self.attachInlineComment(json_data)
1411 self.attachInlineComment(json_data)
1411
1412
1412 //mark visually which comment was resolved
1413 //mark visually which comment was resolved
1413 if (resolvesCommentId) {
1414 if (resolvesCommentId) {
1414 self.markCommentResolved(resolvesCommentId);
1415 self.markCommentResolved(resolvesCommentId);
1415 }
1416 }
1416
1417
1417 // run global callback on submit
1418 // run global callback on submit
1418 commentForm.globalSubmitSuccessCallback({
1419 commentForm.globalSubmitSuccessCallback({
1419 draft: isDraft,
1420 draft: isDraft,
1420 comment_id: comment_id
1421 comment_id: comment_id
1421 });
1422 });
1422
1423
1423 } catch (e) {
1424 } catch (e) {
1424 console.error(e);
1425 console.error(e);
1425 }
1426 }
1426
1427
1427 if (window.updateSticky !== undefined) {
1428 if (window.updateSticky !== undefined) {
1428 // potentially our comments change the active window size, so we
1429 // potentially our comments change the active window size, so we
1429 // notify sticky elements
1430 // notify sticky elements
1430 updateSticky()
1431 updateSticky()
1431 }
1432 }
1432
1433
1433 if (window.refreshAllComments !== undefined && !isDraft) {
1434 if (window.refreshAllComments !== undefined && !isDraft) {
1434 // if we have this handler, run it, and refresh all comments boxes
1435 // if we have this handler, run it, and refresh all comments boxes
1435 refreshAllComments()
1436 refreshAllComments()
1436 }
1437 }
1437 else if (window.refreshDraftComments !== undefined && isDraft) {
1438 else if (window.refreshDraftComments !== undefined && isDraft) {
1438 // if we have this handler, run it, and refresh all comments boxes
1439 // if we have this handler, run it, and refresh all comments boxes
1439 refreshDraftComments();
1440 refreshDraftComments();
1440 }
1441 }
1441
1442
1442 commentForm.setActionButtonsDisabled(false);
1443 commentForm.setActionButtonsDisabled(false);
1443
1444
1444 // re trigger the linkification of next/prev navigation
1445 // re trigger the linkification of next/prev navigation
1445 linkifyComments($('.inline-comment-injected'));
1446 linkifyComments($('.inline-comment-injected'));
1446 timeagoActivate();
1447 timeagoActivate();
1447 tooltipActivate();
1448 tooltipActivate();
1448 };
1449 };
1449
1450
1450 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1451 var submitFailCallback = function(jqXHR, textStatus, errorThrown) {
1451 var prefix = "Error while submitting comment.\n"
1452 var prefix = "Error while submitting comment.\n"
1452 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1453 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1453 ajaxErrorSwal(message);
1454 ajaxErrorSwal(message);
1454 commentForm.resetCommentFormState(text)
1455 commentForm.resetCommentFormState(text)
1455 };
1456 };
1456
1457
1457 commentForm.submitAjaxPOST(
1458 commentForm.submitAjaxPOST(
1458 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
1459 commentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
1459 });
1460 });
1460 }
1461 }
1461
1462
1462 // Finally "open" our reply form, since we know there are comments and we have the "attached" old form
1463 // Finally "open" our reply form, since we know there are comments and we have the "attached" old form
1463 $replyForm.addClass('comment-inline-form-open');
1464 $replyForm.addClass('comment-inline-form-open');
1464 tooltipActivate();
1465 tooltipActivate();
1465 };
1466 };
1466
1467
1467 this.createResolutionComment = function(commentId){
1468 this.createResolutionComment = function(commentId){
1468 // hide the trigger text
1469 // hide the trigger text
1469 $('#resolve-comment-{0}'.format(commentId)).hide();
1470 $('#resolve-comment-{0}'.format(commentId)).hide();
1470
1471
1471 var comment = $('#comment-'+commentId);
1472 var comment = $('#comment-'+commentId);
1472 var commentData = comment.data();
1473 var commentData = comment.data();
1473
1474
1474 if (commentData.commentInline) {
1475 if (commentData.commentInline) {
1475 var f_path = commentData.commentFPath;
1476 var f_path = commentData.commentFPath;
1476 var line_no = commentData.commentLineNo;
1477 var line_no = commentData.commentLineNo;
1477 this.createComment(comment, f_path, line_no, commentId)
1478 this.createComment(comment, f_path, line_no, commentId)
1478 } else {
1479 } else {
1479 this.createGeneralComment('general', "$placeholder", commentId)
1480 this.createGeneralComment('general', "$placeholder", commentId)
1480 }
1481 }
1481
1482
1482 return false;
1483 return false;
1483 };
1484 };
1484
1485
1485 this.submitResolution = function(commentId){
1486 this.submitResolution = function(commentId){
1486 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
1487 var form = $('#resolve_comment_{0}'.format(commentId)).closest('form');
1487 var commentForm = form.get(0).CommentForm;
1488 var commentForm = form.get(0).CommentForm;
1488
1489
1489 var cm = commentForm.getCmInstance();
1490 var cm = commentForm.getCmInstance();
1490 var renderer = templateContext.visual.default_renderer;
1491 var renderer = templateContext.visual.default_renderer;
1491 if (renderer == 'rst'){
1492 if (renderer == 'rst'){
1492 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
1493 var commentUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentForm.selfUrl);
1493 } else if (renderer == 'markdown') {
1494 } else if (renderer == 'markdown') {
1494 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
1495 var commentUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentForm.selfUrl);
1495 } else {
1496 } else {
1496 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
1497 var commentUrl = '{1}#comment-{0}'.format(commentId, commentForm.selfUrl);
1497 }
1498 }
1498
1499
1499 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
1500 cm.setValue(_gettext('TODO from comment {0} was fixed.').format(commentUrl));
1500 form.submit();
1501 form.submit();
1501 return false;
1502 return false;
1502 };
1503 };
1503
1504
1504 this.resolveTodo = function (elem, todoId) {
1505 this.resolveTodo = function (elem, todoId) {
1505 var commentId = todoId;
1506 var commentId = todoId;
1506
1507
1507 SwalNoAnimation.fire({
1508 SwalNoAnimation.fire({
1508 title: 'Resolve TODO {0}'.format(todoId),
1509 title: 'Resolve TODO {0}'.format(todoId),
1509 showCancelButton: true,
1510 showCancelButton: true,
1510 confirmButtonText: _gettext('Yes'),
1511 confirmButtonText: _gettext('Yes'),
1511 showLoaderOnConfirm: true,
1512 showLoaderOnConfirm: true,
1512
1513
1513 allowOutsideClick: function () {
1514 allowOutsideClick: function () {
1514 !Swal.isLoading()
1515 !Swal.isLoading()
1515 },
1516 },
1516 preConfirm: function () {
1517 preConfirm: function () {
1517 var comment = $('#comment-' + commentId);
1518 var comment = $('#comment-' + commentId);
1518 var commentData = comment.data();
1519 var commentData = comment.data();
1519
1520
1520 var f_path = null
1521 var f_path = null
1521 var line_no = null
1522 var line_no = null
1522 if (commentData.commentInline) {
1523 if (commentData.commentInline) {
1523 f_path = commentData.commentFPath;
1524 f_path = commentData.commentFPath;
1524 line_no = commentData.commentLineNo;
1525 line_no = commentData.commentLineNo;
1525 }
1526 }
1526
1527
1527 var renderer = templateContext.visual.default_renderer;
1528 var renderer = templateContext.visual.default_renderer;
1528 var commentBoxUrl = '{1}#comment-{0}'.format(commentId);
1529 var commentBoxUrl = '{1}#comment-{0}'.format(commentId);
1529
1530
1530 // Pull request case
1531 // Pull request case
1531 if (templateContext.pull_request_data.pull_request_id !== null) {
1532 if (templateContext.pull_request_data.pull_request_id !== null) {
1532 var commentUrl = pyroutes.url('pullrequest_comment_create',
1533 var commentUrl = pyroutes.url('pullrequest_comment_create',
1533 {
1534 {
1534 'repo_name': templateContext.repo_name,
1535 'repo_name': templateContext.repo_name,
1535 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1536 'pull_request_id': templateContext.pull_request_data.pull_request_id,
1536 'comment_id': commentId
1537 'comment_id': commentId
1537 });
1538 });
1538 } else {
1539 } else {
1539 var commentUrl = pyroutes.url('repo_commit_comment_create',
1540 var commentUrl = pyroutes.url('repo_commit_comment_create',
1540 {
1541 {
1541 'repo_name': templateContext.repo_name,
1542 'repo_name': templateContext.repo_name,
1542 'commit_id': templateContext.commit_data.commit_id,
1543 'commit_id': templateContext.commit_data.commit_id,
1543 'comment_id': commentId
1544 'comment_id': commentId
1544 });
1545 });
1545 }
1546 }
1546
1547
1547 if (renderer === 'rst') {
1548 if (renderer === 'rst') {
1548 commentBoxUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentUrl);
1549 commentBoxUrl = '`#{0} <{1}#comment-{0}>`_'.format(commentId, commentUrl);
1549 } else if (renderer === 'markdown') {
1550 } else if (renderer === 'markdown') {
1550 commentBoxUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentUrl);
1551 commentBoxUrl = '[#{0}]({1}#comment-{0})'.format(commentId, commentUrl);
1551 }
1552 }
1552 var resolveText = _gettext('TODO from comment {0} was fixed.').format(commentBoxUrl);
1553 var resolveText = _gettext('TODO from comment {0} was fixed.').format(commentBoxUrl);
1553
1554
1554 var postData = {
1555 var postData = {
1555 text: resolveText,
1556 text: resolveText,
1556 comment_type: 'note',
1557 comment_type: 'note',
1557 draft: false,
1558 draft: false,
1558 csrf_token: CSRF_TOKEN,
1559 csrf_token: CSRF_TOKEN,
1559 resolves_comment_id: commentId
1560 resolves_comment_id: commentId
1560 }
1561 }
1561 if (commentData.commentInline) {
1562 if (commentData.commentInline) {
1562 postData['f_path'] = f_path;
1563 postData['f_path'] = f_path;
1563 postData['line'] = line_no;
1564 postData['line'] = line_no;
1564 }
1565 }
1565
1566
1566 return new Promise(function (resolve, reject) {
1567 return new Promise(function (resolve, reject) {
1567 $.ajax({
1568 $.ajax({
1568 type: 'POST',
1569 type: 'POST',
1569 data: postData,
1570 data: postData,
1570 url: commentUrl,
1571 url: commentUrl,
1571 headers: {'X-PARTIAL-XHR': true}
1572 headers: {'X-PARTIAL-XHR': true}
1572 })
1573 })
1573 .done(function (data) {
1574 .done(function (data) {
1574 resolve(data);
1575 resolve(data);
1575 })
1576 })
1576 .fail(function (jqXHR, textStatus, errorThrown) {
1577 .fail(function (jqXHR, textStatus, errorThrown) {
1577 var prefix = "Error while resolving TODO.\n"
1578 var prefix = "Error while resolving TODO.\n"
1578 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1579 var message = formatErrorMessage(jqXHR, textStatus, errorThrown, prefix);
1579 ajaxErrorSwal(message);
1580 ajaxErrorSwal(message);
1580 });
1581 });
1581 })
1582 })
1582 }
1583 }
1583
1584
1584 })
1585 })
1585 .then(function (result) {
1586 .then(function (result) {
1586 var success = function (json_data) {
1587 var success = function (json_data) {
1587 resolvesCommentId = commentId;
1588 resolvesCommentId = commentId;
1588 var commentResolved = json_data[Object.keys(json_data)[0]]
1589 var commentResolved = json_data[Object.keys(json_data)[0]]
1589
1590
1590 try {
1591 try {
1591
1592
1592 if (commentResolved.f_path) {
1593 if (commentResolved.f_path) {
1593 // inject newly created comments, json_data is {<comment_id>: {}}
1594 // inject newly created comments, json_data is {<comment_id>: {}}
1594 self.attachInlineComment(json_data)
1595 self.attachInlineComment(json_data)
1595 } else {
1596 } else {
1596 self.attachGeneralComment(json_data)
1597 self.attachGeneralComment(json_data)
1597 }
1598 }
1598
1599
1599 //mark visually which comment was resolved
1600 //mark visually which comment was resolved
1600 if (resolvesCommentId) {
1601 if (resolvesCommentId) {
1601 self.markCommentResolved(resolvesCommentId);
1602 self.markCommentResolved(resolvesCommentId);
1602 }
1603 }
1603
1604
1604 // run global callback on submit
1605 // run global callback on submit
1605 if (window.commentFormGlobalSubmitSuccessCallback !== undefined) {
1606 if (window.commentFormGlobalSubmitSuccessCallback !== undefined) {
1606 commentFormGlobalSubmitSuccessCallback({
1607 commentFormGlobalSubmitSuccessCallback({
1607 draft: false,
1608 draft: false,
1608 comment_id: commentId
1609 comment_id: commentId
1609 });
1610 });
1610 }
1611 }
1611
1612
1612 } catch (e) {
1613 } catch (e) {
1613 console.error(e);
1614 console.error(e);
1614 }
1615 }
1615
1616
1616 if (window.updateSticky !== undefined) {
1617 if (window.updateSticky !== undefined) {
1617 // potentially our comments change the active window size, so we
1618 // potentially our comments change the active window size, so we
1618 // notify sticky elements
1619 // notify sticky elements
1619 updateSticky()
1620 updateSticky()
1620 }
1621 }
1621
1622
1622 if (window.refreshAllComments !== undefined) {
1623 if (window.refreshAllComments !== undefined) {
1623 // if we have this handler, run it, and refresh all comments boxes
1624 // if we have this handler, run it, and refresh all comments boxes
1624 refreshAllComments()
1625 refreshAllComments()
1625 }
1626 }
1626 // re trigger the linkification of next/prev navigation
1627 // re trigger the linkification of next/prev navigation
1627 linkifyComments($('.inline-comment-injected'));
1628 linkifyComments($('.inline-comment-injected'));
1628 timeagoActivate();
1629 timeagoActivate();
1629 tooltipActivate();
1630 tooltipActivate();
1630 };
1631 };
1631
1632
1632 if (result.value) {
1633 if (result.value) {
1633 $(elem).remove();
1634 $(elem).remove();
1634 success(result.value)
1635 success(result.value)
1635 }
1636 }
1636 })
1637 })
1637 };
1638 };
1638
1639
1639 };
1640 };
1640
1641
1641 window.commentHelp = function(renderer) {
1642 window.commentHelp = function(renderer) {
1642 var funcData = {'renderer': renderer}
1643 var funcData = {'renderer': renderer}
1643 return renderTemplate('commentHelpHovercard', funcData)
1644 return renderTemplate('commentHelpHovercard', funcData)
1644 }
1645 }
General Comments 0
You need to be logged in to leave comments. Login now