##// END OF EJS Templates
users: use two distinct actions for user password reset....
marcink -
r3378:f96b7591 default
parent child Browse files
Show More
@@ -1,442 +1,446 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 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
21
22 from rhodecode.apps._base import ADMIN_PREFIX
22 from rhodecode.apps._base import ADMIN_PREFIX
23
23
24
24
25 def admin_routes(config):
25 def admin_routes(config):
26 """
26 """
27 Admin prefixed routes
27 Admin prefixed routes
28 """
28 """
29
29
30 config.add_route(
30 config.add_route(
31 name='admin_audit_logs',
31 name='admin_audit_logs',
32 pattern='/audit_logs')
32 pattern='/audit_logs')
33
33
34 config.add_route(
34 config.add_route(
35 name='admin_audit_log_entry',
35 name='admin_audit_log_entry',
36 pattern='/audit_logs/{audit_log_id}')
36 pattern='/audit_logs/{audit_log_id}')
37
37
38 config.add_route(
38 config.add_route(
39 name='pull_requests_global_0', # backward compat
39 name='pull_requests_global_0', # backward compat
40 pattern='/pull_requests/{pull_request_id:\d+}')
40 pattern='/pull_requests/{pull_request_id:\d+}')
41 config.add_route(
41 config.add_route(
42 name='pull_requests_global_1', # backward compat
42 name='pull_requests_global_1', # backward compat
43 pattern='/pull-requests/{pull_request_id:\d+}')
43 pattern='/pull-requests/{pull_request_id:\d+}')
44 config.add_route(
44 config.add_route(
45 name='pull_requests_global',
45 name='pull_requests_global',
46 pattern='/pull-request/{pull_request_id:\d+}')
46 pattern='/pull-request/{pull_request_id:\d+}')
47
47
48 config.add_route(
48 config.add_route(
49 name='admin_settings_open_source',
49 name='admin_settings_open_source',
50 pattern='/settings/open_source')
50 pattern='/settings/open_source')
51 config.add_route(
51 config.add_route(
52 name='admin_settings_vcs_svn_generate_cfg',
52 name='admin_settings_vcs_svn_generate_cfg',
53 pattern='/settings/vcs/svn_generate_cfg')
53 pattern='/settings/vcs/svn_generate_cfg')
54
54
55 config.add_route(
55 config.add_route(
56 name='admin_settings_system',
56 name='admin_settings_system',
57 pattern='/settings/system')
57 pattern='/settings/system')
58 config.add_route(
58 config.add_route(
59 name='admin_settings_system_update',
59 name='admin_settings_system_update',
60 pattern='/settings/system/updates')
60 pattern='/settings/system/updates')
61
61
62 config.add_route(
62 config.add_route(
63 name='admin_settings_exception_tracker',
63 name='admin_settings_exception_tracker',
64 pattern='/settings/exceptions')
64 pattern='/settings/exceptions')
65 config.add_route(
65 config.add_route(
66 name='admin_settings_exception_tracker_delete_all',
66 name='admin_settings_exception_tracker_delete_all',
67 pattern='/settings/exceptions/delete')
67 pattern='/settings/exceptions/delete')
68 config.add_route(
68 config.add_route(
69 name='admin_settings_exception_tracker_show',
69 name='admin_settings_exception_tracker_show',
70 pattern='/settings/exceptions/{exception_id}')
70 pattern='/settings/exceptions/{exception_id}')
71 config.add_route(
71 config.add_route(
72 name='admin_settings_exception_tracker_delete',
72 name='admin_settings_exception_tracker_delete',
73 pattern='/settings/exceptions/{exception_id}/delete')
73 pattern='/settings/exceptions/{exception_id}/delete')
74
74
75 config.add_route(
75 config.add_route(
76 name='admin_settings_sessions',
76 name='admin_settings_sessions',
77 pattern='/settings/sessions')
77 pattern='/settings/sessions')
78 config.add_route(
78 config.add_route(
79 name='admin_settings_sessions_cleanup',
79 name='admin_settings_sessions_cleanup',
80 pattern='/settings/sessions/cleanup')
80 pattern='/settings/sessions/cleanup')
81
81
82 config.add_route(
82 config.add_route(
83 name='admin_settings_process_management',
83 name='admin_settings_process_management',
84 pattern='/settings/process_management')
84 pattern='/settings/process_management')
85 config.add_route(
85 config.add_route(
86 name='admin_settings_process_management_data',
86 name='admin_settings_process_management_data',
87 pattern='/settings/process_management/data')
87 pattern='/settings/process_management/data')
88 config.add_route(
88 config.add_route(
89 name='admin_settings_process_management_signal',
89 name='admin_settings_process_management_signal',
90 pattern='/settings/process_management/signal')
90 pattern='/settings/process_management/signal')
91 config.add_route(
91 config.add_route(
92 name='admin_settings_process_management_master_signal',
92 name='admin_settings_process_management_master_signal',
93 pattern='/settings/process_management/master_signal')
93 pattern='/settings/process_management/master_signal')
94
94
95 # default settings
95 # default settings
96 config.add_route(
96 config.add_route(
97 name='admin_defaults_repositories',
97 name='admin_defaults_repositories',
98 pattern='/defaults/repositories')
98 pattern='/defaults/repositories')
99 config.add_route(
99 config.add_route(
100 name='admin_defaults_repositories_update',
100 name='admin_defaults_repositories_update',
101 pattern='/defaults/repositories/update')
101 pattern='/defaults/repositories/update')
102
102
103 # admin settings
103 # admin settings
104
104
105 config.add_route(
105 config.add_route(
106 name='admin_settings',
106 name='admin_settings',
107 pattern='/settings')
107 pattern='/settings')
108 config.add_route(
108 config.add_route(
109 name='admin_settings_update',
109 name='admin_settings_update',
110 pattern='/settings/update')
110 pattern='/settings/update')
111
111
112 config.add_route(
112 config.add_route(
113 name='admin_settings_global',
113 name='admin_settings_global',
114 pattern='/settings/global')
114 pattern='/settings/global')
115 config.add_route(
115 config.add_route(
116 name='admin_settings_global_update',
116 name='admin_settings_global_update',
117 pattern='/settings/global/update')
117 pattern='/settings/global/update')
118
118
119 config.add_route(
119 config.add_route(
120 name='admin_settings_vcs',
120 name='admin_settings_vcs',
121 pattern='/settings/vcs')
121 pattern='/settings/vcs')
122 config.add_route(
122 config.add_route(
123 name='admin_settings_vcs_update',
123 name='admin_settings_vcs_update',
124 pattern='/settings/vcs/update')
124 pattern='/settings/vcs/update')
125 config.add_route(
125 config.add_route(
126 name='admin_settings_vcs_svn_pattern_delete',
126 name='admin_settings_vcs_svn_pattern_delete',
127 pattern='/settings/vcs/svn_pattern_delete')
127 pattern='/settings/vcs/svn_pattern_delete')
128
128
129 config.add_route(
129 config.add_route(
130 name='admin_settings_mapping',
130 name='admin_settings_mapping',
131 pattern='/settings/mapping')
131 pattern='/settings/mapping')
132 config.add_route(
132 config.add_route(
133 name='admin_settings_mapping_update',
133 name='admin_settings_mapping_update',
134 pattern='/settings/mapping/update')
134 pattern='/settings/mapping/update')
135
135
136 config.add_route(
136 config.add_route(
137 name='admin_settings_visual',
137 name='admin_settings_visual',
138 pattern='/settings/visual')
138 pattern='/settings/visual')
139 config.add_route(
139 config.add_route(
140 name='admin_settings_visual_update',
140 name='admin_settings_visual_update',
141 pattern='/settings/visual/update')
141 pattern='/settings/visual/update')
142
142
143
143
144 config.add_route(
144 config.add_route(
145 name='admin_settings_issuetracker',
145 name='admin_settings_issuetracker',
146 pattern='/settings/issue-tracker')
146 pattern='/settings/issue-tracker')
147 config.add_route(
147 config.add_route(
148 name='admin_settings_issuetracker_update',
148 name='admin_settings_issuetracker_update',
149 pattern='/settings/issue-tracker/update')
149 pattern='/settings/issue-tracker/update')
150 config.add_route(
150 config.add_route(
151 name='admin_settings_issuetracker_test',
151 name='admin_settings_issuetracker_test',
152 pattern='/settings/issue-tracker/test')
152 pattern='/settings/issue-tracker/test')
153 config.add_route(
153 config.add_route(
154 name='admin_settings_issuetracker_delete',
154 name='admin_settings_issuetracker_delete',
155 pattern='/settings/issue-tracker/delete')
155 pattern='/settings/issue-tracker/delete')
156
156
157 config.add_route(
157 config.add_route(
158 name='admin_settings_email',
158 name='admin_settings_email',
159 pattern='/settings/email')
159 pattern='/settings/email')
160 config.add_route(
160 config.add_route(
161 name='admin_settings_email_update',
161 name='admin_settings_email_update',
162 pattern='/settings/email/update')
162 pattern='/settings/email/update')
163
163
164 config.add_route(
164 config.add_route(
165 name='admin_settings_hooks',
165 name='admin_settings_hooks',
166 pattern='/settings/hooks')
166 pattern='/settings/hooks')
167 config.add_route(
167 config.add_route(
168 name='admin_settings_hooks_update',
168 name='admin_settings_hooks_update',
169 pattern='/settings/hooks/update')
169 pattern='/settings/hooks/update')
170 config.add_route(
170 config.add_route(
171 name='admin_settings_hooks_delete',
171 name='admin_settings_hooks_delete',
172 pattern='/settings/hooks/delete')
172 pattern='/settings/hooks/delete')
173
173
174 config.add_route(
174 config.add_route(
175 name='admin_settings_search',
175 name='admin_settings_search',
176 pattern='/settings/search')
176 pattern='/settings/search')
177
177
178 config.add_route(
178 config.add_route(
179 name='admin_settings_labs',
179 name='admin_settings_labs',
180 pattern='/settings/labs')
180 pattern='/settings/labs')
181 config.add_route(
181 config.add_route(
182 name='admin_settings_labs_update',
182 name='admin_settings_labs_update',
183 pattern='/settings/labs/update')
183 pattern='/settings/labs/update')
184
184
185 # Automation EE feature
185 # Automation EE feature
186 config.add_route(
186 config.add_route(
187 'admin_settings_automation',
187 'admin_settings_automation',
188 pattern=ADMIN_PREFIX + '/settings/automation')
188 pattern=ADMIN_PREFIX + '/settings/automation')
189
189
190 # global permissions
190 # global permissions
191
191
192 config.add_route(
192 config.add_route(
193 name='admin_permissions_application',
193 name='admin_permissions_application',
194 pattern='/permissions/application')
194 pattern='/permissions/application')
195 config.add_route(
195 config.add_route(
196 name='admin_permissions_application_update',
196 name='admin_permissions_application_update',
197 pattern='/permissions/application/update')
197 pattern='/permissions/application/update')
198
198
199 config.add_route(
199 config.add_route(
200 name='admin_permissions_global',
200 name='admin_permissions_global',
201 pattern='/permissions/global')
201 pattern='/permissions/global')
202 config.add_route(
202 config.add_route(
203 name='admin_permissions_global_update',
203 name='admin_permissions_global_update',
204 pattern='/permissions/global/update')
204 pattern='/permissions/global/update')
205
205
206 config.add_route(
206 config.add_route(
207 name='admin_permissions_object',
207 name='admin_permissions_object',
208 pattern='/permissions/object')
208 pattern='/permissions/object')
209 config.add_route(
209 config.add_route(
210 name='admin_permissions_object_update',
210 name='admin_permissions_object_update',
211 pattern='/permissions/object/update')
211 pattern='/permissions/object/update')
212
212
213 # Branch perms EE feature
213 # Branch perms EE feature
214 config.add_route(
214 config.add_route(
215 name='admin_permissions_branch',
215 name='admin_permissions_branch',
216 pattern='/permissions/branch')
216 pattern='/permissions/branch')
217
217
218 config.add_route(
218 config.add_route(
219 name='admin_permissions_ips',
219 name='admin_permissions_ips',
220 pattern='/permissions/ips')
220 pattern='/permissions/ips')
221
221
222 config.add_route(
222 config.add_route(
223 name='admin_permissions_overview',
223 name='admin_permissions_overview',
224 pattern='/permissions/overview')
224 pattern='/permissions/overview')
225
225
226 config.add_route(
226 config.add_route(
227 name='admin_permissions_auth_token_access',
227 name='admin_permissions_auth_token_access',
228 pattern='/permissions/auth_token_access')
228 pattern='/permissions/auth_token_access')
229
229
230 config.add_route(
230 config.add_route(
231 name='admin_permissions_ssh_keys',
231 name='admin_permissions_ssh_keys',
232 pattern='/permissions/ssh_keys')
232 pattern='/permissions/ssh_keys')
233 config.add_route(
233 config.add_route(
234 name='admin_permissions_ssh_keys_data',
234 name='admin_permissions_ssh_keys_data',
235 pattern='/permissions/ssh_keys/data')
235 pattern='/permissions/ssh_keys/data')
236 config.add_route(
236 config.add_route(
237 name='admin_permissions_ssh_keys_update',
237 name='admin_permissions_ssh_keys_update',
238 pattern='/permissions/ssh_keys/update')
238 pattern='/permissions/ssh_keys/update')
239
239
240 # users admin
240 # users admin
241 config.add_route(
241 config.add_route(
242 name='users',
242 name='users',
243 pattern='/users')
243 pattern='/users')
244
244
245 config.add_route(
245 config.add_route(
246 name='users_data',
246 name='users_data',
247 pattern='/users_data')
247 pattern='/users_data')
248
248
249 config.add_route(
249 config.add_route(
250 name='users_create',
250 name='users_create',
251 pattern='/users/create')
251 pattern='/users/create')
252
252
253 config.add_route(
253 config.add_route(
254 name='users_new',
254 name='users_new',
255 pattern='/users/new')
255 pattern='/users/new')
256
256
257 # user management
257 # user management
258 config.add_route(
258 config.add_route(
259 name='user_edit',
259 name='user_edit',
260 pattern='/users/{user_id:\d+}/edit',
260 pattern='/users/{user_id:\d+}/edit',
261 user_route=True)
261 user_route=True)
262 config.add_route(
262 config.add_route(
263 name='user_edit_advanced',
263 name='user_edit_advanced',
264 pattern='/users/{user_id:\d+}/edit/advanced',
264 pattern='/users/{user_id:\d+}/edit/advanced',
265 user_route=True)
265 user_route=True)
266 config.add_route(
266 config.add_route(
267 name='user_edit_global_perms',
267 name='user_edit_global_perms',
268 pattern='/users/{user_id:\d+}/edit/global_permissions',
268 pattern='/users/{user_id:\d+}/edit/global_permissions',
269 user_route=True)
269 user_route=True)
270 config.add_route(
270 config.add_route(
271 name='user_edit_global_perms_update',
271 name='user_edit_global_perms_update',
272 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
272 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
273 user_route=True)
273 user_route=True)
274 config.add_route(
274 config.add_route(
275 name='user_update',
275 name='user_update',
276 pattern='/users/{user_id:\d+}/update',
276 pattern='/users/{user_id:\d+}/update',
277 user_route=True)
277 user_route=True)
278 config.add_route(
278 config.add_route(
279 name='user_delete',
279 name='user_delete',
280 pattern='/users/{user_id:\d+}/delete',
280 pattern='/users/{user_id:\d+}/delete',
281 user_route=True)
281 user_route=True)
282 config.add_route(
282 config.add_route(
283 name='user_force_password_reset',
283 name='user_enable_force_password_reset',
284 pattern='/users/{user_id:\d+}/password_reset',
284 pattern='/users/{user_id:\d+}/password_reset_enable',
285 user_route=True)
286 config.add_route(
287 name='user_disable_force_password_reset',
288 pattern='/users/{user_id:\d+}/password_reset_disable',
285 user_route=True)
289 user_route=True)
286 config.add_route(
290 config.add_route(
287 name='user_create_personal_repo_group',
291 name='user_create_personal_repo_group',
288 pattern='/users/{user_id:\d+}/create_repo_group',
292 pattern='/users/{user_id:\d+}/create_repo_group',
289 user_route=True)
293 user_route=True)
290
294
291 # user auth tokens
295 # user auth tokens
292 config.add_route(
296 config.add_route(
293 name='edit_user_auth_tokens',
297 name='edit_user_auth_tokens',
294 pattern='/users/{user_id:\d+}/edit/auth_tokens',
298 pattern='/users/{user_id:\d+}/edit/auth_tokens',
295 user_route=True)
299 user_route=True)
296 config.add_route(
300 config.add_route(
297 name='edit_user_auth_tokens_add',
301 name='edit_user_auth_tokens_add',
298 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
302 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
299 user_route=True)
303 user_route=True)
300 config.add_route(
304 config.add_route(
301 name='edit_user_auth_tokens_delete',
305 name='edit_user_auth_tokens_delete',
302 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
306 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
303 user_route=True)
307 user_route=True)
304
308
305 # user ssh keys
309 # user ssh keys
306 config.add_route(
310 config.add_route(
307 name='edit_user_ssh_keys',
311 name='edit_user_ssh_keys',
308 pattern='/users/{user_id:\d+}/edit/ssh_keys',
312 pattern='/users/{user_id:\d+}/edit/ssh_keys',
309 user_route=True)
313 user_route=True)
310 config.add_route(
314 config.add_route(
311 name='edit_user_ssh_keys_generate_keypair',
315 name='edit_user_ssh_keys_generate_keypair',
312 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
316 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
313 user_route=True)
317 user_route=True)
314 config.add_route(
318 config.add_route(
315 name='edit_user_ssh_keys_add',
319 name='edit_user_ssh_keys_add',
316 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
320 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
317 user_route=True)
321 user_route=True)
318 config.add_route(
322 config.add_route(
319 name='edit_user_ssh_keys_delete',
323 name='edit_user_ssh_keys_delete',
320 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
324 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
321 user_route=True)
325 user_route=True)
322
326
323 # user emails
327 # user emails
324 config.add_route(
328 config.add_route(
325 name='edit_user_emails',
329 name='edit_user_emails',
326 pattern='/users/{user_id:\d+}/edit/emails',
330 pattern='/users/{user_id:\d+}/edit/emails',
327 user_route=True)
331 user_route=True)
328 config.add_route(
332 config.add_route(
329 name='edit_user_emails_add',
333 name='edit_user_emails_add',
330 pattern='/users/{user_id:\d+}/edit/emails/new',
334 pattern='/users/{user_id:\d+}/edit/emails/new',
331 user_route=True)
335 user_route=True)
332 config.add_route(
336 config.add_route(
333 name='edit_user_emails_delete',
337 name='edit_user_emails_delete',
334 pattern='/users/{user_id:\d+}/edit/emails/delete',
338 pattern='/users/{user_id:\d+}/edit/emails/delete',
335 user_route=True)
339 user_route=True)
336
340
337 # user IPs
341 # user IPs
338 config.add_route(
342 config.add_route(
339 name='edit_user_ips',
343 name='edit_user_ips',
340 pattern='/users/{user_id:\d+}/edit/ips',
344 pattern='/users/{user_id:\d+}/edit/ips',
341 user_route=True)
345 user_route=True)
342 config.add_route(
346 config.add_route(
343 name='edit_user_ips_add',
347 name='edit_user_ips_add',
344 pattern='/users/{user_id:\d+}/edit/ips/new',
348 pattern='/users/{user_id:\d+}/edit/ips/new',
345 user_route_with_default=True) # enabled for default user too
349 user_route_with_default=True) # enabled for default user too
346 config.add_route(
350 config.add_route(
347 name='edit_user_ips_delete',
351 name='edit_user_ips_delete',
348 pattern='/users/{user_id:\d+}/edit/ips/delete',
352 pattern='/users/{user_id:\d+}/edit/ips/delete',
349 user_route_with_default=True) # enabled for default user too
353 user_route_with_default=True) # enabled for default user too
350
354
351 # user perms
355 # user perms
352 config.add_route(
356 config.add_route(
353 name='edit_user_perms_summary',
357 name='edit_user_perms_summary',
354 pattern='/users/{user_id:\d+}/edit/permissions_summary',
358 pattern='/users/{user_id:\d+}/edit/permissions_summary',
355 user_route=True)
359 user_route=True)
356 config.add_route(
360 config.add_route(
357 name='edit_user_perms_summary_json',
361 name='edit_user_perms_summary_json',
358 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
362 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
359 user_route=True)
363 user_route=True)
360
364
361 # user user groups management
365 # user user groups management
362 config.add_route(
366 config.add_route(
363 name='edit_user_groups_management',
367 name='edit_user_groups_management',
364 pattern='/users/{user_id:\d+}/edit/groups_management',
368 pattern='/users/{user_id:\d+}/edit/groups_management',
365 user_route=True)
369 user_route=True)
366
370
367 config.add_route(
371 config.add_route(
368 name='edit_user_groups_management_updates',
372 name='edit_user_groups_management_updates',
369 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
373 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
370 user_route=True)
374 user_route=True)
371
375
372 # user audit logs
376 # user audit logs
373 config.add_route(
377 config.add_route(
374 name='edit_user_audit_logs',
378 name='edit_user_audit_logs',
375 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
379 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
376
380
377 # user caches
381 # user caches
378 config.add_route(
382 config.add_route(
379 name='edit_user_caches',
383 name='edit_user_caches',
380 pattern='/users/{user_id:\d+}/edit/caches',
384 pattern='/users/{user_id:\d+}/edit/caches',
381 user_route=True)
385 user_route=True)
382 config.add_route(
386 config.add_route(
383 name='edit_user_caches_update',
387 name='edit_user_caches_update',
384 pattern='/users/{user_id:\d+}/edit/caches/update',
388 pattern='/users/{user_id:\d+}/edit/caches/update',
385 user_route=True)
389 user_route=True)
386
390
387 # user-groups admin
391 # user-groups admin
388 config.add_route(
392 config.add_route(
389 name='user_groups',
393 name='user_groups',
390 pattern='/user_groups')
394 pattern='/user_groups')
391
395
392 config.add_route(
396 config.add_route(
393 name='user_groups_data',
397 name='user_groups_data',
394 pattern='/user_groups_data')
398 pattern='/user_groups_data')
395
399
396 config.add_route(
400 config.add_route(
397 name='user_groups_new',
401 name='user_groups_new',
398 pattern='/user_groups/new')
402 pattern='/user_groups/new')
399
403
400 config.add_route(
404 config.add_route(
401 name='user_groups_create',
405 name='user_groups_create',
402 pattern='/user_groups/create')
406 pattern='/user_groups/create')
403
407
404 # repos admin
408 # repos admin
405 config.add_route(
409 config.add_route(
406 name='repos',
410 name='repos',
407 pattern='/repos')
411 pattern='/repos')
408
412
409 config.add_route(
413 config.add_route(
410 name='repo_new',
414 name='repo_new',
411 pattern='/repos/new')
415 pattern='/repos/new')
412
416
413 config.add_route(
417 config.add_route(
414 name='repo_create',
418 name='repo_create',
415 pattern='/repos/create')
419 pattern='/repos/create')
416
420
417 # repo groups admin
421 # repo groups admin
418 config.add_route(
422 config.add_route(
419 name='repo_groups',
423 name='repo_groups',
420 pattern='/repo_groups')
424 pattern='/repo_groups')
421
425
422 config.add_route(
426 config.add_route(
423 name='repo_group_new',
427 name='repo_group_new',
424 pattern='/repo_group/new')
428 pattern='/repo_group/new')
425
429
426 config.add_route(
430 config.add_route(
427 name='repo_group_create',
431 name='repo_group_create',
428 pattern='/repo_group/create')
432 pattern='/repo_group/create')
429
433
430
434
431 def includeme(config):
435 def includeme(config):
432 from rhodecode.apps._base.navigation import includeme as nav_includeme
436 from rhodecode.apps._base.navigation import includeme as nav_includeme
433
437
434 # Create admin navigation registry and add it to the pyramid registry.
438 # Create admin navigation registry and add it to the pyramid registry.
435 nav_includeme(config)
439 nav_includeme(config)
436
440
437 # main admin routes
441 # main admin routes
438 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
442 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
439 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
443 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
440
444
441 # Scan module for configuration decorators.
445 # Scan module for configuration decorators.
442 config.scan('.views', ignore='.tests')
446 config.scan('.views', ignore='.tests')
@@ -1,783 +1,781 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 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 pytest
21 import pytest
22 from sqlalchemy.orm.exc import NoResultFound
22 from sqlalchemy.orm.exc import NoResultFound
23
23
24 from rhodecode.lib import auth
24 from rhodecode.lib import auth
25 from rhodecode.lib import helpers as h
25 from rhodecode.lib import helpers as h
26 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
26 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
27 from rhodecode.model.meta import Session
27 from rhodecode.model.meta import Session
28 from rhodecode.model.user import UserModel
28 from rhodecode.model.user import UserModel
29
29
30 from rhodecode.tests import (
30 from rhodecode.tests import (
31 TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash)
31 TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash)
32 from rhodecode.tests.fixture import Fixture
32 from rhodecode.tests.fixture import Fixture
33
33
34 fixture = Fixture()
34 fixture = Fixture()
35
35
36
36
37 def route_path(name, params=None, **kwargs):
37 def route_path(name, params=None, **kwargs):
38 import urllib
38 import urllib
39 from rhodecode.apps._base import ADMIN_PREFIX
39 from rhodecode.apps._base import ADMIN_PREFIX
40
40
41 base_url = {
41 base_url = {
42 'users':
42 'users':
43 ADMIN_PREFIX + '/users',
43 ADMIN_PREFIX + '/users',
44 'users_data':
44 'users_data':
45 ADMIN_PREFIX + '/users_data',
45 ADMIN_PREFIX + '/users_data',
46 'users_create':
46 'users_create':
47 ADMIN_PREFIX + '/users/create',
47 ADMIN_PREFIX + '/users/create',
48 'users_new':
48 'users_new':
49 ADMIN_PREFIX + '/users/new',
49 ADMIN_PREFIX + '/users/new',
50 'user_edit':
50 'user_edit':
51 ADMIN_PREFIX + '/users/{user_id}/edit',
51 ADMIN_PREFIX + '/users/{user_id}/edit',
52 'user_edit_advanced':
52 'user_edit_advanced':
53 ADMIN_PREFIX + '/users/{user_id}/edit/advanced',
53 ADMIN_PREFIX + '/users/{user_id}/edit/advanced',
54 'user_edit_global_perms':
54 'user_edit_global_perms':
55 ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions',
55 ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions',
56 'user_edit_global_perms_update':
56 'user_edit_global_perms_update':
57 ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions/update',
57 ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions/update',
58 'user_update':
58 'user_update':
59 ADMIN_PREFIX + '/users/{user_id}/update',
59 ADMIN_PREFIX + '/users/{user_id}/update',
60 'user_delete':
60 'user_delete':
61 ADMIN_PREFIX + '/users/{user_id}/delete',
61 ADMIN_PREFIX + '/users/{user_id}/delete',
62 'user_force_password_reset':
63 ADMIN_PREFIX + '/users/{user_id}/password_reset',
64 'user_create_personal_repo_group':
62 'user_create_personal_repo_group':
65 ADMIN_PREFIX + '/users/{user_id}/create_repo_group',
63 ADMIN_PREFIX + '/users/{user_id}/create_repo_group',
66
64
67 'edit_user_auth_tokens':
65 'edit_user_auth_tokens':
68 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens',
66 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens',
69 'edit_user_auth_tokens_add':
67 'edit_user_auth_tokens_add':
70 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/new',
68 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/new',
71 'edit_user_auth_tokens_delete':
69 'edit_user_auth_tokens_delete':
72 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/delete',
70 ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens/delete',
73
71
74 'edit_user_emails':
72 'edit_user_emails':
75 ADMIN_PREFIX + '/users/{user_id}/edit/emails',
73 ADMIN_PREFIX + '/users/{user_id}/edit/emails',
76 'edit_user_emails_add':
74 'edit_user_emails_add':
77 ADMIN_PREFIX + '/users/{user_id}/edit/emails/new',
75 ADMIN_PREFIX + '/users/{user_id}/edit/emails/new',
78 'edit_user_emails_delete':
76 'edit_user_emails_delete':
79 ADMIN_PREFIX + '/users/{user_id}/edit/emails/delete',
77 ADMIN_PREFIX + '/users/{user_id}/edit/emails/delete',
80
78
81 'edit_user_ips':
79 'edit_user_ips':
82 ADMIN_PREFIX + '/users/{user_id}/edit/ips',
80 ADMIN_PREFIX + '/users/{user_id}/edit/ips',
83 'edit_user_ips_add':
81 'edit_user_ips_add':
84 ADMIN_PREFIX + '/users/{user_id}/edit/ips/new',
82 ADMIN_PREFIX + '/users/{user_id}/edit/ips/new',
85 'edit_user_ips_delete':
83 'edit_user_ips_delete':
86 ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete',
84 ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete',
87
85
88 'edit_user_perms_summary':
86 'edit_user_perms_summary':
89 ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary',
87 ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary',
90 'edit_user_perms_summary_json':
88 'edit_user_perms_summary_json':
91 ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary/json',
89 ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary/json',
92
90
93 'edit_user_audit_logs':
91 'edit_user_audit_logs':
94 ADMIN_PREFIX + '/users/{user_id}/edit/audit',
92 ADMIN_PREFIX + '/users/{user_id}/edit/audit',
95
93
96 }[name].format(**kwargs)
94 }[name].format(**kwargs)
97
95
98 if params:
96 if params:
99 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
97 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
100 return base_url
98 return base_url
101
99
102
100
103 class TestAdminUsersView(TestController):
101 class TestAdminUsersView(TestController):
104
102
105 def test_show_users(self):
103 def test_show_users(self):
106 self.log_user()
104 self.log_user()
107 self.app.get(route_path('users'))
105 self.app.get(route_path('users'))
108
106
109 def test_show_users_data(self, xhr_header):
107 def test_show_users_data(self, xhr_header):
110 self.log_user()
108 self.log_user()
111 response = self.app.get(route_path(
109 response = self.app.get(route_path(
112 'users_data'), extra_environ=xhr_header)
110 'users_data'), extra_environ=xhr_header)
113
111
114 all_users = User.query().filter(
112 all_users = User.query().filter(
115 User.username != User.DEFAULT_USER).count()
113 User.username != User.DEFAULT_USER).count()
116 assert response.json['recordsTotal'] == all_users
114 assert response.json['recordsTotal'] == all_users
117
115
118 def test_show_users_data_filtered(self, xhr_header):
116 def test_show_users_data_filtered(self, xhr_header):
119 self.log_user()
117 self.log_user()
120 response = self.app.get(route_path(
118 response = self.app.get(route_path(
121 'users_data', params={'search[value]': 'empty_search'}),
119 'users_data', params={'search[value]': 'empty_search'}),
122 extra_environ=xhr_header)
120 extra_environ=xhr_header)
123
121
124 all_users = User.query().filter(
122 all_users = User.query().filter(
125 User.username != User.DEFAULT_USER).count()
123 User.username != User.DEFAULT_USER).count()
126 assert response.json['recordsTotal'] == all_users
124 assert response.json['recordsTotal'] == all_users
127 assert response.json['recordsFiltered'] == 0
125 assert response.json['recordsFiltered'] == 0
128
126
129 def test_auth_tokens_default_user(self):
127 def test_auth_tokens_default_user(self):
130 self.log_user()
128 self.log_user()
131 user = User.get_default_user()
129 user = User.get_default_user()
132 response = self.app.get(
130 response = self.app.get(
133 route_path('edit_user_auth_tokens', user_id=user.user_id),
131 route_path('edit_user_auth_tokens', user_id=user.user_id),
134 status=302)
132 status=302)
135
133
136 def test_auth_tokens(self):
134 def test_auth_tokens(self):
137 self.log_user()
135 self.log_user()
138
136
139 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
137 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
140 user_id = user.user_id
138 user_id = user.user_id
141 auth_tokens = user.auth_tokens
139 auth_tokens = user.auth_tokens
142 response = self.app.get(
140 response = self.app.get(
143 route_path('edit_user_auth_tokens', user_id=user_id))
141 route_path('edit_user_auth_tokens', user_id=user_id))
144 for token in auth_tokens:
142 for token in auth_tokens:
145 response.mustcontain(token)
143 response.mustcontain(token)
146 response.mustcontain('never')
144 response.mustcontain('never')
147
145
148 @pytest.mark.parametrize("desc, lifetime", [
146 @pytest.mark.parametrize("desc, lifetime", [
149 ('forever', -1),
147 ('forever', -1),
150 ('5mins', 60*5),
148 ('5mins', 60*5),
151 ('30days', 60*60*24*30),
149 ('30days', 60*60*24*30),
152 ])
150 ])
153 def test_add_auth_token(self, desc, lifetime, user_util):
151 def test_add_auth_token(self, desc, lifetime, user_util):
154 self.log_user()
152 self.log_user()
155 user = user_util.create_user()
153 user = user_util.create_user()
156 user_id = user.user_id
154 user_id = user.user_id
157
155
158 response = self.app.post(
156 response = self.app.post(
159 route_path('edit_user_auth_tokens_add', user_id=user_id),
157 route_path('edit_user_auth_tokens_add', user_id=user_id),
160 {'description': desc, 'lifetime': lifetime,
158 {'description': desc, 'lifetime': lifetime,
161 'csrf_token': self.csrf_token})
159 'csrf_token': self.csrf_token})
162 assert_session_flash(response, 'Auth token successfully created')
160 assert_session_flash(response, 'Auth token successfully created')
163
161
164 response = response.follow()
162 response = response.follow()
165 user = User.get(user_id)
163 user = User.get(user_id)
166 for auth_token in user.auth_tokens:
164 for auth_token in user.auth_tokens:
167 response.mustcontain(auth_token)
165 response.mustcontain(auth_token)
168
166
169 def test_delete_auth_token(self, user_util):
167 def test_delete_auth_token(self, user_util):
170 self.log_user()
168 self.log_user()
171 user = user_util.create_user()
169 user = user_util.create_user()
172 user_id = user.user_id
170 user_id = user.user_id
173 keys = user.auth_tokens
171 keys = user.auth_tokens
174 assert 2 == len(keys)
172 assert 2 == len(keys)
175
173
176 response = self.app.post(
174 response = self.app.post(
177 route_path('edit_user_auth_tokens_add', user_id=user_id),
175 route_path('edit_user_auth_tokens_add', user_id=user_id),
178 {'description': 'desc', 'lifetime': -1,
176 {'description': 'desc', 'lifetime': -1,
179 'csrf_token': self.csrf_token})
177 'csrf_token': self.csrf_token})
180 assert_session_flash(response, 'Auth token successfully created')
178 assert_session_flash(response, 'Auth token successfully created')
181 response.follow()
179 response.follow()
182
180
183 # now delete our key
181 # now delete our key
184 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
182 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
185 assert 3 == len(keys)
183 assert 3 == len(keys)
186
184
187 response = self.app.post(
185 response = self.app.post(
188 route_path('edit_user_auth_tokens_delete', user_id=user_id),
186 route_path('edit_user_auth_tokens_delete', user_id=user_id),
189 {'del_auth_token': keys[0].user_api_key_id,
187 {'del_auth_token': keys[0].user_api_key_id,
190 'csrf_token': self.csrf_token})
188 'csrf_token': self.csrf_token})
191
189
192 assert_session_flash(response, 'Auth token successfully deleted')
190 assert_session_flash(response, 'Auth token successfully deleted')
193 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
191 keys = UserApiKeys.query().filter(UserApiKeys.user_id == user_id).all()
194 assert 2 == len(keys)
192 assert 2 == len(keys)
195
193
196 def test_ips(self):
194 def test_ips(self):
197 self.log_user()
195 self.log_user()
198 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
196 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
199 response = self.app.get(route_path('edit_user_ips', user_id=user.user_id))
197 response = self.app.get(route_path('edit_user_ips', user_id=user.user_id))
200 response.mustcontain('All IP addresses are allowed')
198 response.mustcontain('All IP addresses are allowed')
201
199
202 @pytest.mark.parametrize("test_name, ip, ip_range, failure", [
200 @pytest.mark.parametrize("test_name, ip, ip_range, failure", [
203 ('127/24', '127.0.0.1/24', '127.0.0.0 - 127.0.0.255', False),
201 ('127/24', '127.0.0.1/24', '127.0.0.0 - 127.0.0.255', False),
204 ('10/32', '10.0.0.10/32', '10.0.0.10 - 10.0.0.10', False),
202 ('10/32', '10.0.0.10/32', '10.0.0.10 - 10.0.0.10', False),
205 ('0/16', '0.0.0.0/16', '0.0.0.0 - 0.0.255.255', False),
203 ('0/16', '0.0.0.0/16', '0.0.0.0 - 0.0.255.255', False),
206 ('0/8', '0.0.0.0/8', '0.0.0.0 - 0.255.255.255', False),
204 ('0/8', '0.0.0.0/8', '0.0.0.0 - 0.255.255.255', False),
207 ('127_bad_mask', '127.0.0.1/99', '127.0.0.1 - 127.0.0.1', True),
205 ('127_bad_mask', '127.0.0.1/99', '127.0.0.1 - 127.0.0.1', True),
208 ('127_bad_ip', 'foobar', 'foobar', True),
206 ('127_bad_ip', 'foobar', 'foobar', True),
209 ])
207 ])
210 def test_ips_add(self, user_util, test_name, ip, ip_range, failure):
208 def test_ips_add(self, user_util, test_name, ip, ip_range, failure):
211 self.log_user()
209 self.log_user()
212 user = user_util.create_user(username=test_name)
210 user = user_util.create_user(username=test_name)
213 user_id = user.user_id
211 user_id = user.user_id
214
212
215 response = self.app.post(
213 response = self.app.post(
216 route_path('edit_user_ips_add', user_id=user_id),
214 route_path('edit_user_ips_add', user_id=user_id),
217 params={'new_ip': ip, 'csrf_token': self.csrf_token})
215 params={'new_ip': ip, 'csrf_token': self.csrf_token})
218
216
219 if failure:
217 if failure:
220 assert_session_flash(
218 assert_session_flash(
221 response, 'Please enter a valid IPv4 or IpV6 address')
219 response, 'Please enter a valid IPv4 or IpV6 address')
222 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
220 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
223
221
224 response.mustcontain(no=[ip])
222 response.mustcontain(no=[ip])
225 response.mustcontain(no=[ip_range])
223 response.mustcontain(no=[ip_range])
226
224
227 else:
225 else:
228 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
226 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
229 response.mustcontain(ip)
227 response.mustcontain(ip)
230 response.mustcontain(ip_range)
228 response.mustcontain(ip_range)
231
229
232 def test_ips_delete(self, user_util):
230 def test_ips_delete(self, user_util):
233 self.log_user()
231 self.log_user()
234 user = user_util.create_user()
232 user = user_util.create_user()
235 user_id = user.user_id
233 user_id = user.user_id
236 ip = '127.0.0.1/32'
234 ip = '127.0.0.1/32'
237 ip_range = '127.0.0.1 - 127.0.0.1'
235 ip_range = '127.0.0.1 - 127.0.0.1'
238 new_ip = UserModel().add_extra_ip(user_id, ip)
236 new_ip = UserModel().add_extra_ip(user_id, ip)
239 Session().commit()
237 Session().commit()
240 new_ip_id = new_ip.ip_id
238 new_ip_id = new_ip.ip_id
241
239
242 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
240 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
243 response.mustcontain(ip)
241 response.mustcontain(ip)
244 response.mustcontain(ip_range)
242 response.mustcontain(ip_range)
245
243
246 self.app.post(
244 self.app.post(
247 route_path('edit_user_ips_delete', user_id=user_id),
245 route_path('edit_user_ips_delete', user_id=user_id),
248 params={'del_ip_id': new_ip_id, 'csrf_token': self.csrf_token})
246 params={'del_ip_id': new_ip_id, 'csrf_token': self.csrf_token})
249
247
250 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
248 response = self.app.get(route_path('edit_user_ips', user_id=user_id))
251 response.mustcontain('All IP addresses are allowed')
249 response.mustcontain('All IP addresses are allowed')
252 response.mustcontain(no=[ip])
250 response.mustcontain(no=[ip])
253 response.mustcontain(no=[ip_range])
251 response.mustcontain(no=[ip_range])
254
252
255 def test_emails(self):
253 def test_emails(self):
256 self.log_user()
254 self.log_user()
257 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
255 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
258 response = self.app.get(
256 response = self.app.get(
259 route_path('edit_user_emails', user_id=user.user_id))
257 route_path('edit_user_emails', user_id=user.user_id))
260 response.mustcontain('No additional emails specified')
258 response.mustcontain('No additional emails specified')
261
259
262 def test_emails_add(self, user_util):
260 def test_emails_add(self, user_util):
263 self.log_user()
261 self.log_user()
264 user = user_util.create_user()
262 user = user_util.create_user()
265 user_id = user.user_id
263 user_id = user.user_id
266
264
267 self.app.post(
265 self.app.post(
268 route_path('edit_user_emails_add', user_id=user_id),
266 route_path('edit_user_emails_add', user_id=user_id),
269 params={'new_email': 'example@rhodecode.com',
267 params={'new_email': 'example@rhodecode.com',
270 'csrf_token': self.csrf_token})
268 'csrf_token': self.csrf_token})
271
269
272 response = self.app.get(
270 response = self.app.get(
273 route_path('edit_user_emails', user_id=user_id))
271 route_path('edit_user_emails', user_id=user_id))
274 response.mustcontain('example@rhodecode.com')
272 response.mustcontain('example@rhodecode.com')
275
273
276 def test_emails_add_existing_email(self, user_util, user_regular):
274 def test_emails_add_existing_email(self, user_util, user_regular):
277 existing_email = user_regular.email
275 existing_email = user_regular.email
278
276
279 self.log_user()
277 self.log_user()
280 user = user_util.create_user()
278 user = user_util.create_user()
281 user_id = user.user_id
279 user_id = user.user_id
282
280
283 response = self.app.post(
281 response = self.app.post(
284 route_path('edit_user_emails_add', user_id=user_id),
282 route_path('edit_user_emails_add', user_id=user_id),
285 params={'new_email': existing_email,
283 params={'new_email': existing_email,
286 'csrf_token': self.csrf_token})
284 'csrf_token': self.csrf_token})
287 assert_session_flash(
285 assert_session_flash(
288 response, 'This e-mail address is already taken')
286 response, 'This e-mail address is already taken')
289
287
290 response = self.app.get(
288 response = self.app.get(
291 route_path('edit_user_emails', user_id=user_id))
289 route_path('edit_user_emails', user_id=user_id))
292 response.mustcontain(no=[existing_email])
290 response.mustcontain(no=[existing_email])
293
291
294 def test_emails_delete(self, user_util):
292 def test_emails_delete(self, user_util):
295 self.log_user()
293 self.log_user()
296 user = user_util.create_user()
294 user = user_util.create_user()
297 user_id = user.user_id
295 user_id = user.user_id
298
296
299 self.app.post(
297 self.app.post(
300 route_path('edit_user_emails_add', user_id=user_id),
298 route_path('edit_user_emails_add', user_id=user_id),
301 params={'new_email': 'example@rhodecode.com',
299 params={'new_email': 'example@rhodecode.com',
302 'csrf_token': self.csrf_token})
300 'csrf_token': self.csrf_token})
303
301
304 response = self.app.get(
302 response = self.app.get(
305 route_path('edit_user_emails', user_id=user_id))
303 route_path('edit_user_emails', user_id=user_id))
306 response.mustcontain('example@rhodecode.com')
304 response.mustcontain('example@rhodecode.com')
307
305
308 user_email = UserEmailMap.query()\
306 user_email = UserEmailMap.query()\
309 .filter(UserEmailMap.email == 'example@rhodecode.com') \
307 .filter(UserEmailMap.email == 'example@rhodecode.com') \
310 .filter(UserEmailMap.user_id == user_id)\
308 .filter(UserEmailMap.user_id == user_id)\
311 .one()
309 .one()
312
310
313 del_email_id = user_email.email_id
311 del_email_id = user_email.email_id
314 self.app.post(
312 self.app.post(
315 route_path('edit_user_emails_delete', user_id=user_id),
313 route_path('edit_user_emails_delete', user_id=user_id),
316 params={'del_email_id': del_email_id,
314 params={'del_email_id': del_email_id,
317 'csrf_token': self.csrf_token})
315 'csrf_token': self.csrf_token})
318
316
319 response = self.app.get(
317 response = self.app.get(
320 route_path('edit_user_emails', user_id=user_id))
318 route_path('edit_user_emails', user_id=user_id))
321 response.mustcontain(no=['example@rhodecode.com'])
319 response.mustcontain(no=['example@rhodecode.com'])
322
320
323
321
324 def test_create(self, request, xhr_header):
322 def test_create(self, request, xhr_header):
325 self.log_user()
323 self.log_user()
326 username = 'newtestuser'
324 username = 'newtestuser'
327 password = 'test12'
325 password = 'test12'
328 password_confirmation = password
326 password_confirmation = password
329 name = 'name'
327 name = 'name'
330 lastname = 'lastname'
328 lastname = 'lastname'
331 email = 'mail@mail.com'
329 email = 'mail@mail.com'
332
330
333 self.app.get(route_path('users_new'))
331 self.app.get(route_path('users_new'))
334
332
335 response = self.app.post(route_path('users_create'), params={
333 response = self.app.post(route_path('users_create'), params={
336 'username': username,
334 'username': username,
337 'password': password,
335 'password': password,
338 'password_confirmation': password_confirmation,
336 'password_confirmation': password_confirmation,
339 'firstname': name,
337 'firstname': name,
340 'active': True,
338 'active': True,
341 'lastname': lastname,
339 'lastname': lastname,
342 'extern_name': 'rhodecode',
340 'extern_name': 'rhodecode',
343 'extern_type': 'rhodecode',
341 'extern_type': 'rhodecode',
344 'email': email,
342 'email': email,
345 'csrf_token': self.csrf_token,
343 'csrf_token': self.csrf_token,
346 })
344 })
347 user_link = h.link_to(
345 user_link = h.link_to(
348 username,
346 username,
349 route_path(
347 route_path(
350 'user_edit', user_id=User.get_by_username(username).user_id))
348 'user_edit', user_id=User.get_by_username(username).user_id))
351 assert_session_flash(response, 'Created user %s' % (user_link,))
349 assert_session_flash(response, 'Created user %s' % (user_link,))
352
350
353 @request.addfinalizer
351 @request.addfinalizer
354 def cleanup():
352 def cleanup():
355 fixture.destroy_user(username)
353 fixture.destroy_user(username)
356 Session().commit()
354 Session().commit()
357
355
358 new_user = User.query().filter(User.username == username).one()
356 new_user = User.query().filter(User.username == username).one()
359
357
360 assert new_user.username == username
358 assert new_user.username == username
361 assert auth.check_password(password, new_user.password)
359 assert auth.check_password(password, new_user.password)
362 assert new_user.name == name
360 assert new_user.name == name
363 assert new_user.lastname == lastname
361 assert new_user.lastname == lastname
364 assert new_user.email == email
362 assert new_user.email == email
365
363
366 response = self.app.get(route_path('users_data'),
364 response = self.app.get(route_path('users_data'),
367 extra_environ=xhr_header)
365 extra_environ=xhr_header)
368 response.mustcontain(username)
366 response.mustcontain(username)
369
367
370 def test_create_err(self):
368 def test_create_err(self):
371 self.log_user()
369 self.log_user()
372 username = 'new_user'
370 username = 'new_user'
373 password = ''
371 password = ''
374 name = 'name'
372 name = 'name'
375 lastname = 'lastname'
373 lastname = 'lastname'
376 email = 'errmail.com'
374 email = 'errmail.com'
377
375
378 self.app.get(route_path('users_new'))
376 self.app.get(route_path('users_new'))
379
377
380 response = self.app.post(route_path('users_create'), params={
378 response = self.app.post(route_path('users_create'), params={
381 'username': username,
379 'username': username,
382 'password': password,
380 'password': password,
383 'name': name,
381 'name': name,
384 'active': False,
382 'active': False,
385 'lastname': lastname,
383 'lastname': lastname,
386 'email': email,
384 'email': email,
387 'csrf_token': self.csrf_token,
385 'csrf_token': self.csrf_token,
388 })
386 })
389
387
390 msg = u'Username "%(username)s" is forbidden'
388 msg = u'Username "%(username)s" is forbidden'
391 msg = h.html_escape(msg % {'username': 'new_user'})
389 msg = h.html_escape(msg % {'username': 'new_user'})
392 response.mustcontain('<span class="error-message">%s</span>' % msg)
390 response.mustcontain('<span class="error-message">%s</span>' % msg)
393 response.mustcontain(
391 response.mustcontain(
394 '<span class="error-message">Please enter a value</span>')
392 '<span class="error-message">Please enter a value</span>')
395 response.mustcontain(
393 response.mustcontain(
396 '<span class="error-message">An email address must contain a'
394 '<span class="error-message">An email address must contain a'
397 ' single @</span>')
395 ' single @</span>')
398
396
399 def get_user():
397 def get_user():
400 Session().query(User).filter(User.username == username).one()
398 Session().query(User).filter(User.username == username).one()
401
399
402 with pytest.raises(NoResultFound):
400 with pytest.raises(NoResultFound):
403 get_user()
401 get_user()
404
402
405 def test_new(self):
403 def test_new(self):
406 self.log_user()
404 self.log_user()
407 self.app.get(route_path('users_new'))
405 self.app.get(route_path('users_new'))
408
406
409 @pytest.mark.parametrize("name, attrs", [
407 @pytest.mark.parametrize("name, attrs", [
410 ('firstname', {'firstname': 'new_username'}),
408 ('firstname', {'firstname': 'new_username'}),
411 ('lastname', {'lastname': 'new_username'}),
409 ('lastname', {'lastname': 'new_username'}),
412 ('admin', {'admin': True}),
410 ('admin', {'admin': True}),
413 ('admin', {'admin': False}),
411 ('admin', {'admin': False}),
414 ('extern_type', {'extern_type': 'ldap'}),
412 ('extern_type', {'extern_type': 'ldap'}),
415 ('extern_type', {'extern_type': None}),
413 ('extern_type', {'extern_type': None}),
416 ('extern_name', {'extern_name': 'test'}),
414 ('extern_name', {'extern_name': 'test'}),
417 ('extern_name', {'extern_name': None}),
415 ('extern_name', {'extern_name': None}),
418 ('active', {'active': False}),
416 ('active', {'active': False}),
419 ('active', {'active': True}),
417 ('active', {'active': True}),
420 ('email', {'email': 'some@email.com'}),
418 ('email', {'email': 'some@email.com'}),
421 ('language', {'language': 'de'}),
419 ('language', {'language': 'de'}),
422 ('language', {'language': 'en'}),
420 ('language', {'language': 'en'}),
423 # ('new_password', {'new_password': 'foobar123',
421 # ('new_password', {'new_password': 'foobar123',
424 # 'password_confirmation': 'foobar123'})
422 # 'password_confirmation': 'foobar123'})
425 ])
423 ])
426 def test_update(self, name, attrs, user_util):
424 def test_update(self, name, attrs, user_util):
427 self.log_user()
425 self.log_user()
428 usr = user_util.create_user(
426 usr = user_util.create_user(
429 password='qweqwe',
427 password='qweqwe',
430 email='testme@rhodecode.org',
428 email='testme@rhodecode.org',
431 extern_type='rhodecode',
429 extern_type='rhodecode',
432 extern_name='xxx',
430 extern_name='xxx',
433 )
431 )
434 user_id = usr.user_id
432 user_id = usr.user_id
435 Session().commit()
433 Session().commit()
436
434
437 params = usr.get_api_data()
435 params = usr.get_api_data()
438 cur_lang = params['language'] or 'en'
436 cur_lang = params['language'] or 'en'
439 params.update({
437 params.update({
440 'password_confirmation': '',
438 'password_confirmation': '',
441 'new_password': '',
439 'new_password': '',
442 'language': cur_lang,
440 'language': cur_lang,
443 'csrf_token': self.csrf_token,
441 'csrf_token': self.csrf_token,
444 })
442 })
445 params.update({'new_password': ''})
443 params.update({'new_password': ''})
446 params.update(attrs)
444 params.update(attrs)
447 if name == 'email':
445 if name == 'email':
448 params['emails'] = [attrs['email']]
446 params['emails'] = [attrs['email']]
449 elif name == 'extern_type':
447 elif name == 'extern_type':
450 # cannot update this via form, expected value is original one
448 # cannot update this via form, expected value is original one
451 params['extern_type'] = "rhodecode"
449 params['extern_type'] = "rhodecode"
452 elif name == 'extern_name':
450 elif name == 'extern_name':
453 # cannot update this via form, expected value is original one
451 # cannot update this via form, expected value is original one
454 params['extern_name'] = 'xxx'
452 params['extern_name'] = 'xxx'
455 # special case since this user is not
453 # special case since this user is not
456 # logged in yet his data is not filled
454 # logged in yet his data is not filled
457 # so we use creation data
455 # so we use creation data
458
456
459 response = self.app.post(
457 response = self.app.post(
460 route_path('user_update', user_id=usr.user_id), params)
458 route_path('user_update', user_id=usr.user_id), params)
461 assert response.status_int == 302
459 assert response.status_int == 302
462 assert_session_flash(response, 'User updated successfully')
460 assert_session_flash(response, 'User updated successfully')
463
461
464 updated_user = User.get(user_id)
462 updated_user = User.get(user_id)
465 updated_params = updated_user.get_api_data()
463 updated_params = updated_user.get_api_data()
466 updated_params.update({'password_confirmation': ''})
464 updated_params.update({'password_confirmation': ''})
467 updated_params.update({'new_password': ''})
465 updated_params.update({'new_password': ''})
468
466
469 del params['csrf_token']
467 del params['csrf_token']
470 assert params == updated_params
468 assert params == updated_params
471
469
472 def test_update_and_migrate_password(
470 def test_update_and_migrate_password(
473 self, autologin_user, real_crypto_backend, user_util):
471 self, autologin_user, real_crypto_backend, user_util):
474
472
475 user = user_util.create_user()
473 user = user_util.create_user()
476 temp_user = user.username
474 temp_user = user.username
477 user.password = auth._RhodeCodeCryptoSha256().hash_create(
475 user.password = auth._RhodeCodeCryptoSha256().hash_create(
478 b'test123')
476 b'test123')
479 Session().add(user)
477 Session().add(user)
480 Session().commit()
478 Session().commit()
481
479
482 params = user.get_api_data()
480 params = user.get_api_data()
483
481
484 params.update({
482 params.update({
485 'password_confirmation': 'qweqwe123',
483 'password_confirmation': 'qweqwe123',
486 'new_password': 'qweqwe123',
484 'new_password': 'qweqwe123',
487 'language': 'en',
485 'language': 'en',
488 'csrf_token': autologin_user.csrf_token,
486 'csrf_token': autologin_user.csrf_token,
489 })
487 })
490
488
491 response = self.app.post(
489 response = self.app.post(
492 route_path('user_update', user_id=user.user_id), params)
490 route_path('user_update', user_id=user.user_id), params)
493 assert response.status_int == 302
491 assert response.status_int == 302
494 assert_session_flash(response, 'User updated successfully')
492 assert_session_flash(response, 'User updated successfully')
495
493
496 # new password should be bcrypted, after log-in and transfer
494 # new password should be bcrypted, after log-in and transfer
497 user = User.get_by_username(temp_user)
495 user = User.get_by_username(temp_user)
498 assert user.password.startswith('$')
496 assert user.password.startswith('$')
499
497
500 updated_user = User.get_by_username(temp_user)
498 updated_user = User.get_by_username(temp_user)
501 updated_params = updated_user.get_api_data()
499 updated_params = updated_user.get_api_data()
502 updated_params.update({'password_confirmation': 'qweqwe123'})
500 updated_params.update({'password_confirmation': 'qweqwe123'})
503 updated_params.update({'new_password': 'qweqwe123'})
501 updated_params.update({'new_password': 'qweqwe123'})
504
502
505 del params['csrf_token']
503 del params['csrf_token']
506 assert params == updated_params
504 assert params == updated_params
507
505
508 def test_delete(self):
506 def test_delete(self):
509 self.log_user()
507 self.log_user()
510 username = 'newtestuserdeleteme'
508 username = 'newtestuserdeleteme'
511
509
512 fixture.create_user(name=username)
510 fixture.create_user(name=username)
513
511
514 new_user = Session().query(User)\
512 new_user = Session().query(User)\
515 .filter(User.username == username).one()
513 .filter(User.username == username).one()
516 response = self.app.post(
514 response = self.app.post(
517 route_path('user_delete', user_id=new_user.user_id),
515 route_path('user_delete', user_id=new_user.user_id),
518 params={'csrf_token': self.csrf_token})
516 params={'csrf_token': self.csrf_token})
519
517
520 assert_session_flash(response, 'Successfully deleted user')
518 assert_session_flash(response, 'Successfully deleted user')
521
519
522 def test_delete_owner_of_repository(self, request, user_util):
520 def test_delete_owner_of_repository(self, request, user_util):
523 self.log_user()
521 self.log_user()
524 obj_name = 'test_repo'
522 obj_name = 'test_repo'
525 usr = user_util.create_user()
523 usr = user_util.create_user()
526 username = usr.username
524 username = usr.username
527 fixture.create_repo(obj_name, cur_user=usr.username)
525 fixture.create_repo(obj_name, cur_user=usr.username)
528
526
529 new_user = Session().query(User)\
527 new_user = Session().query(User)\
530 .filter(User.username == username).one()
528 .filter(User.username == username).one()
531 response = self.app.post(
529 response = self.app.post(
532 route_path('user_delete', user_id=new_user.user_id),
530 route_path('user_delete', user_id=new_user.user_id),
533 params={'csrf_token': self.csrf_token})
531 params={'csrf_token': self.csrf_token})
534
532
535 msg = 'user "%s" still owns 1 repositories and cannot be removed. ' \
533 msg = 'user "%s" still owns 1 repositories and cannot be removed. ' \
536 'Switch owners or remove those repositories:%s' % (username,
534 'Switch owners or remove those repositories:%s' % (username,
537 obj_name)
535 obj_name)
538 assert_session_flash(response, msg)
536 assert_session_flash(response, msg)
539 fixture.destroy_repo(obj_name)
537 fixture.destroy_repo(obj_name)
540
538
541 def test_delete_owner_of_repository_detaching(self, request, user_util):
539 def test_delete_owner_of_repository_detaching(self, request, user_util):
542 self.log_user()
540 self.log_user()
543 obj_name = 'test_repo'
541 obj_name = 'test_repo'
544 usr = user_util.create_user(auto_cleanup=False)
542 usr = user_util.create_user(auto_cleanup=False)
545 username = usr.username
543 username = usr.username
546 fixture.create_repo(obj_name, cur_user=usr.username)
544 fixture.create_repo(obj_name, cur_user=usr.username)
547
545
548 new_user = Session().query(User)\
546 new_user = Session().query(User)\
549 .filter(User.username == username).one()
547 .filter(User.username == username).one()
550 response = self.app.post(
548 response = self.app.post(
551 route_path('user_delete', user_id=new_user.user_id),
549 route_path('user_delete', user_id=new_user.user_id),
552 params={'user_repos': 'detach', 'csrf_token': self.csrf_token})
550 params={'user_repos': 'detach', 'csrf_token': self.csrf_token})
553
551
554 msg = 'Detached 1 repositories'
552 msg = 'Detached 1 repositories'
555 assert_session_flash(response, msg)
553 assert_session_flash(response, msg)
556 fixture.destroy_repo(obj_name)
554 fixture.destroy_repo(obj_name)
557
555
558 def test_delete_owner_of_repository_deleting(self, request, user_util):
556 def test_delete_owner_of_repository_deleting(self, request, user_util):
559 self.log_user()
557 self.log_user()
560 obj_name = 'test_repo'
558 obj_name = 'test_repo'
561 usr = user_util.create_user(auto_cleanup=False)
559 usr = user_util.create_user(auto_cleanup=False)
562 username = usr.username
560 username = usr.username
563 fixture.create_repo(obj_name, cur_user=usr.username)
561 fixture.create_repo(obj_name, cur_user=usr.username)
564
562
565 new_user = Session().query(User)\
563 new_user = Session().query(User)\
566 .filter(User.username == username).one()
564 .filter(User.username == username).one()
567 response = self.app.post(
565 response = self.app.post(
568 route_path('user_delete', user_id=new_user.user_id),
566 route_path('user_delete', user_id=new_user.user_id),
569 params={'user_repos': 'delete', 'csrf_token': self.csrf_token})
567 params={'user_repos': 'delete', 'csrf_token': self.csrf_token})
570
568
571 msg = 'Deleted 1 repositories'
569 msg = 'Deleted 1 repositories'
572 assert_session_flash(response, msg)
570 assert_session_flash(response, msg)
573
571
574 def test_delete_owner_of_repository_group(self, request, user_util):
572 def test_delete_owner_of_repository_group(self, request, user_util):
575 self.log_user()
573 self.log_user()
576 obj_name = 'test_group'
574 obj_name = 'test_group'
577 usr = user_util.create_user()
575 usr = user_util.create_user()
578 username = usr.username
576 username = usr.username
579 fixture.create_repo_group(obj_name, cur_user=usr.username)
577 fixture.create_repo_group(obj_name, cur_user=usr.username)
580
578
581 new_user = Session().query(User)\
579 new_user = Session().query(User)\
582 .filter(User.username == username).one()
580 .filter(User.username == username).one()
583 response = self.app.post(
581 response = self.app.post(
584 route_path('user_delete', user_id=new_user.user_id),
582 route_path('user_delete', user_id=new_user.user_id),
585 params={'csrf_token': self.csrf_token})
583 params={'csrf_token': self.csrf_token})
586
584
587 msg = 'user "%s" still owns 1 repository groups and cannot be removed. ' \
585 msg = 'user "%s" still owns 1 repository groups and cannot be removed. ' \
588 'Switch owners or remove those repository groups:%s' % (username,
586 'Switch owners or remove those repository groups:%s' % (username,
589 obj_name)
587 obj_name)
590 assert_session_flash(response, msg)
588 assert_session_flash(response, msg)
591 fixture.destroy_repo_group(obj_name)
589 fixture.destroy_repo_group(obj_name)
592
590
593 def test_delete_owner_of_repository_group_detaching(self, request, user_util):
591 def test_delete_owner_of_repository_group_detaching(self, request, user_util):
594 self.log_user()
592 self.log_user()
595 obj_name = 'test_group'
593 obj_name = 'test_group'
596 usr = user_util.create_user(auto_cleanup=False)
594 usr = user_util.create_user(auto_cleanup=False)
597 username = usr.username
595 username = usr.username
598 fixture.create_repo_group(obj_name, cur_user=usr.username)
596 fixture.create_repo_group(obj_name, cur_user=usr.username)
599
597
600 new_user = Session().query(User)\
598 new_user = Session().query(User)\
601 .filter(User.username == username).one()
599 .filter(User.username == username).one()
602 response = self.app.post(
600 response = self.app.post(
603 route_path('user_delete', user_id=new_user.user_id),
601 route_path('user_delete', user_id=new_user.user_id),
604 params={'user_repo_groups': 'delete', 'csrf_token': self.csrf_token})
602 params={'user_repo_groups': 'delete', 'csrf_token': self.csrf_token})
605
603
606 msg = 'Deleted 1 repository groups'
604 msg = 'Deleted 1 repository groups'
607 assert_session_flash(response, msg)
605 assert_session_flash(response, msg)
608
606
609 def test_delete_owner_of_repository_group_deleting(self, request, user_util):
607 def test_delete_owner_of_repository_group_deleting(self, request, user_util):
610 self.log_user()
608 self.log_user()
611 obj_name = 'test_group'
609 obj_name = 'test_group'
612 usr = user_util.create_user(auto_cleanup=False)
610 usr = user_util.create_user(auto_cleanup=False)
613 username = usr.username
611 username = usr.username
614 fixture.create_repo_group(obj_name, cur_user=usr.username)
612 fixture.create_repo_group(obj_name, cur_user=usr.username)
615
613
616 new_user = Session().query(User)\
614 new_user = Session().query(User)\
617 .filter(User.username == username).one()
615 .filter(User.username == username).one()
618 response = self.app.post(
616 response = self.app.post(
619 route_path('user_delete', user_id=new_user.user_id),
617 route_path('user_delete', user_id=new_user.user_id),
620 params={'user_repo_groups': 'detach', 'csrf_token': self.csrf_token})
618 params={'user_repo_groups': 'detach', 'csrf_token': self.csrf_token})
621
619
622 msg = 'Detached 1 repository groups'
620 msg = 'Detached 1 repository groups'
623 assert_session_flash(response, msg)
621 assert_session_flash(response, msg)
624 fixture.destroy_repo_group(obj_name)
622 fixture.destroy_repo_group(obj_name)
625
623
626 def test_delete_owner_of_user_group(self, request, user_util):
624 def test_delete_owner_of_user_group(self, request, user_util):
627 self.log_user()
625 self.log_user()
628 obj_name = 'test_user_group'
626 obj_name = 'test_user_group'
629 usr = user_util.create_user()
627 usr = user_util.create_user()
630 username = usr.username
628 username = usr.username
631 fixture.create_user_group(obj_name, cur_user=usr.username)
629 fixture.create_user_group(obj_name, cur_user=usr.username)
632
630
633 new_user = Session().query(User)\
631 new_user = Session().query(User)\
634 .filter(User.username == username).one()
632 .filter(User.username == username).one()
635 response = self.app.post(
633 response = self.app.post(
636 route_path('user_delete', user_id=new_user.user_id),
634 route_path('user_delete', user_id=new_user.user_id),
637 params={'csrf_token': self.csrf_token})
635 params={'csrf_token': self.csrf_token})
638
636
639 msg = 'user "%s" still owns 1 user groups and cannot be removed. ' \
637 msg = 'user "%s" still owns 1 user groups and cannot be removed. ' \
640 'Switch owners or remove those user groups:%s' % (username,
638 'Switch owners or remove those user groups:%s' % (username,
641 obj_name)
639 obj_name)
642 assert_session_flash(response, msg)
640 assert_session_flash(response, msg)
643 fixture.destroy_user_group(obj_name)
641 fixture.destroy_user_group(obj_name)
644
642
645 def test_delete_owner_of_user_group_detaching(self, request, user_util):
643 def test_delete_owner_of_user_group_detaching(self, request, user_util):
646 self.log_user()
644 self.log_user()
647 obj_name = 'test_user_group'
645 obj_name = 'test_user_group'
648 usr = user_util.create_user(auto_cleanup=False)
646 usr = user_util.create_user(auto_cleanup=False)
649 username = usr.username
647 username = usr.username
650 fixture.create_user_group(obj_name, cur_user=usr.username)
648 fixture.create_user_group(obj_name, cur_user=usr.username)
651
649
652 new_user = Session().query(User)\
650 new_user = Session().query(User)\
653 .filter(User.username == username).one()
651 .filter(User.username == username).one()
654 try:
652 try:
655 response = self.app.post(
653 response = self.app.post(
656 route_path('user_delete', user_id=new_user.user_id),
654 route_path('user_delete', user_id=new_user.user_id),
657 params={'user_user_groups': 'detach',
655 params={'user_user_groups': 'detach',
658 'csrf_token': self.csrf_token})
656 'csrf_token': self.csrf_token})
659
657
660 msg = 'Detached 1 user groups'
658 msg = 'Detached 1 user groups'
661 assert_session_flash(response, msg)
659 assert_session_flash(response, msg)
662 finally:
660 finally:
663 fixture.destroy_user_group(obj_name)
661 fixture.destroy_user_group(obj_name)
664
662
665 def test_delete_owner_of_user_group_deleting(self, request, user_util):
663 def test_delete_owner_of_user_group_deleting(self, request, user_util):
666 self.log_user()
664 self.log_user()
667 obj_name = 'test_user_group'
665 obj_name = 'test_user_group'
668 usr = user_util.create_user(auto_cleanup=False)
666 usr = user_util.create_user(auto_cleanup=False)
669 username = usr.username
667 username = usr.username
670 fixture.create_user_group(obj_name, cur_user=usr.username)
668 fixture.create_user_group(obj_name, cur_user=usr.username)
671
669
672 new_user = Session().query(User)\
670 new_user = Session().query(User)\
673 .filter(User.username == username).one()
671 .filter(User.username == username).one()
674 response = self.app.post(
672 response = self.app.post(
675 route_path('user_delete', user_id=new_user.user_id),
673 route_path('user_delete', user_id=new_user.user_id),
676 params={'user_user_groups': 'delete', 'csrf_token': self.csrf_token})
674 params={'user_user_groups': 'delete', 'csrf_token': self.csrf_token})
677
675
678 msg = 'Deleted 1 user groups'
676 msg = 'Deleted 1 user groups'
679 assert_session_flash(response, msg)
677 assert_session_flash(response, msg)
680
678
681 def test_edit(self, user_util):
679 def test_edit(self, user_util):
682 self.log_user()
680 self.log_user()
683 user = user_util.create_user()
681 user = user_util.create_user()
684 self.app.get(route_path('user_edit', user_id=user.user_id))
682 self.app.get(route_path('user_edit', user_id=user.user_id))
685
683
686 def test_edit_default_user_redirect(self):
684 def test_edit_default_user_redirect(self):
687 self.log_user()
685 self.log_user()
688 user = User.get_default_user()
686 user = User.get_default_user()
689 self.app.get(route_path('user_edit', user_id=user.user_id), status=302)
687 self.app.get(route_path('user_edit', user_id=user.user_id), status=302)
690
688
691 @pytest.mark.parametrize(
689 @pytest.mark.parametrize(
692 'repo_create, repo_create_write, user_group_create, repo_group_create,'
690 'repo_create, repo_create_write, user_group_create, repo_group_create,'
693 'fork_create, inherit_default_permissions, expect_error,'
691 'fork_create, inherit_default_permissions, expect_error,'
694 'expect_form_error', [
692 'expect_form_error', [
695 ('hg.create.none', 'hg.create.write_on_repogroup.false',
693 ('hg.create.none', 'hg.create.write_on_repogroup.false',
696 'hg.usergroup.create.false', 'hg.repogroup.create.false',
694 'hg.usergroup.create.false', 'hg.repogroup.create.false',
697 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
695 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
698 ('hg.create.repository', 'hg.create.write_on_repogroup.false',
696 ('hg.create.repository', 'hg.create.write_on_repogroup.false',
699 'hg.usergroup.create.false', 'hg.repogroup.create.false',
697 'hg.usergroup.create.false', 'hg.repogroup.create.false',
700 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
698 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
701 ('hg.create.repository', 'hg.create.write_on_repogroup.true',
699 ('hg.create.repository', 'hg.create.write_on_repogroup.true',
702 'hg.usergroup.create.true', 'hg.repogroup.create.true',
700 'hg.usergroup.create.true', 'hg.repogroup.create.true',
703 'hg.fork.repository', 'hg.inherit_default_perms.false', False,
701 'hg.fork.repository', 'hg.inherit_default_perms.false', False,
704 False),
702 False),
705 ('hg.create.XXX', 'hg.create.write_on_repogroup.true',
703 ('hg.create.XXX', 'hg.create.write_on_repogroup.true',
706 'hg.usergroup.create.true', 'hg.repogroup.create.true',
704 'hg.usergroup.create.true', 'hg.repogroup.create.true',
707 'hg.fork.repository', 'hg.inherit_default_perms.false', False,
705 'hg.fork.repository', 'hg.inherit_default_perms.false', False,
708 True),
706 True),
709 ('', '', '', '', '', '', True, False),
707 ('', '', '', '', '', '', True, False),
710 ])
708 ])
711 def test_global_perms_on_user(
709 def test_global_perms_on_user(
712 self, repo_create, repo_create_write, user_group_create,
710 self, repo_create, repo_create_write, user_group_create,
713 repo_group_create, fork_create, expect_error, expect_form_error,
711 repo_group_create, fork_create, expect_error, expect_form_error,
714 inherit_default_permissions, user_util):
712 inherit_default_permissions, user_util):
715 self.log_user()
713 self.log_user()
716 user = user_util.create_user()
714 user = user_util.create_user()
717 uid = user.user_id
715 uid = user.user_id
718
716
719 # ENABLE REPO CREATE ON A GROUP
717 # ENABLE REPO CREATE ON A GROUP
720 perm_params = {
718 perm_params = {
721 'inherit_default_permissions': False,
719 'inherit_default_permissions': False,
722 'default_repo_create': repo_create,
720 'default_repo_create': repo_create,
723 'default_repo_create_on_write': repo_create_write,
721 'default_repo_create_on_write': repo_create_write,
724 'default_user_group_create': user_group_create,
722 'default_user_group_create': user_group_create,
725 'default_repo_group_create': repo_group_create,
723 'default_repo_group_create': repo_group_create,
726 'default_fork_create': fork_create,
724 'default_fork_create': fork_create,
727 'default_inherit_default_permissions': inherit_default_permissions,
725 'default_inherit_default_permissions': inherit_default_permissions,
728 'csrf_token': self.csrf_token,
726 'csrf_token': self.csrf_token,
729 }
727 }
730 response = self.app.post(
728 response = self.app.post(
731 route_path('user_edit_global_perms_update', user_id=uid),
729 route_path('user_edit_global_perms_update', user_id=uid),
732 params=perm_params)
730 params=perm_params)
733
731
734 if expect_form_error:
732 if expect_form_error:
735 assert response.status_int == 200
733 assert response.status_int == 200
736 response.mustcontain('Value must be one of')
734 response.mustcontain('Value must be one of')
737 else:
735 else:
738 if expect_error:
736 if expect_error:
739 msg = 'An error occurred during permissions saving'
737 msg = 'An error occurred during permissions saving'
740 else:
738 else:
741 msg = 'User global permissions updated successfully'
739 msg = 'User global permissions updated successfully'
742 ug = User.get(uid)
740 ug = User.get(uid)
743 del perm_params['inherit_default_permissions']
741 del perm_params['inherit_default_permissions']
744 del perm_params['csrf_token']
742 del perm_params['csrf_token']
745 assert perm_params == ug.get_default_perms()
743 assert perm_params == ug.get_default_perms()
746 assert_session_flash(response, msg)
744 assert_session_flash(response, msg)
747
745
748 def test_global_permissions_initial_values(self, user_util):
746 def test_global_permissions_initial_values(self, user_util):
749 self.log_user()
747 self.log_user()
750 user = user_util.create_user()
748 user = user_util.create_user()
751 uid = user.user_id
749 uid = user.user_id
752 response = self.app.get(
750 response = self.app.get(
753 route_path('user_edit_global_perms', user_id=uid))
751 route_path('user_edit_global_perms', user_id=uid))
754 default_user = User.get_default_user()
752 default_user = User.get_default_user()
755 default_permissions = default_user.get_default_perms()
753 default_permissions = default_user.get_default_perms()
756 assert_response = response.assert_response()
754 assert_response = response.assert_response()
757 expected_permissions = (
755 expected_permissions = (
758 'default_repo_create', 'default_repo_create_on_write',
756 'default_repo_create', 'default_repo_create_on_write',
759 'default_fork_create', 'default_repo_group_create',
757 'default_fork_create', 'default_repo_group_create',
760 'default_user_group_create', 'default_inherit_default_permissions')
758 'default_user_group_create', 'default_inherit_default_permissions')
761 for permission in expected_permissions:
759 for permission in expected_permissions:
762 css_selector = '[name={}][checked=checked]'.format(permission)
760 css_selector = '[name={}][checked=checked]'.format(permission)
763 element = assert_response.get_element(css_selector)
761 element = assert_response.get_element(css_selector)
764 assert element.value == default_permissions[permission]
762 assert element.value == default_permissions[permission]
765
763
766 def test_perms_summary_page(self):
764 def test_perms_summary_page(self):
767 user = self.log_user()
765 user = self.log_user()
768 response = self.app.get(
766 response = self.app.get(
769 route_path('edit_user_perms_summary', user_id=user['user_id']))
767 route_path('edit_user_perms_summary', user_id=user['user_id']))
770 for repo in Repository.query().all():
768 for repo in Repository.query().all():
771 response.mustcontain(repo.repo_name)
769 response.mustcontain(repo.repo_name)
772
770
773 def test_perms_summary_page_json(self):
771 def test_perms_summary_page_json(self):
774 user = self.log_user()
772 user = self.log_user()
775 response = self.app.get(
773 response = self.app.get(
776 route_path('edit_user_perms_summary_json', user_id=user['user_id']))
774 route_path('edit_user_perms_summary_json', user_id=user['user_id']))
777 for repo in Repository.query().all():
775 for repo in Repository.query().all():
778 response.mustcontain(repo.repo_name)
776 response.mustcontain(repo.repo_name)
779
777
780 def test_audit_log_page(self):
778 def test_audit_log_page(self):
781 user = self.log_user()
779 user = self.log_user()
782 self.app.get(
780 self.app.get(
783 route_path('edit_user_audit_logs', user_id=user['user_id']))
781 route_path('edit_user_audit_logs', user_id=user['user_id']))
@@ -1,1242 +1,1261 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 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 datetime
22 import datetime
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25
25
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28 from pyramid.renderers import render
28 from pyramid.renderers import render
29 from pyramid.response import Response
29 from pyramid.response import Response
30
30
31 from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
31 from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView
32 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
32 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
33 from rhodecode.authentication.plugins import auth_rhodecode
33 from rhodecode.authentication.plugins import auth_rhodecode
34 from rhodecode.events import trigger
34 from rhodecode.events import trigger
35 from rhodecode.model.db import true
35 from rhodecode.model.db import true
36
36
37 from rhodecode.lib import audit_logger, rc_cache
37 from rhodecode.lib import audit_logger, rc_cache
38 from rhodecode.lib.exceptions import (
38 from rhodecode.lib.exceptions import (
39 UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
39 UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException,
40 UserOwnsUserGroupsException, DefaultUserException)
40 UserOwnsUserGroupsException, DefaultUserException)
41 from rhodecode.lib.ext_json import json
41 from rhodecode.lib.ext_json import json
42 from rhodecode.lib.auth import (
42 from rhodecode.lib.auth import (
43 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
43 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
44 from rhodecode.lib import helpers as h
44 from rhodecode.lib import helpers as h
45 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
45 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
46 from rhodecode.model.auth_token import AuthTokenModel
46 from rhodecode.model.auth_token import AuthTokenModel
47 from rhodecode.model.forms import (
47 from rhodecode.model.forms import (
48 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
48 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
49 UserExtraEmailForm, UserExtraIpForm)
49 UserExtraEmailForm, UserExtraIpForm)
50 from rhodecode.model.permission import PermissionModel
50 from rhodecode.model.permission import PermissionModel
51 from rhodecode.model.repo_group import RepoGroupModel
51 from rhodecode.model.repo_group import RepoGroupModel
52 from rhodecode.model.ssh_key import SshKeyModel
52 from rhodecode.model.ssh_key import SshKeyModel
53 from rhodecode.model.user import UserModel
53 from rhodecode.model.user import UserModel
54 from rhodecode.model.user_group import UserGroupModel
54 from rhodecode.model.user_group import UserGroupModel
55 from rhodecode.model.db import (
55 from rhodecode.model.db import (
56 or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap,
56 or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap,
57 UserApiKeys, UserSshKeys, RepoGroup)
57 UserApiKeys, UserSshKeys, RepoGroup)
58 from rhodecode.model.meta import Session
58 from rhodecode.model.meta import Session
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class AdminUsersView(BaseAppView, DataGridAppView):
63 class AdminUsersView(BaseAppView, DataGridAppView):
64
64
65 def load_default_context(self):
65 def load_default_context(self):
66 c = self._get_local_tmpl_context()
66 c = self._get_local_tmpl_context()
67 return c
67 return c
68
68
69 @LoginRequired()
69 @LoginRequired()
70 @HasPermissionAllDecorator('hg.admin')
70 @HasPermissionAllDecorator('hg.admin')
71 @view_config(
71 @view_config(
72 route_name='users', request_method='GET',
72 route_name='users', request_method='GET',
73 renderer='rhodecode:templates/admin/users/users.mako')
73 renderer='rhodecode:templates/admin/users/users.mako')
74 def users_list(self):
74 def users_list(self):
75 c = self.load_default_context()
75 c = self.load_default_context()
76 return self._get_template_context(c)
76 return self._get_template_context(c)
77
77
78 @LoginRequired()
78 @LoginRequired()
79 @HasPermissionAllDecorator('hg.admin')
79 @HasPermissionAllDecorator('hg.admin')
80 @view_config(
80 @view_config(
81 # renderer defined below
81 # renderer defined below
82 route_name='users_data', request_method='GET',
82 route_name='users_data', request_method='GET',
83 renderer='json_ext', xhr=True)
83 renderer='json_ext', xhr=True)
84 def users_list_data(self):
84 def users_list_data(self):
85 self.load_default_context()
85 self.load_default_context()
86 column_map = {
86 column_map = {
87 'first_name': 'name',
87 'first_name': 'name',
88 'last_name': 'lastname',
88 'last_name': 'lastname',
89 }
89 }
90 draw, start, limit = self._extract_chunk(self.request)
90 draw, start, limit = self._extract_chunk(self.request)
91 search_q, order_by, order_dir = self._extract_ordering(
91 search_q, order_by, order_dir = self._extract_ordering(
92 self.request, column_map=column_map)
92 self.request, column_map=column_map)
93 _render = self.request.get_partial_renderer(
93 _render = self.request.get_partial_renderer(
94 'rhodecode:templates/data_table/_dt_elements.mako')
94 'rhodecode:templates/data_table/_dt_elements.mako')
95
95
96 def user_actions(user_id, username):
96 def user_actions(user_id, username):
97 return _render("user_actions", user_id, username)
97 return _render("user_actions", user_id, username)
98
98
99 users_data_total_count = User.query()\
99 users_data_total_count = User.query()\
100 .filter(User.username != User.DEFAULT_USER) \
100 .filter(User.username != User.DEFAULT_USER) \
101 .count()
101 .count()
102
102
103 users_data_total_inactive_count = User.query()\
103 users_data_total_inactive_count = User.query()\
104 .filter(User.username != User.DEFAULT_USER) \
104 .filter(User.username != User.DEFAULT_USER) \
105 .filter(User.active != true())\
105 .filter(User.active != true())\
106 .count()
106 .count()
107
107
108 # json generate
108 # json generate
109 base_q = User.query().filter(User.username != User.DEFAULT_USER)
109 base_q = User.query().filter(User.username != User.DEFAULT_USER)
110 base_inactive_q = base_q.filter(User.active != true())
110 base_inactive_q = base_q.filter(User.active != true())
111
111
112 if search_q:
112 if search_q:
113 like_expression = u'%{}%'.format(safe_unicode(search_q))
113 like_expression = u'%{}%'.format(safe_unicode(search_q))
114 base_q = base_q.filter(or_(
114 base_q = base_q.filter(or_(
115 User.username.ilike(like_expression),
115 User.username.ilike(like_expression),
116 User._email.ilike(like_expression),
116 User._email.ilike(like_expression),
117 User.name.ilike(like_expression),
117 User.name.ilike(like_expression),
118 User.lastname.ilike(like_expression),
118 User.lastname.ilike(like_expression),
119 ))
119 ))
120 base_inactive_q = base_q.filter(User.active != true())
120 base_inactive_q = base_q.filter(User.active != true())
121
121
122 users_data_total_filtered_count = base_q.count()
122 users_data_total_filtered_count = base_q.count()
123 users_data_total_filtered_inactive_count = base_inactive_q.count()
123 users_data_total_filtered_inactive_count = base_inactive_q.count()
124
124
125 sort_col = getattr(User, order_by, None)
125 sort_col = getattr(User, order_by, None)
126 if sort_col:
126 if sort_col:
127 if order_dir == 'asc':
127 if order_dir == 'asc':
128 # handle null values properly to order by NULL last
128 # handle null values properly to order by NULL last
129 if order_by in ['last_activity']:
129 if order_by in ['last_activity']:
130 sort_col = coalesce(sort_col, datetime.date.max)
130 sort_col = coalesce(sort_col, datetime.date.max)
131 sort_col = sort_col.asc()
131 sort_col = sort_col.asc()
132 else:
132 else:
133 # handle null values properly to order by NULL last
133 # handle null values properly to order by NULL last
134 if order_by in ['last_activity']:
134 if order_by in ['last_activity']:
135 sort_col = coalesce(sort_col, datetime.date.min)
135 sort_col = coalesce(sort_col, datetime.date.min)
136 sort_col = sort_col.desc()
136 sort_col = sort_col.desc()
137
137
138 base_q = base_q.order_by(sort_col)
138 base_q = base_q.order_by(sort_col)
139 base_q = base_q.offset(start).limit(limit)
139 base_q = base_q.offset(start).limit(limit)
140
140
141 users_list = base_q.all()
141 users_list = base_q.all()
142
142
143 users_data = []
143 users_data = []
144 for user in users_list:
144 for user in users_list:
145 users_data.append({
145 users_data.append({
146 "username": h.gravatar_with_user(self.request, user.username),
146 "username": h.gravatar_with_user(self.request, user.username),
147 "email": user.email,
147 "email": user.email,
148 "first_name": user.first_name,
148 "first_name": user.first_name,
149 "last_name": user.last_name,
149 "last_name": user.last_name,
150 "last_login": h.format_date(user.last_login),
150 "last_login": h.format_date(user.last_login),
151 "last_activity": h.format_date(user.last_activity),
151 "last_activity": h.format_date(user.last_activity),
152 "active": h.bool2icon(user.active),
152 "active": h.bool2icon(user.active),
153 "active_raw": user.active,
153 "active_raw": user.active,
154 "admin": h.bool2icon(user.admin),
154 "admin": h.bool2icon(user.admin),
155 "extern_type": user.extern_type,
155 "extern_type": user.extern_type,
156 "extern_name": user.extern_name,
156 "extern_name": user.extern_name,
157 "action": user_actions(user.user_id, user.username),
157 "action": user_actions(user.user_id, user.username),
158 })
158 })
159 data = ({
159 data = ({
160 'draw': draw,
160 'draw': draw,
161 'data': users_data,
161 'data': users_data,
162 'recordsTotal': users_data_total_count,
162 'recordsTotal': users_data_total_count,
163 'recordsFiltered': users_data_total_filtered_count,
163 'recordsFiltered': users_data_total_filtered_count,
164 'recordsTotalInactive': users_data_total_inactive_count,
164 'recordsTotalInactive': users_data_total_inactive_count,
165 'recordsFilteredInactive': users_data_total_filtered_inactive_count
165 'recordsFilteredInactive': users_data_total_filtered_inactive_count
166 })
166 })
167
167
168 return data
168 return data
169
169
170 def _set_personal_repo_group_template_vars(self, c_obj):
170 def _set_personal_repo_group_template_vars(self, c_obj):
171 DummyUser = AttributeDict({
171 DummyUser = AttributeDict({
172 'username': '${username}',
172 'username': '${username}',
173 'user_id': '${user_id}',
173 'user_id': '${user_id}',
174 })
174 })
175 c_obj.default_create_repo_group = RepoGroupModel() \
175 c_obj.default_create_repo_group = RepoGroupModel() \
176 .get_default_create_personal_repo_group()
176 .get_default_create_personal_repo_group()
177 c_obj.personal_repo_group_name = RepoGroupModel() \
177 c_obj.personal_repo_group_name = RepoGroupModel() \
178 .get_personal_group_name(DummyUser)
178 .get_personal_group_name(DummyUser)
179
179
180 @LoginRequired()
180 @LoginRequired()
181 @HasPermissionAllDecorator('hg.admin')
181 @HasPermissionAllDecorator('hg.admin')
182 @view_config(
182 @view_config(
183 route_name='users_new', request_method='GET',
183 route_name='users_new', request_method='GET',
184 renderer='rhodecode:templates/admin/users/user_add.mako')
184 renderer='rhodecode:templates/admin/users/user_add.mako')
185 def users_new(self):
185 def users_new(self):
186 _ = self.request.translate
186 _ = self.request.translate
187 c = self.load_default_context()
187 c = self.load_default_context()
188 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
188 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
189 self._set_personal_repo_group_template_vars(c)
189 self._set_personal_repo_group_template_vars(c)
190 return self._get_template_context(c)
190 return self._get_template_context(c)
191
191
192 @LoginRequired()
192 @LoginRequired()
193 @HasPermissionAllDecorator('hg.admin')
193 @HasPermissionAllDecorator('hg.admin')
194 @CSRFRequired()
194 @CSRFRequired()
195 @view_config(
195 @view_config(
196 route_name='users_create', request_method='POST',
196 route_name='users_create', request_method='POST',
197 renderer='rhodecode:templates/admin/users/user_add.mako')
197 renderer='rhodecode:templates/admin/users/user_add.mako')
198 def users_create(self):
198 def users_create(self):
199 _ = self.request.translate
199 _ = self.request.translate
200 c = self.load_default_context()
200 c = self.load_default_context()
201 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
201 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.uid
202 user_model = UserModel()
202 user_model = UserModel()
203 user_form = UserForm(self.request.translate)()
203 user_form = UserForm(self.request.translate)()
204 try:
204 try:
205 form_result = user_form.to_python(dict(self.request.POST))
205 form_result = user_form.to_python(dict(self.request.POST))
206 user = user_model.create(form_result)
206 user = user_model.create(form_result)
207 Session().flush()
207 Session().flush()
208 creation_data = user.get_api_data()
208 creation_data = user.get_api_data()
209 username = form_result['username']
209 username = form_result['username']
210
210
211 audit_logger.store_web(
211 audit_logger.store_web(
212 'user.create', action_data={'data': creation_data},
212 'user.create', action_data={'data': creation_data},
213 user=c.rhodecode_user)
213 user=c.rhodecode_user)
214
214
215 user_link = h.link_to(
215 user_link = h.link_to(
216 h.escape(username),
216 h.escape(username),
217 h.route_path('user_edit', user_id=user.user_id))
217 h.route_path('user_edit', user_id=user.user_id))
218 h.flash(h.literal(_('Created user %(user_link)s')
218 h.flash(h.literal(_('Created user %(user_link)s')
219 % {'user_link': user_link}), category='success')
219 % {'user_link': user_link}), category='success')
220 Session().commit()
220 Session().commit()
221 except formencode.Invalid as errors:
221 except formencode.Invalid as errors:
222 self._set_personal_repo_group_template_vars(c)
222 self._set_personal_repo_group_template_vars(c)
223 data = render(
223 data = render(
224 'rhodecode:templates/admin/users/user_add.mako',
224 'rhodecode:templates/admin/users/user_add.mako',
225 self._get_template_context(c), self.request)
225 self._get_template_context(c), self.request)
226 html = formencode.htmlfill.render(
226 html = formencode.htmlfill.render(
227 data,
227 data,
228 defaults=errors.value,
228 defaults=errors.value,
229 errors=errors.error_dict or {},
229 errors=errors.error_dict or {},
230 prefix_error=False,
230 prefix_error=False,
231 encoding="UTF-8",
231 encoding="UTF-8",
232 force_defaults=False
232 force_defaults=False
233 )
233 )
234 return Response(html)
234 return Response(html)
235 except UserCreationError as e:
235 except UserCreationError as e:
236 h.flash(e, 'error')
236 h.flash(e, 'error')
237 except Exception:
237 except Exception:
238 log.exception("Exception creation of user")
238 log.exception("Exception creation of user")
239 h.flash(_('Error occurred during creation of user %s')
239 h.flash(_('Error occurred during creation of user %s')
240 % self.request.POST.get('username'), category='error')
240 % self.request.POST.get('username'), category='error')
241 raise HTTPFound(h.route_path('users'))
241 raise HTTPFound(h.route_path('users'))
242
242
243
243
244 class UsersView(UserAppView):
244 class UsersView(UserAppView):
245 ALLOW_SCOPED_TOKENS = False
245 ALLOW_SCOPED_TOKENS = False
246 """
246 """
247 This view has alternative version inside EE, if modified please take a look
247 This view has alternative version inside EE, if modified please take a look
248 in there as well.
248 in there as well.
249 """
249 """
250
250
251 def load_default_context(self):
251 def load_default_context(self):
252 c = self._get_local_tmpl_context()
252 c = self._get_local_tmpl_context()
253 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
253 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
254 c.allowed_languages = [
254 c.allowed_languages = [
255 ('en', 'English (en)'),
255 ('en', 'English (en)'),
256 ('de', 'German (de)'),
256 ('de', 'German (de)'),
257 ('fr', 'French (fr)'),
257 ('fr', 'French (fr)'),
258 ('it', 'Italian (it)'),
258 ('it', 'Italian (it)'),
259 ('ja', 'Japanese (ja)'),
259 ('ja', 'Japanese (ja)'),
260 ('pl', 'Polish (pl)'),
260 ('pl', 'Polish (pl)'),
261 ('pt', 'Portuguese (pt)'),
261 ('pt', 'Portuguese (pt)'),
262 ('ru', 'Russian (ru)'),
262 ('ru', 'Russian (ru)'),
263 ('zh', 'Chinese (zh)'),
263 ('zh', 'Chinese (zh)'),
264 ]
264 ]
265 req = self.request
265 req = self.request
266
266
267 c.available_permissions = req.registry.settings['available_permissions']
267 c.available_permissions = req.registry.settings['available_permissions']
268 PermissionModel().set_global_permission_choices(
268 PermissionModel().set_global_permission_choices(
269 c, gettext_translator=req.translate)
269 c, gettext_translator=req.translate)
270
270
271 return c
271 return c
272
272
273 @LoginRequired()
273 @LoginRequired()
274 @HasPermissionAllDecorator('hg.admin')
274 @HasPermissionAllDecorator('hg.admin')
275 @CSRFRequired()
275 @CSRFRequired()
276 @view_config(
276 @view_config(
277 route_name='user_update', request_method='POST',
277 route_name='user_update', request_method='POST',
278 renderer='rhodecode:templates/admin/users/user_edit.mako')
278 renderer='rhodecode:templates/admin/users/user_edit.mako')
279 def user_update(self):
279 def user_update(self):
280 _ = self.request.translate
280 _ = self.request.translate
281 c = self.load_default_context()
281 c = self.load_default_context()
282
282
283 user_id = self.db_user_id
283 user_id = self.db_user_id
284 c.user = self.db_user
284 c.user = self.db_user
285
285
286 c.active = 'profile'
286 c.active = 'profile'
287 c.extern_type = c.user.extern_type
287 c.extern_type = c.user.extern_type
288 c.extern_name = c.user.extern_name
288 c.extern_name = c.user.extern_name
289 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
289 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
290 available_languages = [x[0] for x in c.allowed_languages]
290 available_languages = [x[0] for x in c.allowed_languages]
291 _form = UserForm(self.request.translate, edit=True,
291 _form = UserForm(self.request.translate, edit=True,
292 available_languages=available_languages,
292 available_languages=available_languages,
293 old_data={'user_id': user_id,
293 old_data={'user_id': user_id,
294 'email': c.user.email})()
294 'email': c.user.email})()
295 form_result = {}
295 form_result = {}
296 old_values = c.user.get_api_data()
296 old_values = c.user.get_api_data()
297 try:
297 try:
298 form_result = _form.to_python(dict(self.request.POST))
298 form_result = _form.to_python(dict(self.request.POST))
299 skip_attrs = ['extern_type', 'extern_name']
299 skip_attrs = ['extern_type', 'extern_name']
300 # TODO: plugin should define if username can be updated
300 # TODO: plugin should define if username can be updated
301 if c.extern_type != "rhodecode":
301 if c.extern_type != "rhodecode":
302 # forbid updating username for external accounts
302 # forbid updating username for external accounts
303 skip_attrs.append('username')
303 skip_attrs.append('username')
304
304
305 UserModel().update_user(
305 UserModel().update_user(
306 user_id, skip_attrs=skip_attrs, **form_result)
306 user_id, skip_attrs=skip_attrs, **form_result)
307
307
308 audit_logger.store_web(
308 audit_logger.store_web(
309 'user.edit', action_data={'old_data': old_values},
309 'user.edit', action_data={'old_data': old_values},
310 user=c.rhodecode_user)
310 user=c.rhodecode_user)
311
311
312 Session().commit()
312 Session().commit()
313 h.flash(_('User updated successfully'), category='success')
313 h.flash(_('User updated successfully'), category='success')
314 except formencode.Invalid as errors:
314 except formencode.Invalid as errors:
315 data = render(
315 data = render(
316 'rhodecode:templates/admin/users/user_edit.mako',
316 'rhodecode:templates/admin/users/user_edit.mako',
317 self._get_template_context(c), self.request)
317 self._get_template_context(c), self.request)
318 html = formencode.htmlfill.render(
318 html = formencode.htmlfill.render(
319 data,
319 data,
320 defaults=errors.value,
320 defaults=errors.value,
321 errors=errors.error_dict or {},
321 errors=errors.error_dict or {},
322 prefix_error=False,
322 prefix_error=False,
323 encoding="UTF-8",
323 encoding="UTF-8",
324 force_defaults=False
324 force_defaults=False
325 )
325 )
326 return Response(html)
326 return Response(html)
327 except UserCreationError as e:
327 except UserCreationError as e:
328 h.flash(e, 'error')
328 h.flash(e, 'error')
329 except Exception:
329 except Exception:
330 log.exception("Exception updating user")
330 log.exception("Exception updating user")
331 h.flash(_('Error occurred during update of user %s')
331 h.flash(_('Error occurred during update of user %s')
332 % form_result.get('username'), category='error')
332 % form_result.get('username'), category='error')
333 raise HTTPFound(h.route_path('user_edit', user_id=user_id))
333 raise HTTPFound(h.route_path('user_edit', user_id=user_id))
334
334
335 @LoginRequired()
335 @LoginRequired()
336 @HasPermissionAllDecorator('hg.admin')
336 @HasPermissionAllDecorator('hg.admin')
337 @CSRFRequired()
337 @CSRFRequired()
338 @view_config(
338 @view_config(
339 route_name='user_delete', request_method='POST',
339 route_name='user_delete', request_method='POST',
340 renderer='rhodecode:templates/admin/users/user_edit.mako')
340 renderer='rhodecode:templates/admin/users/user_edit.mako')
341 def user_delete(self):
341 def user_delete(self):
342 _ = self.request.translate
342 _ = self.request.translate
343 c = self.load_default_context()
343 c = self.load_default_context()
344 c.user = self.db_user
344 c.user = self.db_user
345
345
346 _repos = c.user.repositories
346 _repos = c.user.repositories
347 _repo_groups = c.user.repository_groups
347 _repo_groups = c.user.repository_groups
348 _user_groups = c.user.user_groups
348 _user_groups = c.user.user_groups
349
349
350 handle_repos = None
350 handle_repos = None
351 handle_repo_groups = None
351 handle_repo_groups = None
352 handle_user_groups = None
352 handle_user_groups = None
353 # dummy call for flash of handle
353 # dummy call for flash of handle
354 set_handle_flash_repos = lambda: None
354 set_handle_flash_repos = lambda: None
355 set_handle_flash_repo_groups = lambda: None
355 set_handle_flash_repo_groups = lambda: None
356 set_handle_flash_user_groups = lambda: None
356 set_handle_flash_user_groups = lambda: None
357
357
358 if _repos and self.request.POST.get('user_repos'):
358 if _repos and self.request.POST.get('user_repos'):
359 do = self.request.POST['user_repos']
359 do = self.request.POST['user_repos']
360 if do == 'detach':
360 if do == 'detach':
361 handle_repos = 'detach'
361 handle_repos = 'detach'
362 set_handle_flash_repos = lambda: h.flash(
362 set_handle_flash_repos = lambda: h.flash(
363 _('Detached %s repositories') % len(_repos),
363 _('Detached %s repositories') % len(_repos),
364 category='success')
364 category='success')
365 elif do == 'delete':
365 elif do == 'delete':
366 handle_repos = 'delete'
366 handle_repos = 'delete'
367 set_handle_flash_repos = lambda: h.flash(
367 set_handle_flash_repos = lambda: h.flash(
368 _('Deleted %s repositories') % len(_repos),
368 _('Deleted %s repositories') % len(_repos),
369 category='success')
369 category='success')
370
370
371 if _repo_groups and self.request.POST.get('user_repo_groups'):
371 if _repo_groups and self.request.POST.get('user_repo_groups'):
372 do = self.request.POST['user_repo_groups']
372 do = self.request.POST['user_repo_groups']
373 if do == 'detach':
373 if do == 'detach':
374 handle_repo_groups = 'detach'
374 handle_repo_groups = 'detach'
375 set_handle_flash_repo_groups = lambda: h.flash(
375 set_handle_flash_repo_groups = lambda: h.flash(
376 _('Detached %s repository groups') % len(_repo_groups),
376 _('Detached %s repository groups') % len(_repo_groups),
377 category='success')
377 category='success')
378 elif do == 'delete':
378 elif do == 'delete':
379 handle_repo_groups = 'delete'
379 handle_repo_groups = 'delete'
380 set_handle_flash_repo_groups = lambda: h.flash(
380 set_handle_flash_repo_groups = lambda: h.flash(
381 _('Deleted %s repository groups') % len(_repo_groups),
381 _('Deleted %s repository groups') % len(_repo_groups),
382 category='success')
382 category='success')
383
383
384 if _user_groups and self.request.POST.get('user_user_groups'):
384 if _user_groups and self.request.POST.get('user_user_groups'):
385 do = self.request.POST['user_user_groups']
385 do = self.request.POST['user_user_groups']
386 if do == 'detach':
386 if do == 'detach':
387 handle_user_groups = 'detach'
387 handle_user_groups = 'detach'
388 set_handle_flash_user_groups = lambda: h.flash(
388 set_handle_flash_user_groups = lambda: h.flash(
389 _('Detached %s user groups') % len(_user_groups),
389 _('Detached %s user groups') % len(_user_groups),
390 category='success')
390 category='success')
391 elif do == 'delete':
391 elif do == 'delete':
392 handle_user_groups = 'delete'
392 handle_user_groups = 'delete'
393 set_handle_flash_user_groups = lambda: h.flash(
393 set_handle_flash_user_groups = lambda: h.flash(
394 _('Deleted %s user groups') % len(_user_groups),
394 _('Deleted %s user groups') % len(_user_groups),
395 category='success')
395 category='success')
396
396
397 old_values = c.user.get_api_data()
397 old_values = c.user.get_api_data()
398 try:
398 try:
399 UserModel().delete(c.user, handle_repos=handle_repos,
399 UserModel().delete(c.user, handle_repos=handle_repos,
400 handle_repo_groups=handle_repo_groups,
400 handle_repo_groups=handle_repo_groups,
401 handle_user_groups=handle_user_groups)
401 handle_user_groups=handle_user_groups)
402
402
403 audit_logger.store_web(
403 audit_logger.store_web(
404 'user.delete', action_data={'old_data': old_values},
404 'user.delete', action_data={'old_data': old_values},
405 user=c.rhodecode_user)
405 user=c.rhodecode_user)
406
406
407 Session().commit()
407 Session().commit()
408 set_handle_flash_repos()
408 set_handle_flash_repos()
409 set_handle_flash_repo_groups()
409 set_handle_flash_repo_groups()
410 set_handle_flash_user_groups()
410 set_handle_flash_user_groups()
411 h.flash(_('Successfully deleted user'), category='success')
411 h.flash(_('Successfully deleted user'), category='success')
412 except (UserOwnsReposException, UserOwnsRepoGroupsException,
412 except (UserOwnsReposException, UserOwnsRepoGroupsException,
413 UserOwnsUserGroupsException, DefaultUserException) as e:
413 UserOwnsUserGroupsException, DefaultUserException) as e:
414 h.flash(e, category='warning')
414 h.flash(e, category='warning')
415 except Exception:
415 except Exception:
416 log.exception("Exception during deletion of user")
416 log.exception("Exception during deletion of user")
417 h.flash(_('An error occurred during deletion of user'),
417 h.flash(_('An error occurred during deletion of user'),
418 category='error')
418 category='error')
419 raise HTTPFound(h.route_path('users'))
419 raise HTTPFound(h.route_path('users'))
420
420
421 @LoginRequired()
421 @LoginRequired()
422 @HasPermissionAllDecorator('hg.admin')
422 @HasPermissionAllDecorator('hg.admin')
423 @view_config(
423 @view_config(
424 route_name='user_edit', request_method='GET',
424 route_name='user_edit', request_method='GET',
425 renderer='rhodecode:templates/admin/users/user_edit.mako')
425 renderer='rhodecode:templates/admin/users/user_edit.mako')
426 def user_edit(self):
426 def user_edit(self):
427 _ = self.request.translate
427 _ = self.request.translate
428 c = self.load_default_context()
428 c = self.load_default_context()
429 c.user = self.db_user
429 c.user = self.db_user
430
430
431 c.active = 'profile'
431 c.active = 'profile'
432 c.extern_type = c.user.extern_type
432 c.extern_type = c.user.extern_type
433 c.extern_name = c.user.extern_name
433 c.extern_name = c.user.extern_name
434 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
434 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
435
435
436 defaults = c.user.get_dict()
436 defaults = c.user.get_dict()
437 defaults.update({'language': c.user.user_data.get('language')})
437 defaults.update({'language': c.user.user_data.get('language')})
438
438
439 data = render(
439 data = render(
440 'rhodecode:templates/admin/users/user_edit.mako',
440 'rhodecode:templates/admin/users/user_edit.mako',
441 self._get_template_context(c), self.request)
441 self._get_template_context(c), self.request)
442 html = formencode.htmlfill.render(
442 html = formencode.htmlfill.render(
443 data,
443 data,
444 defaults=defaults,
444 defaults=defaults,
445 encoding="UTF-8",
445 encoding="UTF-8",
446 force_defaults=False
446 force_defaults=False
447 )
447 )
448 return Response(html)
448 return Response(html)
449
449
450 @LoginRequired()
450 @LoginRequired()
451 @HasPermissionAllDecorator('hg.admin')
451 @HasPermissionAllDecorator('hg.admin')
452 @view_config(
452 @view_config(
453 route_name='user_edit_advanced', request_method='GET',
453 route_name='user_edit_advanced', request_method='GET',
454 renderer='rhodecode:templates/admin/users/user_edit.mako')
454 renderer='rhodecode:templates/admin/users/user_edit.mako')
455 def user_edit_advanced(self):
455 def user_edit_advanced(self):
456 _ = self.request.translate
456 _ = self.request.translate
457 c = self.load_default_context()
457 c = self.load_default_context()
458
458
459 user_id = self.db_user_id
459 user_id = self.db_user_id
460 c.user = self.db_user
460 c.user = self.db_user
461
461
462 c.active = 'advanced'
462 c.active = 'advanced'
463 c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id)
463 c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id)
464 c.personal_repo_group_name = RepoGroupModel()\
464 c.personal_repo_group_name = RepoGroupModel()\
465 .get_personal_group_name(c.user)
465 .get_personal_group_name(c.user)
466
466
467 c.user_to_review_rules = sorted(
467 c.user_to_review_rules = sorted(
468 (x.user for x in c.user.user_review_rules),
468 (x.user for x in c.user.user_review_rules),
469 key=lambda u: u.username.lower())
469 key=lambda u: u.username.lower())
470
470
471 c.first_admin = User.get_first_super_admin()
471 c.first_admin = User.get_first_super_admin()
472 defaults = c.user.get_dict()
472 defaults = c.user.get_dict()
473
473
474 # Interim workaround if the user participated on any pull requests as a
474 # Interim workaround if the user participated on any pull requests as a
475 # reviewer.
475 # reviewer.
476 has_review = len(c.user.reviewer_pull_requests)
476 has_review = len(c.user.reviewer_pull_requests)
477 c.can_delete_user = not has_review
477 c.can_delete_user = not has_review
478 c.can_delete_user_message = ''
478 c.can_delete_user_message = ''
479 inactive_link = h.link_to(
479 inactive_link = h.link_to(
480 'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active'))
480 'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active'))
481 if has_review == 1:
481 if has_review == 1:
482 c.can_delete_user_message = h.literal(_(
482 c.can_delete_user_message = h.literal(_(
483 'The user participates as reviewer in {} pull request and '
483 'The user participates as reviewer in {} pull request and '
484 'cannot be deleted. \nYou can set the user to '
484 'cannot be deleted. \nYou can set the user to '
485 '"{}" instead of deleting it.').format(
485 '"{}" instead of deleting it.').format(
486 has_review, inactive_link))
486 has_review, inactive_link))
487 elif has_review:
487 elif has_review:
488 c.can_delete_user_message = h.literal(_(
488 c.can_delete_user_message = h.literal(_(
489 'The user participates as reviewer in {} pull requests and '
489 'The user participates as reviewer in {} pull requests and '
490 'cannot be deleted. \nYou can set the user to '
490 'cannot be deleted. \nYou can set the user to '
491 '"{}" instead of deleting it.').format(
491 '"{}" instead of deleting it.').format(
492 has_review, inactive_link))
492 has_review, inactive_link))
493
493
494 data = render(
494 data = render(
495 'rhodecode:templates/admin/users/user_edit.mako',
495 'rhodecode:templates/admin/users/user_edit.mako',
496 self._get_template_context(c), self.request)
496 self._get_template_context(c), self.request)
497 html = formencode.htmlfill.render(
497 html = formencode.htmlfill.render(
498 data,
498 data,
499 defaults=defaults,
499 defaults=defaults,
500 encoding="UTF-8",
500 encoding="UTF-8",
501 force_defaults=False
501 force_defaults=False
502 )
502 )
503 return Response(html)
503 return Response(html)
504
504
505 @LoginRequired()
505 @LoginRequired()
506 @HasPermissionAllDecorator('hg.admin')
506 @HasPermissionAllDecorator('hg.admin')
507 @view_config(
507 @view_config(
508 route_name='user_edit_global_perms', request_method='GET',
508 route_name='user_edit_global_perms', request_method='GET',
509 renderer='rhodecode:templates/admin/users/user_edit.mako')
509 renderer='rhodecode:templates/admin/users/user_edit.mako')
510 def user_edit_global_perms(self):
510 def user_edit_global_perms(self):
511 _ = self.request.translate
511 _ = self.request.translate
512 c = self.load_default_context()
512 c = self.load_default_context()
513 c.user = self.db_user
513 c.user = self.db_user
514
514
515 c.active = 'global_perms'
515 c.active = 'global_perms'
516
516
517 c.default_user = User.get_default_user()
517 c.default_user = User.get_default_user()
518 defaults = c.user.get_dict()
518 defaults = c.user.get_dict()
519 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
519 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
520 defaults.update(c.default_user.get_default_perms())
520 defaults.update(c.default_user.get_default_perms())
521 defaults.update(c.user.get_default_perms())
521 defaults.update(c.user.get_default_perms())
522
522
523 data = render(
523 data = render(
524 'rhodecode:templates/admin/users/user_edit.mako',
524 'rhodecode:templates/admin/users/user_edit.mako',
525 self._get_template_context(c), self.request)
525 self._get_template_context(c), self.request)
526 html = formencode.htmlfill.render(
526 html = formencode.htmlfill.render(
527 data,
527 data,
528 defaults=defaults,
528 defaults=defaults,
529 encoding="UTF-8",
529 encoding="UTF-8",
530 force_defaults=False
530 force_defaults=False
531 )
531 )
532 return Response(html)
532 return Response(html)
533
533
534 @LoginRequired()
534 @LoginRequired()
535 @HasPermissionAllDecorator('hg.admin')
535 @HasPermissionAllDecorator('hg.admin')
536 @CSRFRequired()
536 @CSRFRequired()
537 @view_config(
537 @view_config(
538 route_name='user_edit_global_perms_update', request_method='POST',
538 route_name='user_edit_global_perms_update', request_method='POST',
539 renderer='rhodecode:templates/admin/users/user_edit.mako')
539 renderer='rhodecode:templates/admin/users/user_edit.mako')
540 def user_edit_global_perms_update(self):
540 def user_edit_global_perms_update(self):
541 _ = self.request.translate
541 _ = self.request.translate
542 c = self.load_default_context()
542 c = self.load_default_context()
543
543
544 user_id = self.db_user_id
544 user_id = self.db_user_id
545 c.user = self.db_user
545 c.user = self.db_user
546
546
547 c.active = 'global_perms'
547 c.active = 'global_perms'
548 try:
548 try:
549 # first stage that verifies the checkbox
549 # first stage that verifies the checkbox
550 _form = UserIndividualPermissionsForm(self.request.translate)
550 _form = UserIndividualPermissionsForm(self.request.translate)
551 form_result = _form.to_python(dict(self.request.POST))
551 form_result = _form.to_python(dict(self.request.POST))
552 inherit_perms = form_result['inherit_default_permissions']
552 inherit_perms = form_result['inherit_default_permissions']
553 c.user.inherit_default_permissions = inherit_perms
553 c.user.inherit_default_permissions = inherit_perms
554 Session().add(c.user)
554 Session().add(c.user)
555
555
556 if not inherit_perms:
556 if not inherit_perms:
557 # only update the individual ones if we un check the flag
557 # only update the individual ones if we un check the flag
558 _form = UserPermissionsForm(
558 _form = UserPermissionsForm(
559 self.request.translate,
559 self.request.translate,
560 [x[0] for x in c.repo_create_choices],
560 [x[0] for x in c.repo_create_choices],
561 [x[0] for x in c.repo_create_on_write_choices],
561 [x[0] for x in c.repo_create_on_write_choices],
562 [x[0] for x in c.repo_group_create_choices],
562 [x[0] for x in c.repo_group_create_choices],
563 [x[0] for x in c.user_group_create_choices],
563 [x[0] for x in c.user_group_create_choices],
564 [x[0] for x in c.fork_choices],
564 [x[0] for x in c.fork_choices],
565 [x[0] for x in c.inherit_default_permission_choices])()
565 [x[0] for x in c.inherit_default_permission_choices])()
566
566
567 form_result = _form.to_python(dict(self.request.POST))
567 form_result = _form.to_python(dict(self.request.POST))
568 form_result.update({'perm_user_id': c.user.user_id})
568 form_result.update({'perm_user_id': c.user.user_id})
569
569
570 PermissionModel().update_user_permissions(form_result)
570 PermissionModel().update_user_permissions(form_result)
571
571
572 # TODO(marcink): implement global permissions
572 # TODO(marcink): implement global permissions
573 # audit_log.store_web('user.edit.permissions')
573 # audit_log.store_web('user.edit.permissions')
574
574
575 Session().commit()
575 Session().commit()
576 h.flash(_('User global permissions updated successfully'),
576 h.flash(_('User global permissions updated successfully'),
577 category='success')
577 category='success')
578
578
579 except formencode.Invalid as errors:
579 except formencode.Invalid as errors:
580 data = render(
580 data = render(
581 'rhodecode:templates/admin/users/user_edit.mako',
581 'rhodecode:templates/admin/users/user_edit.mako',
582 self._get_template_context(c), self.request)
582 self._get_template_context(c), self.request)
583 html = formencode.htmlfill.render(
583 html = formencode.htmlfill.render(
584 data,
584 data,
585 defaults=errors.value,
585 defaults=errors.value,
586 errors=errors.error_dict or {},
586 errors=errors.error_dict or {},
587 prefix_error=False,
587 prefix_error=False,
588 encoding="UTF-8",
588 encoding="UTF-8",
589 force_defaults=False
589 force_defaults=False
590 )
590 )
591 return Response(html)
591 return Response(html)
592 except Exception:
592 except Exception:
593 log.exception("Exception during permissions saving")
593 log.exception("Exception during permissions saving")
594 h.flash(_('An error occurred during permissions saving'),
594 h.flash(_('An error occurred during permissions saving'),
595 category='error')
595 category='error')
596 raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
596 raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id))
597
597
598 @LoginRequired()
598 @LoginRequired()
599 @HasPermissionAllDecorator('hg.admin')
599 @HasPermissionAllDecorator('hg.admin')
600 @CSRFRequired()
600 @CSRFRequired()
601 @view_config(
601 @view_config(
602 route_name='user_force_password_reset', request_method='POST',
602 route_name='user_enable_force_password_reset', request_method='POST',
603 renderer='rhodecode:templates/admin/users/user_edit.mako')
603 renderer='rhodecode:templates/admin/users/user_edit.mako')
604 def user_force_password_reset(self):
604 def user_enable_force_password_reset(self):
605 """
606 toggle reset password flag for this user
607 """
608 _ = self.request.translate
605 _ = self.request.translate
609 c = self.load_default_context()
606 c = self.load_default_context()
610
607
611 user_id = self.db_user_id
608 user_id = self.db_user_id
612 c.user = self.db_user
609 c.user = self.db_user
613
610
614 try:
611 try:
615 old_value = c.user.user_data.get('force_password_change')
612 c.user.update_userdata(force_password_change=True)
616 c.user.update_userdata(force_password_change=not old_value)
613
614 msg = _('Force password change enabled for user')
615 audit_logger.store_web('user.edit.password_reset.enabled',
616 user=c.rhodecode_user)
617
618 Session().commit()
619 h.flash(msg, category='success')
620 except Exception:
621 log.exception("Exception during password reset for user")
622 h.flash(_('An error occurred during password reset for user'),
623 category='error')
624
625 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
617
626
618 if old_value:
627 @LoginRequired()
619 msg = _('Force password change disabled for user')
628 @HasPermissionAllDecorator('hg.admin')
620 audit_logger.store_web(
629 @CSRFRequired()
621 'user.edit.password_reset.disabled',
630 @view_config(
622 user=c.rhodecode_user)
631 route_name='user_disable_force_password_reset', request_method='POST',
623 else:
632 renderer='rhodecode:templates/admin/users/user_edit.mako')
624 msg = _('Force password change enabled for user')
633 def user_disable_force_password_reset(self):
625 audit_logger.store_web(
634 _ = self.request.translate
626 'user.edit.password_reset.enabled',
635 c = self.load_default_context()
627 user=c.rhodecode_user)
636
637 user_id = self.db_user_id
638 c.user = self.db_user
639
640 try:
641 c.user.update_userdata(force_password_change=False)
642
643 msg = _('Force password change disabled for user')
644 audit_logger.store_web(
645 'user.edit.password_reset.disabled',
646 user=c.rhodecode_user)
628
647
629 Session().commit()
648 Session().commit()
630 h.flash(msg, category='success')
649 h.flash(msg, category='success')
631 except Exception:
650 except Exception:
632 log.exception("Exception during password reset for user")
651 log.exception("Exception during password reset for user")
633 h.flash(_('An error occurred during password reset for user'),
652 h.flash(_('An error occurred during password reset for user'),
634 category='error')
653 category='error')
635
654
636 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
655 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
637
656
638 @LoginRequired()
657 @LoginRequired()
639 @HasPermissionAllDecorator('hg.admin')
658 @HasPermissionAllDecorator('hg.admin')
640 @CSRFRequired()
659 @CSRFRequired()
641 @view_config(
660 @view_config(
642 route_name='user_create_personal_repo_group', request_method='POST',
661 route_name='user_create_personal_repo_group', request_method='POST',
643 renderer='rhodecode:templates/admin/users/user_edit.mako')
662 renderer='rhodecode:templates/admin/users/user_edit.mako')
644 def user_create_personal_repo_group(self):
663 def user_create_personal_repo_group(self):
645 """
664 """
646 Create personal repository group for this user
665 Create personal repository group for this user
647 """
666 """
648 from rhodecode.model.repo_group import RepoGroupModel
667 from rhodecode.model.repo_group import RepoGroupModel
649
668
650 _ = self.request.translate
669 _ = self.request.translate
651 c = self.load_default_context()
670 c = self.load_default_context()
652
671
653 user_id = self.db_user_id
672 user_id = self.db_user_id
654 c.user = self.db_user
673 c.user = self.db_user
655
674
656 personal_repo_group = RepoGroup.get_user_personal_repo_group(
675 personal_repo_group = RepoGroup.get_user_personal_repo_group(
657 c.user.user_id)
676 c.user.user_id)
658 if personal_repo_group:
677 if personal_repo_group:
659 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
678 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
660
679
661 personal_repo_group_name = RepoGroupModel().get_personal_group_name(
680 personal_repo_group_name = RepoGroupModel().get_personal_group_name(
662 c.user)
681 c.user)
663 named_personal_group = RepoGroup.get_by_group_name(
682 named_personal_group = RepoGroup.get_by_group_name(
664 personal_repo_group_name)
683 personal_repo_group_name)
665 try:
684 try:
666
685
667 if named_personal_group and named_personal_group.user_id == c.user.user_id:
686 if named_personal_group and named_personal_group.user_id == c.user.user_id:
668 # migrate the same named group, and mark it as personal
687 # migrate the same named group, and mark it as personal
669 named_personal_group.personal = True
688 named_personal_group.personal = True
670 Session().add(named_personal_group)
689 Session().add(named_personal_group)
671 Session().commit()
690 Session().commit()
672 msg = _('Linked repository group `%s` as personal' % (
691 msg = _('Linked repository group `%s` as personal' % (
673 personal_repo_group_name,))
692 personal_repo_group_name,))
674 h.flash(msg, category='success')
693 h.flash(msg, category='success')
675 elif not named_personal_group:
694 elif not named_personal_group:
676 RepoGroupModel().create_personal_repo_group(c.user)
695 RepoGroupModel().create_personal_repo_group(c.user)
677
696
678 msg = _('Created repository group `%s`' % (
697 msg = _('Created repository group `%s`' % (
679 personal_repo_group_name,))
698 personal_repo_group_name,))
680 h.flash(msg, category='success')
699 h.flash(msg, category='success')
681 else:
700 else:
682 msg = _('Repository group `%s` is already taken' % (
701 msg = _('Repository group `%s` is already taken' % (
683 personal_repo_group_name,))
702 personal_repo_group_name,))
684 h.flash(msg, category='warning')
703 h.flash(msg, category='warning')
685 except Exception:
704 except Exception:
686 log.exception("Exception during repository group creation")
705 log.exception("Exception during repository group creation")
687 msg = _(
706 msg = _(
688 'An error occurred during repository group creation for user')
707 'An error occurred during repository group creation for user')
689 h.flash(msg, category='error')
708 h.flash(msg, category='error')
690 Session().rollback()
709 Session().rollback()
691
710
692 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
711 raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
693
712
694 @LoginRequired()
713 @LoginRequired()
695 @HasPermissionAllDecorator('hg.admin')
714 @HasPermissionAllDecorator('hg.admin')
696 @view_config(
715 @view_config(
697 route_name='edit_user_auth_tokens', request_method='GET',
716 route_name='edit_user_auth_tokens', request_method='GET',
698 renderer='rhodecode:templates/admin/users/user_edit.mako')
717 renderer='rhodecode:templates/admin/users/user_edit.mako')
699 def auth_tokens(self):
718 def auth_tokens(self):
700 _ = self.request.translate
719 _ = self.request.translate
701 c = self.load_default_context()
720 c = self.load_default_context()
702 c.user = self.db_user
721 c.user = self.db_user
703
722
704 c.active = 'auth_tokens'
723 c.active = 'auth_tokens'
705
724
706 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
725 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
707 c.role_values = [
726 c.role_values = [
708 (x, AuthTokenModel.cls._get_role_name(x))
727 (x, AuthTokenModel.cls._get_role_name(x))
709 for x in AuthTokenModel.cls.ROLES]
728 for x in AuthTokenModel.cls.ROLES]
710 c.role_options = [(c.role_values, _("Role"))]
729 c.role_options = [(c.role_values, _("Role"))]
711 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
730 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
712 c.user.user_id, show_expired=True)
731 c.user.user_id, show_expired=True)
713 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
732 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
714 return self._get_template_context(c)
733 return self._get_template_context(c)
715
734
716 def maybe_attach_token_scope(self, token):
735 def maybe_attach_token_scope(self, token):
717 # implemented in EE edition
736 # implemented in EE edition
718 pass
737 pass
719
738
720 @LoginRequired()
739 @LoginRequired()
721 @HasPermissionAllDecorator('hg.admin')
740 @HasPermissionAllDecorator('hg.admin')
722 @CSRFRequired()
741 @CSRFRequired()
723 @view_config(
742 @view_config(
724 route_name='edit_user_auth_tokens_add', request_method='POST')
743 route_name='edit_user_auth_tokens_add', request_method='POST')
725 def auth_tokens_add(self):
744 def auth_tokens_add(self):
726 _ = self.request.translate
745 _ = self.request.translate
727 c = self.load_default_context()
746 c = self.load_default_context()
728
747
729 user_id = self.db_user_id
748 user_id = self.db_user_id
730 c.user = self.db_user
749 c.user = self.db_user
731
750
732 user_data = c.user.get_api_data()
751 user_data = c.user.get_api_data()
733 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
752 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
734 description = self.request.POST.get('description')
753 description = self.request.POST.get('description')
735 role = self.request.POST.get('role')
754 role = self.request.POST.get('role')
736
755
737 token = UserModel().add_auth_token(
756 token = UserModel().add_auth_token(
738 user=c.user.user_id,
757 user=c.user.user_id,
739 lifetime_minutes=lifetime, role=role, description=description,
758 lifetime_minutes=lifetime, role=role, description=description,
740 scope_callback=self.maybe_attach_token_scope)
759 scope_callback=self.maybe_attach_token_scope)
741 token_data = token.get_api_data()
760 token_data = token.get_api_data()
742
761
743 audit_logger.store_web(
762 audit_logger.store_web(
744 'user.edit.token.add', action_data={
763 'user.edit.token.add', action_data={
745 'data': {'token': token_data, 'user': user_data}},
764 'data': {'token': token_data, 'user': user_data}},
746 user=self._rhodecode_user, )
765 user=self._rhodecode_user, )
747 Session().commit()
766 Session().commit()
748
767
749 h.flash(_("Auth token successfully created"), category='success')
768 h.flash(_("Auth token successfully created"), category='success')
750 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
769 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
751
770
752 @LoginRequired()
771 @LoginRequired()
753 @HasPermissionAllDecorator('hg.admin')
772 @HasPermissionAllDecorator('hg.admin')
754 @CSRFRequired()
773 @CSRFRequired()
755 @view_config(
774 @view_config(
756 route_name='edit_user_auth_tokens_delete', request_method='POST')
775 route_name='edit_user_auth_tokens_delete', request_method='POST')
757 def auth_tokens_delete(self):
776 def auth_tokens_delete(self):
758 _ = self.request.translate
777 _ = self.request.translate
759 c = self.load_default_context()
778 c = self.load_default_context()
760
779
761 user_id = self.db_user_id
780 user_id = self.db_user_id
762 c.user = self.db_user
781 c.user = self.db_user
763
782
764 user_data = c.user.get_api_data()
783 user_data = c.user.get_api_data()
765
784
766 del_auth_token = self.request.POST.get('del_auth_token')
785 del_auth_token = self.request.POST.get('del_auth_token')
767
786
768 if del_auth_token:
787 if del_auth_token:
769 token = UserApiKeys.get_or_404(del_auth_token)
788 token = UserApiKeys.get_or_404(del_auth_token)
770 token_data = token.get_api_data()
789 token_data = token.get_api_data()
771
790
772 AuthTokenModel().delete(del_auth_token, c.user.user_id)
791 AuthTokenModel().delete(del_auth_token, c.user.user_id)
773 audit_logger.store_web(
792 audit_logger.store_web(
774 'user.edit.token.delete', action_data={
793 'user.edit.token.delete', action_data={
775 'data': {'token': token_data, 'user': user_data}},
794 'data': {'token': token_data, 'user': user_data}},
776 user=self._rhodecode_user,)
795 user=self._rhodecode_user,)
777 Session().commit()
796 Session().commit()
778 h.flash(_("Auth token successfully deleted"), category='success')
797 h.flash(_("Auth token successfully deleted"), category='success')
779
798
780 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
799 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
781
800
782 @LoginRequired()
801 @LoginRequired()
783 @HasPermissionAllDecorator('hg.admin')
802 @HasPermissionAllDecorator('hg.admin')
784 @view_config(
803 @view_config(
785 route_name='edit_user_ssh_keys', request_method='GET',
804 route_name='edit_user_ssh_keys', request_method='GET',
786 renderer='rhodecode:templates/admin/users/user_edit.mako')
805 renderer='rhodecode:templates/admin/users/user_edit.mako')
787 def ssh_keys(self):
806 def ssh_keys(self):
788 _ = self.request.translate
807 _ = self.request.translate
789 c = self.load_default_context()
808 c = self.load_default_context()
790 c.user = self.db_user
809 c.user = self.db_user
791
810
792 c.active = 'ssh_keys'
811 c.active = 'ssh_keys'
793 c.default_key = self.request.GET.get('default_key')
812 c.default_key = self.request.GET.get('default_key')
794 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
813 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
795 return self._get_template_context(c)
814 return self._get_template_context(c)
796
815
797 @LoginRequired()
816 @LoginRequired()
798 @HasPermissionAllDecorator('hg.admin')
817 @HasPermissionAllDecorator('hg.admin')
799 @view_config(
818 @view_config(
800 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
819 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
801 renderer='rhodecode:templates/admin/users/user_edit.mako')
820 renderer='rhodecode:templates/admin/users/user_edit.mako')
802 def ssh_keys_generate_keypair(self):
821 def ssh_keys_generate_keypair(self):
803 _ = self.request.translate
822 _ = self.request.translate
804 c = self.load_default_context()
823 c = self.load_default_context()
805
824
806 c.user = self.db_user
825 c.user = self.db_user
807
826
808 c.active = 'ssh_keys_generate'
827 c.active = 'ssh_keys_generate'
809 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
828 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
810 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
829 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
811
830
812 return self._get_template_context(c)
831 return self._get_template_context(c)
813
832
814 @LoginRequired()
833 @LoginRequired()
815 @HasPermissionAllDecorator('hg.admin')
834 @HasPermissionAllDecorator('hg.admin')
816 @CSRFRequired()
835 @CSRFRequired()
817 @view_config(
836 @view_config(
818 route_name='edit_user_ssh_keys_add', request_method='POST')
837 route_name='edit_user_ssh_keys_add', request_method='POST')
819 def ssh_keys_add(self):
838 def ssh_keys_add(self):
820 _ = self.request.translate
839 _ = self.request.translate
821 c = self.load_default_context()
840 c = self.load_default_context()
822
841
823 user_id = self.db_user_id
842 user_id = self.db_user_id
824 c.user = self.db_user
843 c.user = self.db_user
825
844
826 user_data = c.user.get_api_data()
845 user_data = c.user.get_api_data()
827 key_data = self.request.POST.get('key_data')
846 key_data = self.request.POST.get('key_data')
828 description = self.request.POST.get('description')
847 description = self.request.POST.get('description')
829
848
830 fingerprint = 'unknown'
849 fingerprint = 'unknown'
831 try:
850 try:
832 if not key_data:
851 if not key_data:
833 raise ValueError('Please add a valid public key')
852 raise ValueError('Please add a valid public key')
834
853
835 key = SshKeyModel().parse_key(key_data.strip())
854 key = SshKeyModel().parse_key(key_data.strip())
836 fingerprint = key.hash_md5()
855 fingerprint = key.hash_md5()
837
856
838 ssh_key = SshKeyModel().create(
857 ssh_key = SshKeyModel().create(
839 c.user.user_id, fingerprint, key.keydata, description)
858 c.user.user_id, fingerprint, key.keydata, description)
840 ssh_key_data = ssh_key.get_api_data()
859 ssh_key_data = ssh_key.get_api_data()
841
860
842 audit_logger.store_web(
861 audit_logger.store_web(
843 'user.edit.ssh_key.add', action_data={
862 'user.edit.ssh_key.add', action_data={
844 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
863 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
845 user=self._rhodecode_user, )
864 user=self._rhodecode_user, )
846 Session().commit()
865 Session().commit()
847
866
848 # Trigger an event on change of keys.
867 # Trigger an event on change of keys.
849 trigger(SshKeyFileChangeEvent(), self.request.registry)
868 trigger(SshKeyFileChangeEvent(), self.request.registry)
850
869
851 h.flash(_("Ssh Key successfully created"), category='success')
870 h.flash(_("Ssh Key successfully created"), category='success')
852
871
853 except IntegrityError:
872 except IntegrityError:
854 log.exception("Exception during ssh key saving")
873 log.exception("Exception during ssh key saving")
855 err = 'Such key with fingerprint `{}` already exists, ' \
874 err = 'Such key with fingerprint `{}` already exists, ' \
856 'please use a different one'.format(fingerprint)
875 'please use a different one'.format(fingerprint)
857 h.flash(_('An error occurred during ssh key saving: {}').format(err),
876 h.flash(_('An error occurred during ssh key saving: {}').format(err),
858 category='error')
877 category='error')
859 except Exception as e:
878 except Exception as e:
860 log.exception("Exception during ssh key saving")
879 log.exception("Exception during ssh key saving")
861 h.flash(_('An error occurred during ssh key saving: {}').format(e),
880 h.flash(_('An error occurred during ssh key saving: {}').format(e),
862 category='error')
881 category='error')
863
882
864 return HTTPFound(
883 return HTTPFound(
865 h.route_path('edit_user_ssh_keys', user_id=user_id))
884 h.route_path('edit_user_ssh_keys', user_id=user_id))
866
885
867 @LoginRequired()
886 @LoginRequired()
868 @HasPermissionAllDecorator('hg.admin')
887 @HasPermissionAllDecorator('hg.admin')
869 @CSRFRequired()
888 @CSRFRequired()
870 @view_config(
889 @view_config(
871 route_name='edit_user_ssh_keys_delete', request_method='POST')
890 route_name='edit_user_ssh_keys_delete', request_method='POST')
872 def ssh_keys_delete(self):
891 def ssh_keys_delete(self):
873 _ = self.request.translate
892 _ = self.request.translate
874 c = self.load_default_context()
893 c = self.load_default_context()
875
894
876 user_id = self.db_user_id
895 user_id = self.db_user_id
877 c.user = self.db_user
896 c.user = self.db_user
878
897
879 user_data = c.user.get_api_data()
898 user_data = c.user.get_api_data()
880
899
881 del_ssh_key = self.request.POST.get('del_ssh_key')
900 del_ssh_key = self.request.POST.get('del_ssh_key')
882
901
883 if del_ssh_key:
902 if del_ssh_key:
884 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
903 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
885 ssh_key_data = ssh_key.get_api_data()
904 ssh_key_data = ssh_key.get_api_data()
886
905
887 SshKeyModel().delete(del_ssh_key, c.user.user_id)
906 SshKeyModel().delete(del_ssh_key, c.user.user_id)
888 audit_logger.store_web(
907 audit_logger.store_web(
889 'user.edit.ssh_key.delete', action_data={
908 'user.edit.ssh_key.delete', action_data={
890 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
909 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
891 user=self._rhodecode_user,)
910 user=self._rhodecode_user,)
892 Session().commit()
911 Session().commit()
893 # Trigger an event on change of keys.
912 # Trigger an event on change of keys.
894 trigger(SshKeyFileChangeEvent(), self.request.registry)
913 trigger(SshKeyFileChangeEvent(), self.request.registry)
895 h.flash(_("Ssh key successfully deleted"), category='success')
914 h.flash(_("Ssh key successfully deleted"), category='success')
896
915
897 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
916 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
898
917
899 @LoginRequired()
918 @LoginRequired()
900 @HasPermissionAllDecorator('hg.admin')
919 @HasPermissionAllDecorator('hg.admin')
901 @view_config(
920 @view_config(
902 route_name='edit_user_emails', request_method='GET',
921 route_name='edit_user_emails', request_method='GET',
903 renderer='rhodecode:templates/admin/users/user_edit.mako')
922 renderer='rhodecode:templates/admin/users/user_edit.mako')
904 def emails(self):
923 def emails(self):
905 _ = self.request.translate
924 _ = self.request.translate
906 c = self.load_default_context()
925 c = self.load_default_context()
907 c.user = self.db_user
926 c.user = self.db_user
908
927
909 c.active = 'emails'
928 c.active = 'emails'
910 c.user_email_map = UserEmailMap.query() \
929 c.user_email_map = UserEmailMap.query() \
911 .filter(UserEmailMap.user == c.user).all()
930 .filter(UserEmailMap.user == c.user).all()
912
931
913 return self._get_template_context(c)
932 return self._get_template_context(c)
914
933
915 @LoginRequired()
934 @LoginRequired()
916 @HasPermissionAllDecorator('hg.admin')
935 @HasPermissionAllDecorator('hg.admin')
917 @CSRFRequired()
936 @CSRFRequired()
918 @view_config(
937 @view_config(
919 route_name='edit_user_emails_add', request_method='POST')
938 route_name='edit_user_emails_add', request_method='POST')
920 def emails_add(self):
939 def emails_add(self):
921 _ = self.request.translate
940 _ = self.request.translate
922 c = self.load_default_context()
941 c = self.load_default_context()
923
942
924 user_id = self.db_user_id
943 user_id = self.db_user_id
925 c.user = self.db_user
944 c.user = self.db_user
926
945
927 email = self.request.POST.get('new_email')
946 email = self.request.POST.get('new_email')
928 user_data = c.user.get_api_data()
947 user_data = c.user.get_api_data()
929 try:
948 try:
930
949
931 form = UserExtraEmailForm(self.request.translate)()
950 form = UserExtraEmailForm(self.request.translate)()
932 data = form.to_python({'email': email})
951 data = form.to_python({'email': email})
933 email = data['email']
952 email = data['email']
934
953
935 UserModel().add_extra_email(c.user.user_id, email)
954 UserModel().add_extra_email(c.user.user_id, email)
936 audit_logger.store_web(
955 audit_logger.store_web(
937 'user.edit.email.add',
956 'user.edit.email.add',
938 action_data={'email': email, 'user': user_data},
957 action_data={'email': email, 'user': user_data},
939 user=self._rhodecode_user)
958 user=self._rhodecode_user)
940 Session().commit()
959 Session().commit()
941 h.flash(_("Added new email address `%s` for user account") % email,
960 h.flash(_("Added new email address `%s` for user account") % email,
942 category='success')
961 category='success')
943 except formencode.Invalid as error:
962 except formencode.Invalid as error:
944 h.flash(h.escape(error.error_dict['email']), category='error')
963 h.flash(h.escape(error.error_dict['email']), category='error')
945 except IntegrityError:
964 except IntegrityError:
946 log.warning("Email %s already exists", email)
965 log.warning("Email %s already exists", email)
947 h.flash(_('Email `{}` is already registered for another user.').format(email),
966 h.flash(_('Email `{}` is already registered for another user.').format(email),
948 category='error')
967 category='error')
949 except Exception:
968 except Exception:
950 log.exception("Exception during email saving")
969 log.exception("Exception during email saving")
951 h.flash(_('An error occurred during email saving'),
970 h.flash(_('An error occurred during email saving'),
952 category='error')
971 category='error')
953 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
972 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
954
973
955 @LoginRequired()
974 @LoginRequired()
956 @HasPermissionAllDecorator('hg.admin')
975 @HasPermissionAllDecorator('hg.admin')
957 @CSRFRequired()
976 @CSRFRequired()
958 @view_config(
977 @view_config(
959 route_name='edit_user_emails_delete', request_method='POST')
978 route_name='edit_user_emails_delete', request_method='POST')
960 def emails_delete(self):
979 def emails_delete(self):
961 _ = self.request.translate
980 _ = self.request.translate
962 c = self.load_default_context()
981 c = self.load_default_context()
963
982
964 user_id = self.db_user_id
983 user_id = self.db_user_id
965 c.user = self.db_user
984 c.user = self.db_user
966
985
967 email_id = self.request.POST.get('del_email_id')
986 email_id = self.request.POST.get('del_email_id')
968 user_model = UserModel()
987 user_model = UserModel()
969
988
970 email = UserEmailMap.query().get(email_id).email
989 email = UserEmailMap.query().get(email_id).email
971 user_data = c.user.get_api_data()
990 user_data = c.user.get_api_data()
972 user_model.delete_extra_email(c.user.user_id, email_id)
991 user_model.delete_extra_email(c.user.user_id, email_id)
973 audit_logger.store_web(
992 audit_logger.store_web(
974 'user.edit.email.delete',
993 'user.edit.email.delete',
975 action_data={'email': email, 'user': user_data},
994 action_data={'email': email, 'user': user_data},
976 user=self._rhodecode_user)
995 user=self._rhodecode_user)
977 Session().commit()
996 Session().commit()
978 h.flash(_("Removed email address from user account"),
997 h.flash(_("Removed email address from user account"),
979 category='success')
998 category='success')
980 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
999 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
981
1000
982 @LoginRequired()
1001 @LoginRequired()
983 @HasPermissionAllDecorator('hg.admin')
1002 @HasPermissionAllDecorator('hg.admin')
984 @view_config(
1003 @view_config(
985 route_name='edit_user_ips', request_method='GET',
1004 route_name='edit_user_ips', request_method='GET',
986 renderer='rhodecode:templates/admin/users/user_edit.mako')
1005 renderer='rhodecode:templates/admin/users/user_edit.mako')
987 def ips(self):
1006 def ips(self):
988 _ = self.request.translate
1007 _ = self.request.translate
989 c = self.load_default_context()
1008 c = self.load_default_context()
990 c.user = self.db_user
1009 c.user = self.db_user
991
1010
992 c.active = 'ips'
1011 c.active = 'ips'
993 c.user_ip_map = UserIpMap.query() \
1012 c.user_ip_map = UserIpMap.query() \
994 .filter(UserIpMap.user == c.user).all()
1013 .filter(UserIpMap.user == c.user).all()
995
1014
996 c.inherit_default_ips = c.user.inherit_default_permissions
1015 c.inherit_default_ips = c.user.inherit_default_permissions
997 c.default_user_ip_map = UserIpMap.query() \
1016 c.default_user_ip_map = UserIpMap.query() \
998 .filter(UserIpMap.user == User.get_default_user()).all()
1017 .filter(UserIpMap.user == User.get_default_user()).all()
999
1018
1000 return self._get_template_context(c)
1019 return self._get_template_context(c)
1001
1020
1002 @LoginRequired()
1021 @LoginRequired()
1003 @HasPermissionAllDecorator('hg.admin')
1022 @HasPermissionAllDecorator('hg.admin')
1004 @CSRFRequired()
1023 @CSRFRequired()
1005 @view_config(
1024 @view_config(
1006 route_name='edit_user_ips_add', request_method='POST')
1025 route_name='edit_user_ips_add', request_method='POST')
1007 # NOTE(marcink): this view is allowed for default users, as we can
1026 # NOTE(marcink): this view is allowed for default users, as we can
1008 # edit their IP white list
1027 # edit their IP white list
1009 def ips_add(self):
1028 def ips_add(self):
1010 _ = self.request.translate
1029 _ = self.request.translate
1011 c = self.load_default_context()
1030 c = self.load_default_context()
1012
1031
1013 user_id = self.db_user_id
1032 user_id = self.db_user_id
1014 c.user = self.db_user
1033 c.user = self.db_user
1015
1034
1016 user_model = UserModel()
1035 user_model = UserModel()
1017 desc = self.request.POST.get('description')
1036 desc = self.request.POST.get('description')
1018 try:
1037 try:
1019 ip_list = user_model.parse_ip_range(
1038 ip_list = user_model.parse_ip_range(
1020 self.request.POST.get('new_ip'))
1039 self.request.POST.get('new_ip'))
1021 except Exception as e:
1040 except Exception as e:
1022 ip_list = []
1041 ip_list = []
1023 log.exception("Exception during ip saving")
1042 log.exception("Exception during ip saving")
1024 h.flash(_('An error occurred during ip saving:%s' % (e,)),
1043 h.flash(_('An error occurred during ip saving:%s' % (e,)),
1025 category='error')
1044 category='error')
1026 added = []
1045 added = []
1027 user_data = c.user.get_api_data()
1046 user_data = c.user.get_api_data()
1028 for ip in ip_list:
1047 for ip in ip_list:
1029 try:
1048 try:
1030 form = UserExtraIpForm(self.request.translate)()
1049 form = UserExtraIpForm(self.request.translate)()
1031 data = form.to_python({'ip': ip})
1050 data = form.to_python({'ip': ip})
1032 ip = data['ip']
1051 ip = data['ip']
1033
1052
1034 user_model.add_extra_ip(c.user.user_id, ip, desc)
1053 user_model.add_extra_ip(c.user.user_id, ip, desc)
1035 audit_logger.store_web(
1054 audit_logger.store_web(
1036 'user.edit.ip.add',
1055 'user.edit.ip.add',
1037 action_data={'ip': ip, 'user': user_data},
1056 action_data={'ip': ip, 'user': user_data},
1038 user=self._rhodecode_user)
1057 user=self._rhodecode_user)
1039 Session().commit()
1058 Session().commit()
1040 added.append(ip)
1059 added.append(ip)
1041 except formencode.Invalid as error:
1060 except formencode.Invalid as error:
1042 msg = error.error_dict['ip']
1061 msg = error.error_dict['ip']
1043 h.flash(msg, category='error')
1062 h.flash(msg, category='error')
1044 except Exception:
1063 except Exception:
1045 log.exception("Exception during ip saving")
1064 log.exception("Exception during ip saving")
1046 h.flash(_('An error occurred during ip saving'),
1065 h.flash(_('An error occurred during ip saving'),
1047 category='error')
1066 category='error')
1048 if added:
1067 if added:
1049 h.flash(
1068 h.flash(
1050 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
1069 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
1051 category='success')
1070 category='success')
1052 if 'default_user' in self.request.POST:
1071 if 'default_user' in self.request.POST:
1053 # case for editing global IP list we do it for 'DEFAULT' user
1072 # case for editing global IP list we do it for 'DEFAULT' user
1054 raise HTTPFound(h.route_path('admin_permissions_ips'))
1073 raise HTTPFound(h.route_path('admin_permissions_ips'))
1055 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1074 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1056
1075
1057 @LoginRequired()
1076 @LoginRequired()
1058 @HasPermissionAllDecorator('hg.admin')
1077 @HasPermissionAllDecorator('hg.admin')
1059 @CSRFRequired()
1078 @CSRFRequired()
1060 @view_config(
1079 @view_config(
1061 route_name='edit_user_ips_delete', request_method='POST')
1080 route_name='edit_user_ips_delete', request_method='POST')
1062 # NOTE(marcink): this view is allowed for default users, as we can
1081 # NOTE(marcink): this view is allowed for default users, as we can
1063 # edit their IP white list
1082 # edit their IP white list
1064 def ips_delete(self):
1083 def ips_delete(self):
1065 _ = self.request.translate
1084 _ = self.request.translate
1066 c = self.load_default_context()
1085 c = self.load_default_context()
1067
1086
1068 user_id = self.db_user_id
1087 user_id = self.db_user_id
1069 c.user = self.db_user
1088 c.user = self.db_user
1070
1089
1071 ip_id = self.request.POST.get('del_ip_id')
1090 ip_id = self.request.POST.get('del_ip_id')
1072 user_model = UserModel()
1091 user_model = UserModel()
1073 user_data = c.user.get_api_data()
1092 user_data = c.user.get_api_data()
1074 ip = UserIpMap.query().get(ip_id).ip_addr
1093 ip = UserIpMap.query().get(ip_id).ip_addr
1075 user_model.delete_extra_ip(c.user.user_id, ip_id)
1094 user_model.delete_extra_ip(c.user.user_id, ip_id)
1076 audit_logger.store_web(
1095 audit_logger.store_web(
1077 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
1096 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
1078 user=self._rhodecode_user)
1097 user=self._rhodecode_user)
1079 Session().commit()
1098 Session().commit()
1080 h.flash(_("Removed ip address from user whitelist"), category='success')
1099 h.flash(_("Removed ip address from user whitelist"), category='success')
1081
1100
1082 if 'default_user' in self.request.POST:
1101 if 'default_user' in self.request.POST:
1083 # case for editing global IP list we do it for 'DEFAULT' user
1102 # case for editing global IP list we do it for 'DEFAULT' user
1084 raise HTTPFound(h.route_path('admin_permissions_ips'))
1103 raise HTTPFound(h.route_path('admin_permissions_ips'))
1085 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1104 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
1086
1105
1087 @LoginRequired()
1106 @LoginRequired()
1088 @HasPermissionAllDecorator('hg.admin')
1107 @HasPermissionAllDecorator('hg.admin')
1089 @view_config(
1108 @view_config(
1090 route_name='edit_user_groups_management', request_method='GET',
1109 route_name='edit_user_groups_management', request_method='GET',
1091 renderer='rhodecode:templates/admin/users/user_edit.mako')
1110 renderer='rhodecode:templates/admin/users/user_edit.mako')
1092 def groups_management(self):
1111 def groups_management(self):
1093 c = self.load_default_context()
1112 c = self.load_default_context()
1094 c.user = self.db_user
1113 c.user = self.db_user
1095 c.data = c.user.group_member
1114 c.data = c.user.group_member
1096
1115
1097 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
1116 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
1098 for group in c.user.group_member]
1117 for group in c.user.group_member]
1099 c.groups = json.dumps(groups)
1118 c.groups = json.dumps(groups)
1100 c.active = 'groups'
1119 c.active = 'groups'
1101
1120
1102 return self._get_template_context(c)
1121 return self._get_template_context(c)
1103
1122
1104 @LoginRequired()
1123 @LoginRequired()
1105 @HasPermissionAllDecorator('hg.admin')
1124 @HasPermissionAllDecorator('hg.admin')
1106 @CSRFRequired()
1125 @CSRFRequired()
1107 @view_config(
1126 @view_config(
1108 route_name='edit_user_groups_management_updates', request_method='POST')
1127 route_name='edit_user_groups_management_updates', request_method='POST')
1109 def groups_management_updates(self):
1128 def groups_management_updates(self):
1110 _ = self.request.translate
1129 _ = self.request.translate
1111 c = self.load_default_context()
1130 c = self.load_default_context()
1112
1131
1113 user_id = self.db_user_id
1132 user_id = self.db_user_id
1114 c.user = self.db_user
1133 c.user = self.db_user
1115
1134
1116 user_groups = set(self.request.POST.getall('users_group_id'))
1135 user_groups = set(self.request.POST.getall('users_group_id'))
1117 user_groups_objects = []
1136 user_groups_objects = []
1118
1137
1119 for ugid in user_groups:
1138 for ugid in user_groups:
1120 user_groups_objects.append(
1139 user_groups_objects.append(
1121 UserGroupModel().get_group(safe_int(ugid)))
1140 UserGroupModel().get_group(safe_int(ugid)))
1122 user_group_model = UserGroupModel()
1141 user_group_model = UserGroupModel()
1123 added_to_groups, removed_from_groups = \
1142 added_to_groups, removed_from_groups = \
1124 user_group_model.change_groups(c.user, user_groups_objects)
1143 user_group_model.change_groups(c.user, user_groups_objects)
1125
1144
1126 user_data = c.user.get_api_data()
1145 user_data = c.user.get_api_data()
1127 for user_group_id in added_to_groups:
1146 for user_group_id in added_to_groups:
1128 user_group = UserGroup.get(user_group_id)
1147 user_group = UserGroup.get(user_group_id)
1129 old_values = user_group.get_api_data()
1148 old_values = user_group.get_api_data()
1130 audit_logger.store_web(
1149 audit_logger.store_web(
1131 'user_group.edit.member.add',
1150 'user_group.edit.member.add',
1132 action_data={'user': user_data, 'old_data': old_values},
1151 action_data={'user': user_data, 'old_data': old_values},
1133 user=self._rhodecode_user)
1152 user=self._rhodecode_user)
1134
1153
1135 for user_group_id in removed_from_groups:
1154 for user_group_id in removed_from_groups:
1136 user_group = UserGroup.get(user_group_id)
1155 user_group = UserGroup.get(user_group_id)
1137 old_values = user_group.get_api_data()
1156 old_values = user_group.get_api_data()
1138 audit_logger.store_web(
1157 audit_logger.store_web(
1139 'user_group.edit.member.delete',
1158 'user_group.edit.member.delete',
1140 action_data={'user': user_data, 'old_data': old_values},
1159 action_data={'user': user_data, 'old_data': old_values},
1141 user=self._rhodecode_user)
1160 user=self._rhodecode_user)
1142
1161
1143 Session().commit()
1162 Session().commit()
1144 c.active = 'user_groups_management'
1163 c.active = 'user_groups_management'
1145 h.flash(_("Groups successfully changed"), category='success')
1164 h.flash(_("Groups successfully changed"), category='success')
1146
1165
1147 return HTTPFound(h.route_path(
1166 return HTTPFound(h.route_path(
1148 'edit_user_groups_management', user_id=user_id))
1167 'edit_user_groups_management', user_id=user_id))
1149
1168
1150 @LoginRequired()
1169 @LoginRequired()
1151 @HasPermissionAllDecorator('hg.admin')
1170 @HasPermissionAllDecorator('hg.admin')
1152 @view_config(
1171 @view_config(
1153 route_name='edit_user_audit_logs', request_method='GET',
1172 route_name='edit_user_audit_logs', request_method='GET',
1154 renderer='rhodecode:templates/admin/users/user_edit.mako')
1173 renderer='rhodecode:templates/admin/users/user_edit.mako')
1155 def user_audit_logs(self):
1174 def user_audit_logs(self):
1156 _ = self.request.translate
1175 _ = self.request.translate
1157 c = self.load_default_context()
1176 c = self.load_default_context()
1158 c.user = self.db_user
1177 c.user = self.db_user
1159
1178
1160 c.active = 'audit'
1179 c.active = 'audit'
1161
1180
1162 p = safe_int(self.request.GET.get('page', 1), 1)
1181 p = safe_int(self.request.GET.get('page', 1), 1)
1163
1182
1164 filter_term = self.request.GET.get('filter')
1183 filter_term = self.request.GET.get('filter')
1165 user_log = UserModel().get_user_log(c.user, filter_term)
1184 user_log = UserModel().get_user_log(c.user, filter_term)
1166
1185
1167 def url_generator(**kw):
1186 def url_generator(**kw):
1168 if filter_term:
1187 if filter_term:
1169 kw['filter'] = filter_term
1188 kw['filter'] = filter_term
1170 return self.request.current_route_path(_query=kw)
1189 return self.request.current_route_path(_query=kw)
1171
1190
1172 c.audit_logs = h.Page(
1191 c.audit_logs = h.Page(
1173 user_log, page=p, items_per_page=10, url=url_generator)
1192 user_log, page=p, items_per_page=10, url=url_generator)
1174 c.filter_term = filter_term
1193 c.filter_term = filter_term
1175 return self._get_template_context(c)
1194 return self._get_template_context(c)
1176
1195
1177 @LoginRequired()
1196 @LoginRequired()
1178 @HasPermissionAllDecorator('hg.admin')
1197 @HasPermissionAllDecorator('hg.admin')
1179 @view_config(
1198 @view_config(
1180 route_name='edit_user_perms_summary', request_method='GET',
1199 route_name='edit_user_perms_summary', request_method='GET',
1181 renderer='rhodecode:templates/admin/users/user_edit.mako')
1200 renderer='rhodecode:templates/admin/users/user_edit.mako')
1182 def user_perms_summary(self):
1201 def user_perms_summary(self):
1183 _ = self.request.translate
1202 _ = self.request.translate
1184 c = self.load_default_context()
1203 c = self.load_default_context()
1185 c.user = self.db_user
1204 c.user = self.db_user
1186
1205
1187 c.active = 'perms_summary'
1206 c.active = 'perms_summary'
1188 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1207 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1189
1208
1190 return self._get_template_context(c)
1209 return self._get_template_context(c)
1191
1210
1192 @LoginRequired()
1211 @LoginRequired()
1193 @HasPermissionAllDecorator('hg.admin')
1212 @HasPermissionAllDecorator('hg.admin')
1194 @view_config(
1213 @view_config(
1195 route_name='edit_user_perms_summary_json', request_method='GET',
1214 route_name='edit_user_perms_summary_json', request_method='GET',
1196 renderer='json_ext')
1215 renderer='json_ext')
1197 def user_perms_summary_json(self):
1216 def user_perms_summary_json(self):
1198 self.load_default_context()
1217 self.load_default_context()
1199 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
1218 perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr)
1200
1219
1201 return perm_user.permissions
1220 return perm_user.permissions
1202
1221
1203 @LoginRequired()
1222 @LoginRequired()
1204 @HasPermissionAllDecorator('hg.admin')
1223 @HasPermissionAllDecorator('hg.admin')
1205 @view_config(
1224 @view_config(
1206 route_name='edit_user_caches', request_method='GET',
1225 route_name='edit_user_caches', request_method='GET',
1207 renderer='rhodecode:templates/admin/users/user_edit.mako')
1226 renderer='rhodecode:templates/admin/users/user_edit.mako')
1208 def user_caches(self):
1227 def user_caches(self):
1209 _ = self.request.translate
1228 _ = self.request.translate
1210 c = self.load_default_context()
1229 c = self.load_default_context()
1211 c.user = self.db_user
1230 c.user = self.db_user
1212
1231
1213 c.active = 'caches'
1232 c.active = 'caches'
1214 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1233 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1215
1234
1216 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1235 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1217 c.region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1236 c.region = rc_cache.get_or_create_region('cache_perms', cache_namespace_uid)
1218 c.backend = c.region.backend
1237 c.backend = c.region.backend
1219 c.user_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
1238 c.user_keys = sorted(c.region.backend.list_keys(prefix=cache_namespace_uid))
1220
1239
1221 return self._get_template_context(c)
1240 return self._get_template_context(c)
1222
1241
1223 @LoginRequired()
1242 @LoginRequired()
1224 @HasPermissionAllDecorator('hg.admin')
1243 @HasPermissionAllDecorator('hg.admin')
1225 @CSRFRequired()
1244 @CSRFRequired()
1226 @view_config(
1245 @view_config(
1227 route_name='edit_user_caches_update', request_method='POST')
1246 route_name='edit_user_caches_update', request_method='POST')
1228 def user_caches_update(self):
1247 def user_caches_update(self):
1229 _ = self.request.translate
1248 _ = self.request.translate
1230 c = self.load_default_context()
1249 c = self.load_default_context()
1231 c.user = self.db_user
1250 c.user = self.db_user
1232
1251
1233 c.active = 'caches'
1252 c.active = 'caches'
1234 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1253 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
1235
1254
1236 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1255 cache_namespace_uid = 'cache_user_auth.{}'.format(self.db_user.user_id)
1237 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1256 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
1238
1257
1239 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1258 h.flash(_("Deleted {} cache keys").format(del_keys), category='success')
1240
1259
1241 return HTTPFound(h.route_path(
1260 return HTTPFound(h.route_path(
1242 'edit_user_caches', user_id=c.user.user_id))
1261 'edit_user_caches', user_id=c.user.user_id))
@@ -1,355 +1,356 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('favicon', '/favicon.ico', []);
15 pyroutes.register('favicon', '/favicon.ico', []);
16 pyroutes.register('robots', '/robots.txt', []);
16 pyroutes.register('robots', '/robots.txt', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
17 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
18 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
19 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
20 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
21 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
22 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
24 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
26 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
27 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
28 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
29 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
31 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
32 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
33 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
34 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
35 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
36 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
37 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
38 pyroutes.register('admin_home', '/_admin', []);
38 pyroutes.register('admin_home', '/_admin', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
39 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
40 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
41 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
42 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
43 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
44 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
45 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
46 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
47 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
48 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
49 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
50 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
51 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
52 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
53 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
54 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
55 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
56 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
57 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
58 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
59 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
60 pyroutes.register('admin_settings', '/_admin/settings', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
61 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
62 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
63 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
64 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
65 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
66 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
67 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
68 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
69 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
70 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
71 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
72 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
73 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
74 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
75 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
76 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
77 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
78 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
79 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
80 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
81 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
82 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
83 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
84 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
85 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
86 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
87 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
88 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
89 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
90 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
91 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
92 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
93 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
94 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
95 pyroutes.register('users', '/_admin/users', []);
95 pyroutes.register('users', '/_admin/users', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
96 pyroutes.register('users_data', '/_admin/users_data', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
97 pyroutes.register('users_create', '/_admin/users/create', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
98 pyroutes.register('users_new', '/_admin/users/new', []);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
99 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
100 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
101 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
102 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
103 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
104 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
105 pyroutes.register('user_force_password_reset', '/_admin/users/%(user_id)s/password_reset', ['user_id']);
105 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
106 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
106 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
107 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
107 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
108 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
108 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
109 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
110 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
111 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
112 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
112 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
113 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
113 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
114 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
114 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
115 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
115 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
116 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
116 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
117 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
117 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
118 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
118 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
119 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
119 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
120 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
120 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
121 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
121 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
122 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
122 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
123 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
123 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
124 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
124 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
125 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
125 pyroutes.register('user_groups', '/_admin/user_groups', []);
126 pyroutes.register('user_groups', '/_admin/user_groups', []);
126 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
127 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
127 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
128 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
128 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
129 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
129 pyroutes.register('repos', '/_admin/repos', []);
130 pyroutes.register('repos', '/_admin/repos', []);
130 pyroutes.register('repo_new', '/_admin/repos/new', []);
131 pyroutes.register('repo_new', '/_admin/repos/new', []);
131 pyroutes.register('repo_create', '/_admin/repos/create', []);
132 pyroutes.register('repo_create', '/_admin/repos/create', []);
132 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
133 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
133 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
134 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
134 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
135 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
135 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
136 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
136 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
137 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
137 pyroutes.register('channelstream_proxy', '/_channelstream', []);
138 pyroutes.register('channelstream_proxy', '/_channelstream', []);
138 pyroutes.register('logout', '/_admin/logout', []);
139 pyroutes.register('logout', '/_admin/logout', []);
139 pyroutes.register('reset_password', '/_admin/password_reset', []);
140 pyroutes.register('reset_password', '/_admin/password_reset', []);
140 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
141 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
141 pyroutes.register('home', '/', []);
142 pyroutes.register('home', '/', []);
142 pyroutes.register('user_autocomplete_data', '/_users', []);
143 pyroutes.register('user_autocomplete_data', '/_users', []);
143 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
144 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
144 pyroutes.register('repo_list_data', '/_repos', []);
145 pyroutes.register('repo_list_data', '/_repos', []);
145 pyroutes.register('goto_switcher_data', '/_goto_data', []);
146 pyroutes.register('goto_switcher_data', '/_goto_data', []);
146 pyroutes.register('markup_preview', '/_markup_preview', []);
147 pyroutes.register('markup_preview', '/_markup_preview', []);
147 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
148 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
148 pyroutes.register('journal', '/_admin/journal', []);
149 pyroutes.register('journal', '/_admin/journal', []);
149 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
150 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
150 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
151 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
151 pyroutes.register('journal_public', '/_admin/public_journal', []);
152 pyroutes.register('journal_public', '/_admin/public_journal', []);
152 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
153 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
153 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
154 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
154 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
155 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
155 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
156 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
156 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
157 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
157 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
158 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
158 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
159 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
159 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
160 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
160 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
161 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
161 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
162 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
162 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
163 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
163 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
164 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
164 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
165 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
165 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
166 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
166 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
167 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
167 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
168 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
169 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
170 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
171 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
171 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
172 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
173 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
173 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
174 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
174 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
175 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
175 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
176 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
176 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
177 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
177 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
178 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
178 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
179 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
179 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
180 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
180 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
181 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
181 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
182 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
183 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
183 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
184 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
185 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
186 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
187 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
188 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
189 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
190 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
191 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
192 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
195 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
196 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
196 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
197 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
197 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
198 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
198 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
199 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
199 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
201 pyroutes.register('repo_changelog_elements', '/%(repo_name)s/changelog_elements', ['repo_name']);
201 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_changelog_elements_file', '/%(repo_name)s/changelog_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
203 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
203 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']);
204 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']);
204 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
205 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
205 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
206 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
206 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
207 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
207 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
208 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
208 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
209 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
209 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
210 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
210 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
211 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
211 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
212 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
212 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
213 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
213 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
214 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
214 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
215 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
215 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
216 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
216 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
217 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
217 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
218 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
218 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
219 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
219 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
220 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
220 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
221 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
221 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
222 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
222 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']);
223 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']);
223 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
224 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
224 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
225 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
225 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
226 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
226 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
227 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
227 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
228 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
228 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
229 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
229 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
230 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
230 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
231 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
231 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
232 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
232 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
233 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
233 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
234 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
234 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
235 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
235 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
236 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
236 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
237 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
237 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
238 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
238 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
239 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
239 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
240 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
240 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
241 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
241 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
242 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
242 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
243 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
243 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
244 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
244 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
245 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
245 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
246 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
246 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
247 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
247 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
248 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
248 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
249 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
249 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
250 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
250 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
251 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
251 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
252 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
252 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
253 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
253 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
254 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
254 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
255 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
255 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
256 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
256 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
257 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed/rss', ['repo_name']);
257 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
258 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed/atom', ['repo_name']);
258 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
259 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
259 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
260 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
260 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
261 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
261 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
262 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
262 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
263 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
263 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
264 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
264 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
265 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
265 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
266 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
266 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
267 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
267 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
268 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
268 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
269 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
269 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
270 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
270 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
271 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
271 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
272 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
272 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
273 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
273 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
274 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
274 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
275 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
275 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
276 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
276 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
277 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
277 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
278 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
278 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
279 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
279 pyroutes.register('search', '/_admin/search', []);
280 pyroutes.register('search', '/_admin/search', []);
280 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
281 pyroutes.register('search_repo', '/%(repo_name)s/search', ['repo_name']);
281 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
282 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
282 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
283 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
283 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
284 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
284 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
285 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
285 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
286 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
286 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
287 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
287 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
288 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
288 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
289 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
289 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
290 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
290 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
291 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
291 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
292 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
292 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
293 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
293 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
294 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
294 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
295 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
295 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
296 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
296 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
297 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
297 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
298 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
298 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
299 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
299 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
300 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
300 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
301 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
301 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
302 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
302 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
303 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
303 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
304 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
304 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
305 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
305 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
306 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
306 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
307 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
307 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
308 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
308 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
309 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
309 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
310 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
310 pyroutes.register('gists_show', '/_admin/gists', []);
311 pyroutes.register('gists_show', '/_admin/gists', []);
311 pyroutes.register('gists_new', '/_admin/gists/new', []);
312 pyroutes.register('gists_new', '/_admin/gists/new', []);
312 pyroutes.register('gists_create', '/_admin/gists/create', []);
313 pyroutes.register('gists_create', '/_admin/gists/create', []);
313 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
314 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
314 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
315 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
315 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
316 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
316 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
317 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
317 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
318 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
318 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
319 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
319 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
320 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
320 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
321 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
321 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
322 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
322 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
323 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
323 pyroutes.register('apiv2', '/_admin/api', []);
324 pyroutes.register('apiv2', '/_admin/api', []);
324 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
325 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
325 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
326 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
326 pyroutes.register('login', '/_admin/login', []);
327 pyroutes.register('login', '/_admin/login', []);
327 pyroutes.register('register', '/_admin/register', []);
328 pyroutes.register('register', '/_admin/register', []);
328 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
329 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
329 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
330 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
330 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
331 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
331 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
332 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
332 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
333 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
333 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
334 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
334 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
335 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
335 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
336 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
336 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
337 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
337 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
338 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
338 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
339 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
339 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
340 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
340 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
341 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
341 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
342 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
342 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
343 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
343 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
344 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
344 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
345 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
345 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
346 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
346 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
347 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
347 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
348 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
348 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
349 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
349 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
350 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
350 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
351 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
351 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
352 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
352 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
353 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
353 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
354 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
354 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
355 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
355 }
356 }
@@ -1,329 +1,329 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
3
3
4 <div class="panel panel-default">
4 <div class="panel panel-default">
5 <div class="panel-heading">
5 <div class="panel-heading">
6 <h3 class="panel-title">${_('Settings for Repository: %s') % c.rhodecode_db_repo.repo_name}</h3>
6 <h3 class="panel-title">${_('Settings for Repository: %s') % c.rhodecode_db_repo.repo_name}</h3>
7 </div>
7 </div>
8 <div class="panel-body">
8 <div class="panel-body">
9 ${h.secure_form(h.route_path('edit_repo', repo_name=c.rhodecode_db_repo.repo_name), request=request)}
9 ${h.secure_form(h.route_path('edit_repo', repo_name=c.rhodecode_db_repo.repo_name), request=request)}
10 <div class="form">
10 <div class="form">
11 <!-- fields -->
11 <!-- fields -->
12 <div class="fields">
12 <div class="fields">
13
13
14 <div class="field">
14 <div class="field">
15 <div class="label">
15 <div class="label">
16 <label for="repo_name">${_('Name')}:</label>
16 <label for="repo_name">${_('Name')}:</label>
17 </div>
17 </div>
18 <div class="input">
18 <div class="input">
19 ${c.form['repo_name'].render(css_class='medium', oid='repo_name')|n}
19 ${c.form['repo_name'].render(css_class='medium', oid='repo_name')|n}
20 ${c.form.render_error(request, c.form['repo_name'])|n}
20 ${c.form.render_error(request, c.form['repo_name'])|n}
21
21
22 <p class="help-block">${_('permalink id')}: `_${c.rhodecode_db_repo.repo_id}` <span><a href="#" onclick="$('#clone_id').toggle();return false">${_('what is that ?')}</a></span></p>
22 <p class="help-block">${_('permalink id')}: `_${c.rhodecode_db_repo.repo_id}` <span><a href="#" onclick="$('#clone_id').toggle();return false">${_('what is that ?')}</a></span></p>
23 <p id="clone_id" style="display:none;">
23 <p id="clone_id" style="display:none;">
24 ${_('URL by id')}: `${c.rhodecode_db_repo.clone_url(with_id=True)}` <br/>
24 ${_('URL by id')}: `${c.rhodecode_db_repo.clone_url(with_id=True)}` <br/>
25 ${_('''In case this repository is renamed or moved into another group the repository url changes.
25 ${_('''In case this repository is renamed or moved into another group the repository url changes.
26 Using above url guarantees that this repository will always be accessible under such url.
26 Using above url guarantees that this repository will always be accessible under such url.
27 Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service.''')}</p>
27 Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service.''')}</p>
28 </div>
28 </div>
29 </div>
29 </div>
30
30
31 <div class="field">
31 <div class="field">
32 <div class="label">
32 <div class="label">
33 <label for="repo_group">${_('Repository group')}:</label>
33 <label for="repo_group">${_('Repository group')}:</label>
34 </div>
34 </div>
35 <div class="select">
35 <div class="select">
36 ${c.form['repo_group'].render(css_class='medium', oid='repo_group')|n}
36 ${c.form['repo_group'].render(css_class='medium', oid='repo_group')|n}
37 ${c.form.render_error(request, c.form['repo_group'])|n}
37 ${c.form.render_error(request, c.form['repo_group'])|n}
38
38
39 % if c.personal_repo_group:
39 % if c.personal_repo_group:
40 <a class="btn" href="#" data-personal-group-name="${c.personal_repo_group.group_name}" data-personal-group-id="${c.personal_repo_group.group_id}" onclick="selectMyGroup(this); return false">
40 <a class="btn" href="#" data-personal-group-name="${c.personal_repo_group.group_name}" data-personal-group-id="${c.personal_repo_group.group_id}" onclick="selectMyGroup(this); return false">
41 ${_('Select my personal group (`%(repo_group_name)s`)') % {'repo_group_name': c.personal_repo_group.group_name}}
41 ${_('Select my personal group (`%(repo_group_name)s`)') % {'repo_group_name': c.personal_repo_group.group_name}}
42 </a>
42 </a>
43 % endif
43 % endif
44 <p class="help-block">${_('Optional select a group to put this repository into.')}</p>
44 <p class="help-block">${_('Optional select a group to put this repository into.')}</p>
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 % if c.rhodecode_db_repo.repo_type != 'svn':
48 % if c.rhodecode_db_repo.repo_type != 'svn':
49 <% sync_link = h.literal(h.link_to('remote sync', h.route_path('edit_repo_remote', repo_name=c.repo_name))) %>
49 <% sync_link = h.literal(h.link_to('remote sync', h.route_path('edit_repo_remote', repo_name=c.repo_name))) %>
50 <div class="field">
50 <div class="field">
51 <div class="label">
51 <div class="label">
52 <label for="clone_uri">${_('Remote pull uri')}:</label>
52 <label for="clone_uri">${_('Remote pull uri')}:</label>
53 </div>
53 </div>
54 <div class="input">
54 <div class="input">
55 %if c.rhodecode_db_repo.clone_uri:
55 %if c.rhodecode_db_repo.clone_uri:
56 ## display, if we don't have any errors
56 ## display, if we don't have any errors
57 % if not c.form['repo_clone_uri'].error:
57 % if not c.form['repo_clone_uri'].error:
58 <div id="clone_uri_hidden" class='text-as-placeholder'>
58 <div id="clone_uri_hidden" class='text-as-placeholder'>
59 <span id="clone_uri_hidden_value">${c.rhodecode_db_repo.clone_uri_hidden}</span>
59 <span id="clone_uri_hidden_value">${c.rhodecode_db_repo.clone_uri_hidden}</span>
60 <span class="link" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
60 <span class="link" id="edit_clone_uri"><i class="icon-edit"></i>${_('edit')}</span>
61 </div>
61 </div>
62 % endif
62 % endif
63
63
64 ## alter field
64 ## alter field
65 <div id="alter_clone_uri" style="${'' if c.form['repo_clone_uri'].error else 'display: none'}">
65 <div id="alter_clone_uri" style="${'' if c.form['repo_clone_uri'].error else 'display: none'}">
66 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
66 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
67 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
67 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
68 % if c.form['repo_clone_uri'].error:
68 % if c.form['repo_clone_uri'].error:
69 ## we got error from form subit, means we modify the url
69 ## we got error from form subit, means we modify the url
70 ${h.hidden('repo_clone_uri_change', 'MOD')}
70 ${h.hidden('repo_clone_uri_change', 'MOD')}
71 % else:
71 % else:
72 ${h.hidden('repo_clone_uri_change', 'OLD')}
72 ${h.hidden('repo_clone_uri_change', 'OLD')}
73 % endif
73 % endif
74
74
75 % if not c.form['repo_clone_uri'].error:
75 % if not c.form['repo_clone_uri'].error:
76 <span class="link" id="cancel_edit_clone_uri">${_('cancel')}</span>
76 <span class="link" id="cancel_edit_clone_uri">${_('cancel')}</span>
77 % endif
77 % endif
78
78
79 </div>
79 </div>
80 %else:
80 %else:
81 ## not set yet, display form to set it
81 ## not set yet, display form to set it
82 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri')|n}
82 ${c.form['repo_clone_uri'].render(css_class='medium', oid='clone_uri')|n}
83 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
83 ${c.form.render_error(request, c.form['repo_clone_uri'])|n}
84 ${h.hidden('repo_clone_uri_change', 'NEW')}
84 ${h.hidden('repo_clone_uri_change', 'NEW')}
85 %endif
85 %endif
86 <p id="alter_clone_uri_help_block" class="help-block">
86 <p id="alter_clone_uri_help_block" class="help-block">
87 ${_('http[s] url where from repository was imported. This field can used for doing {sync_link}.').format(sync_link=sync_link)|n} <br/>
87 ${_('http[s] url where from repository was imported. This field can used for doing {sync_link}.').format(sync_link=sync_link)|n} <br/>
88 ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')}
88 ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')}
89 </p>
89 </p>
90 </div>
90 </div>
91 </div>
91 </div>
92 <div class="field">
92 <div class="field">
93 <div class="label">
93 <div class="label">
94 <label for="push_uri">${_('Remote push uri')}:</label>
94 <label for="push_uri">${_('Remote push uri')}:</label>
95 </div>
95 </div>
96 <div class="input">
96 <div class="input">
97 %if c.rhodecode_db_repo.push_uri:
97 %if c.rhodecode_db_repo.push_uri:
98 ## display, if we don't have any errors
98 ## display, if we don't have any errors
99 % if not c.form['repo_push_uri'].error:
99 % if not c.form['repo_push_uri'].error:
100 <div id="push_uri_hidden" class='text-as-placeholder'>
100 <div id="push_uri_hidden" class='text-as-placeholder'>
101 <span id="push_uri_hidden_value">${c.rhodecode_db_repo.push_uri_hidden}</span>
101 <span id="push_uri_hidden_value">${c.rhodecode_db_repo.push_uri_hidden}</span>
102 <span class="link" id="edit_push_uri"><i class="icon-edit"></i>${_('edit')}</span>
102 <span class="link" id="edit_push_uri"><i class="icon-edit"></i>${_('edit')}</span>
103 </div>
103 </div>
104 % endif
104 % endif
105
105
106 ## alter field
106 ## alter field
107 <div id="alter_push_uri" style="${'' if c.form['repo_push_uri'].error else 'display: none'}">
107 <div id="alter_push_uri" style="${'' if c.form['repo_push_uri'].error else 'display: none'}">
108 ${c.form['repo_push_uri'].render(css_class='medium', oid='push_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
108 ${c.form['repo_push_uri'].render(css_class='medium', oid='push_uri', placeholder=_('enter new value, or leave empty to remove'))|n}
109 ${c.form.render_error(request, c.form['repo_push_uri'])|n}
109 ${c.form.render_error(request, c.form['repo_push_uri'])|n}
110 % if c.form['repo_push_uri'].error:
110 % if c.form['repo_push_uri'].error:
111 ## we got error from form subit, means we modify the url
111 ## we got error from form subit, means we modify the url
112 ${h.hidden('repo_push_uri_change', 'MOD')}
112 ${h.hidden('repo_push_uri_change', 'MOD')}
113 % else:
113 % else:
114 ${h.hidden('repo_push_uri_change', 'OLD')}
114 ${h.hidden('repo_push_uri_change', 'OLD')}
115 % endif
115 % endif
116
116
117 % if not c.form['repo_push_uri'].error:
117 % if not c.form['repo_push_uri'].error:
118 <span class="link" id="cancel_edit_push_uri">${_('cancel')}</span>
118 <span class="link" id="cancel_edit_push_uri">${_('cancel')}</span>
119 % endif
119 % endif
120
120
121 </div>
121 </div>
122 %else:
122 %else:
123 ## not set yet, display form to set it
123 ## not set yet, display form to set it
124 ${c.form['repo_push_uri'].render(css_class='medium', oid='push_uri')|n}
124 ${c.form['repo_push_uri'].render(css_class='medium', oid='push_uri')|n}
125 ${c.form.render_error(request, c.form['repo_push_uri'])|n}
125 ${c.form.render_error(request, c.form['repo_push_uri'])|n}
126 ${h.hidden('repo_push_uri_change', 'NEW')}
126 ${h.hidden('repo_push_uri_change', 'NEW')}
127 %endif
127 %endif
128 <p id="alter_push_uri_help_block" class="help-block">
128 <p id="alter_push_uri_help_block" class="help-block">
129 ${_('http[s] url to sync data back. This field can used for doing {sync_link}.').format(sync_link=sync_link)|n} <br/>
129 ${_('http[s] url to sync data back. This field can used for doing {sync_link}.').format(sync_link=sync_link)|n} <br/>
130 ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')}
130 ${_('This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display.')}
131 </p>
131 </p>
132 </div>
132 </div>
133 </div>
133 </div>
134 % else:
134 % else:
135 ${h.hidden('repo_clone_uri', '')}
135 ${h.hidden('repo_clone_uri', '')}
136 ${h.hidden('repo_push_uri', '')}
136 ${h.hidden('repo_push_uri', '')}
137 % endif
137 % endif
138
138
139 <div class="field">
139 <div class="field">
140 <div class="label">
140 <div class="label">
141 <label for="repo_landing_commit_ref">${_('Landing commit')}:</label>
141 <label for="repo_landing_commit_ref">${_('Landing commit')}:</label>
142 </div>
142 </div>
143 <div class="select">
143 <div class="select">
144 ${c.form['repo_landing_commit_ref'].render(css_class='medium', oid='repo_landing_commit_ref')|n}
144 ${c.form['repo_landing_commit_ref'].render(css_class='medium', oid='repo_landing_commit_ref')|n}
145 ${c.form.render_error(request, c.form['repo_landing_commit_ref'])|n}
145 ${c.form.render_error(request, c.form['repo_landing_commit_ref'])|n}
146 <p class="help-block">${_('Default commit for files page, downloads, full text search index and readme')}</p>
146 <p class="help-block">${_('The default commit for file pages, downloads, full text search index, and README generation.')}</p>
147 </div>
147 </div>
148 </div>
148 </div>
149
149
150 <div class="field badged-field">
150 <div class="field badged-field">
151 <div class="label">
151 <div class="label">
152 <label for="repo_owner">${_('Owner')}:</label>
152 <label for="repo_owner">${_('Owner')}:</label>
153 </div>
153 </div>
154 <div class="input">
154 <div class="input">
155 <div class="badge-input-container">
155 <div class="badge-input-container">
156 <div class="user-badge">
156 <div class="user-badge">
157 ${base.gravatar_with_user(c.rhodecode_db_repo.user.email or c.rhodecode_db_repo.user.username, show_disabled=not c.rhodecode_db_repo.user.active)}
157 ${base.gravatar_with_user(c.rhodecode_db_repo.user.email or c.rhodecode_db_repo.user.username, show_disabled=not c.rhodecode_db_repo.user.active)}
158 </div>
158 </div>
159 <div class="badge-input-wrap">
159 <div class="badge-input-wrap">
160 ${c.form['repo_owner'].render(css_class='medium', oid='repo_owner')|n}
160 ${c.form['repo_owner'].render(css_class='medium', oid='repo_owner')|n}
161 </div>
161 </div>
162 </div>
162 </div>
163 ${c.form.render_error(request, c.form['repo_owner'])|n}
163 ${c.form.render_error(request, c.form['repo_owner'])|n}
164 <p class="help-block">${_('Change owner of this repository.')}</p>
164 <p class="help-block">${_('Change owner of this repository.')}</p>
165 </div>
165 </div>
166 </div>
166 </div>
167
167
168 <div class="field">
168 <div class="field">
169 <div class="label label-textarea">
169 <div class="label label-textarea">
170 <label for="repo_description">${_('Description')}:</label>
170 <label for="repo_description">${_('Description')}:</label>
171 </div>
171 </div>
172 <div class="textarea text-area editor">
172 <div class="textarea text-area editor">
173 ${c.form['repo_description'].render(css_class='medium', oid='repo_description')|n}
173 ${c.form['repo_description'].render(css_class='medium', oid='repo_description')|n}
174 ${c.form.render_error(request, c.form['repo_description'])|n}
174 ${c.form.render_error(request, c.form['repo_description'])|n}
175
175
176 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
176 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
177 <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
177 <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
178 <span id="meta-tags-desc" style="display: none">
178 <span id="meta-tags-desc" style="display: none">
179 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
179 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
180 ${dt.metatags_help()}
180 ${dt.metatags_help()}
181 </span>
181 </span>
182 </div>
182 </div>
183 </div>
183 </div>
184
184
185 <div class="field">
185 <div class="field">
186 <div class="label label-checkbox">
186 <div class="label label-checkbox">
187 <label for="${c.form['repo_private'].oid}">${_('Private repository')}:</label>
187 <label for="${c.form['repo_private'].oid}">${_('Private repository')}:</label>
188 </div>
188 </div>
189 <div class="checkboxes">
189 <div class="checkboxes">
190 ${c.form['repo_private'].render(css_class='medium')|n}
190 ${c.form['repo_private'].render(css_class='medium')|n}
191 ${c.form.render_error(request, c.form['repo_private'])|n}
191 ${c.form.render_error(request, c.form['repo_private'])|n}
192 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
192 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
193 </div>
193 </div>
194 </div>
194 </div>
195 <div class="field">
195 <div class="field">
196 <div class="label label-checkbox">
196 <div class="label label-checkbox">
197 <label for="${c.form['repo_enable_statistics'].oid}">${_('Enable statistics')}:</label>
197 <label for="${c.form['repo_enable_statistics'].oid}">${_('Enable statistics')}:</label>
198 </div>
198 </div>
199 <div class="checkboxes">
199 <div class="checkboxes">
200 ${c.form['repo_enable_statistics'].render(css_class='medium')|n}
200 ${c.form['repo_enable_statistics'].render(css_class='medium')|n}
201 ${c.form.render_error(request, c.form['repo_enable_statistics'])|n}
201 ${c.form.render_error(request, c.form['repo_enable_statistics'])|n}
202 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
202 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
203 </div>
203 </div>
204 </div>
204 </div>
205 <div class="field">
205 <div class="field">
206 <div class="label label-checkbox">
206 <div class="label label-checkbox">
207 <label for="${c.form['repo_enable_downloads'].oid}">${_('Enable downloads')}:</label>
207 <label for="${c.form['repo_enable_downloads'].oid}">${_('Enable downloads')}:</label>
208 </div>
208 </div>
209 <div class="checkboxes">
209 <div class="checkboxes">
210 ${c.form['repo_enable_downloads'].render(css_class='medium')|n}
210 ${c.form['repo_enable_downloads'].render(css_class='medium')|n}
211 ${c.form.render_error(request, c.form['repo_enable_downloads'])|n}
211 ${c.form.render_error(request, c.form['repo_enable_downloads'])|n}
212 <span class="help-block">${_('Enable download menu on summary page.')}</span>
212 <span class="help-block">${_('Enable download menu on summary page.')}</span>
213 </div>
213 </div>
214 </div>
214 </div>
215 <div class="field">
215 <div class="field">
216 <div class="label label-checkbox">
216 <div class="label label-checkbox">
217 <label for="${c.form['repo_enable_locking'].oid}">${_('Enable automatic locking')}:</label>
217 <label for="${c.form['repo_enable_locking'].oid}">${_('Enable automatic locking')}:</label>
218 </div>
218 </div>
219 <div class="checkboxes">
219 <div class="checkboxes">
220 ${c.form['repo_enable_locking'].render(css_class='medium')|n}
220 ${c.form['repo_enable_locking'].render(css_class='medium')|n}
221 ${c.form.render_error(request, c.form['repo_enable_locking'])|n}
221 ${c.form.render_error(request, c.form['repo_enable_locking'])|n}
222 <span class="help-block">${_('Enable automatic locking on repository. Pulling from this repository creates a lock that can be released by pushing back by the same user')}</span>
222 <span class="help-block">${_('Enable automatic locking on repository. Pulling from this repository creates a lock that can be released by pushing back by the same user')}</span>
223 </div>
223 </div>
224 </div>
224 </div>
225
225
226 %if c.visual.repository_fields:
226 %if c.visual.repository_fields:
227 ## EXTRA FIELDS
227 ## EXTRA FIELDS
228 %for field in c.repo_fields:
228 %for field in c.repo_fields:
229 <div class="field">
229 <div class="field">
230 <div class="label">
230 <div class="label">
231 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
231 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
232 </div>
232 </div>
233 <div class="input input-medium">
233 <div class="input input-medium">
234 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
234 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
235 %if field.field_desc:
235 %if field.field_desc:
236 <span class="help-block">${field.field_desc}</span>
236 <span class="help-block">${field.field_desc}</span>
237 %endif
237 %endif
238 </div>
238 </div>
239 </div>
239 </div>
240 %endfor
240 %endfor
241 %endif
241 %endif
242 <div class="buttons">
242 <div class="buttons">
243 ${h.submit('save',_('Save'),class_="btn")}
243 ${h.submit('save',_('Save'),class_="btn")}
244 ${h.reset('reset',_('Reset'),class_="btn")}
244 ${h.reset('reset',_('Reset'),class_="btn")}
245 </div>
245 </div>
246 </div>
246 </div>
247 </div>
247 </div>
248 ${h.end_form()}
248 ${h.end_form()}
249 </div>
249 </div>
250 </div>
250 </div>
251
251
252 <script>
252 <script>
253 $(document).ready(function () {
253 $(document).ready(function () {
254 var cloneUrl = function (
254 var cloneUrl = function (
255 alterButton, editButton, cancelEditButton,
255 alterButton, editButton, cancelEditButton,
256 hiddenUrl, hiddenUrlValue, input, helpBlock, changedFlag) {
256 hiddenUrl, hiddenUrlValue, input, helpBlock, changedFlag) {
257
257
258 var originalText = helpBlock.html();
258 var originalText = helpBlock.html();
259 var obfuscatedUrl = hiddenUrlValue.html();
259 var obfuscatedUrl = hiddenUrlValue.html();
260
260
261 var edit = function(e) {
261 var edit = function(e) {
262 alterButton.show();
262 alterButton.show();
263 editButton.hide();
263 editButton.hide();
264 hiddenUrl.hide();
264 hiddenUrl.hide();
265
265
266 //add the old value next to input for verification
266 //add the old value next to input for verification
267 helpBlock.html("(" + obfuscatedUrl + ")" + "<br\>" + originalText);
267 helpBlock.html("(" + obfuscatedUrl + ")" + "<br\>" + originalText);
268 changedFlag.val('MOD');
268 changedFlag.val('MOD');
269 };
269 };
270
270
271 var cancelEdit = function(e) {
271 var cancelEdit = function(e) {
272 alterButton.hide();
272 alterButton.hide();
273 editButton.show();
273 editButton.show();
274 hiddenUrl.show();
274 hiddenUrl.show();
275
275
276 helpBlock.html(originalText);
276 helpBlock.html(originalText);
277 changedFlag.val('OLD');
277 changedFlag.val('OLD');
278 input.val('');
278 input.val('');
279 };
279 };
280
280
281 var initEvents = function() {
281 var initEvents = function() {
282 editButton.on('click', edit);
282 editButton.on('click', edit);
283 cancelEditButton.on('click', cancelEdit);
283 cancelEditButton.on('click', cancelEdit);
284 };
284 };
285
285
286 var setInitialState = function() {
286 var setInitialState = function() {
287 if (input.hasClass('error')) {
287 if (input.hasClass('error')) {
288 alterButton.show();
288 alterButton.show();
289 editButton.hide();
289 editButton.hide();
290 hiddenUrl.hide();
290 hiddenUrl.hide();
291 }
291 }
292 };
292 };
293
293
294 setInitialState();
294 setInitialState();
295 initEvents();
295 initEvents();
296 };
296 };
297
297
298
298
299 var alterButton = $('#alter_clone_uri');
299 var alterButton = $('#alter_clone_uri');
300 var editButton = $('#edit_clone_uri');
300 var editButton = $('#edit_clone_uri');
301 var cancelEditButton = $('#cancel_edit_clone_uri');
301 var cancelEditButton = $('#cancel_edit_clone_uri');
302 var hiddenUrl = $('#clone_uri_hidden');
302 var hiddenUrl = $('#clone_uri_hidden');
303 var hiddenUrlValue = $('#clone_uri_hidden_value');
303 var hiddenUrlValue = $('#clone_uri_hidden_value');
304 var input = $('#clone_uri');
304 var input = $('#clone_uri');
305 var helpBlock = $('#alter_clone_uri_help_block');
305 var helpBlock = $('#alter_clone_uri_help_block');
306 var changedFlag = $('#repo_clone_uri_change');
306 var changedFlag = $('#repo_clone_uri_change');
307 cloneUrl(
307 cloneUrl(
308 alterButton, editButton, cancelEditButton, hiddenUrl,
308 alterButton, editButton, cancelEditButton, hiddenUrl,
309 hiddenUrlValue, input, helpBlock, changedFlag);
309 hiddenUrlValue, input, helpBlock, changedFlag);
310
310
311 var alterButton = $('#alter_push_uri');
311 var alterButton = $('#alter_push_uri');
312 var editButton = $('#edit_push_uri');
312 var editButton = $('#edit_push_uri');
313 var cancelEditButton = $('#cancel_edit_push_uri');
313 var cancelEditButton = $('#cancel_edit_push_uri');
314 var hiddenUrl = $('#push_uri_hidden');
314 var hiddenUrl = $('#push_uri_hidden');
315 var hiddenUrlValue = $('#push_uri_hidden_value');
315 var hiddenUrlValue = $('#push_uri_hidden_value');
316 var input = $('#push_uri');
316 var input = $('#push_uri');
317 var helpBlock = $('#alter_push_uri_help_block');
317 var helpBlock = $('#alter_push_uri_help_block');
318 var changedFlag = $('#repo_push_uri_change');
318 var changedFlag = $('#repo_push_uri_change');
319 cloneUrl(
319 cloneUrl(
320 alterButton, editButton, cancelEditButton, hiddenUrl,
320 alterButton, editButton, cancelEditButton, hiddenUrl,
321 hiddenUrlValue, input, helpBlock, changedFlag);
321 hiddenUrlValue, input, helpBlock, changedFlag);
322
322
323 selectMyGroup = function(element) {
323 selectMyGroup = function(element) {
324 $("#repo_group").val($(element).data('personalGroupId')).trigger("change");
324 $("#repo_group").val($(element).data('personalGroupId')).trigger("change");
325 };
325 };
326
326
327 UsersAutoComplete('repo_owner', '${c.rhodecode_user.user_id}');
327 UsersAutoComplete('repo_owner', '${c.rhodecode_user.user_id}');
328 });
328 });
329 </script>
329 </script>
@@ -1,162 +1,171 b''
1 <%namespace name="base" file="/base/base.mako"/>
1 <%namespace name="base" file="/base/base.mako"/>
2
2
3 <%
3 <%
4 elems = [
4 elems = [
5 (_('User ID'), c.user.user_id, '', ''),
5 (_('User ID'), c.user.user_id, '', ''),
6 (_('Created on'), h.format_date(c.user.created_on), '', ''),
6 (_('Created on'), h.format_date(c.user.created_on), '', ''),
7 (_('Source of Record'), c.user.extern_type, '', ''),
7 (_('Source of Record'), c.user.extern_type, '', ''),
8
8
9 (_('Last login'), c.user.last_login or '-', '', ''),
9 (_('Last login'), c.user.last_login or '-', '', ''),
10 (_('Last activity'), c.user.last_activity, '', ''),
10 (_('Last activity'), c.user.last_activity, '', ''),
11
11
12 (_('Repositories'), len(c.user.repositories), '', [x.repo_name for x in c.user.repositories]),
12 (_('Repositories'), len(c.user.repositories), '', [x.repo_name for x in c.user.repositories]),
13 (_('Repository groups'), len(c.user.repository_groups), '', [x.group_name for x in c.user.repository_groups]),
13 (_('Repository groups'), len(c.user.repository_groups), '', [x.group_name for x in c.user.repository_groups]),
14 (_('User groups'), len(c.user.user_groups), '', [x.users_group_name for x in c.user.user_groups]),
14 (_('User groups'), len(c.user.user_groups), '', [x.users_group_name for x in c.user.user_groups]),
15
15
16 (_('Reviewer of pull requests'), len(c.user.reviewer_pull_requests), '', ['Pull Request #{}'.format(x.pull_request.pull_request_id) for x in c.user.reviewer_pull_requests]),
16 (_('Reviewer of pull requests'), len(c.user.reviewer_pull_requests), '', ['Pull Request #{}'.format(x.pull_request.pull_request_id) for x in c.user.reviewer_pull_requests]),
17 (_('Assigned to review rules'), len(c.user_to_review_rules), '', [x for x in c.user_to_review_rules]),
17 (_('Assigned to review rules'), len(c.user_to_review_rules), '', [x for x in c.user_to_review_rules]),
18
18
19 (_('Member of User groups'), len(c.user.group_member), '', [x.users_group.users_group_name for x in c.user.group_member]),
19 (_('Member of User groups'), len(c.user.group_member), '', [x.users_group.users_group_name for x in c.user.group_member]),
20 (_('Force password change'), c.user.user_data.get('force_password_change', 'False'), '', ''),
20 (_('Force password change'), c.user.user_data.get('force_password_change', 'False'), '', ''),
21 ]
21 ]
22 %>
22 %>
23
23
24 <div class="panel panel-default">
24 <div class="panel panel-default">
25 <div class="panel-heading">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('User: %s') % c.user.username}</h3>
26 <h3 class="panel-title">${_('User: %s') % c.user.username}</h3>
27 </div>
27 </div>
28 <div class="panel-body">
28 <div class="panel-body">
29 ${base.dt_info_panel(elems)}
29 ${base.dt_info_panel(elems)}
30 </div>
30 </div>
31 </div>
31 </div>
32
32
33 <div class="panel panel-default">
33 <div class="panel panel-default">
34 <div class="panel-heading">
34 <div class="panel-heading">
35 <h3 class="panel-title">${_('Force Password Reset')}</h3>
35 <h3 class="panel-title">${_('Force Password Reset')}</h3>
36 </div>
36 </div>
37 <div class="panel-body">
37 <div class="panel-body">
38 ${h.secure_form(h.route_path('user_force_password_reset', user_id=c.user.user_id), request=request)}
38 ${h.secure_form(h.route_path('user_disable_force_password_reset', user_id=c.user.user_id), request=request)}
39 <div class="field">
39 <div class="field">
40 <button class="btn btn-default" type="submit">
40 <button class="btn btn-default" type="submit">
41 <i class="icon-lock"></i>
41 <i class="icon-unlock"></i> ${_('Disable forced password reset')}
42 %if c.user.user_data.get('force_password_change'):
42 </button>
43 ${_('Disable forced password reset')}
43 </div>
44 %else:
44 <div class="field">
45 ${_('Enable forced password reset')}
45 <span class="help-block">
46 %endif
46 ${_("Clear the forced password change flag.")}
47 </span>
48 </div>
49 ${h.end_form()}
50
51 ${h.secure_form(h.route_path('user_enable_force_password_reset', user_id=c.user.user_id), request=request)}
52 <div class="field">
53 <button class="btn btn-default" type="submit" onclick="return confirm('${_('Confirm to enable forced password change')}');">
54 <i class="icon-lock"></i> ${_('Enable forced password reset')}
47 </button>
55 </button>
48 </div>
56 </div>
49 <div class="field">
57 <div class="field">
50 <span class="help-block">
58 <span class="help-block">
51 ${_("When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface")}
59 ${_("When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface")}
52 </span>
60 </span>
53 </div>
61 </div>
54 ${h.end_form()}
62 ${h.end_form()}
63
55 </div>
64 </div>
56 </div>
65 </div>
57
66
58 <div class="panel panel-default">
67 <div class="panel panel-default">
59 <div class="panel-heading">
68 <div class="panel-heading">
60 <h3 class="panel-title">${_('Personal Repository Group')}</h3>
69 <h3 class="panel-title">${_('Personal Repository Group')}</h3>
61 </div>
70 </div>
62 <div class="panel-body">
71 <div class="panel-body">
63 ${h.secure_form(h.route_path('user_create_personal_repo_group', user_id=c.user.user_id), request=request)}
72 ${h.secure_form(h.route_path('user_create_personal_repo_group', user_id=c.user.user_id), request=request)}
64
73
65 %if c.personal_repo_group:
74 %if c.personal_repo_group:
66 <div class="panel-body-title-text">${_('Users personal repository group')} : ${h.link_to(c.personal_repo_group.group_name, h.route_path('repo_group_home', repo_group_name=c.personal_repo_group.group_name))}</div>
75 <div class="panel-body-title-text">${_('Users personal repository group')} : ${h.link_to(c.personal_repo_group.group_name, h.route_path('repo_group_home', repo_group_name=c.personal_repo_group.group_name))}</div>
67 %else:
76 %else:
68 <div class="panel-body-title-text">
77 <div class="panel-body-title-text">
69 ${_('This user currently does not have a personal repository group')}
78 ${_('This user currently does not have a personal repository group')}
70 <br/>
79 <br/>
71 ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}
80 ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}
72 </div>
81 </div>
73 %endif
82 %endif
74 <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}>
83 <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}>
75 <i class="icon-folder-close"></i>
84 <i class="icon-folder-close"></i>
76 ${_('Create personal repository group')}
85 ${_('Create personal repository group')}
77 </button>
86 </button>
78 ${h.end_form()}
87 ${h.end_form()}
79 </div>
88 </div>
80 </div>
89 </div>
81
90
82
91
83 <div class="panel panel-danger">
92 <div class="panel panel-danger">
84 <div class="panel-heading">
93 <div class="panel-heading">
85 <h3 class="panel-title">${_('Delete User')}</h3>
94 <h3 class="panel-title">${_('Delete User')}</h3>
86 </div>
95 </div>
87 <div class="panel-body">
96 <div class="panel-body">
88 ${h.secure_form(h.route_path('user_delete', user_id=c.user.user_id), request=request)}
97 ${h.secure_form(h.route_path('user_delete', user_id=c.user.user_id), request=request)}
89
98
90 <table class="display">
99 <table class="display">
91 <tr>
100 <tr>
92 <td>
101 <td>
93 ${_ungettext('This user owns %s repository.', 'This user owns %s repositories.', len(c.user.repositories)) % len(c.user.repositories)}
102 ${_ungettext('This user owns %s repository.', 'This user owns %s repositories.', len(c.user.repositories)) % len(c.user.repositories)}
94 </td>
103 </td>
95 <td>
104 <td>
96 %if len(c.user.repositories) > 0:
105 %if len(c.user.repositories) > 0:
97 <input type="radio" id="user_repos_1" name="user_repos" value="detach" checked="checked"/> <label for="user_repos_1">${_('Detach repositories')}</label>
106 <input type="radio" id="user_repos_1" name="user_repos" value="detach" checked="checked"/> <label for="user_repos_1">${_('Detach repositories')}</label>
98 %endif
107 %endif
99 </td>
108 </td>
100 <td>
109 <td>
101 %if len(c.user.repositories) > 0:
110 %if len(c.user.repositories) > 0:
102 <input type="radio" id="user_repos_2" name="user_repos" value="delete" /> <label for="user_repos_2">${_('Delete repositories')}</label>
111 <input type="radio" id="user_repos_2" name="user_repos" value="delete" /> <label for="user_repos_2">${_('Delete repositories')}</label>
103 %endif
112 %endif
104 </td>
113 </td>
105 </tr>
114 </tr>
106
115
107 <tr>
116 <tr>
108 <td>
117 <td>
109 ${_ungettext('This user owns %s repository group.', 'This user owns %s repository groups.', len(c.user.repository_groups)) % len(c.user.repository_groups)}
118 ${_ungettext('This user owns %s repository group.', 'This user owns %s repository groups.', len(c.user.repository_groups)) % len(c.user.repository_groups)}
110 </td>
119 </td>
111 <td>
120 <td>
112 %if len(c.user.repository_groups) > 0:
121 %if len(c.user.repository_groups) > 0:
113 <input type="radio" id="user_repo_groups_1" name="user_repo_groups" value="detach" checked="checked"/> <label for="user_repo_groups_1">${_('Detach repository groups')}</label>
122 <input type="radio" id="user_repo_groups_1" name="user_repo_groups" value="detach" checked="checked"/> <label for="user_repo_groups_1">${_('Detach repository groups')}</label>
114 %endif
123 %endif
115 </td>
124 </td>
116 <td>
125 <td>
117 %if len(c.user.repository_groups) > 0:
126 %if len(c.user.repository_groups) > 0:
118 <input type="radio" id="user_repo_groups_2" name="user_repo_groups" value="delete" /> <label for="user_repo_groups_2">${_('Delete repositories')}</label>
127 <input type="radio" id="user_repo_groups_2" name="user_repo_groups" value="delete" /> <label for="user_repo_groups_2">${_('Delete repositories')}</label>
119 %endif
128 %endif
120 </td>
129 </td>
121 </tr>
130 </tr>
122
131
123 <tr>
132 <tr>
124 <td>
133 <td>
125 ${_ungettext('This user owns %s user group.', 'This user owns %s user groups.', len(c.user.user_groups)) % len(c.user.user_groups)}
134 ${_ungettext('This user owns %s user group.', 'This user owns %s user groups.', len(c.user.user_groups)) % len(c.user.user_groups)}
126 </td>
135 </td>
127 <td>
136 <td>
128 %if len(c.user.user_groups) > 0:
137 %if len(c.user.user_groups) > 0:
129 <input type="radio" id="user_user_groups_1" name="user_user_groups" value="detach" checked="checked"/> <label for="user_user_groups_1">${_('Detach user groups')}</label>
138 <input type="radio" id="user_user_groups_1" name="user_user_groups" value="detach" checked="checked"/> <label for="user_user_groups_1">${_('Detach user groups')}</label>
130 %endif
139 %endif
131 </td>
140 </td>
132 <td>
141 <td>
133 %if len(c.user.user_groups) > 0:
142 %if len(c.user.user_groups) > 0:
134 <input type="radio" id="user_user_groups_2" name="user_user_groups" value="delete" /> <label for="user_user_groups_2">${_('Delete repositories')}</label>
143 <input type="radio" id="user_user_groups_2" name="user_user_groups" value="delete" /> <label for="user_user_groups_2">${_('Delete repositories')}</label>
135 %endif
144 %endif
136 </td>
145 </td>
137 </tr>
146 </tr>
138 </table>
147 </table>
139 <div style="margin: 0 0 20px 0" class="fake-space"></div>
148 <div style="margin: 0 0 20px 0" class="fake-space"></div>
140
149
141 <div class="field">
150 <div class="field">
142 <button class="btn btn-small btn-danger" type="submit"
151 <button class="btn btn-small btn-danger" type="submit"
143 onclick="return confirm('${_('Confirm to delete this user: %s') % c.user.username}');"
152 onclick="return confirm('${_('Confirm to delete this user: %s') % c.user.username}');"
144 ${"disabled" if not c.can_delete_user else ""}>
153 ${"disabled" if not c.can_delete_user else ""}>
145 ${_('Delete this user')}
154 ${_('Delete this user')}
146 </button>
155 </button>
147 </div>
156 </div>
148 % if c.can_delete_user_message:
157 % if c.can_delete_user_message:
149 <p class="help-block pre-formatting">${c.can_delete_user_message}</p>
158 <p class="help-block pre-formatting">${c.can_delete_user_message}</p>
150 % endif
159 % endif
151
160
152 <div class="field">
161 <div class="field">
153 <span class="help-block">
162 <span class="help-block">
154 %if len(c.user.repositories) > 0 or len(c.user.repository_groups) > 0 or len(c.user.user_groups) > 0:
163 %if len(c.user.repositories) > 0 or len(c.user.repository_groups) > 0 or len(c.user.user_groups) > 0:
155 <p class="help-block">${_("When selecting the detach option, the depending objects owned by this user will be assigned to the `%s` super admin in the system. The delete option will delete the user's repositories!") % (c.first_admin.full_name)}</p>
164 <p class="help-block">${_("When selecting the detach option, the depending objects owned by this user will be assigned to the `%s` super admin in the system. The delete option will delete the user's repositories!") % (c.first_admin.full_name)}</p>
156 %endif
165 %endif
157 </span>
166 </span>
158 </div>
167 </div>
159
168
160 ${h.end_form()}
169 ${h.end_form()}
161 </div>
170 </div>
162 </div>
171 </div>
General Comments 0
You need to be logged in to leave comments. Login now