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