##// END OF EJS Templates
events: add event to catch permission changed so we can flush affected users permission caches
marcink -
r2849:21c71a09 default
parent child Browse files
Show More
@@ -0,0 +1,38 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22
23 from rhodecode import events
24
25 log = logging.getLogger(__name__)
26
27
28 def trigger_user_permission_flush(event):
29 """
30 Subscriber to the `UserPermissionChange`. This triggers the
31 automatic flush of permission caches, so the users affected receive new permissions
32 Right Away
33 """
34 affected_user_ids = event.user_ids
35
36
37 def includeme(config):
38 config.add_subscriber(trigger_user_permission_flush, events.UserPermissionsChange)
@@ -1,424 +1,426 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 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_sessions',
63 name='admin_settings_sessions',
64 pattern='/settings/sessions')
64 pattern='/settings/sessions')
65 config.add_route(
65 config.add_route(
66 name='admin_settings_sessions_cleanup',
66 name='admin_settings_sessions_cleanup',
67 pattern='/settings/sessions/cleanup')
67 pattern='/settings/sessions/cleanup')
68
68
69 config.add_route(
69 config.add_route(
70 name='admin_settings_process_management',
70 name='admin_settings_process_management',
71 pattern='/settings/process_management')
71 pattern='/settings/process_management')
72 config.add_route(
72 config.add_route(
73 name='admin_settings_process_management_data',
73 name='admin_settings_process_management_data',
74 pattern='/settings/process_management/data')
74 pattern='/settings/process_management/data')
75 config.add_route(
75 config.add_route(
76 name='admin_settings_process_management_signal',
76 name='admin_settings_process_management_signal',
77 pattern='/settings/process_management/signal')
77 pattern='/settings/process_management/signal')
78 config.add_route(
78 config.add_route(
79 name='admin_settings_process_management_master_signal',
79 name='admin_settings_process_management_master_signal',
80 pattern='/settings/process_management/master_signal')
80 pattern='/settings/process_management/master_signal')
81
81
82 # default settings
82 # default settings
83 config.add_route(
83 config.add_route(
84 name='admin_defaults_repositories',
84 name='admin_defaults_repositories',
85 pattern='/defaults/repositories')
85 pattern='/defaults/repositories')
86 config.add_route(
86 config.add_route(
87 name='admin_defaults_repositories_update',
87 name='admin_defaults_repositories_update',
88 pattern='/defaults/repositories/update')
88 pattern='/defaults/repositories/update')
89
89
90 # admin settings
90 # admin settings
91
91
92 config.add_route(
92 config.add_route(
93 name='admin_settings',
93 name='admin_settings',
94 pattern='/settings')
94 pattern='/settings')
95 config.add_route(
95 config.add_route(
96 name='admin_settings_update',
96 name='admin_settings_update',
97 pattern='/settings/update')
97 pattern='/settings/update')
98
98
99 config.add_route(
99 config.add_route(
100 name='admin_settings_global',
100 name='admin_settings_global',
101 pattern='/settings/global')
101 pattern='/settings/global')
102 config.add_route(
102 config.add_route(
103 name='admin_settings_global_update',
103 name='admin_settings_global_update',
104 pattern='/settings/global/update')
104 pattern='/settings/global/update')
105
105
106 config.add_route(
106 config.add_route(
107 name='admin_settings_vcs',
107 name='admin_settings_vcs',
108 pattern='/settings/vcs')
108 pattern='/settings/vcs')
109 config.add_route(
109 config.add_route(
110 name='admin_settings_vcs_update',
110 name='admin_settings_vcs_update',
111 pattern='/settings/vcs/update')
111 pattern='/settings/vcs/update')
112 config.add_route(
112 config.add_route(
113 name='admin_settings_vcs_svn_pattern_delete',
113 name='admin_settings_vcs_svn_pattern_delete',
114 pattern='/settings/vcs/svn_pattern_delete')
114 pattern='/settings/vcs/svn_pattern_delete')
115
115
116 config.add_route(
116 config.add_route(
117 name='admin_settings_mapping',
117 name='admin_settings_mapping',
118 pattern='/settings/mapping')
118 pattern='/settings/mapping')
119 config.add_route(
119 config.add_route(
120 name='admin_settings_mapping_update',
120 name='admin_settings_mapping_update',
121 pattern='/settings/mapping/update')
121 pattern='/settings/mapping/update')
122
122
123 config.add_route(
123 config.add_route(
124 name='admin_settings_visual',
124 name='admin_settings_visual',
125 pattern='/settings/visual')
125 pattern='/settings/visual')
126 config.add_route(
126 config.add_route(
127 name='admin_settings_visual_update',
127 name='admin_settings_visual_update',
128 pattern='/settings/visual/update')
128 pattern='/settings/visual/update')
129
129
130
130
131 config.add_route(
131 config.add_route(
132 name='admin_settings_issuetracker',
132 name='admin_settings_issuetracker',
133 pattern='/settings/issue-tracker')
133 pattern='/settings/issue-tracker')
134 config.add_route(
134 config.add_route(
135 name='admin_settings_issuetracker_update',
135 name='admin_settings_issuetracker_update',
136 pattern='/settings/issue-tracker/update')
136 pattern='/settings/issue-tracker/update')
137 config.add_route(
137 config.add_route(
138 name='admin_settings_issuetracker_test',
138 name='admin_settings_issuetracker_test',
139 pattern='/settings/issue-tracker/test')
139 pattern='/settings/issue-tracker/test')
140 config.add_route(
140 config.add_route(
141 name='admin_settings_issuetracker_delete',
141 name='admin_settings_issuetracker_delete',
142 pattern='/settings/issue-tracker/delete')
142 pattern='/settings/issue-tracker/delete')
143
143
144 config.add_route(
144 config.add_route(
145 name='admin_settings_email',
145 name='admin_settings_email',
146 pattern='/settings/email')
146 pattern='/settings/email')
147 config.add_route(
147 config.add_route(
148 name='admin_settings_email_update',
148 name='admin_settings_email_update',
149 pattern='/settings/email/update')
149 pattern='/settings/email/update')
150
150
151 config.add_route(
151 config.add_route(
152 name='admin_settings_hooks',
152 name='admin_settings_hooks',
153 pattern='/settings/hooks')
153 pattern='/settings/hooks')
154 config.add_route(
154 config.add_route(
155 name='admin_settings_hooks_update',
155 name='admin_settings_hooks_update',
156 pattern='/settings/hooks/update')
156 pattern='/settings/hooks/update')
157 config.add_route(
157 config.add_route(
158 name='admin_settings_hooks_delete',
158 name='admin_settings_hooks_delete',
159 pattern='/settings/hooks/delete')
159 pattern='/settings/hooks/delete')
160
160
161 config.add_route(
161 config.add_route(
162 name='admin_settings_search',
162 name='admin_settings_search',
163 pattern='/settings/search')
163 pattern='/settings/search')
164
164
165 config.add_route(
165 config.add_route(
166 name='admin_settings_labs',
166 name='admin_settings_labs',
167 pattern='/settings/labs')
167 pattern='/settings/labs')
168 config.add_route(
168 config.add_route(
169 name='admin_settings_labs_update',
169 name='admin_settings_labs_update',
170 pattern='/settings/labs/update')
170 pattern='/settings/labs/update')
171
171
172 # Automation EE feature
172 # Automation EE feature
173 config.add_route(
173 config.add_route(
174 'admin_settings_automation',
174 'admin_settings_automation',
175 pattern=ADMIN_PREFIX + '/settings/automation')
175 pattern=ADMIN_PREFIX + '/settings/automation')
176
176
177 # global permissions
177 # global permissions
178
178
179 config.add_route(
179 config.add_route(
180 name='admin_permissions_application',
180 name='admin_permissions_application',
181 pattern='/permissions/application')
181 pattern='/permissions/application')
182 config.add_route(
182 config.add_route(
183 name='admin_permissions_application_update',
183 name='admin_permissions_application_update',
184 pattern='/permissions/application/update')
184 pattern='/permissions/application/update')
185
185
186 config.add_route(
186 config.add_route(
187 name='admin_permissions_global',
187 name='admin_permissions_global',
188 pattern='/permissions/global')
188 pattern='/permissions/global')
189 config.add_route(
189 config.add_route(
190 name='admin_permissions_global_update',
190 name='admin_permissions_global_update',
191 pattern='/permissions/global/update')
191 pattern='/permissions/global/update')
192
192
193 config.add_route(
193 config.add_route(
194 name='admin_permissions_object',
194 name='admin_permissions_object',
195 pattern='/permissions/object')
195 pattern='/permissions/object')
196 config.add_route(
196 config.add_route(
197 name='admin_permissions_object_update',
197 name='admin_permissions_object_update',
198 pattern='/permissions/object/update')
198 pattern='/permissions/object/update')
199
199
200 config.add_route(
200 config.add_route(
201 name='admin_permissions_ips',
201 name='admin_permissions_ips',
202 pattern='/permissions/ips')
202 pattern='/permissions/ips')
203
203
204 config.add_route(
204 config.add_route(
205 name='admin_permissions_overview',
205 name='admin_permissions_overview',
206 pattern='/permissions/overview')
206 pattern='/permissions/overview')
207
207
208 config.add_route(
208 config.add_route(
209 name='admin_permissions_auth_token_access',
209 name='admin_permissions_auth_token_access',
210 pattern='/permissions/auth_token_access')
210 pattern='/permissions/auth_token_access')
211
211
212 config.add_route(
212 config.add_route(
213 name='admin_permissions_ssh_keys',
213 name='admin_permissions_ssh_keys',
214 pattern='/permissions/ssh_keys')
214 pattern='/permissions/ssh_keys')
215 config.add_route(
215 config.add_route(
216 name='admin_permissions_ssh_keys_data',
216 name='admin_permissions_ssh_keys_data',
217 pattern='/permissions/ssh_keys/data')
217 pattern='/permissions/ssh_keys/data')
218 config.add_route(
218 config.add_route(
219 name='admin_permissions_ssh_keys_update',
219 name='admin_permissions_ssh_keys_update',
220 pattern='/permissions/ssh_keys/update')
220 pattern='/permissions/ssh_keys/update')
221
221
222 # users admin
222 # users admin
223 config.add_route(
223 config.add_route(
224 name='users',
224 name='users',
225 pattern='/users')
225 pattern='/users')
226
226
227 config.add_route(
227 config.add_route(
228 name='users_data',
228 name='users_data',
229 pattern='/users_data')
229 pattern='/users_data')
230
230
231 config.add_route(
231 config.add_route(
232 name='users_create',
232 name='users_create',
233 pattern='/users/create')
233 pattern='/users/create')
234
234
235 config.add_route(
235 config.add_route(
236 name='users_new',
236 name='users_new',
237 pattern='/users/new')
237 pattern='/users/new')
238
238
239 # user management
239 # user management
240 config.add_route(
240 config.add_route(
241 name='user_edit',
241 name='user_edit',
242 pattern='/users/{user_id:\d+}/edit',
242 pattern='/users/{user_id:\d+}/edit',
243 user_route=True)
243 user_route=True)
244 config.add_route(
244 config.add_route(
245 name='user_edit_advanced',
245 name='user_edit_advanced',
246 pattern='/users/{user_id:\d+}/edit/advanced',
246 pattern='/users/{user_id:\d+}/edit/advanced',
247 user_route=True)
247 user_route=True)
248 config.add_route(
248 config.add_route(
249 name='user_edit_global_perms',
249 name='user_edit_global_perms',
250 pattern='/users/{user_id:\d+}/edit/global_permissions',
250 pattern='/users/{user_id:\d+}/edit/global_permissions',
251 user_route=True)
251 user_route=True)
252 config.add_route(
252 config.add_route(
253 name='user_edit_global_perms_update',
253 name='user_edit_global_perms_update',
254 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
254 pattern='/users/{user_id:\d+}/edit/global_permissions/update',
255 user_route=True)
255 user_route=True)
256 config.add_route(
256 config.add_route(
257 name='user_update',
257 name='user_update',
258 pattern='/users/{user_id:\d+}/update',
258 pattern='/users/{user_id:\d+}/update',
259 user_route=True)
259 user_route=True)
260 config.add_route(
260 config.add_route(
261 name='user_delete',
261 name='user_delete',
262 pattern='/users/{user_id:\d+}/delete',
262 pattern='/users/{user_id:\d+}/delete',
263 user_route=True)
263 user_route=True)
264 config.add_route(
264 config.add_route(
265 name='user_force_password_reset',
265 name='user_force_password_reset',
266 pattern='/users/{user_id:\d+}/password_reset',
266 pattern='/users/{user_id:\d+}/password_reset',
267 user_route=True)
267 user_route=True)
268 config.add_route(
268 config.add_route(
269 name='user_create_personal_repo_group',
269 name='user_create_personal_repo_group',
270 pattern='/users/{user_id:\d+}/create_repo_group',
270 pattern='/users/{user_id:\d+}/create_repo_group',
271 user_route=True)
271 user_route=True)
272
272
273 # user auth tokens
273 # user auth tokens
274 config.add_route(
274 config.add_route(
275 name='edit_user_auth_tokens',
275 name='edit_user_auth_tokens',
276 pattern='/users/{user_id:\d+}/edit/auth_tokens',
276 pattern='/users/{user_id:\d+}/edit/auth_tokens',
277 user_route=True)
277 user_route=True)
278 config.add_route(
278 config.add_route(
279 name='edit_user_auth_tokens_add',
279 name='edit_user_auth_tokens_add',
280 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
280 pattern='/users/{user_id:\d+}/edit/auth_tokens/new',
281 user_route=True)
281 user_route=True)
282 config.add_route(
282 config.add_route(
283 name='edit_user_auth_tokens_delete',
283 name='edit_user_auth_tokens_delete',
284 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
284 pattern='/users/{user_id:\d+}/edit/auth_tokens/delete',
285 user_route=True)
285 user_route=True)
286
286
287 # user ssh keys
287 # user ssh keys
288 config.add_route(
288 config.add_route(
289 name='edit_user_ssh_keys',
289 name='edit_user_ssh_keys',
290 pattern='/users/{user_id:\d+}/edit/ssh_keys',
290 pattern='/users/{user_id:\d+}/edit/ssh_keys',
291 user_route=True)
291 user_route=True)
292 config.add_route(
292 config.add_route(
293 name='edit_user_ssh_keys_generate_keypair',
293 name='edit_user_ssh_keys_generate_keypair',
294 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
294 pattern='/users/{user_id:\d+}/edit/ssh_keys/generate',
295 user_route=True)
295 user_route=True)
296 config.add_route(
296 config.add_route(
297 name='edit_user_ssh_keys_add',
297 name='edit_user_ssh_keys_add',
298 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
298 pattern='/users/{user_id:\d+}/edit/ssh_keys/new',
299 user_route=True)
299 user_route=True)
300 config.add_route(
300 config.add_route(
301 name='edit_user_ssh_keys_delete',
301 name='edit_user_ssh_keys_delete',
302 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
302 pattern='/users/{user_id:\d+}/edit/ssh_keys/delete',
303 user_route=True)
303 user_route=True)
304
304
305 # user emails
305 # user emails
306 config.add_route(
306 config.add_route(
307 name='edit_user_emails',
307 name='edit_user_emails',
308 pattern='/users/{user_id:\d+}/edit/emails',
308 pattern='/users/{user_id:\d+}/edit/emails',
309 user_route=True)
309 user_route=True)
310 config.add_route(
310 config.add_route(
311 name='edit_user_emails_add',
311 name='edit_user_emails_add',
312 pattern='/users/{user_id:\d+}/edit/emails/new',
312 pattern='/users/{user_id:\d+}/edit/emails/new',
313 user_route=True)
313 user_route=True)
314 config.add_route(
314 config.add_route(
315 name='edit_user_emails_delete',
315 name='edit_user_emails_delete',
316 pattern='/users/{user_id:\d+}/edit/emails/delete',
316 pattern='/users/{user_id:\d+}/edit/emails/delete',
317 user_route=True)
317 user_route=True)
318
318
319 # user IPs
319 # user IPs
320 config.add_route(
320 config.add_route(
321 name='edit_user_ips',
321 name='edit_user_ips',
322 pattern='/users/{user_id:\d+}/edit/ips',
322 pattern='/users/{user_id:\d+}/edit/ips',
323 user_route=True)
323 user_route=True)
324 config.add_route(
324 config.add_route(
325 name='edit_user_ips_add',
325 name='edit_user_ips_add',
326 pattern='/users/{user_id:\d+}/edit/ips/new',
326 pattern='/users/{user_id:\d+}/edit/ips/new',
327 user_route_with_default=True) # enabled for default user too
327 user_route_with_default=True) # enabled for default user too
328 config.add_route(
328 config.add_route(
329 name='edit_user_ips_delete',
329 name='edit_user_ips_delete',
330 pattern='/users/{user_id:\d+}/edit/ips/delete',
330 pattern='/users/{user_id:\d+}/edit/ips/delete',
331 user_route_with_default=True) # enabled for default user too
331 user_route_with_default=True) # enabled for default user too
332
332
333 # user perms
333 # user perms
334 config.add_route(
334 config.add_route(
335 name='edit_user_perms_summary',
335 name='edit_user_perms_summary',
336 pattern='/users/{user_id:\d+}/edit/permissions_summary',
336 pattern='/users/{user_id:\d+}/edit/permissions_summary',
337 user_route=True)
337 user_route=True)
338 config.add_route(
338 config.add_route(
339 name='edit_user_perms_summary_json',
339 name='edit_user_perms_summary_json',
340 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
340 pattern='/users/{user_id:\d+}/edit/permissions_summary/json',
341 user_route=True)
341 user_route=True)
342
342
343 # user user groups management
343 # user user groups management
344 config.add_route(
344 config.add_route(
345 name='edit_user_groups_management',
345 name='edit_user_groups_management',
346 pattern='/users/{user_id:\d+}/edit/groups_management',
346 pattern='/users/{user_id:\d+}/edit/groups_management',
347 user_route=True)
347 user_route=True)
348
348
349 config.add_route(
349 config.add_route(
350 name='edit_user_groups_management_updates',
350 name='edit_user_groups_management_updates',
351 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
351 pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates',
352 user_route=True)
352 user_route=True)
353
353
354 # user audit logs
354 # user audit logs
355 config.add_route(
355 config.add_route(
356 name='edit_user_audit_logs',
356 name='edit_user_audit_logs',
357 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
357 pattern='/users/{user_id:\d+}/edit/audit', user_route=True)
358
358
359 # user caches
359 # user caches
360 config.add_route(
360 config.add_route(
361 name='edit_user_caches',
361 name='edit_user_caches',
362 pattern='/users/{user_id:\d+}/edit/caches',
362 pattern='/users/{user_id:\d+}/edit/caches',
363 user_route=True)
363 user_route=True)
364 config.add_route(
364 config.add_route(
365 name='edit_user_caches_update',
365 name='edit_user_caches_update',
366 pattern='/users/{user_id:\d+}/edit/caches/update',
366 pattern='/users/{user_id:\d+}/edit/caches/update',
367 user_route=True)
367 user_route=True)
368
368
369 # user-groups admin
369 # user-groups admin
370 config.add_route(
370 config.add_route(
371 name='user_groups',
371 name='user_groups',
372 pattern='/user_groups')
372 pattern='/user_groups')
373
373
374 config.add_route(
374 config.add_route(
375 name='user_groups_data',
375 name='user_groups_data',
376 pattern='/user_groups_data')
376 pattern='/user_groups_data')
377
377
378 config.add_route(
378 config.add_route(
379 name='user_groups_new',
379 name='user_groups_new',
380 pattern='/user_groups/new')
380 pattern='/user_groups/new')
381
381
382 config.add_route(
382 config.add_route(
383 name='user_groups_create',
383 name='user_groups_create',
384 pattern='/user_groups/create')
384 pattern='/user_groups/create')
385
385
386 # repos admin
386 # repos admin
387 config.add_route(
387 config.add_route(
388 name='repos',
388 name='repos',
389 pattern='/repos')
389 pattern='/repos')
390
390
391 config.add_route(
391 config.add_route(
392 name='repo_new',
392 name='repo_new',
393 pattern='/repos/new')
393 pattern='/repos/new')
394
394
395 config.add_route(
395 config.add_route(
396 name='repo_create',
396 name='repo_create',
397 pattern='/repos/create')
397 pattern='/repos/create')
398
398
399 # repo groups admin
399 # repo groups admin
400 config.add_route(
400 config.add_route(
401 name='repo_groups',
401 name='repo_groups',
402 pattern='/repo_groups')
402 pattern='/repo_groups')
403
403
404 config.add_route(
404 config.add_route(
405 name='repo_group_new',
405 name='repo_group_new',
406 pattern='/repo_group/new')
406 pattern='/repo_group/new')
407
407
408 config.add_route(
408 config.add_route(
409 name='repo_group_create',
409 name='repo_group_create',
410 pattern='/repo_group/create')
410 pattern='/repo_group/create')
411
411
412
412
413 def includeme(config):
413 def includeme(config):
414 from rhodecode.apps.admin.navigation import includeme as nav_includeme
414 from rhodecode.apps.admin.navigation import includeme as nav_includeme
415
415
416 # Create admin navigation registry and add it to the pyramid registry.
416 # Create admin navigation registry and add it to the pyramid registry.
417 nav_includeme(config)
417 nav_includeme(config)
418
418
419 # main admin routes
419 # main admin routes
420 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
420 config.add_route(name='admin_home', pattern=ADMIN_PREFIX)
421 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
421 config.include(admin_routes, route_prefix=ADMIN_PREFIX)
422
422
423 config.include('.subscribers')
424
423 # Scan module for configuration decorators.
425 # Scan module for configuration decorators.
424 config.scan('.views', ignore='.tests')
426 config.scan('.views', ignore='.tests')
@@ -1,100 +1,109 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 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
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode import events
26 from rhodecode.apps._base import RepoGroupAppView
27 from rhodecode.apps._base import RepoGroupAppView
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
31 LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.model.repo_group import RepoGroupModel
32 from rhodecode.model.repo_group import RepoGroupModel
32 from rhodecode.model.forms import RepoGroupPermsForm
33 from rhodecode.model.forms import RepoGroupPermsForm
33 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
34
35
35 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
36
37
37
38
38 class RepoGroupPermissionsView(RepoGroupAppView):
39 class RepoGroupPermissionsView(RepoGroupAppView):
39 def load_default_context(self):
40 def load_default_context(self):
40 c = self._get_local_tmpl_context()
41 c = self._get_local_tmpl_context()
41
42
42 return c
43 return c
43
44
44 @LoginRequired()
45 @LoginRequired()
45 @HasRepoGroupPermissionAnyDecorator('group.admin')
46 @HasRepoGroupPermissionAnyDecorator('group.admin')
46 @view_config(
47 @view_config(
47 route_name='edit_repo_group_perms', request_method='GET',
48 route_name='edit_repo_group_perms', request_method='GET',
48 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
49 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
49 def edit_repo_group_permissions(self):
50 def edit_repo_group_permissions(self):
50 c = self.load_default_context()
51 c = self.load_default_context()
51 c.active = 'permissions'
52 c.active = 'permissions'
52 c.repo_group = self.db_repo_group
53 c.repo_group = self.db_repo_group
53 return self._get_template_context(c)
54 return self._get_template_context(c)
54
55
55 @LoginRequired()
56 @LoginRequired()
56 @HasRepoGroupPermissionAnyDecorator('group.admin')
57 @HasRepoGroupPermissionAnyDecorator('group.admin')
57 @CSRFRequired()
58 @CSRFRequired()
58 @view_config(
59 @view_config(
59 route_name='edit_repo_group_perms_update', request_method='POST',
60 route_name='edit_repo_group_perms_update', request_method='POST',
60 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
61 renderer='rhodecode:templates/admin/repo_groups/repo_group_edit.mako')
61 def edit_repo_groups_permissions_update(self):
62 def edit_repo_groups_permissions_update(self):
62 _ = self.request.translate
63 _ = self.request.translate
63 c = self.load_default_context()
64 c = self.load_default_context()
64 c.active = 'perms'
65 c.active = 'perms'
65 c.repo_group = self.db_repo_group
66 c.repo_group = self.db_repo_group
66
67
67 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
68 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
68 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
69 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
69 .to_python(self.request.POST)
70 .to_python(self.request.POST)
70
71
71 if not c.rhodecode_user.is_admin:
72 if not c.rhodecode_user.is_admin:
72 if self._revoke_perms_on_yourself(form):
73 if self._revoke_perms_on_yourself(form):
73 msg = _('Cannot change permission for yourself as admin')
74 msg = _('Cannot change permission for yourself as admin')
74 h.flash(msg, category='warning')
75 h.flash(msg, category='warning')
75 raise HTTPFound(
76 raise HTTPFound(
76 h.route_path('edit_repo_group_perms',
77 h.route_path('edit_repo_group_perms',
77 repo_group_name=self.db_repo_group_name))
78 repo_group_name=self.db_repo_group_name))
78
79
79 # iterate over all members(if in recursive mode) of this groups and
80 # iterate over all members(if in recursive mode) of this groups and
80 # set the permissions !
81 # set the permissions !
81 # this can be potentially heavy operation
82 # this can be potentially heavy operation
82 changes = RepoGroupModel().update_permissions(
83 changes = RepoGroupModel().update_permissions(
83 c.repo_group,
84 c.repo_group,
84 form['perm_additions'], form['perm_updates'], form['perm_deletions'],
85 form['perm_additions'], form['perm_updates'], form['perm_deletions'],
85 form['recursive'])
86 form['recursive'])
86
87
87 action_data = {
88 action_data = {
88 'added': changes['added'],
89 'added': changes['added'],
89 'updated': changes['updated'],
90 'updated': changes['updated'],
90 'deleted': changes['deleted'],
91 'deleted': changes['deleted'],
91 }
92 }
92 audit_logger.store_web(
93 audit_logger.store_web(
93 'repo_group.edit.permissions', action_data=action_data,
94 'repo_group.edit.permissions', action_data=action_data,
94 user=c.rhodecode_user)
95 user=c.rhodecode_user)
95
96
96 Session().commit()
97 Session().commit()
97 h.flash(_('Repository Group permissions updated'), category='success')
98 h.flash(_('Repository Group permissions updated'), category='success')
99
100 affected_user_ids = []
101 for change in changes['added'] + changes['updated'] + changes['deleted']:
102 if change['type'] == 'user':
103 affected_user_ids.append(change['id'])
104
105 events.trigger(events.UserPermissionsChange(affected_user_ids))
106
98 raise HTTPFound(
107 raise HTTPFound(
99 h.route_path('edit_repo_group_perms',
108 h.route_path('edit_repo_group_perms',
100 repo_group_name=self.db_repo_group_name))
109 repo_group_name=self.db_repo_group_name))
@@ -1,89 +1,95 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 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
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode import events
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.model.forms import RepoPermsForm
32 from rhodecode.model.forms import RepoPermsForm
32 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
33 from rhodecode.model.repo import RepoModel
34 from rhodecode.model.repo import RepoModel
34
35
35 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
36
37
37
38
38 class RepoSettingsPermissionsView(RepoAppView):
39 class RepoSettingsPermissionsView(RepoAppView):
39
40
40 def load_default_context(self):
41 def load_default_context(self):
41 c = self._get_local_tmpl_context()
42 c = self._get_local_tmpl_context()
42
43
44 return c
43 return c
45
44
46 @LoginRequired()
45 @LoginRequired()
47 @HasRepoPermissionAnyDecorator('repository.admin')
46 @HasRepoPermissionAnyDecorator('repository.admin')
48 @view_config(
47 @view_config(
49 route_name='edit_repo_perms', request_method='GET',
48 route_name='edit_repo_perms', request_method='GET',
50 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
51 def edit_permissions(self):
50 def edit_permissions(self):
52 c = self.load_default_context()
51 c = self.load_default_context()
53 c.active = 'permissions'
52 c.active = 'permissions'
54 return self._get_template_context(c)
53 return self._get_template_context(c)
55
54
56 @LoginRequired()
55 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.admin')
56 @HasRepoPermissionAnyDecorator('repository.admin')
58 @CSRFRequired()
57 @CSRFRequired()
59 @view_config(
58 @view_config(
60 route_name='edit_repo_perms', request_method='POST',
59 route_name='edit_repo_perms', request_method='POST',
61 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
60 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
62 def edit_permissions_update(self):
61 def edit_permissions_update(self):
63 _ = self.request.translate
62 _ = self.request.translate
64 c = self.load_default_context()
63 c = self.load_default_context()
65 c.active = 'permissions'
64 c.active = 'permissions'
66 data = self.request.POST
65 data = self.request.POST
67 # store private flag outside of HTML to verify if we can modify
66 # store private flag outside of HTML to verify if we can modify
68 # default user permissions, prevents submission of FAKE post data
67 # default user permissions, prevents submission of FAKE post data
69 # into the form for private repos
68 # into the form for private repos
70 data['repo_private'] = self.db_repo.private
69 data['repo_private'] = self.db_repo.private
71 form = RepoPermsForm(self.request.translate)().to_python(data)
70 form = RepoPermsForm(self.request.translate)().to_python(data)
72 changes = RepoModel().update_permissions(
71 changes = RepoModel().update_permissions(
73 self.db_repo_name, form['perm_additions'], form['perm_updates'],
72 self.db_repo_name, form['perm_additions'], form['perm_updates'],
74 form['perm_deletions'])
73 form['perm_deletions'])
75
74
76 action_data = {
75 action_data = {
77 'added': changes['added'],
76 'added': changes['added'],
78 'updated': changes['updated'],
77 'updated': changes['updated'],
79 'deleted': changes['deleted'],
78 'deleted': changes['deleted'],
80 }
79 }
81 audit_logger.store_web(
80 audit_logger.store_web(
82 'repo.edit.permissions', action_data=action_data,
81 'repo.edit.permissions', action_data=action_data,
83 user=self._rhodecode_user, repo=self.db_repo)
82 user=self._rhodecode_user, repo=self.db_repo)
84
83
85 Session().commit()
84 Session().commit()
86 h.flash(_('Repository permissions updated'), category='success')
85 h.flash(_('Repository permissions updated'), category='success')
87
86
87 affected_user_ids = []
88 for change in changes['added'] + changes['updated'] + changes['deleted']:
89 if change['type'] == 'user':
90 affected_user_ids.append(change['id'])
91
92 events.trigger(events.UserPermissionsChange(affected_user_ids))
93
88 raise HTTPFound(
94 raise HTTPFound(
89 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
95 h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
@@ -1,519 +1,534 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 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
22
23 import peppercorn
23 import peppercorn
24 import formencode
24 import formencode
25 import formencode.htmlfill
25 import formencode.htmlfill
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.response import Response
28 from pyramid.response import Response
29 from pyramid.renderers import render
29 from pyramid.renderers import render
30
30
31 from rhodecode import events
31 from rhodecode.lib.exceptions import (
32 from rhodecode.lib.exceptions import (
32 RepoGroupAssignmentError, UserGroupAssignedException)
33 RepoGroupAssignmentError, UserGroupAssignedException)
33 from rhodecode.model.forms import (
34 from rhodecode.model.forms import (
34 UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm,
35 UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm,
35 UserPermissionsForm)
36 UserPermissionsForm)
36 from rhodecode.model.permission import PermissionModel
37 from rhodecode.model.permission import PermissionModel
37
38
38 from rhodecode.apps._base import UserGroupAppView
39 from rhodecode.apps._base import UserGroupAppView
39 from rhodecode.lib.auth import (
40 from rhodecode.lib.auth import (
40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 from rhodecode.lib import helpers as h, audit_logger
42 from rhodecode.lib import helpers as h, audit_logger
42 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.model.db import User
44 from rhodecode.model.db import User
44 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
45 from rhodecode.model.user_group import UserGroupModel
46 from rhodecode.model.user_group import UserGroupModel
46
47
47 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
48
49
49
50
50 class UserGroupsView(UserGroupAppView):
51 class UserGroupsView(UserGroupAppView):
51
52
52 def load_default_context(self):
53 def load_default_context(self):
53 c = self._get_local_tmpl_context()
54 c = self._get_local_tmpl_context()
54
55
55 PermissionModel().set_global_permission_choices(
56 PermissionModel().set_global_permission_choices(
56 c, gettext_translator=self.request.translate)
57 c, gettext_translator=self.request.translate)
57
58
58 return c
59 return c
59
60
60 @LoginRequired()
61 @LoginRequired()
61 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
62 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
62 @view_config(
63 @view_config(
63 route_name='user_group_members_data', request_method='GET',
64 route_name='user_group_members_data', request_method='GET',
64 renderer='json_ext', xhr=True)
65 renderer='json_ext', xhr=True)
65 def user_group_members(self):
66 def user_group_members(self):
66 """
67 """
67 Return members of given user group
68 Return members of given user group
68 """
69 """
69 self.load_default_context()
70 self.load_default_context()
70 user_group = self.db_user_group
71 user_group = self.db_user_group
71 group_members_obj = sorted((x.user for x in user_group.members),
72 group_members_obj = sorted((x.user for x in user_group.members),
72 key=lambda u: u.username.lower())
73 key=lambda u: u.username.lower())
73
74
74 group_members = [
75 group_members = [
75 {
76 {
76 'id': user.user_id,
77 'id': user.user_id,
77 'first_name': user.first_name,
78 'first_name': user.first_name,
78 'last_name': user.last_name,
79 'last_name': user.last_name,
79 'username': user.username,
80 'username': user.username,
80 'icon_link': h.gravatar_url(user.email, 30),
81 'icon_link': h.gravatar_url(user.email, 30),
81 'value_display': h.person(user.email),
82 'value_display': h.person(user.email),
82 'value': user.username,
83 'value': user.username,
83 'value_type': 'user',
84 'value_type': 'user',
84 'active': user.active,
85 'active': user.active,
85 }
86 }
86 for user in group_members_obj
87 for user in group_members_obj
87 ]
88 ]
88
89
89 return {
90 return {
90 'members': group_members
91 'members': group_members
91 }
92 }
92
93
93 @LoginRequired()
94 @LoginRequired()
94 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
95 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
95 @view_config(
96 @view_config(
96 route_name='edit_user_group_perms_summary', request_method='GET',
97 route_name='edit_user_group_perms_summary', request_method='GET',
97 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
98 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
98 def user_group_perms_summary(self):
99 def user_group_perms_summary(self):
99 c = self.load_default_context()
100 c = self.load_default_context()
100 c.user_group = self.db_user_group
101 c.user_group = self.db_user_group
101 c.active = 'perms_summary'
102 c.active = 'perms_summary'
102 c.permissions = UserGroupModel().get_perms_summary(
103 c.permissions = UserGroupModel().get_perms_summary(
103 c.user_group.users_group_id)
104 c.user_group.users_group_id)
104 return self._get_template_context(c)
105 return self._get_template_context(c)
105
106
106 @LoginRequired()
107 @LoginRequired()
107 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
108 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
108 @view_config(
109 @view_config(
109 route_name='edit_user_group_perms_summary_json', request_method='GET',
110 route_name='edit_user_group_perms_summary_json', request_method='GET',
110 renderer='json_ext')
111 renderer='json_ext')
111 def user_group_perms_summary_json(self):
112 def user_group_perms_summary_json(self):
112 self.load_default_context()
113 self.load_default_context()
113 user_group = self.db_user_group
114 user_group = self.db_user_group
114 return UserGroupModel().get_perms_summary(user_group.users_group_id)
115 return UserGroupModel().get_perms_summary(user_group.users_group_id)
115
116
116 def _revoke_perms_on_yourself(self, form_result):
117 def _revoke_perms_on_yourself(self, form_result):
117 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
118 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
118 form_result['perm_updates'])
119 form_result['perm_updates'])
119 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
120 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
120 form_result['perm_additions'])
121 form_result['perm_additions'])
121 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
122 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
122 form_result['perm_deletions'])
123 form_result['perm_deletions'])
123 admin_perm = 'usergroup.admin'
124 admin_perm = 'usergroup.admin'
124 if _updates and _updates[0][1] != admin_perm or \
125 if _updates and _updates[0][1] != admin_perm or \
125 _additions and _additions[0][1] != admin_perm or \
126 _additions and _additions[0][1] != admin_perm or \
126 _deletions and _deletions[0][1] != admin_perm:
127 _deletions and _deletions[0][1] != admin_perm:
127 return True
128 return True
128 return False
129 return False
129
130
130 @LoginRequired()
131 @LoginRequired()
131 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
132 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
132 @CSRFRequired()
133 @CSRFRequired()
133 @view_config(
134 @view_config(
134 route_name='user_groups_update', request_method='POST',
135 route_name='user_groups_update', request_method='POST',
135 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
136 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
136 def user_group_update(self):
137 def user_group_update(self):
137 _ = self.request.translate
138 _ = self.request.translate
138
139
139 user_group = self.db_user_group
140 user_group = self.db_user_group
140 user_group_id = user_group.users_group_id
141 user_group_id = user_group.users_group_id
141
142
142 c = self.load_default_context()
143 c = self.load_default_context()
143 c.user_group = user_group
144 c.user_group = user_group
144 c.group_members_obj = [x.user for x in c.user_group.members]
145 c.group_members_obj = [x.user for x in c.user_group.members]
145 c.group_members_obj.sort(key=lambda u: u.username.lower())
146 c.group_members_obj.sort(key=lambda u: u.username.lower())
146 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
147 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
147 c.active = 'settings'
148 c.active = 'settings'
148
149
149 users_group_form = UserGroupForm(
150 users_group_form = UserGroupForm(
150 self.request.translate, edit=True,
151 self.request.translate, edit=True,
151 old_data=c.user_group.get_dict(), allow_disabled=True)()
152 old_data=c.user_group.get_dict(), allow_disabled=True)()
152
153
153 old_values = c.user_group.get_api_data()
154 old_values = c.user_group.get_api_data()
154 user_group_name = self.request.POST.get('users_group_name')
155 user_group_name = self.request.POST.get('users_group_name')
155 try:
156 try:
156 form_result = users_group_form.to_python(self.request.POST)
157 form_result = users_group_form.to_python(self.request.POST)
157 pstruct = peppercorn.parse(self.request.POST.items())
158 pstruct = peppercorn.parse(self.request.POST.items())
158 form_result['users_group_members'] = pstruct['user_group_members']
159 form_result['users_group_members'] = pstruct['user_group_members']
159
160
160 user_group, added_members, removed_members = \
161 user_group, added_members, removed_members = \
161 UserGroupModel().update(c.user_group, form_result)
162 UserGroupModel().update(c.user_group, form_result)
162 updated_user_group = form_result['users_group_name']
163 updated_user_group = form_result['users_group_name']
163
164
164 for user_id in added_members:
165 for user_id in added_members:
165 user = User.get(user_id)
166 user = User.get(user_id)
166 user_data = user.get_api_data()
167 user_data = user.get_api_data()
167 audit_logger.store_web(
168 audit_logger.store_web(
168 'user_group.edit.member.add',
169 'user_group.edit.member.add',
169 action_data={'user': user_data, 'old_data': old_values},
170 action_data={'user': user_data, 'old_data': old_values},
170 user=self._rhodecode_user)
171 user=self._rhodecode_user)
171
172
172 for user_id in removed_members:
173 for user_id in removed_members:
173 user = User.get(user_id)
174 user = User.get(user_id)
174 user_data = user.get_api_data()
175 user_data = user.get_api_data()
175 audit_logger.store_web(
176 audit_logger.store_web(
176 'user_group.edit.member.delete',
177 'user_group.edit.member.delete',
177 action_data={'user': user_data, 'old_data': old_values},
178 action_data={'user': user_data, 'old_data': old_values},
178 user=self._rhodecode_user)
179 user=self._rhodecode_user)
179
180
180 audit_logger.store_web(
181 audit_logger.store_web(
181 'user_group.edit', action_data={'old_data': old_values},
182 'user_group.edit', action_data={'old_data': old_values},
182 user=self._rhodecode_user)
183 user=self._rhodecode_user)
183
184
184 h.flash(_('Updated user group %s') % updated_user_group,
185 h.flash(_('Updated user group %s') % updated_user_group,
185 category='success')
186 category='success')
187
188 affected_user_ids = []
189 for user_id in added_members + removed_members:
190 affected_user_ids.append(user_id)
191 events.trigger(events.UserPermissionsChange(affected_user_ids))
192
186 Session().commit()
193 Session().commit()
187 except formencode.Invalid as errors:
194 except formencode.Invalid as errors:
188 defaults = errors.value
195 defaults = errors.value
189 e = errors.error_dict or {}
196 e = errors.error_dict or {}
190
197
191 data = render(
198 data = render(
192 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
199 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
193 self._get_template_context(c), self.request)
200 self._get_template_context(c), self.request)
194 html = formencode.htmlfill.render(
201 html = formencode.htmlfill.render(
195 data,
202 data,
196 defaults=defaults,
203 defaults=defaults,
197 errors=e,
204 errors=e,
198 prefix_error=False,
205 prefix_error=False,
199 encoding="UTF-8",
206 encoding="UTF-8",
200 force_defaults=False
207 force_defaults=False
201 )
208 )
202 return Response(html)
209 return Response(html)
203
210
204 except Exception:
211 except Exception:
205 log.exception("Exception during update of user group")
212 log.exception("Exception during update of user group")
206 h.flash(_('Error occurred during update of user group %s')
213 h.flash(_('Error occurred during update of user group %s')
207 % user_group_name, category='error')
214 % user_group_name, category='error')
208
215
209 raise HTTPFound(
216 raise HTTPFound(
210 h.route_path('edit_user_group', user_group_id=user_group_id))
217 h.route_path('edit_user_group', user_group_id=user_group_id))
211
218
212 @LoginRequired()
219 @LoginRequired()
213 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
220 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
214 @CSRFRequired()
221 @CSRFRequired()
215 @view_config(
222 @view_config(
216 route_name='user_groups_delete', request_method='POST',
223 route_name='user_groups_delete', request_method='POST',
217 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
224 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
218 def user_group_delete(self):
225 def user_group_delete(self):
219 _ = self.request.translate
226 _ = self.request.translate
220 user_group = self.db_user_group
227 user_group = self.db_user_group
221
228
222 self.load_default_context()
229 self.load_default_context()
223 force = str2bool(self.request.POST.get('force'))
230 force = str2bool(self.request.POST.get('force'))
224
231
225 old_values = user_group.get_api_data()
232 old_values = user_group.get_api_data()
226 try:
233 try:
227 UserGroupModel().delete(user_group, force=force)
234 UserGroupModel().delete(user_group, force=force)
228 audit_logger.store_web(
235 audit_logger.store_web(
229 'user.delete', action_data={'old_data': old_values},
236 'user.delete', action_data={'old_data': old_values},
230 user=self._rhodecode_user)
237 user=self._rhodecode_user)
231 Session().commit()
238 Session().commit()
232 h.flash(_('Successfully deleted user group'), category='success')
239 h.flash(_('Successfully deleted user group'), category='success')
233 except UserGroupAssignedException as e:
240 except UserGroupAssignedException as e:
234 h.flash(str(e), category='error')
241 h.flash(str(e), category='error')
235 except Exception:
242 except Exception:
236 log.exception("Exception during deletion of user group")
243 log.exception("Exception during deletion of user group")
237 h.flash(_('An error occurred during deletion of user group'),
244 h.flash(_('An error occurred during deletion of user group'),
238 category='error')
245 category='error')
239 raise HTTPFound(h.route_path('user_groups'))
246 raise HTTPFound(h.route_path('user_groups'))
240
247
241 @LoginRequired()
248 @LoginRequired()
242 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
249 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
243 @view_config(
250 @view_config(
244 route_name='edit_user_group', request_method='GET',
251 route_name='edit_user_group', request_method='GET',
245 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
252 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
246 def user_group_edit(self):
253 def user_group_edit(self):
247 user_group = self.db_user_group
254 user_group = self.db_user_group
248
255
249 c = self.load_default_context()
256 c = self.load_default_context()
250 c.user_group = user_group
257 c.user_group = user_group
251 c.group_members_obj = [x.user for x in c.user_group.members]
258 c.group_members_obj = [x.user for x in c.user_group.members]
252 c.group_members_obj.sort(key=lambda u: u.username.lower())
259 c.group_members_obj.sort(key=lambda u: u.username.lower())
253 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
260 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
254
261
255 c.active = 'settings'
262 c.active = 'settings'
256
263
257 defaults = user_group.get_dict()
264 defaults = user_group.get_dict()
258 # fill owner
265 # fill owner
259 if user_group.user:
266 if user_group.user:
260 defaults.update({'user': user_group.user.username})
267 defaults.update({'user': user_group.user.username})
261 else:
268 else:
262 replacement_user = User.get_first_super_admin().username
269 replacement_user = User.get_first_super_admin().username
263 defaults.update({'user': replacement_user})
270 defaults.update({'user': replacement_user})
264
271
265 data = render(
272 data = render(
266 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
273 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
267 self._get_template_context(c), self.request)
274 self._get_template_context(c), self.request)
268 html = formencode.htmlfill.render(
275 html = formencode.htmlfill.render(
269 data,
276 data,
270 defaults=defaults,
277 defaults=defaults,
271 encoding="UTF-8",
278 encoding="UTF-8",
272 force_defaults=False
279 force_defaults=False
273 )
280 )
274 return Response(html)
281 return Response(html)
275
282
276 @LoginRequired()
283 @LoginRequired()
277 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
284 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
278 @view_config(
285 @view_config(
279 route_name='edit_user_group_perms', request_method='GET',
286 route_name='edit_user_group_perms', request_method='GET',
280 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
287 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
281 def user_group_edit_perms(self):
288 def user_group_edit_perms(self):
282 user_group = self.db_user_group
289 user_group = self.db_user_group
283 c = self.load_default_context()
290 c = self.load_default_context()
284 c.user_group = user_group
291 c.user_group = user_group
285 c.active = 'perms'
292 c.active = 'perms'
286
293
287 defaults = {}
294 defaults = {}
288 # fill user group users
295 # fill user group users
289 for p in c.user_group.user_user_group_to_perm:
296 for p in c.user_group.user_user_group_to_perm:
290 defaults.update({'u_perm_%s' % p.user.user_id:
297 defaults.update({'u_perm_%s' % p.user.user_id:
291 p.permission.permission_name})
298 p.permission.permission_name})
292
299
293 for p in c.user_group.user_group_user_group_to_perm:
300 for p in c.user_group.user_group_user_group_to_perm:
294 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
301 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
295 p.permission.permission_name})
302 p.permission.permission_name})
296
303
297 data = render(
304 data = render(
298 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
305 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
299 self._get_template_context(c), self.request)
306 self._get_template_context(c), self.request)
300 html = formencode.htmlfill.render(
307 html = formencode.htmlfill.render(
301 data,
308 data,
302 defaults=defaults,
309 defaults=defaults,
303 encoding="UTF-8",
310 encoding="UTF-8",
304 force_defaults=False
311 force_defaults=False
305 )
312 )
306 return Response(html)
313 return Response(html)
307
314
308 @LoginRequired()
315 @LoginRequired()
309 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
316 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
310 @CSRFRequired()
317 @CSRFRequired()
311 @view_config(
318 @view_config(
312 route_name='edit_user_group_perms_update', request_method='POST',
319 route_name='edit_user_group_perms_update', request_method='POST',
313 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
320 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
314 def user_group_update_perms(self):
321 def user_group_update_perms(self):
315 """
322 """
316 grant permission for given user group
323 grant permission for given user group
317 """
324 """
318 _ = self.request.translate
325 _ = self.request.translate
319
326
320 user_group = self.db_user_group
327 user_group = self.db_user_group
321 user_group_id = user_group.users_group_id
328 user_group_id = user_group.users_group_id
322 c = self.load_default_context()
329 c = self.load_default_context()
323 c.user_group = user_group
330 c.user_group = user_group
324 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
331 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
325
332
326 if not self._rhodecode_user.is_admin:
333 if not self._rhodecode_user.is_admin:
327 if self._revoke_perms_on_yourself(form):
334 if self._revoke_perms_on_yourself(form):
328 msg = _('Cannot change permission for yourself as admin')
335 msg = _('Cannot change permission for yourself as admin')
329 h.flash(msg, category='warning')
336 h.flash(msg, category='warning')
330 raise HTTPFound(
337 raise HTTPFound(
331 h.route_path('edit_user_group_perms',
338 h.route_path('edit_user_group_perms',
332 user_group_id=user_group_id))
339 user_group_id=user_group_id))
333
340
334 try:
341 try:
335 changes = UserGroupModel().update_permissions(
342 changes = UserGroupModel().update_permissions(
336 user_group,
343 user_group,
337 form['perm_additions'], form['perm_updates'],
344 form['perm_additions'], form['perm_updates'],
338 form['perm_deletions'])
345 form['perm_deletions'])
339
346
340 except RepoGroupAssignmentError:
347 except RepoGroupAssignmentError:
341 h.flash(_('Target group cannot be the same'), category='error')
348 h.flash(_('Target group cannot be the same'), category='error')
342 raise HTTPFound(
349 raise HTTPFound(
343 h.route_path('edit_user_group_perms',
350 h.route_path('edit_user_group_perms',
344 user_group_id=user_group_id))
351 user_group_id=user_group_id))
345
352
346 action_data = {
353 action_data = {
347 'added': changes['added'],
354 'added': changes['added'],
348 'updated': changes['updated'],
355 'updated': changes['updated'],
349 'deleted': changes['deleted'],
356 'deleted': changes['deleted'],
350 }
357 }
351 audit_logger.store_web(
358 audit_logger.store_web(
352 'user_group.edit.permissions', action_data=action_data,
359 'user_group.edit.permissions', action_data=action_data,
353 user=self._rhodecode_user)
360 user=self._rhodecode_user)
354
361
355 Session().commit()
362 Session().commit()
356 h.flash(_('User Group permissions updated'), category='success')
363 h.flash(_('User Group permissions updated'), category='success')
364
365 affected_user_ids = []
366 for change in changes['added'] + changes['updated'] + changes['deleted']:
367 if change['type'] == 'user':
368 affected_user_ids.append(change['id'])
369
370 events.trigger(events.UserPermissionsChange(affected_user_ids))
371
357 raise HTTPFound(
372 raise HTTPFound(
358 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
373 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
359
374
360 @LoginRequired()
375 @LoginRequired()
361 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
376 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
362 @view_config(
377 @view_config(
363 route_name='edit_user_group_global_perms', request_method='GET',
378 route_name='edit_user_group_global_perms', request_method='GET',
364 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
379 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
365 def user_group_global_perms_edit(self):
380 def user_group_global_perms_edit(self):
366 user_group = self.db_user_group
381 user_group = self.db_user_group
367 c = self.load_default_context()
382 c = self.load_default_context()
368 c.user_group = user_group
383 c.user_group = user_group
369 c.active = 'global_perms'
384 c.active = 'global_perms'
370
385
371 c.default_user = User.get_default_user()
386 c.default_user = User.get_default_user()
372 defaults = c.user_group.get_dict()
387 defaults = c.user_group.get_dict()
373 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
388 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
374 defaults.update(c.user_group.get_default_perms())
389 defaults.update(c.user_group.get_default_perms())
375
390
376 data = render(
391 data = render(
377 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
392 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
378 self._get_template_context(c), self.request)
393 self._get_template_context(c), self.request)
379 html = formencode.htmlfill.render(
394 html = formencode.htmlfill.render(
380 data,
395 data,
381 defaults=defaults,
396 defaults=defaults,
382 encoding="UTF-8",
397 encoding="UTF-8",
383 force_defaults=False
398 force_defaults=False
384 )
399 )
385 return Response(html)
400 return Response(html)
386
401
387 @LoginRequired()
402 @LoginRequired()
388 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
403 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
389 @CSRFRequired()
404 @CSRFRequired()
390 @view_config(
405 @view_config(
391 route_name='edit_user_group_global_perms_update', request_method='POST',
406 route_name='edit_user_group_global_perms_update', request_method='POST',
392 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
407 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
393 def user_group_global_perms_update(self):
408 def user_group_global_perms_update(self):
394 _ = self.request.translate
409 _ = self.request.translate
395 user_group = self.db_user_group
410 user_group = self.db_user_group
396 user_group_id = self.db_user_group.users_group_id
411 user_group_id = self.db_user_group.users_group_id
397
412
398 c = self.load_default_context()
413 c = self.load_default_context()
399 c.user_group = user_group
414 c.user_group = user_group
400 c.active = 'global_perms'
415 c.active = 'global_perms'
401
416
402 try:
417 try:
403 # first stage that verifies the checkbox
418 # first stage that verifies the checkbox
404 _form = UserIndividualPermissionsForm(self.request.translate)
419 _form = UserIndividualPermissionsForm(self.request.translate)
405 form_result = _form.to_python(dict(self.request.POST))
420 form_result = _form.to_python(dict(self.request.POST))
406 inherit_perms = form_result['inherit_default_permissions']
421 inherit_perms = form_result['inherit_default_permissions']
407 user_group.inherit_default_permissions = inherit_perms
422 user_group.inherit_default_permissions = inherit_perms
408 Session().add(user_group)
423 Session().add(user_group)
409
424
410 if not inherit_perms:
425 if not inherit_perms:
411 # only update the individual ones if we un check the flag
426 # only update the individual ones if we un check the flag
412 _form = UserPermissionsForm(
427 _form = UserPermissionsForm(
413 self.request.translate,
428 self.request.translate,
414 [x[0] for x in c.repo_create_choices],
429 [x[0] for x in c.repo_create_choices],
415 [x[0] for x in c.repo_create_on_write_choices],
430 [x[0] for x in c.repo_create_on_write_choices],
416 [x[0] for x in c.repo_group_create_choices],
431 [x[0] for x in c.repo_group_create_choices],
417 [x[0] for x in c.user_group_create_choices],
432 [x[0] for x in c.user_group_create_choices],
418 [x[0] for x in c.fork_choices],
433 [x[0] for x in c.fork_choices],
419 [x[0] for x in c.inherit_default_permission_choices])()
434 [x[0] for x in c.inherit_default_permission_choices])()
420
435
421 form_result = _form.to_python(dict(self.request.POST))
436 form_result = _form.to_python(dict(self.request.POST))
422 form_result.update(
437 form_result.update(
423 {'perm_user_group_id': user_group.users_group_id})
438 {'perm_user_group_id': user_group.users_group_id})
424
439
425 PermissionModel().update_user_group_permissions(form_result)
440 PermissionModel().update_user_group_permissions(form_result)
426
441
427 Session().commit()
442 Session().commit()
428 h.flash(_('User Group global permissions updated successfully'),
443 h.flash(_('User Group global permissions updated successfully'),
429 category='success')
444 category='success')
430
445
431 except formencode.Invalid as errors:
446 except formencode.Invalid as errors:
432 defaults = errors.value
447 defaults = errors.value
433
448
434 data = render(
449 data = render(
435 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
450 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
436 self._get_template_context(c), self.request)
451 self._get_template_context(c), self.request)
437 html = formencode.htmlfill.render(
452 html = formencode.htmlfill.render(
438 data,
453 data,
439 defaults=defaults,
454 defaults=defaults,
440 errors=errors.error_dict or {},
455 errors=errors.error_dict or {},
441 prefix_error=False,
456 prefix_error=False,
442 encoding="UTF-8",
457 encoding="UTF-8",
443 force_defaults=False
458 force_defaults=False
444 )
459 )
445 return Response(html)
460 return Response(html)
446 except Exception:
461 except Exception:
447 log.exception("Exception during permissions saving")
462 log.exception("Exception during permissions saving")
448 h.flash(_('An error occurred during permissions saving'),
463 h.flash(_('An error occurred during permissions saving'),
449 category='error')
464 category='error')
450
465
451 raise HTTPFound(
466 raise HTTPFound(
452 h.route_path('edit_user_group_global_perms',
467 h.route_path('edit_user_group_global_perms',
453 user_group_id=user_group_id))
468 user_group_id=user_group_id))
454
469
455 @LoginRequired()
470 @LoginRequired()
456 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
471 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
457 @view_config(
472 @view_config(
458 route_name='edit_user_group_advanced', request_method='GET',
473 route_name='edit_user_group_advanced', request_method='GET',
459 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
474 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
460 def user_group_edit_advanced(self):
475 def user_group_edit_advanced(self):
461 user_group = self.db_user_group
476 user_group = self.db_user_group
462
477
463 c = self.load_default_context()
478 c = self.load_default_context()
464 c.user_group = user_group
479 c.user_group = user_group
465 c.active = 'advanced'
480 c.active = 'advanced'
466 c.group_members_obj = sorted(
481 c.group_members_obj = sorted(
467 (x.user for x in c.user_group.members),
482 (x.user for x in c.user_group.members),
468 key=lambda u: u.username.lower())
483 key=lambda u: u.username.lower())
469
484
470 c.group_to_repos = sorted(
485 c.group_to_repos = sorted(
471 (x.repository for x in c.user_group.users_group_repo_to_perm),
486 (x.repository for x in c.user_group.users_group_repo_to_perm),
472 key=lambda u: u.repo_name.lower())
487 key=lambda u: u.repo_name.lower())
473
488
474 c.group_to_repo_groups = sorted(
489 c.group_to_repo_groups = sorted(
475 (x.group for x in c.user_group.users_group_repo_group_to_perm),
490 (x.group for x in c.user_group.users_group_repo_group_to_perm),
476 key=lambda u: u.group_name.lower())
491 key=lambda u: u.group_name.lower())
477
492
478 c.group_to_review_rules = sorted(
493 c.group_to_review_rules = sorted(
479 (x.users_group for x in c.user_group.user_group_review_rules),
494 (x.users_group for x in c.user_group.user_group_review_rules),
480 key=lambda u: u.users_group_name.lower())
495 key=lambda u: u.users_group_name.lower())
481
496
482 return self._get_template_context(c)
497 return self._get_template_context(c)
483
498
484 @LoginRequired()
499 @LoginRequired()
485 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
500 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
486 @CSRFRequired()
501 @CSRFRequired()
487 @view_config(
502 @view_config(
488 route_name='edit_user_group_advanced_sync', request_method='POST',
503 route_name='edit_user_group_advanced_sync', request_method='POST',
489 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
504 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
490 def user_group_edit_advanced_set_synchronization(self):
505 def user_group_edit_advanced_set_synchronization(self):
491 _ = self.request.translate
506 _ = self.request.translate
492 user_group = self.db_user_group
507 user_group = self.db_user_group
493 user_group_id = user_group.users_group_id
508 user_group_id = user_group.users_group_id
494
509
495 existing = user_group.group_data.get('extern_type')
510 existing = user_group.group_data.get('extern_type')
496
511
497 if existing:
512 if existing:
498 new_state = user_group.group_data
513 new_state = user_group.group_data
499 new_state['extern_type'] = None
514 new_state['extern_type'] = None
500 else:
515 else:
501 new_state = user_group.group_data
516 new_state = user_group.group_data
502 new_state['extern_type'] = 'manual'
517 new_state['extern_type'] = 'manual'
503 new_state['extern_type_set_by'] = self._rhodecode_user.username
518 new_state['extern_type_set_by'] = self._rhodecode_user.username
504
519
505 try:
520 try:
506 user_group.group_data = new_state
521 user_group.group_data = new_state
507 Session().add(user_group)
522 Session().add(user_group)
508 Session().commit()
523 Session().commit()
509
524
510 h.flash(_('User Group synchronization updated successfully'),
525 h.flash(_('User Group synchronization updated successfully'),
511 category='success')
526 category='success')
512 except Exception:
527 except Exception:
513 log.exception("Exception during sync settings saving")
528 log.exception("Exception during sync settings saving")
514 h.flash(_('An error occurred during synchronization update'),
529 h.flash(_('An error occurred during synchronization update'),
515 category='error')
530 category='error')
516
531
517 raise HTTPFound(
532 raise HTTPFound(
518 h.route_path('edit_user_group_advanced',
533 h.route_path('edit_user_group_advanced',
519 user_group_id=user_group_id))
534 user_group_id=user_group_id))
@@ -1,82 +1,84 b''
1 # Copyright (C) 2016-2018 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import logging
19 import logging
20 from pyramid.threadlocal import get_current_registry
20 from pyramid.threadlocal import get_current_registry
21 from rhodecode.events.base import RhodecodeEvent
21 from rhodecode.events.base import RhodecodeEvent
22
22
23
23
24 log = logging.getLogger(__name__)
24 log = logging.getLogger(__name__)
25
25
26
26
27 def trigger(event, registry=None):
27 def trigger(event, registry=None):
28 """
28 """
29 Helper method to send an event. This wraps the pyramid logic to send an
29 Helper method to send an event. This wraps the pyramid logic to send an
30 event.
30 event.
31 """
31 """
32 # For the first step we are using pyramids thread locals here. If the
32 # For the first step we are using pyramids thread locals here. If the
33 # event mechanism works out as a good solution we should think about
33 # event mechanism works out as a good solution we should think about
34 # passing the registry as an argument to get rid of it.
34 # passing the registry as an argument to get rid of it.
35 registry = registry or get_current_registry()
35 registry = registry or get_current_registry()
36 registry.notify(event)
36 registry.notify(event)
37 log.debug('event %s triggered using registry %s', event, registry)
37 log.debug('event %s triggered using registry %s', event, registry)
38
38
39 # Until we can work around the problem that VCS operations do not have a
39 # Until we can work around the problem that VCS operations do not have a
40 # pyramid context to work with, we send the events to integrations directly
40 # pyramid context to work with, we send the events to integrations directly
41
41
42 # Later it will be possible to use regular pyramid subscribers ie:
42 # Later it will be possible to use regular pyramid subscribers ie:
43 # config.add_subscriber(
43 # config.add_subscriber(
44 # 'rhodecode.integrations.integrations_event_handler',
44 # 'rhodecode.integrations.integrations_event_handler',
45 # 'rhodecode.events.RhodecodeEvent')
45 # 'rhodecode.events.RhodecodeEvent')
46 # trigger(event, request.registry)
46 # trigger(event, request.registry)
47
47
48 from rhodecode.integrations import integrations_event_handler
48 from rhodecode.integrations import integrations_event_handler
49 if isinstance(event, RhodecodeEvent):
49 if isinstance(event, RhodecodeEvent):
50 integrations_event_handler(event)
50 integrations_event_handler(event)
51
51
52
52 from rhodecode.events.user import ( # noqa
53 from rhodecode.events.user import ( # noqa
53 UserPreCreate,
54 UserPreCreate,
54 UserPostCreate,
55 UserPostCreate,
55 UserPreUpdate,
56 UserPreUpdate,
56 UserRegistered
57 UserRegistered,
58 UserPermissionsChange,
57 )
59 )
58
60
59 from rhodecode.events.repo import ( # noqa
61 from rhodecode.events.repo import ( # noqa
60 RepoEvent,
62 RepoEvent,
61 RepoPreCreateEvent, RepoCreateEvent,
63 RepoPreCreateEvent, RepoCreateEvent,
62 RepoPreDeleteEvent, RepoDeleteEvent,
64 RepoPreDeleteEvent, RepoDeleteEvent,
63 RepoPrePushEvent, RepoPushEvent,
65 RepoPrePushEvent, RepoPushEvent,
64 RepoPrePullEvent, RepoPullEvent,
66 RepoPrePullEvent, RepoPullEvent,
65 )
67 )
66
68
67 from rhodecode.events.repo_group import ( # noqa
69 from rhodecode.events.repo_group import ( # noqa
68 RepoGroupEvent,
70 RepoGroupEvent,
69 RepoGroupCreateEvent,
71 RepoGroupCreateEvent,
70 RepoGroupUpdateEvent,
72 RepoGroupUpdateEvent,
71 RepoGroupDeleteEvent,
73 RepoGroupDeleteEvent,
72 )
74 )
73
75
74 from rhodecode.events.pullrequest import ( # noqa
76 from rhodecode.events.pullrequest import ( # noqa
75 PullRequestEvent,
77 PullRequestEvent,
76 PullRequestCreateEvent,
78 PullRequestCreateEvent,
77 PullRequestUpdateEvent,
79 PullRequestUpdateEvent,
78 PullRequestCommentEvent,
80 PullRequestCommentEvent,
79 PullRequestReviewEvent,
81 PullRequestReviewEvent,
80 PullRequestMergeEvent,
82 PullRequestMergeEvent,
81 PullRequestCloseEvent,
83 PullRequestCloseEvent,
82 )
84 )
@@ -1,85 +1,104 b''
1 # Copyright (C) 2016-2018 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 import logging
18 import logging
19
19
20 from zope.interface import implementer
20 from zope.interface import implementer
21
21
22 from rhodecode.translation import lazy_ugettext
22 from rhodecode.translation import lazy_ugettext
23 from rhodecode.events.base import RhodecodeEvent
23 from rhodecode.events.base import RhodecodeEvent
24 from rhodecode.events.interfaces import (
24 from rhodecode.events.interfaces import (
25 IUserRegistered, IUserPreCreate, IUserPreUpdate)
25 IUserRegistered, IUserPreCreate, IUserPreUpdate)
26
26
27 log = logging.getLogger(__name__)
27 log = logging.getLogger(__name__)
28
28
29
29
30 @implementer(IUserRegistered)
30 @implementer(IUserRegistered)
31 class UserRegistered(RhodecodeEvent):
31 class UserRegistered(RhodecodeEvent):
32 """
32 """
33 An instance of this class is emitted as an :term:`event` whenever a user
33 An instance of this class is emitted as an :term:`event` whenever a user
34 account is registered.
34 account is registered.
35 """
35 """
36 name = 'user-register'
36 name = 'user-register'
37 display_name = lazy_ugettext('user registered')
37 display_name = lazy_ugettext('user registered')
38
38
39 def __init__(self, user, session):
39 def __init__(self, user, session):
40 super(UserRegistered, self).__init__()
40 super(UserRegistered, self).__init__()
41 self.user = user
41 self.user = user
42 self.session = session
42 self.session = session
43
43
44
44
45 @implementer(IUserPreCreate)
45 @implementer(IUserPreCreate)
46 class UserPreCreate(RhodecodeEvent):
46 class UserPreCreate(RhodecodeEvent):
47 """
47 """
48 An instance of this class is emitted as an :term:`event` before a new user
48 An instance of this class is emitted as an :term:`event` before a new user
49 object is created.
49 object is created.
50 """
50 """
51 name = 'user-pre-create'
51 name = 'user-pre-create'
52 display_name = lazy_ugettext('user pre create')
52 display_name = lazy_ugettext('user pre create')
53
53
54 def __init__(self, user_data):
54 def __init__(self, user_data):
55 super(UserPreCreate, self).__init__()
55 super(UserPreCreate, self).__init__()
56 self.user_data = user_data
56 self.user_data = user_data
57
57
58
58
59 @implementer(IUserPreCreate)
59 @implementer(IUserPreCreate)
60 class UserPostCreate(RhodecodeEvent):
60 class UserPostCreate(RhodecodeEvent):
61 """
61 """
62 An instance of this class is emitted as an :term:`event` after a new user
62 An instance of this class is emitted as an :term:`event` after a new user
63 object is created.
63 object is created.
64 """
64 """
65 name = 'user-post-create'
65 name = 'user-post-create'
66 display_name = lazy_ugettext('user post create')
66 display_name = lazy_ugettext('user post create')
67
67
68 def __init__(self, user_data):
68 def __init__(self, user_data):
69 super(UserPostCreate, self).__init__()
69 super(UserPostCreate, self).__init__()
70 self.user_data = user_data
70 self.user_data = user_data
71
71
72
72
73 @implementer(IUserPreUpdate)
73 @implementer(IUserPreUpdate)
74 class UserPreUpdate(RhodecodeEvent):
74 class UserPreUpdate(RhodecodeEvent):
75 """
75 """
76 An instance of this class is emitted as an :term:`event` before a user
76 An instance of this class is emitted as an :term:`event` before a user
77 object is updated.
77 object is updated.
78 """
78 """
79 name = 'user-pre-update'
79 name = 'user-pre-update'
80 display_name = lazy_ugettext('user pre update')
80 display_name = lazy_ugettext('user pre update')
81
81
82 def __init__(self, user, user_data):
82 def __init__(self, user, user_data):
83 super(UserPreUpdate, self).__init__()
83 super(UserPreUpdate, self).__init__()
84 self.user = user
84 self.user = user
85 self.user_data = user_data
85 self.user_data = user_data
86
87
88 class UserPermissionsChange(RhodecodeEvent):
89 """
90 This event should be triggered on an event that permissions of user might changed.
91 Currently this should be triggered on:
92
93 - user added/removed from user group
94 - repo permissions changed
95 - repo group permissions changed
96 - user group permissions changed
97
98 """
99 name = 'user-permissions-change'
100 display_name = lazy_ugettext('user permissions change')
101
102 def __init__(self, user_ids):
103 super(UserPermissionsChange, self).__init__()
104 self.user_ids = user_ids
@@ -1,327 +1,328 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 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 import io
20 import io
21 import re
21 import re
22 import datetime
22 import datetime
23 import logging
23 import logging
24 import Queue
24 import Queue
25 import subprocess32
25 import subprocess32
26 import os
26 import os
27
27
28
28
29 from dateutil.parser import parse
29 from dateutil.parser import parse
30 from pyramid.i18n import get_localizer
30 from pyramid.i18n import get_localizer
31 from pyramid.threadlocal import get_current_request
31 from pyramid.threadlocal import get_current_request
32 from pyramid.interfaces import IRoutesMapper
32 from pyramid.interfaces import IRoutesMapper
33 from pyramid.settings import asbool
33 from pyramid.settings import asbool
34 from pyramid.path import AssetResolver
34 from pyramid.path import AssetResolver
35 from threading import Thread
35 from threading import Thread
36
36
37 from rhodecode.translation import _ as tsf
37 from rhodecode.translation import _ as tsf
38 from rhodecode.config.jsroutes import generate_jsroutes_content
38 from rhodecode.config.jsroutes import generate_jsroutes_content
39 from rhodecode.lib import auth
39 from rhodecode.lib import auth
40 from rhodecode.lib.base import get_auth_user
40 from rhodecode.lib.base import get_auth_user
41
41
42
42
43 import rhodecode
43 import rhodecode
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 def add_renderer_globals(event):
49 def add_renderer_globals(event):
50 from rhodecode.lib import helpers
50 from rhodecode.lib import helpers
51
51
52 # TODO: When executed in pyramid view context the request is not available
52 # TODO: When executed in pyramid view context the request is not available
53 # in the event. Find a better solution to get the request.
53 # in the event. Find a better solution to get the request.
54 request = event['request'] or get_current_request()
54 request = event['request'] or get_current_request()
55
55
56 # Add Pyramid translation as '_' to context
56 # Add Pyramid translation as '_' to context
57 event['_'] = request.translate
57 event['_'] = request.translate
58 event['_ungettext'] = request.plularize
58 event['_ungettext'] = request.plularize
59 event['h'] = helpers
59 event['h'] = helpers
60
60
61
61
62 def add_localizer(event):
62 def add_localizer(event):
63 request = event.request
63 request = event.request
64 localizer = request.localizer
64 localizer = request.localizer
65
65
66 def auto_translate(*args, **kwargs):
66 def auto_translate(*args, **kwargs):
67 return localizer.translate(tsf(*args, **kwargs))
67 return localizer.translate(tsf(*args, **kwargs))
68
68
69 request.translate = auto_translate
69 request.translate = auto_translate
70 request.plularize = localizer.pluralize
70 request.plularize = localizer.pluralize
71
71
72
72
73 def set_user_lang(event):
73 def set_user_lang(event):
74 request = event.request
74 request = event.request
75 cur_user = getattr(request, 'user', None)
75 cur_user = getattr(request, 'user', None)
76
76
77 if cur_user:
77 if cur_user:
78 user_lang = cur_user.get_instance().user_data.get('language')
78 user_lang = cur_user.get_instance().user_data.get('language')
79 if user_lang:
79 if user_lang:
80 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
80 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
81 event.request._LOCALE_ = user_lang
81 event.request._LOCALE_ = user_lang
82
82
83
83
84 def add_request_user_context(event):
84 def add_request_user_context(event):
85 """
85 """
86 Adds auth user into request context
86 Adds auth user into request context
87 """
87 """
88 request = event.request
88 request = event.request
89 # access req_id as soon as possible
89 # access req_id as soon as possible
90 req_id = request.req_id
90 req_id = request.req_id
91
91
92 if hasattr(request, 'vcs_call'):
92 if hasattr(request, 'vcs_call'):
93 # skip vcs calls
93 # skip vcs calls
94 return
94 return
95
95
96 if hasattr(request, 'rpc_method'):
96 if hasattr(request, 'rpc_method'):
97 # skip api calls
97 # skip api calls
98 return
98 return
99
99
100 auth_user = get_auth_user(request)
100 auth_user = get_auth_user(request)
101 request.user = auth_user
101 request.user = auth_user
102 request.environ['rc_auth_user'] = auth_user
102 request.environ['rc_auth_user'] = auth_user
103 request.environ['rc_req_id'] = req_id
103 request.environ['rc_req_id'] = req_id
104
104
105
105 def inject_app_settings(event):
106 def inject_app_settings(event):
106 settings = event.app.registry.settings
107 settings = event.app.registry.settings
107 # inject info about available permissions
108 # inject info about available permissions
108 auth.set_available_permissions(settings)
109 auth.set_available_permissions(settings)
109
110
110
111
111 def scan_repositories_if_enabled(event):
112 def scan_repositories_if_enabled(event):
112 """
113 """
113 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
114 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
114 does a repository scan if enabled in the settings.
115 does a repository scan if enabled in the settings.
115 """
116 """
116 settings = event.app.registry.settings
117 settings = event.app.registry.settings
117 vcs_server_enabled = settings['vcs.server.enable']
118 vcs_server_enabled = settings['vcs.server.enable']
118 import_on_startup = settings['startup.import_repos']
119 import_on_startup = settings['startup.import_repos']
119 if vcs_server_enabled and import_on_startup:
120 if vcs_server_enabled and import_on_startup:
120 from rhodecode.model.scm import ScmModel
121 from rhodecode.model.scm import ScmModel
121 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
122 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
122 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
123 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
123 repo2db_mapper(repositories, remove_obsolete=False)
124 repo2db_mapper(repositories, remove_obsolete=False)
124
125
125
126
126 def write_metadata_if_needed(event):
127 def write_metadata_if_needed(event):
127 """
128 """
128 Writes upgrade metadata
129 Writes upgrade metadata
129 """
130 """
130 import rhodecode
131 import rhodecode
131 from rhodecode.lib import system_info
132 from rhodecode.lib import system_info
132 from rhodecode.lib import ext_json
133 from rhodecode.lib import ext_json
133
134
134 fname = '.rcmetadata.json'
135 fname = '.rcmetadata.json'
135 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
136 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
136 metadata_destination = os.path.join(ini_loc, fname)
137 metadata_destination = os.path.join(ini_loc, fname)
137
138
138 def get_update_age():
139 def get_update_age():
139 now = datetime.datetime.utcnow()
140 now = datetime.datetime.utcnow()
140
141
141 with open(metadata_destination, 'rb') as f:
142 with open(metadata_destination, 'rb') as f:
142 data = ext_json.json.loads(f.read())
143 data = ext_json.json.loads(f.read())
143 if 'created_on' in data:
144 if 'created_on' in data:
144 update_date = parse(data['created_on'])
145 update_date = parse(data['created_on'])
145 diff = now - update_date
146 diff = now - update_date
146 return diff.total_seconds() / 60.0
147 return diff.total_seconds() / 60.0
147
148
148 return 0
149 return 0
149
150
150 def write():
151 def write():
151 configuration = system_info.SysInfo(
152 configuration = system_info.SysInfo(
152 system_info.rhodecode_config)()['value']
153 system_info.rhodecode_config)()['value']
153 license_token = configuration['config']['license_token']
154 license_token = configuration['config']['license_token']
154
155
155 setup = dict(
156 setup = dict(
156 workers=configuration['config']['server:main'].get(
157 workers=configuration['config']['server:main'].get(
157 'workers', '?'),
158 'workers', '?'),
158 worker_type=configuration['config']['server:main'].get(
159 worker_type=configuration['config']['server:main'].get(
159 'worker_class', 'sync'),
160 'worker_class', 'sync'),
160 )
161 )
161 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
162 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
162 del dbinfo['url']
163 del dbinfo['url']
163
164
164 metadata = dict(
165 metadata = dict(
165 desc='upgrade metadata info',
166 desc='upgrade metadata info',
166 license_token=license_token,
167 license_token=license_token,
167 created_on=datetime.datetime.utcnow().isoformat(),
168 created_on=datetime.datetime.utcnow().isoformat(),
168 usage=system_info.SysInfo(system_info.usage_info)()['value'],
169 usage=system_info.SysInfo(system_info.usage_info)()['value'],
169 platform=system_info.SysInfo(system_info.platform_type)()['value'],
170 platform=system_info.SysInfo(system_info.platform_type)()['value'],
170 database=dbinfo,
171 database=dbinfo,
171 cpu=system_info.SysInfo(system_info.cpu)()['value'],
172 cpu=system_info.SysInfo(system_info.cpu)()['value'],
172 memory=system_info.SysInfo(system_info.memory)()['value'],
173 memory=system_info.SysInfo(system_info.memory)()['value'],
173 setup=setup
174 setup=setup
174 )
175 )
175
176
176 with open(metadata_destination, 'wb') as f:
177 with open(metadata_destination, 'wb') as f:
177 f.write(ext_json.json.dumps(metadata))
178 f.write(ext_json.json.dumps(metadata))
178
179
179 settings = event.app.registry.settings
180 settings = event.app.registry.settings
180 if settings.get('metadata.skip'):
181 if settings.get('metadata.skip'):
181 return
182 return
182
183
183 # only write this every 24h, workers restart caused unwanted delays
184 # only write this every 24h, workers restart caused unwanted delays
184 try:
185 try:
185 age_in_min = get_update_age()
186 age_in_min = get_update_age()
186 except Exception:
187 except Exception:
187 age_in_min = 0
188 age_in_min = 0
188
189
189 if age_in_min > 60 * 60 * 24:
190 if age_in_min > 60 * 60 * 24:
190 return
191 return
191
192
192 try:
193 try:
193 write()
194 write()
194 except Exception:
195 except Exception:
195 pass
196 pass
196
197
197
198
198 def write_js_routes_if_enabled(event):
199 def write_js_routes_if_enabled(event):
199 registry = event.app.registry
200 registry = event.app.registry
200
201
201 mapper = registry.queryUtility(IRoutesMapper)
202 mapper = registry.queryUtility(IRoutesMapper)
202 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
203 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
203
204
204 def _extract_route_information(route):
205 def _extract_route_information(route):
205 """
206 """
206 Convert a route into tuple(name, path, args), eg:
207 Convert a route into tuple(name, path, args), eg:
207 ('show_user', '/profile/%(username)s', ['username'])
208 ('show_user', '/profile/%(username)s', ['username'])
208 """
209 """
209
210
210 routepath = route.pattern
211 routepath = route.pattern
211 pattern = route.pattern
212 pattern = route.pattern
212
213
213 def replace(matchobj):
214 def replace(matchobj):
214 if matchobj.group(1):
215 if matchobj.group(1):
215 return "%%(%s)s" % matchobj.group(1).split(':')[0]
216 return "%%(%s)s" % matchobj.group(1).split(':')[0]
216 else:
217 else:
217 return "%%(%s)s" % matchobj.group(2)
218 return "%%(%s)s" % matchobj.group(2)
218
219
219 routepath = _argument_prog.sub(replace, routepath)
220 routepath = _argument_prog.sub(replace, routepath)
220
221
221 if not routepath.startswith('/'):
222 if not routepath.startswith('/'):
222 routepath = '/'+routepath
223 routepath = '/'+routepath
223
224
224 return (
225 return (
225 route.name,
226 route.name,
226 routepath,
227 routepath,
227 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
228 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
228 for arg in _argument_prog.findall(pattern)]
229 for arg in _argument_prog.findall(pattern)]
229 )
230 )
230
231
231 def get_routes():
232 def get_routes():
232 # pyramid routes
233 # pyramid routes
233 for route in mapper.get_routes():
234 for route in mapper.get_routes():
234 if not route.name.startswith('__'):
235 if not route.name.startswith('__'):
235 yield _extract_route_information(route)
236 yield _extract_route_information(route)
236
237
237 if asbool(registry.settings.get('generate_js_files', 'false')):
238 if asbool(registry.settings.get('generate_js_files', 'false')):
238 static_path = AssetResolver().resolve('rhodecode:public').abspath()
239 static_path = AssetResolver().resolve('rhodecode:public').abspath()
239 jsroutes = get_routes()
240 jsroutes = get_routes()
240 jsroutes_file_content = generate_jsroutes_content(jsroutes)
241 jsroutes_file_content = generate_jsroutes_content(jsroutes)
241 jsroutes_file_path = os.path.join(
242 jsroutes_file_path = os.path.join(
242 static_path, 'js', 'rhodecode', 'routes.js')
243 static_path, 'js', 'rhodecode', 'routes.js')
243
244
244 try:
245 try:
245 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
246 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
246 f.write(jsroutes_file_content)
247 f.write(jsroutes_file_content)
247 except Exception:
248 except Exception:
248 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
249 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
249
250
250
251
251 class Subscriber(object):
252 class Subscriber(object):
252 """
253 """
253 Base class for subscribers to the pyramid event system.
254 Base class for subscribers to the pyramid event system.
254 """
255 """
255 def __call__(self, event):
256 def __call__(self, event):
256 self.run(event)
257 self.run(event)
257
258
258 def run(self, event):
259 def run(self, event):
259 raise NotImplementedError('Subclass has to implement this.')
260 raise NotImplementedError('Subclass has to implement this.')
260
261
261
262
262 class AsyncSubscriber(Subscriber):
263 class AsyncSubscriber(Subscriber):
263 """
264 """
264 Subscriber that handles the execution of events in a separate task to not
265 Subscriber that handles the execution of events in a separate task to not
265 block the execution of the code which triggers the event. It puts the
266 block the execution of the code which triggers the event. It puts the
266 received events into a queue from which the worker process takes them in
267 received events into a queue from which the worker process takes them in
267 order.
268 order.
268 """
269 """
269 def __init__(self):
270 def __init__(self):
270 self._stop = False
271 self._stop = False
271 self._eventq = Queue.Queue()
272 self._eventq = Queue.Queue()
272 self._worker = self.create_worker()
273 self._worker = self.create_worker()
273 self._worker.start()
274 self._worker.start()
274
275
275 def __call__(self, event):
276 def __call__(self, event):
276 self._eventq.put(event)
277 self._eventq.put(event)
277
278
278 def create_worker(self):
279 def create_worker(self):
279 worker = Thread(target=self.do_work)
280 worker = Thread(target=self.do_work)
280 worker.daemon = True
281 worker.daemon = True
281 return worker
282 return worker
282
283
283 def stop_worker(self):
284 def stop_worker(self):
284 self._stop = False
285 self._stop = False
285 self._eventq.put(None)
286 self._eventq.put(None)
286 self._worker.join()
287 self._worker.join()
287
288
288 def do_work(self):
289 def do_work(self):
289 while not self._stop:
290 while not self._stop:
290 event = self._eventq.get()
291 event = self._eventq.get()
291 if event is not None:
292 if event is not None:
292 self.run(event)
293 self.run(event)
293
294
294
295
295 class AsyncSubprocessSubscriber(AsyncSubscriber):
296 class AsyncSubprocessSubscriber(AsyncSubscriber):
296 """
297 """
297 Subscriber that uses the subprocess32 module to execute a command if an
298 Subscriber that uses the subprocess32 module to execute a command if an
298 event is received. Events are handled asynchronously.
299 event is received. Events are handled asynchronously.
299 """
300 """
300
301
301 def __init__(self, cmd, timeout=None):
302 def __init__(self, cmd, timeout=None):
302 super(AsyncSubprocessSubscriber, self).__init__()
303 super(AsyncSubprocessSubscriber, self).__init__()
303 self._cmd = cmd
304 self._cmd = cmd
304 self._timeout = timeout
305 self._timeout = timeout
305
306
306 def run(self, event):
307 def run(self, event):
307 cmd = self._cmd
308 cmd = self._cmd
308 timeout = self._timeout
309 timeout = self._timeout
309 log.debug('Executing command %s.', cmd)
310 log.debug('Executing command %s.', cmd)
310
311
311 try:
312 try:
312 output = subprocess32.check_output(
313 output = subprocess32.check_output(
313 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
314 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
314 log.debug('Command finished %s', cmd)
315 log.debug('Command finished %s', cmd)
315 if output:
316 if output:
316 log.debug('Command output: %s', output)
317 log.debug('Command output: %s', output)
317 except subprocess32.TimeoutExpired as e:
318 except subprocess32.TimeoutExpired as e:
318 log.exception('Timeout while executing command.')
319 log.exception('Timeout while executing command.')
319 if e.output:
320 if e.output:
320 log.error('Command output: %s', e.output)
321 log.error('Command output: %s', e.output)
321 except subprocess32.CalledProcessError as e:
322 except subprocess32.CalledProcessError as e:
322 log.exception('Error while executing command.')
323 log.exception('Error while executing command.')
323 if e.output:
324 if e.output:
324 log.error('Command output: %s', e.output)
325 log.error('Command output: %s', e.output)
325 except:
326 except:
326 log.exception(
327 log.exception(
327 'Exception while executing command %s.', cmd)
328 'Exception while executing command %s.', cmd)
General Comments 0
You need to be logged in to leave comments. Login now