##// END OF EJS Templates
settings: reduce number of settings fetch since it uses locking for cache invalidation and is generally slow....
marcink -
r3855:e1ec64bd default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,518 +1,519 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import re
21 import re
22 import logging
22 import logging
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25 import datetime
25 import datetime
26 from pyramid.interfaces import IRoutesMapper
26 from pyramid.interfaces import IRoutesMapper
27
27
28 from pyramid.view import view_config
28 from pyramid.view import view_config
29 from pyramid.httpexceptions import HTTPFound
29 from pyramid.httpexceptions import HTTPFound
30 from pyramid.renderers import render
30 from pyramid.renderers import render
31 from pyramid.response import Response
31 from pyramid.response import Response
32
32
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
34 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
34 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
35 from rhodecode import events
35 from rhodecode import events
36
36
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
39 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
40 from rhodecode.lib.utils2 import aslist, safe_unicode
40 from rhodecode.lib.utils2 import aslist, safe_unicode
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 or_, coalesce, User, UserIpMap, UserSshKeys)
42 or_, coalesce, User, UserIpMap, UserSshKeys)
43 from rhodecode.model.forms import (
43 from rhodecode.model.forms import (
44 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
44 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.permission import PermissionModel
46 from rhodecode.model.permission import PermissionModel
47 from rhodecode.model.settings import SettingsModel
47 from rhodecode.model.settings import SettingsModel
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
54 def load_default_context(self):
54 def load_default_context(self):
55 c = self._get_local_tmpl_context()
55 c = self._get_local_tmpl_context()
56 PermissionModel().set_global_permission_choices(
56 PermissionModel().set_global_permission_choices(
57 c, gettext_translator=self.request.translate)
57 c, gettext_translator=self.request.translate)
58 return c
58 return c
59
59
60 @LoginRequired()
60 @LoginRequired()
61 @HasPermissionAllDecorator('hg.admin')
61 @HasPermissionAllDecorator('hg.admin')
62 @view_config(
62 @view_config(
63 route_name='admin_permissions_application', request_method='GET',
63 route_name='admin_permissions_application', request_method='GET',
64 renderer='rhodecode:templates/admin/permissions/permissions.mako')
64 renderer='rhodecode:templates/admin/permissions/permissions.mako')
65 def permissions_application(self):
65 def permissions_application(self):
66 c = self.load_default_context()
66 c = self.load_default_context()
67 c.active = 'application'
67 c.active = 'application'
68
68
69 c.user = User.get_default_user(refresh=True)
69 c.user = User.get_default_user(refresh=True)
70
70
71 app_settings = SettingsModel().get_all_settings()
71 app_settings = c.rc_config
72
72 defaults = {
73 defaults = {
73 'anonymous': c.user.active,
74 'anonymous': c.user.active,
74 'default_register_message': app_settings.get(
75 'default_register_message': app_settings.get(
75 'rhodecode_register_message')
76 'rhodecode_register_message')
76 }
77 }
77 defaults.update(c.user.get_default_perms())
78 defaults.update(c.user.get_default_perms())
78
79
79 data = render('rhodecode:templates/admin/permissions/permissions.mako',
80 data = render('rhodecode:templates/admin/permissions/permissions.mako',
80 self._get_template_context(c), self.request)
81 self._get_template_context(c), self.request)
81 html = formencode.htmlfill.render(
82 html = formencode.htmlfill.render(
82 data,
83 data,
83 defaults=defaults,
84 defaults=defaults,
84 encoding="UTF-8",
85 encoding="UTF-8",
85 force_defaults=False
86 force_defaults=False
86 )
87 )
87 return Response(html)
88 return Response(html)
88
89
89 @LoginRequired()
90 @LoginRequired()
90 @HasPermissionAllDecorator('hg.admin')
91 @HasPermissionAllDecorator('hg.admin')
91 @CSRFRequired()
92 @CSRFRequired()
92 @view_config(
93 @view_config(
93 route_name='admin_permissions_application_update', request_method='POST',
94 route_name='admin_permissions_application_update', request_method='POST',
94 renderer='rhodecode:templates/admin/permissions/permissions.mako')
95 renderer='rhodecode:templates/admin/permissions/permissions.mako')
95 def permissions_application_update(self):
96 def permissions_application_update(self):
96 _ = self.request.translate
97 _ = self.request.translate
97 c = self.load_default_context()
98 c = self.load_default_context()
98 c.active = 'application'
99 c.active = 'application'
99
100
100 _form = ApplicationPermissionsForm(
101 _form = ApplicationPermissionsForm(
101 self.request.translate,
102 self.request.translate,
102 [x[0] for x in c.register_choices],
103 [x[0] for x in c.register_choices],
103 [x[0] for x in c.password_reset_choices],
104 [x[0] for x in c.password_reset_choices],
104 [x[0] for x in c.extern_activate_choices])()
105 [x[0] for x in c.extern_activate_choices])()
105
106
106 try:
107 try:
107 form_result = _form.to_python(dict(self.request.POST))
108 form_result = _form.to_python(dict(self.request.POST))
108 form_result.update({'perm_user_name': User.DEFAULT_USER})
109 form_result.update({'perm_user_name': User.DEFAULT_USER})
109 PermissionModel().update_application_permissions(form_result)
110 PermissionModel().update_application_permissions(form_result)
110
111
111 settings = [
112 settings = [
112 ('register_message', 'default_register_message'),
113 ('register_message', 'default_register_message'),
113 ]
114 ]
114 for setting, form_key in settings:
115 for setting, form_key in settings:
115 sett = SettingsModel().create_or_update_setting(
116 sett = SettingsModel().create_or_update_setting(
116 setting, form_result[form_key])
117 setting, form_result[form_key])
117 Session().add(sett)
118 Session().add(sett)
118
119
119 Session().commit()
120 Session().commit()
120 h.flash(_('Application permissions updated successfully'),
121 h.flash(_('Application permissions updated successfully'),
121 category='success')
122 category='success')
122
123
123 except formencode.Invalid as errors:
124 except formencode.Invalid as errors:
124 defaults = errors.value
125 defaults = errors.value
125
126
126 data = render(
127 data = render(
127 'rhodecode:templates/admin/permissions/permissions.mako',
128 'rhodecode:templates/admin/permissions/permissions.mako',
128 self._get_template_context(c), self.request)
129 self._get_template_context(c), self.request)
129 html = formencode.htmlfill.render(
130 html = formencode.htmlfill.render(
130 data,
131 data,
131 defaults=defaults,
132 defaults=defaults,
132 errors=errors.error_dict or {},
133 errors=errors.error_dict or {},
133 prefix_error=False,
134 prefix_error=False,
134 encoding="UTF-8",
135 encoding="UTF-8",
135 force_defaults=False
136 force_defaults=False
136 )
137 )
137 return Response(html)
138 return Response(html)
138
139
139 except Exception:
140 except Exception:
140 log.exception("Exception during update of permissions")
141 log.exception("Exception during update of permissions")
141 h.flash(_('Error occurred during update of permissions'),
142 h.flash(_('Error occurred during update of permissions'),
142 category='error')
143 category='error')
143
144
144 affected_user_ids = [User.get_default_user().user_id]
145 affected_user_ids = [User.get_default_user().user_id]
145 events.trigger(events.UserPermissionsChange(affected_user_ids))
146 events.trigger(events.UserPermissionsChange(affected_user_ids))
146
147
147 raise HTTPFound(h.route_path('admin_permissions_application'))
148 raise HTTPFound(h.route_path('admin_permissions_application'))
148
149
149 @LoginRequired()
150 @LoginRequired()
150 @HasPermissionAllDecorator('hg.admin')
151 @HasPermissionAllDecorator('hg.admin')
151 @view_config(
152 @view_config(
152 route_name='admin_permissions_object', request_method='GET',
153 route_name='admin_permissions_object', request_method='GET',
153 renderer='rhodecode:templates/admin/permissions/permissions.mako')
154 renderer='rhodecode:templates/admin/permissions/permissions.mako')
154 def permissions_objects(self):
155 def permissions_objects(self):
155 c = self.load_default_context()
156 c = self.load_default_context()
156 c.active = 'objects'
157 c.active = 'objects'
157
158
158 c.user = User.get_default_user(refresh=True)
159 c.user = User.get_default_user(refresh=True)
159 defaults = {}
160 defaults = {}
160 defaults.update(c.user.get_default_perms())
161 defaults.update(c.user.get_default_perms())
161
162
162 data = render(
163 data = render(
163 'rhodecode:templates/admin/permissions/permissions.mako',
164 'rhodecode:templates/admin/permissions/permissions.mako',
164 self._get_template_context(c), self.request)
165 self._get_template_context(c), self.request)
165 html = formencode.htmlfill.render(
166 html = formencode.htmlfill.render(
166 data,
167 data,
167 defaults=defaults,
168 defaults=defaults,
168 encoding="UTF-8",
169 encoding="UTF-8",
169 force_defaults=False
170 force_defaults=False
170 )
171 )
171 return Response(html)
172 return Response(html)
172
173
173 @LoginRequired()
174 @LoginRequired()
174 @HasPermissionAllDecorator('hg.admin')
175 @HasPermissionAllDecorator('hg.admin')
175 @CSRFRequired()
176 @CSRFRequired()
176 @view_config(
177 @view_config(
177 route_name='admin_permissions_object_update', request_method='POST',
178 route_name='admin_permissions_object_update', request_method='POST',
178 renderer='rhodecode:templates/admin/permissions/permissions.mako')
179 renderer='rhodecode:templates/admin/permissions/permissions.mako')
179 def permissions_objects_update(self):
180 def permissions_objects_update(self):
180 _ = self.request.translate
181 _ = self.request.translate
181 c = self.load_default_context()
182 c = self.load_default_context()
182 c.active = 'objects'
183 c.active = 'objects'
183
184
184 _form = ObjectPermissionsForm(
185 _form = ObjectPermissionsForm(
185 self.request.translate,
186 self.request.translate,
186 [x[0] for x in c.repo_perms_choices],
187 [x[0] for x in c.repo_perms_choices],
187 [x[0] for x in c.group_perms_choices],
188 [x[0] for x in c.group_perms_choices],
188 [x[0] for x in c.user_group_perms_choices],
189 [x[0] for x in c.user_group_perms_choices],
189 )()
190 )()
190
191
191 try:
192 try:
192 form_result = _form.to_python(dict(self.request.POST))
193 form_result = _form.to_python(dict(self.request.POST))
193 form_result.update({'perm_user_name': User.DEFAULT_USER})
194 form_result.update({'perm_user_name': User.DEFAULT_USER})
194 PermissionModel().update_object_permissions(form_result)
195 PermissionModel().update_object_permissions(form_result)
195
196
196 Session().commit()
197 Session().commit()
197 h.flash(_('Object permissions updated successfully'),
198 h.flash(_('Object permissions updated successfully'),
198 category='success')
199 category='success')
199
200
200 except formencode.Invalid as errors:
201 except formencode.Invalid as errors:
201 defaults = errors.value
202 defaults = errors.value
202
203
203 data = render(
204 data = render(
204 'rhodecode:templates/admin/permissions/permissions.mako',
205 'rhodecode:templates/admin/permissions/permissions.mako',
205 self._get_template_context(c), self.request)
206 self._get_template_context(c), self.request)
206 html = formencode.htmlfill.render(
207 html = formencode.htmlfill.render(
207 data,
208 data,
208 defaults=defaults,
209 defaults=defaults,
209 errors=errors.error_dict or {},
210 errors=errors.error_dict or {},
210 prefix_error=False,
211 prefix_error=False,
211 encoding="UTF-8",
212 encoding="UTF-8",
212 force_defaults=False
213 force_defaults=False
213 )
214 )
214 return Response(html)
215 return Response(html)
215 except Exception:
216 except Exception:
216 log.exception("Exception during update of permissions")
217 log.exception("Exception during update of permissions")
217 h.flash(_('Error occurred during update of permissions'),
218 h.flash(_('Error occurred during update of permissions'),
218 category='error')
219 category='error')
219
220
220 affected_user_ids = [User.get_default_user().user_id]
221 affected_user_ids = [User.get_default_user().user_id]
221 events.trigger(events.UserPermissionsChange(affected_user_ids))
222 events.trigger(events.UserPermissionsChange(affected_user_ids))
222
223
223 raise HTTPFound(h.route_path('admin_permissions_object'))
224 raise HTTPFound(h.route_path('admin_permissions_object'))
224
225
225 @LoginRequired()
226 @LoginRequired()
226 @HasPermissionAllDecorator('hg.admin')
227 @HasPermissionAllDecorator('hg.admin')
227 @view_config(
228 @view_config(
228 route_name='admin_permissions_branch', request_method='GET',
229 route_name='admin_permissions_branch', request_method='GET',
229 renderer='rhodecode:templates/admin/permissions/permissions.mako')
230 renderer='rhodecode:templates/admin/permissions/permissions.mako')
230 def permissions_branch(self):
231 def permissions_branch(self):
231 c = self.load_default_context()
232 c = self.load_default_context()
232 c.active = 'branch'
233 c.active = 'branch'
233
234
234 c.user = User.get_default_user(refresh=True)
235 c.user = User.get_default_user(refresh=True)
235 defaults = {}
236 defaults = {}
236 defaults.update(c.user.get_default_perms())
237 defaults.update(c.user.get_default_perms())
237
238
238 data = render(
239 data = render(
239 'rhodecode:templates/admin/permissions/permissions.mako',
240 'rhodecode:templates/admin/permissions/permissions.mako',
240 self._get_template_context(c), self.request)
241 self._get_template_context(c), self.request)
241 html = formencode.htmlfill.render(
242 html = formencode.htmlfill.render(
242 data,
243 data,
243 defaults=defaults,
244 defaults=defaults,
244 encoding="UTF-8",
245 encoding="UTF-8",
245 force_defaults=False
246 force_defaults=False
246 )
247 )
247 return Response(html)
248 return Response(html)
248
249
249 @LoginRequired()
250 @LoginRequired()
250 @HasPermissionAllDecorator('hg.admin')
251 @HasPermissionAllDecorator('hg.admin')
251 @view_config(
252 @view_config(
252 route_name='admin_permissions_global', request_method='GET',
253 route_name='admin_permissions_global', request_method='GET',
253 renderer='rhodecode:templates/admin/permissions/permissions.mako')
254 renderer='rhodecode:templates/admin/permissions/permissions.mako')
254 def permissions_global(self):
255 def permissions_global(self):
255 c = self.load_default_context()
256 c = self.load_default_context()
256 c.active = 'global'
257 c.active = 'global'
257
258
258 c.user = User.get_default_user(refresh=True)
259 c.user = User.get_default_user(refresh=True)
259 defaults = {}
260 defaults = {}
260 defaults.update(c.user.get_default_perms())
261 defaults.update(c.user.get_default_perms())
261
262
262 data = render(
263 data = render(
263 'rhodecode:templates/admin/permissions/permissions.mako',
264 'rhodecode:templates/admin/permissions/permissions.mako',
264 self._get_template_context(c), self.request)
265 self._get_template_context(c), self.request)
265 html = formencode.htmlfill.render(
266 html = formencode.htmlfill.render(
266 data,
267 data,
267 defaults=defaults,
268 defaults=defaults,
268 encoding="UTF-8",
269 encoding="UTF-8",
269 force_defaults=False
270 force_defaults=False
270 )
271 )
271 return Response(html)
272 return Response(html)
272
273
273 @LoginRequired()
274 @LoginRequired()
274 @HasPermissionAllDecorator('hg.admin')
275 @HasPermissionAllDecorator('hg.admin')
275 @CSRFRequired()
276 @CSRFRequired()
276 @view_config(
277 @view_config(
277 route_name='admin_permissions_global_update', request_method='POST',
278 route_name='admin_permissions_global_update', request_method='POST',
278 renderer='rhodecode:templates/admin/permissions/permissions.mako')
279 renderer='rhodecode:templates/admin/permissions/permissions.mako')
279 def permissions_global_update(self):
280 def permissions_global_update(self):
280 _ = self.request.translate
281 _ = self.request.translate
281 c = self.load_default_context()
282 c = self.load_default_context()
282 c.active = 'global'
283 c.active = 'global'
283
284
284 _form = UserPermissionsForm(
285 _form = UserPermissionsForm(
285 self.request.translate,
286 self.request.translate,
286 [x[0] for x in c.repo_create_choices],
287 [x[0] for x in c.repo_create_choices],
287 [x[0] for x in c.repo_create_on_write_choices],
288 [x[0] for x in c.repo_create_on_write_choices],
288 [x[0] for x in c.repo_group_create_choices],
289 [x[0] for x in c.repo_group_create_choices],
289 [x[0] for x in c.user_group_create_choices],
290 [x[0] for x in c.user_group_create_choices],
290 [x[0] for x in c.fork_choices],
291 [x[0] for x in c.fork_choices],
291 [x[0] for x in c.inherit_default_permission_choices])()
292 [x[0] for x in c.inherit_default_permission_choices])()
292
293
293 try:
294 try:
294 form_result = _form.to_python(dict(self.request.POST))
295 form_result = _form.to_python(dict(self.request.POST))
295 form_result.update({'perm_user_name': User.DEFAULT_USER})
296 form_result.update({'perm_user_name': User.DEFAULT_USER})
296 PermissionModel().update_user_permissions(form_result)
297 PermissionModel().update_user_permissions(form_result)
297
298
298 Session().commit()
299 Session().commit()
299 h.flash(_('Global permissions updated successfully'),
300 h.flash(_('Global permissions updated successfully'),
300 category='success')
301 category='success')
301
302
302 except formencode.Invalid as errors:
303 except formencode.Invalid as errors:
303 defaults = errors.value
304 defaults = errors.value
304
305
305 data = render(
306 data = render(
306 'rhodecode:templates/admin/permissions/permissions.mako',
307 'rhodecode:templates/admin/permissions/permissions.mako',
307 self._get_template_context(c), self.request)
308 self._get_template_context(c), self.request)
308 html = formencode.htmlfill.render(
309 html = formencode.htmlfill.render(
309 data,
310 data,
310 defaults=defaults,
311 defaults=defaults,
311 errors=errors.error_dict or {},
312 errors=errors.error_dict or {},
312 prefix_error=False,
313 prefix_error=False,
313 encoding="UTF-8",
314 encoding="UTF-8",
314 force_defaults=False
315 force_defaults=False
315 )
316 )
316 return Response(html)
317 return Response(html)
317 except Exception:
318 except Exception:
318 log.exception("Exception during update of permissions")
319 log.exception("Exception during update of permissions")
319 h.flash(_('Error occurred during update of permissions'),
320 h.flash(_('Error occurred during update of permissions'),
320 category='error')
321 category='error')
321
322
322 affected_user_ids = [User.get_default_user().user_id]
323 affected_user_ids = [User.get_default_user().user_id]
323 events.trigger(events.UserPermissionsChange(affected_user_ids))
324 events.trigger(events.UserPermissionsChange(affected_user_ids))
324
325
325 raise HTTPFound(h.route_path('admin_permissions_global'))
326 raise HTTPFound(h.route_path('admin_permissions_global'))
326
327
327 @LoginRequired()
328 @LoginRequired()
328 @HasPermissionAllDecorator('hg.admin')
329 @HasPermissionAllDecorator('hg.admin')
329 @view_config(
330 @view_config(
330 route_name='admin_permissions_ips', request_method='GET',
331 route_name='admin_permissions_ips', request_method='GET',
331 renderer='rhodecode:templates/admin/permissions/permissions.mako')
332 renderer='rhodecode:templates/admin/permissions/permissions.mako')
332 def permissions_ips(self):
333 def permissions_ips(self):
333 c = self.load_default_context()
334 c = self.load_default_context()
334 c.active = 'ips'
335 c.active = 'ips'
335
336
336 c.user = User.get_default_user(refresh=True)
337 c.user = User.get_default_user(refresh=True)
337 c.user_ip_map = (
338 c.user_ip_map = (
338 UserIpMap.query().filter(UserIpMap.user == c.user).all())
339 UserIpMap.query().filter(UserIpMap.user == c.user).all())
339
340
340 return self._get_template_context(c)
341 return self._get_template_context(c)
341
342
342 @LoginRequired()
343 @LoginRequired()
343 @HasPermissionAllDecorator('hg.admin')
344 @HasPermissionAllDecorator('hg.admin')
344 @view_config(
345 @view_config(
345 route_name='admin_permissions_overview', request_method='GET',
346 route_name='admin_permissions_overview', request_method='GET',
346 renderer='rhodecode:templates/admin/permissions/permissions.mako')
347 renderer='rhodecode:templates/admin/permissions/permissions.mako')
347 def permissions_overview(self):
348 def permissions_overview(self):
348 c = self.load_default_context()
349 c = self.load_default_context()
349 c.active = 'perms'
350 c.active = 'perms'
350
351
351 c.user = User.get_default_user(refresh=True)
352 c.user = User.get_default_user(refresh=True)
352 c.perm_user = c.user.AuthUser()
353 c.perm_user = c.user.AuthUser()
353 return self._get_template_context(c)
354 return self._get_template_context(c)
354
355
355 @LoginRequired()
356 @LoginRequired()
356 @HasPermissionAllDecorator('hg.admin')
357 @HasPermissionAllDecorator('hg.admin')
357 @view_config(
358 @view_config(
358 route_name='admin_permissions_auth_token_access', request_method='GET',
359 route_name='admin_permissions_auth_token_access', request_method='GET',
359 renderer='rhodecode:templates/admin/permissions/permissions.mako')
360 renderer='rhodecode:templates/admin/permissions/permissions.mako')
360 def auth_token_access(self):
361 def auth_token_access(self):
361 from rhodecode import CONFIG
362 from rhodecode import CONFIG
362
363
363 c = self.load_default_context()
364 c = self.load_default_context()
364 c.active = 'auth_token_access'
365 c.active = 'auth_token_access'
365
366
366 c.user = User.get_default_user(refresh=True)
367 c.user = User.get_default_user(refresh=True)
367 c.perm_user = c.user.AuthUser()
368 c.perm_user = c.user.AuthUser()
368
369
369 mapper = self.request.registry.queryUtility(IRoutesMapper)
370 mapper = self.request.registry.queryUtility(IRoutesMapper)
370 c.view_data = []
371 c.view_data = []
371
372
372 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
373 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
373 introspector = self.request.registry.introspector
374 introspector = self.request.registry.introspector
374
375
375 view_intr = {}
376 view_intr = {}
376 for view_data in introspector.get_category('views'):
377 for view_data in introspector.get_category('views'):
377 intr = view_data['introspectable']
378 intr = view_data['introspectable']
378
379
379 if 'route_name' in intr and intr['attr']:
380 if 'route_name' in intr and intr['attr']:
380 view_intr[intr['route_name']] = '{}:{}'.format(
381 view_intr[intr['route_name']] = '{}:{}'.format(
381 str(intr['derived_callable'].func_name), intr['attr']
382 str(intr['derived_callable'].func_name), intr['attr']
382 )
383 )
383
384
384 c.whitelist_key = 'api_access_controllers_whitelist'
385 c.whitelist_key = 'api_access_controllers_whitelist'
385 c.whitelist_file = CONFIG.get('__file__')
386 c.whitelist_file = CONFIG.get('__file__')
386 whitelist_views = aslist(
387 whitelist_views = aslist(
387 CONFIG.get(c.whitelist_key), sep=',')
388 CONFIG.get(c.whitelist_key), sep=',')
388
389
389 for route_info in mapper.get_routes():
390 for route_info in mapper.get_routes():
390 if not route_info.name.startswith('__'):
391 if not route_info.name.startswith('__'):
391 routepath = route_info.pattern
392 routepath = route_info.pattern
392
393
393 def replace(matchobj):
394 def replace(matchobj):
394 if matchobj.group(1):
395 if matchobj.group(1):
395 return "{%s}" % matchobj.group(1).split(':')[0]
396 return "{%s}" % matchobj.group(1).split(':')[0]
396 else:
397 else:
397 return "{%s}" % matchobj.group(2)
398 return "{%s}" % matchobj.group(2)
398
399
399 routepath = _argument_prog.sub(replace, routepath)
400 routepath = _argument_prog.sub(replace, routepath)
400
401
401 if not routepath.startswith('/'):
402 if not routepath.startswith('/'):
402 routepath = '/' + routepath
403 routepath = '/' + routepath
403
404
404 view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE')
405 view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE')
405 active = view_fqn in whitelist_views
406 active = view_fqn in whitelist_views
406 c.view_data.append((route_info.name, view_fqn, routepath, active))
407 c.view_data.append((route_info.name, view_fqn, routepath, active))
407
408
408 c.whitelist_views = whitelist_views
409 c.whitelist_views = whitelist_views
409 return self._get_template_context(c)
410 return self._get_template_context(c)
410
411
411 def ssh_enabled(self):
412 def ssh_enabled(self):
412 return self.request.registry.settings.get(
413 return self.request.registry.settings.get(
413 'ssh.generate_authorized_keyfile')
414 'ssh.generate_authorized_keyfile')
414
415
415 @LoginRequired()
416 @LoginRequired()
416 @HasPermissionAllDecorator('hg.admin')
417 @HasPermissionAllDecorator('hg.admin')
417 @view_config(
418 @view_config(
418 route_name='admin_permissions_ssh_keys', request_method='GET',
419 route_name='admin_permissions_ssh_keys', request_method='GET',
419 renderer='rhodecode:templates/admin/permissions/permissions.mako')
420 renderer='rhodecode:templates/admin/permissions/permissions.mako')
420 def ssh_keys(self):
421 def ssh_keys(self):
421 c = self.load_default_context()
422 c = self.load_default_context()
422 c.active = 'ssh_keys'
423 c.active = 'ssh_keys'
423 c.ssh_enabled = self.ssh_enabled()
424 c.ssh_enabled = self.ssh_enabled()
424 return self._get_template_context(c)
425 return self._get_template_context(c)
425
426
426 @LoginRequired()
427 @LoginRequired()
427 @HasPermissionAllDecorator('hg.admin')
428 @HasPermissionAllDecorator('hg.admin')
428 @view_config(
429 @view_config(
429 route_name='admin_permissions_ssh_keys_data', request_method='GET',
430 route_name='admin_permissions_ssh_keys_data', request_method='GET',
430 renderer='json_ext', xhr=True)
431 renderer='json_ext', xhr=True)
431 def ssh_keys_data(self):
432 def ssh_keys_data(self):
432 _ = self.request.translate
433 _ = self.request.translate
433 self.load_default_context()
434 self.load_default_context()
434 column_map = {
435 column_map = {
435 'fingerprint': 'ssh_key_fingerprint',
436 'fingerprint': 'ssh_key_fingerprint',
436 'username': User.username
437 'username': User.username
437 }
438 }
438 draw, start, limit = self._extract_chunk(self.request)
439 draw, start, limit = self._extract_chunk(self.request)
439 search_q, order_by, order_dir = self._extract_ordering(
440 search_q, order_by, order_dir = self._extract_ordering(
440 self.request, column_map=column_map)
441 self.request, column_map=column_map)
441
442
442 ssh_keys_data_total_count = UserSshKeys.query()\
443 ssh_keys_data_total_count = UserSshKeys.query()\
443 .count()
444 .count()
444
445
445 # json generate
446 # json generate
446 base_q = UserSshKeys.query().join(UserSshKeys.user)
447 base_q = UserSshKeys.query().join(UserSshKeys.user)
447
448
448 if search_q:
449 if search_q:
449 like_expression = u'%{}%'.format(safe_unicode(search_q))
450 like_expression = u'%{}%'.format(safe_unicode(search_q))
450 base_q = base_q.filter(or_(
451 base_q = base_q.filter(or_(
451 User.username.ilike(like_expression),
452 User.username.ilike(like_expression),
452 UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
453 UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
453 ))
454 ))
454
455
455 users_data_total_filtered_count = base_q.count()
456 users_data_total_filtered_count = base_q.count()
456
457
457 sort_col = self._get_order_col(order_by, UserSshKeys)
458 sort_col = self._get_order_col(order_by, UserSshKeys)
458 if sort_col:
459 if sort_col:
459 if order_dir == 'asc':
460 if order_dir == 'asc':
460 # handle null values properly to order by NULL last
461 # handle null values properly to order by NULL last
461 if order_by in ['created_on']:
462 if order_by in ['created_on']:
462 sort_col = coalesce(sort_col, datetime.date.max)
463 sort_col = coalesce(sort_col, datetime.date.max)
463 sort_col = sort_col.asc()
464 sort_col = sort_col.asc()
464 else:
465 else:
465 # handle null values properly to order by NULL last
466 # handle null values properly to order by NULL last
466 if order_by in ['created_on']:
467 if order_by in ['created_on']:
467 sort_col = coalesce(sort_col, datetime.date.min)
468 sort_col = coalesce(sort_col, datetime.date.min)
468 sort_col = sort_col.desc()
469 sort_col = sort_col.desc()
469
470
470 base_q = base_q.order_by(sort_col)
471 base_q = base_q.order_by(sort_col)
471 base_q = base_q.offset(start).limit(limit)
472 base_q = base_q.offset(start).limit(limit)
472
473
473 ssh_keys = base_q.all()
474 ssh_keys = base_q.all()
474
475
475 ssh_keys_data = []
476 ssh_keys_data = []
476 for ssh_key in ssh_keys:
477 for ssh_key in ssh_keys:
477 ssh_keys_data.append({
478 ssh_keys_data.append({
478 "username": h.gravatar_with_user(self.request, ssh_key.user.username),
479 "username": h.gravatar_with_user(self.request, ssh_key.user.username),
479 "fingerprint": ssh_key.ssh_key_fingerprint,
480 "fingerprint": ssh_key.ssh_key_fingerprint,
480 "description": ssh_key.description,
481 "description": ssh_key.description,
481 "created_on": h.format_date(ssh_key.created_on),
482 "created_on": h.format_date(ssh_key.created_on),
482 "accessed_on": h.format_date(ssh_key.accessed_on),
483 "accessed_on": h.format_date(ssh_key.accessed_on),
483 "action": h.link_to(
484 "action": h.link_to(
484 _('Edit'), h.route_path('edit_user_ssh_keys',
485 _('Edit'), h.route_path('edit_user_ssh_keys',
485 user_id=ssh_key.user.user_id))
486 user_id=ssh_key.user.user_id))
486 })
487 })
487
488
488 data = ({
489 data = ({
489 'draw': draw,
490 'draw': draw,
490 'data': ssh_keys_data,
491 'data': ssh_keys_data,
491 'recordsTotal': ssh_keys_data_total_count,
492 'recordsTotal': ssh_keys_data_total_count,
492 'recordsFiltered': users_data_total_filtered_count,
493 'recordsFiltered': users_data_total_filtered_count,
493 })
494 })
494
495
495 return data
496 return data
496
497
497 @LoginRequired()
498 @LoginRequired()
498 @HasPermissionAllDecorator('hg.admin')
499 @HasPermissionAllDecorator('hg.admin')
499 @CSRFRequired()
500 @CSRFRequired()
500 @view_config(
501 @view_config(
501 route_name='admin_permissions_ssh_keys_update', request_method='POST',
502 route_name='admin_permissions_ssh_keys_update', request_method='POST',
502 renderer='rhodecode:templates/admin/permissions/permissions.mako')
503 renderer='rhodecode:templates/admin/permissions/permissions.mako')
503 def ssh_keys_update(self):
504 def ssh_keys_update(self):
504 _ = self.request.translate
505 _ = self.request.translate
505 self.load_default_context()
506 self.load_default_context()
506
507
507 ssh_enabled = self.ssh_enabled()
508 ssh_enabled = self.ssh_enabled()
508 key_file = self.request.registry.settings.get(
509 key_file = self.request.registry.settings.get(
509 'ssh.authorized_keys_file_path')
510 'ssh.authorized_keys_file_path')
510 if ssh_enabled:
511 if ssh_enabled:
511 events.trigger(SshKeyFileChangeEvent(), self.request.registry)
512 events.trigger(SshKeyFileChangeEvent(), self.request.registry)
512 h.flash(_('Updated SSH keys file: {}').format(key_file),
513 h.flash(_('Updated SSH keys file: {}').format(key_file),
513 category='success')
514 category='success')
514 else:
515 else:
515 h.flash(_('SSH key support is disabled in .ini file'),
516 h.flash(_('SSH key support is disabled in .ini file'),
516 category='warning')
517 category='warning')
517
518
518 raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
519 raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
@@ -1,780 +1,780 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import collections
23 import collections
24
24
25 import datetime
25 import datetime
26 import formencode
26 import formencode
27 import formencode.htmlfill
27 import formencode.htmlfill
28
28
29 import rhodecode
29 import rhodecode
30 from pyramid.view import view_config
30 from pyramid.view import view_config
31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
31 from pyramid.httpexceptions import HTTPFound, HTTPNotFound
32 from pyramid.renderers import render
32 from pyramid.renderers import render
33 from pyramid.response import Response
33 from pyramid.response import Response
34
34
35 from rhodecode.apps._base import BaseAppView
35 from rhodecode.apps._base import BaseAppView
36 from rhodecode.apps._base.navigation import navigation_list
36 from rhodecode.apps._base.navigation import navigation_list
37 from rhodecode.apps.svn_support.config_keys import generate_config
37 from rhodecode.apps.svn_support.config_keys import generate_config
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
40 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
41 from rhodecode.lib.celerylib import tasks, run_task
41 from rhodecode.lib.celerylib import tasks, run_task
42 from rhodecode.lib.utils import repo2db_mapper
42 from rhodecode.lib.utils import repo2db_mapper
43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
43 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict
44 from rhodecode.lib.index import searcher_from_config
44 from rhodecode.lib.index import searcher_from_config
45
45
46 from rhodecode.model.db import RhodeCodeUi, Repository
46 from rhodecode.model.db import RhodeCodeUi, Repository
47 from rhodecode.model.forms import (ApplicationSettingsForm,
47 from rhodecode.model.forms import (ApplicationSettingsForm,
48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
48 ApplicationUiSettingsForm, ApplicationVisualisationForm,
49 LabsSettingsForm, IssueTrackerPatternsForm)
49 LabsSettingsForm, IssueTrackerPatternsForm)
50 from rhodecode.model.repo_group import RepoGroupModel
50 from rhodecode.model.repo_group import RepoGroupModel
51
51
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.notification import EmailNotificationModel
53 from rhodecode.model.notification import EmailNotificationModel
54 from rhodecode.model.meta import Session
54 from rhodecode.model.meta import Session
55 from rhodecode.model.settings import (
55 from rhodecode.model.settings import (
56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
56 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
57 SettingsModel)
57 SettingsModel)
58
58
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62
62
63 class AdminSettingsView(BaseAppView):
63 class AdminSettingsView(BaseAppView):
64
64
65 def load_default_context(self):
65 def load_default_context(self):
66 c = self._get_local_tmpl_context()
66 c = self._get_local_tmpl_context()
67 c.labs_active = str2bool(
67 c.labs_active = str2bool(
68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
69 c.navlist = navigation_list(self.request)
69 c.navlist = navigation_list(self.request)
70
70
71 return c
71 return c
72
72
73 @classmethod
73 @classmethod
74 def _get_ui_settings(cls):
74 def _get_ui_settings(cls):
75 ret = RhodeCodeUi.query().all()
75 ret = RhodeCodeUi.query().all()
76
76
77 if not ret:
77 if not ret:
78 raise Exception('Could not get application ui settings !')
78 raise Exception('Could not get application ui settings !')
79 settings = {}
79 settings = {}
80 for each in ret:
80 for each in ret:
81 k = each.ui_key
81 k = each.ui_key
82 v = each.ui_value
82 v = each.ui_value
83 if k == '/':
83 if k == '/':
84 k = 'root_path'
84 k = 'root_path'
85
85
86 if k in ['push_ssl', 'publish', 'enabled']:
86 if k in ['push_ssl', 'publish', 'enabled']:
87 v = str2bool(v)
87 v = str2bool(v)
88
88
89 if k.find('.') != -1:
89 if k.find('.') != -1:
90 k = k.replace('.', '_')
90 k = k.replace('.', '_')
91
91
92 if each.ui_section in ['hooks', 'extensions']:
92 if each.ui_section in ['hooks', 'extensions']:
93 v = each.ui_active
93 v = each.ui_active
94
94
95 settings[each.ui_section + '_' + k] = v
95 settings[each.ui_section + '_' + k] = v
96 return settings
96 return settings
97
97
98 @classmethod
98 @classmethod
99 def _form_defaults(cls):
99 def _form_defaults(cls):
100 defaults = SettingsModel().get_all_settings()
100 defaults = SettingsModel().get_all_settings()
101 defaults.update(cls._get_ui_settings())
101 defaults.update(cls._get_ui_settings())
102
102
103 defaults.update({
103 defaults.update({
104 'new_svn_branch': '',
104 'new_svn_branch': '',
105 'new_svn_tag': '',
105 'new_svn_tag': '',
106 })
106 })
107 return defaults
107 return defaults
108
108
109 @LoginRequired()
109 @LoginRequired()
110 @HasPermissionAllDecorator('hg.admin')
110 @HasPermissionAllDecorator('hg.admin')
111 @view_config(
111 @view_config(
112 route_name='admin_settings_vcs', request_method='GET',
112 route_name='admin_settings_vcs', request_method='GET',
113 renderer='rhodecode:templates/admin/settings/settings.mako')
113 renderer='rhodecode:templates/admin/settings/settings.mako')
114 def settings_vcs(self):
114 def settings_vcs(self):
115 c = self.load_default_context()
115 c = self.load_default_context()
116 c.active = 'vcs'
116 c.active = 'vcs'
117 model = VcsSettingsModel()
117 model = VcsSettingsModel()
118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
118 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
119 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
120
120
121 settings = self.request.registry.settings
121 settings = self.request.registry.settings
122 c.svn_proxy_generate_config = settings[generate_config]
122 c.svn_proxy_generate_config = settings[generate_config]
123
123
124 defaults = self._form_defaults()
124 defaults = self._form_defaults()
125
125
126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
126 model.create_largeobjects_dirs_if_needed(defaults['paths_root_path'])
127
127
128 data = render('rhodecode:templates/admin/settings/settings.mako',
128 data = render('rhodecode:templates/admin/settings/settings.mako',
129 self._get_template_context(c), self.request)
129 self._get_template_context(c), self.request)
130 html = formencode.htmlfill.render(
130 html = formencode.htmlfill.render(
131 data,
131 data,
132 defaults=defaults,
132 defaults=defaults,
133 encoding="UTF-8",
133 encoding="UTF-8",
134 force_defaults=False
134 force_defaults=False
135 )
135 )
136 return Response(html)
136 return Response(html)
137
137
138 @LoginRequired()
138 @LoginRequired()
139 @HasPermissionAllDecorator('hg.admin')
139 @HasPermissionAllDecorator('hg.admin')
140 @CSRFRequired()
140 @CSRFRequired()
141 @view_config(
141 @view_config(
142 route_name='admin_settings_vcs_update', request_method='POST',
142 route_name='admin_settings_vcs_update', request_method='POST',
143 renderer='rhodecode:templates/admin/settings/settings.mako')
143 renderer='rhodecode:templates/admin/settings/settings.mako')
144 def settings_vcs_update(self):
144 def settings_vcs_update(self):
145 _ = self.request.translate
145 _ = self.request.translate
146 c = self.load_default_context()
146 c = self.load_default_context()
147 c.active = 'vcs'
147 c.active = 'vcs'
148
148
149 model = VcsSettingsModel()
149 model = VcsSettingsModel()
150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
150 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
151 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
152
152
153 settings = self.request.registry.settings
153 settings = self.request.registry.settings
154 c.svn_proxy_generate_config = settings[generate_config]
154 c.svn_proxy_generate_config = settings[generate_config]
155
155
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
157
157
158 try:
158 try:
159 form_result = application_form.to_python(dict(self.request.POST))
159 form_result = application_form.to_python(dict(self.request.POST))
160 except formencode.Invalid as errors:
160 except formencode.Invalid as errors:
161 h.flash(
161 h.flash(
162 _("Some form inputs contain invalid data."),
162 _("Some form inputs contain invalid data."),
163 category='error')
163 category='error')
164 data = render('rhodecode:templates/admin/settings/settings.mako',
164 data = render('rhodecode:templates/admin/settings/settings.mako',
165 self._get_template_context(c), self.request)
165 self._get_template_context(c), self.request)
166 html = formencode.htmlfill.render(
166 html = formencode.htmlfill.render(
167 data,
167 data,
168 defaults=errors.value,
168 defaults=errors.value,
169 errors=errors.error_dict or {},
169 errors=errors.error_dict or {},
170 prefix_error=False,
170 prefix_error=False,
171 encoding="UTF-8",
171 encoding="UTF-8",
172 force_defaults=False
172 force_defaults=False
173 )
173 )
174 return Response(html)
174 return Response(html)
175
175
176 try:
176 try:
177 if c.visual.allow_repo_location_change:
177 if c.visual.allow_repo_location_change:
178 model.update_global_path_setting(form_result['paths_root_path'])
178 model.update_global_path_setting(form_result['paths_root_path'])
179
179
180 model.update_global_ssl_setting(form_result['web_push_ssl'])
180 model.update_global_ssl_setting(form_result['web_push_ssl'])
181 model.update_global_hook_settings(form_result)
181 model.update_global_hook_settings(form_result)
182
182
183 model.create_or_update_global_svn_settings(form_result)
183 model.create_or_update_global_svn_settings(form_result)
184 model.create_or_update_global_hg_settings(form_result)
184 model.create_or_update_global_hg_settings(form_result)
185 model.create_or_update_global_git_settings(form_result)
185 model.create_or_update_global_git_settings(form_result)
186 model.create_or_update_global_pr_settings(form_result)
186 model.create_or_update_global_pr_settings(form_result)
187 except Exception:
187 except Exception:
188 log.exception("Exception while updating settings")
188 log.exception("Exception while updating settings")
189 h.flash(_('Error occurred during updating '
189 h.flash(_('Error occurred during updating '
190 'application settings'), category='error')
190 'application settings'), category='error')
191 else:
191 else:
192 Session().commit()
192 Session().commit()
193 h.flash(_('Updated VCS settings'), category='success')
193 h.flash(_('Updated VCS settings'), category='success')
194 raise HTTPFound(h.route_path('admin_settings_vcs'))
194 raise HTTPFound(h.route_path('admin_settings_vcs'))
195
195
196 data = render('rhodecode:templates/admin/settings/settings.mako',
196 data = render('rhodecode:templates/admin/settings/settings.mako',
197 self._get_template_context(c), self.request)
197 self._get_template_context(c), self.request)
198 html = formencode.htmlfill.render(
198 html = formencode.htmlfill.render(
199 data,
199 data,
200 defaults=self._form_defaults(),
200 defaults=self._form_defaults(),
201 encoding="UTF-8",
201 encoding="UTF-8",
202 force_defaults=False
202 force_defaults=False
203 )
203 )
204 return Response(html)
204 return Response(html)
205
205
206 @LoginRequired()
206 @LoginRequired()
207 @HasPermissionAllDecorator('hg.admin')
207 @HasPermissionAllDecorator('hg.admin')
208 @CSRFRequired()
208 @CSRFRequired()
209 @view_config(
209 @view_config(
210 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
210 route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST',
211 renderer='json_ext', xhr=True)
211 renderer='json_ext', xhr=True)
212 def settings_vcs_delete_svn_pattern(self):
212 def settings_vcs_delete_svn_pattern(self):
213 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
213 delete_pattern_id = self.request.POST.get('delete_svn_pattern')
214 model = VcsSettingsModel()
214 model = VcsSettingsModel()
215 try:
215 try:
216 model.delete_global_svn_pattern(delete_pattern_id)
216 model.delete_global_svn_pattern(delete_pattern_id)
217 except SettingNotFound:
217 except SettingNotFound:
218 log.exception(
218 log.exception(
219 'Failed to delete svn_pattern with id %s', delete_pattern_id)
219 'Failed to delete svn_pattern with id %s', delete_pattern_id)
220 raise HTTPNotFound()
220 raise HTTPNotFound()
221
221
222 Session().commit()
222 Session().commit()
223 return True
223 return True
224
224
225 @LoginRequired()
225 @LoginRequired()
226 @HasPermissionAllDecorator('hg.admin')
226 @HasPermissionAllDecorator('hg.admin')
227 @view_config(
227 @view_config(
228 route_name='admin_settings_mapping', request_method='GET',
228 route_name='admin_settings_mapping', request_method='GET',
229 renderer='rhodecode:templates/admin/settings/settings.mako')
229 renderer='rhodecode:templates/admin/settings/settings.mako')
230 def settings_mapping(self):
230 def settings_mapping(self):
231 c = self.load_default_context()
231 c = self.load_default_context()
232 c.active = 'mapping'
232 c.active = 'mapping'
233
233
234 data = render('rhodecode:templates/admin/settings/settings.mako',
234 data = render('rhodecode:templates/admin/settings/settings.mako',
235 self._get_template_context(c), self.request)
235 self._get_template_context(c), self.request)
236 html = formencode.htmlfill.render(
236 html = formencode.htmlfill.render(
237 data,
237 data,
238 defaults=self._form_defaults(),
238 defaults=self._form_defaults(),
239 encoding="UTF-8",
239 encoding="UTF-8",
240 force_defaults=False
240 force_defaults=False
241 )
241 )
242 return Response(html)
242 return Response(html)
243
243
244 @LoginRequired()
244 @LoginRequired()
245 @HasPermissionAllDecorator('hg.admin')
245 @HasPermissionAllDecorator('hg.admin')
246 @CSRFRequired()
246 @CSRFRequired()
247 @view_config(
247 @view_config(
248 route_name='admin_settings_mapping_update', request_method='POST',
248 route_name='admin_settings_mapping_update', request_method='POST',
249 renderer='rhodecode:templates/admin/settings/settings.mako')
249 renderer='rhodecode:templates/admin/settings/settings.mako')
250 def settings_mapping_update(self):
250 def settings_mapping_update(self):
251 _ = self.request.translate
251 _ = self.request.translate
252 c = self.load_default_context()
252 c = self.load_default_context()
253 c.active = 'mapping'
253 c.active = 'mapping'
254 rm_obsolete = self.request.POST.get('destroy', False)
254 rm_obsolete = self.request.POST.get('destroy', False)
255 invalidate_cache = self.request.POST.get('invalidate', False)
255 invalidate_cache = self.request.POST.get('invalidate', False)
256 log.debug(
256 log.debug(
257 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
257 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
258
258
259 if invalidate_cache:
259 if invalidate_cache:
260 log.debug('invalidating all repositories cache')
260 log.debug('invalidating all repositories cache')
261 for repo in Repository.get_all():
261 for repo in Repository.get_all():
262 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
262 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
263
263
264 filesystem_repos = ScmModel().repo_scan()
264 filesystem_repos = ScmModel().repo_scan()
265 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
265 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
266 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
266 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
267 h.flash(_('Repositories successfully '
267 h.flash(_('Repositories successfully '
268 'rescanned added: %s ; removed: %s') %
268 'rescanned added: %s ; removed: %s') %
269 (_repr(added), _repr(removed)),
269 (_repr(added), _repr(removed)),
270 category='success')
270 category='success')
271 raise HTTPFound(h.route_path('admin_settings_mapping'))
271 raise HTTPFound(h.route_path('admin_settings_mapping'))
272
272
273 @LoginRequired()
273 @LoginRequired()
274 @HasPermissionAllDecorator('hg.admin')
274 @HasPermissionAllDecorator('hg.admin')
275 @view_config(
275 @view_config(
276 route_name='admin_settings', request_method='GET',
276 route_name='admin_settings', request_method='GET',
277 renderer='rhodecode:templates/admin/settings/settings.mako')
277 renderer='rhodecode:templates/admin/settings/settings.mako')
278 @view_config(
278 @view_config(
279 route_name='admin_settings_global', request_method='GET',
279 route_name='admin_settings_global', request_method='GET',
280 renderer='rhodecode:templates/admin/settings/settings.mako')
280 renderer='rhodecode:templates/admin/settings/settings.mako')
281 def settings_global(self):
281 def settings_global(self):
282 c = self.load_default_context()
282 c = self.load_default_context()
283 c.active = 'global'
283 c.active = 'global'
284 c.personal_repo_group_default_pattern = RepoGroupModel()\
284 c.personal_repo_group_default_pattern = RepoGroupModel()\
285 .get_personal_group_name_pattern()
285 .get_personal_group_name_pattern()
286
286
287 data = render('rhodecode:templates/admin/settings/settings.mako',
287 data = render('rhodecode:templates/admin/settings/settings.mako',
288 self._get_template_context(c), self.request)
288 self._get_template_context(c), self.request)
289 html = formencode.htmlfill.render(
289 html = formencode.htmlfill.render(
290 data,
290 data,
291 defaults=self._form_defaults(),
291 defaults=self._form_defaults(),
292 encoding="UTF-8",
292 encoding="UTF-8",
293 force_defaults=False
293 force_defaults=False
294 )
294 )
295 return Response(html)
295 return Response(html)
296
296
297 @LoginRequired()
297 @LoginRequired()
298 @HasPermissionAllDecorator('hg.admin')
298 @HasPermissionAllDecorator('hg.admin')
299 @CSRFRequired()
299 @CSRFRequired()
300 @view_config(
300 @view_config(
301 route_name='admin_settings_update', request_method='POST',
301 route_name='admin_settings_update', request_method='POST',
302 renderer='rhodecode:templates/admin/settings/settings.mako')
302 renderer='rhodecode:templates/admin/settings/settings.mako')
303 @view_config(
303 @view_config(
304 route_name='admin_settings_global_update', request_method='POST',
304 route_name='admin_settings_global_update', request_method='POST',
305 renderer='rhodecode:templates/admin/settings/settings.mako')
305 renderer='rhodecode:templates/admin/settings/settings.mako')
306 def settings_global_update(self):
306 def settings_global_update(self):
307 _ = self.request.translate
307 _ = self.request.translate
308 c = self.load_default_context()
308 c = self.load_default_context()
309 c.active = 'global'
309 c.active = 'global'
310 c.personal_repo_group_default_pattern = RepoGroupModel()\
310 c.personal_repo_group_default_pattern = RepoGroupModel()\
311 .get_personal_group_name_pattern()
311 .get_personal_group_name_pattern()
312 application_form = ApplicationSettingsForm(self.request.translate)()
312 application_form = ApplicationSettingsForm(self.request.translate)()
313 try:
313 try:
314 form_result = application_form.to_python(dict(self.request.POST))
314 form_result = application_form.to_python(dict(self.request.POST))
315 except formencode.Invalid as errors:
315 except formencode.Invalid as errors:
316 h.flash(
316 h.flash(
317 _("Some form inputs contain invalid data."),
317 _("Some form inputs contain invalid data."),
318 category='error')
318 category='error')
319 data = render('rhodecode:templates/admin/settings/settings.mako',
319 data = render('rhodecode:templates/admin/settings/settings.mako',
320 self._get_template_context(c), self.request)
320 self._get_template_context(c), self.request)
321 html = formencode.htmlfill.render(
321 html = formencode.htmlfill.render(
322 data,
322 data,
323 defaults=errors.value,
323 defaults=errors.value,
324 errors=errors.error_dict or {},
324 errors=errors.error_dict or {},
325 prefix_error=False,
325 prefix_error=False,
326 encoding="UTF-8",
326 encoding="UTF-8",
327 force_defaults=False
327 force_defaults=False
328 )
328 )
329 return Response(html)
329 return Response(html)
330
330
331 settings = [
331 settings = [
332 ('title', 'rhodecode_title', 'unicode'),
332 ('title', 'rhodecode_title', 'unicode'),
333 ('realm', 'rhodecode_realm', 'unicode'),
333 ('realm', 'rhodecode_realm', 'unicode'),
334 ('pre_code', 'rhodecode_pre_code', 'unicode'),
334 ('pre_code', 'rhodecode_pre_code', 'unicode'),
335 ('post_code', 'rhodecode_post_code', 'unicode'),
335 ('post_code', 'rhodecode_post_code', 'unicode'),
336 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
336 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
337 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
337 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
338 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
338 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
339 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
339 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
340 ]
340 ]
341 try:
341 try:
342 for setting, form_key, type_ in settings:
342 for setting, form_key, type_ in settings:
343 sett = SettingsModel().create_or_update_setting(
343 sett = SettingsModel().create_or_update_setting(
344 setting, form_result[form_key], type_)
344 setting, form_result[form_key], type_)
345 Session().add(sett)
345 Session().add(sett)
346
346
347 Session().commit()
347 Session().commit()
348 SettingsModel().invalidate_settings_cache()
348 SettingsModel().invalidate_settings_cache()
349 h.flash(_('Updated application settings'), category='success')
349 h.flash(_('Updated application settings'), category='success')
350 except Exception:
350 except Exception:
351 log.exception("Exception while updating application settings")
351 log.exception("Exception while updating application settings")
352 h.flash(
352 h.flash(
353 _('Error occurred during updating application settings'),
353 _('Error occurred during updating application settings'),
354 category='error')
354 category='error')
355
355
356 raise HTTPFound(h.route_path('admin_settings_global'))
356 raise HTTPFound(h.route_path('admin_settings_global'))
357
357
358 @LoginRequired()
358 @LoginRequired()
359 @HasPermissionAllDecorator('hg.admin')
359 @HasPermissionAllDecorator('hg.admin')
360 @view_config(
360 @view_config(
361 route_name='admin_settings_visual', request_method='GET',
361 route_name='admin_settings_visual', request_method='GET',
362 renderer='rhodecode:templates/admin/settings/settings.mako')
362 renderer='rhodecode:templates/admin/settings/settings.mako')
363 def settings_visual(self):
363 def settings_visual(self):
364 c = self.load_default_context()
364 c = self.load_default_context()
365 c.active = 'visual'
365 c.active = 'visual'
366
366
367 data = render('rhodecode:templates/admin/settings/settings.mako',
367 data = render('rhodecode:templates/admin/settings/settings.mako',
368 self._get_template_context(c), self.request)
368 self._get_template_context(c), self.request)
369 html = formencode.htmlfill.render(
369 html = formencode.htmlfill.render(
370 data,
370 data,
371 defaults=self._form_defaults(),
371 defaults=self._form_defaults(),
372 encoding="UTF-8",
372 encoding="UTF-8",
373 force_defaults=False
373 force_defaults=False
374 )
374 )
375 return Response(html)
375 return Response(html)
376
376
377 @LoginRequired()
377 @LoginRequired()
378 @HasPermissionAllDecorator('hg.admin')
378 @HasPermissionAllDecorator('hg.admin')
379 @CSRFRequired()
379 @CSRFRequired()
380 @view_config(
380 @view_config(
381 route_name='admin_settings_visual_update', request_method='POST',
381 route_name='admin_settings_visual_update', request_method='POST',
382 renderer='rhodecode:templates/admin/settings/settings.mako')
382 renderer='rhodecode:templates/admin/settings/settings.mako')
383 def settings_visual_update(self):
383 def settings_visual_update(self):
384 _ = self.request.translate
384 _ = self.request.translate
385 c = self.load_default_context()
385 c = self.load_default_context()
386 c.active = 'visual'
386 c.active = 'visual'
387 application_form = ApplicationVisualisationForm(self.request.translate)()
387 application_form = ApplicationVisualisationForm(self.request.translate)()
388 try:
388 try:
389 form_result = application_form.to_python(dict(self.request.POST))
389 form_result = application_form.to_python(dict(self.request.POST))
390 except formencode.Invalid as errors:
390 except formencode.Invalid as errors:
391 h.flash(
391 h.flash(
392 _("Some form inputs contain invalid data."),
392 _("Some form inputs contain invalid data."),
393 category='error')
393 category='error')
394 data = render('rhodecode:templates/admin/settings/settings.mako',
394 data = render('rhodecode:templates/admin/settings/settings.mako',
395 self._get_template_context(c), self.request)
395 self._get_template_context(c), self.request)
396 html = formencode.htmlfill.render(
396 html = formencode.htmlfill.render(
397 data,
397 data,
398 defaults=errors.value,
398 defaults=errors.value,
399 errors=errors.error_dict or {},
399 errors=errors.error_dict or {},
400 prefix_error=False,
400 prefix_error=False,
401 encoding="UTF-8",
401 encoding="UTF-8",
402 force_defaults=False
402 force_defaults=False
403 )
403 )
404 return Response(html)
404 return Response(html)
405
405
406 try:
406 try:
407 settings = [
407 settings = [
408 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
408 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
409 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
409 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
410 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
410 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
411 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
411 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
412 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
412 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
413 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
413 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
414 ('show_version', 'rhodecode_show_version', 'bool'),
414 ('show_version', 'rhodecode_show_version', 'bool'),
415 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
415 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
416 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
416 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
417 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
417 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
418 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
418 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
419 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
419 ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'),
420 ('support_url', 'rhodecode_support_url', 'unicode'),
420 ('support_url', 'rhodecode_support_url', 'unicode'),
421 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
421 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
422 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
422 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
423 ]
423 ]
424 for setting, form_key, type_ in settings:
424 for setting, form_key, type_ in settings:
425 sett = SettingsModel().create_or_update_setting(
425 sett = SettingsModel().create_or_update_setting(
426 setting, form_result[form_key], type_)
426 setting, form_result[form_key], type_)
427 Session().add(sett)
427 Session().add(sett)
428
428
429 Session().commit()
429 Session().commit()
430 SettingsModel().invalidate_settings_cache()
430 SettingsModel().invalidate_settings_cache()
431 h.flash(_('Updated visualisation settings'), category='success')
431 h.flash(_('Updated visualisation settings'), category='success')
432 except Exception:
432 except Exception:
433 log.exception("Exception updating visualization settings")
433 log.exception("Exception updating visualization settings")
434 h.flash(_('Error occurred during updating '
434 h.flash(_('Error occurred during updating '
435 'visualisation settings'),
435 'visualisation settings'),
436 category='error')
436 category='error')
437
437
438 raise HTTPFound(h.route_path('admin_settings_visual'))
438 raise HTTPFound(h.route_path('admin_settings_visual'))
439
439
440 @LoginRequired()
440 @LoginRequired()
441 @HasPermissionAllDecorator('hg.admin')
441 @HasPermissionAllDecorator('hg.admin')
442 @view_config(
442 @view_config(
443 route_name='admin_settings_issuetracker', request_method='GET',
443 route_name='admin_settings_issuetracker', request_method='GET',
444 renderer='rhodecode:templates/admin/settings/settings.mako')
444 renderer='rhodecode:templates/admin/settings/settings.mako')
445 def settings_issuetracker(self):
445 def settings_issuetracker(self):
446 c = self.load_default_context()
446 c = self.load_default_context()
447 c.active = 'issuetracker'
447 c.active = 'issuetracker'
448 defaults = SettingsModel().get_all_settings()
448 defaults = c.rc_config
449
449
450 entry_key = 'rhodecode_issuetracker_pat_'
450 entry_key = 'rhodecode_issuetracker_pat_'
451
451
452 c.issuetracker_entries = {}
452 c.issuetracker_entries = {}
453 for k, v in defaults.items():
453 for k, v in defaults.items():
454 if k.startswith(entry_key):
454 if k.startswith(entry_key):
455 uid = k[len(entry_key):]
455 uid = k[len(entry_key):]
456 c.issuetracker_entries[uid] = None
456 c.issuetracker_entries[uid] = None
457
457
458 for uid in c.issuetracker_entries:
458 for uid in c.issuetracker_entries:
459 c.issuetracker_entries[uid] = AttributeDict({
459 c.issuetracker_entries[uid] = AttributeDict({
460 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
460 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
461 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
461 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
462 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
462 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
463 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
463 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
464 })
464 })
465
465
466 return self._get_template_context(c)
466 return self._get_template_context(c)
467
467
468 @LoginRequired()
468 @LoginRequired()
469 @HasPermissionAllDecorator('hg.admin')
469 @HasPermissionAllDecorator('hg.admin')
470 @CSRFRequired()
470 @CSRFRequired()
471 @view_config(
471 @view_config(
472 route_name='admin_settings_issuetracker_test', request_method='POST',
472 route_name='admin_settings_issuetracker_test', request_method='POST',
473 renderer='string', xhr=True)
473 renderer='string', xhr=True)
474 def settings_issuetracker_test(self):
474 def settings_issuetracker_test(self):
475 return h.urlify_commit_message(
475 return h.urlify_commit_message(
476 self.request.POST.get('test_text', ''),
476 self.request.POST.get('test_text', ''),
477 'repo_group/test_repo1')
477 'repo_group/test_repo1')
478
478
479 @LoginRequired()
479 @LoginRequired()
480 @HasPermissionAllDecorator('hg.admin')
480 @HasPermissionAllDecorator('hg.admin')
481 @CSRFRequired()
481 @CSRFRequired()
482 @view_config(
482 @view_config(
483 route_name='admin_settings_issuetracker_update', request_method='POST',
483 route_name='admin_settings_issuetracker_update', request_method='POST',
484 renderer='rhodecode:templates/admin/settings/settings.mako')
484 renderer='rhodecode:templates/admin/settings/settings.mako')
485 def settings_issuetracker_update(self):
485 def settings_issuetracker_update(self):
486 _ = self.request.translate
486 _ = self.request.translate
487 self.load_default_context()
487 self.load_default_context()
488 settings_model = IssueTrackerSettingsModel()
488 settings_model = IssueTrackerSettingsModel()
489
489
490 try:
490 try:
491 form = IssueTrackerPatternsForm(self.request.translate)()
491 form = IssueTrackerPatternsForm(self.request.translate)()
492 data = form.to_python(self.request.POST)
492 data = form.to_python(self.request.POST)
493 except formencode.Invalid as errors:
493 except formencode.Invalid as errors:
494 log.exception('Failed to add new pattern')
494 log.exception('Failed to add new pattern')
495 error = errors
495 error = errors
496 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
496 h.flash(_('Invalid issue tracker pattern: {}'.format(error)),
497 category='error')
497 category='error')
498 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
498 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
499
499
500 if data:
500 if data:
501 for uid in data.get('delete_patterns', []):
501 for uid in data.get('delete_patterns', []):
502 settings_model.delete_entries(uid)
502 settings_model.delete_entries(uid)
503
503
504 for pattern in data.get('patterns', []):
504 for pattern in data.get('patterns', []):
505 for setting, value, type_ in pattern:
505 for setting, value, type_ in pattern:
506 sett = settings_model.create_or_update_setting(
506 sett = settings_model.create_or_update_setting(
507 setting, value, type_)
507 setting, value, type_)
508 Session().add(sett)
508 Session().add(sett)
509
509
510 Session().commit()
510 Session().commit()
511
511
512 SettingsModel().invalidate_settings_cache()
512 SettingsModel().invalidate_settings_cache()
513 h.flash(_('Updated issue tracker entries'), category='success')
513 h.flash(_('Updated issue tracker entries'), category='success')
514 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
514 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
515
515
516 @LoginRequired()
516 @LoginRequired()
517 @HasPermissionAllDecorator('hg.admin')
517 @HasPermissionAllDecorator('hg.admin')
518 @CSRFRequired()
518 @CSRFRequired()
519 @view_config(
519 @view_config(
520 route_name='admin_settings_issuetracker_delete', request_method='POST',
520 route_name='admin_settings_issuetracker_delete', request_method='POST',
521 renderer='rhodecode:templates/admin/settings/settings.mako')
521 renderer='rhodecode:templates/admin/settings/settings.mako')
522 def settings_issuetracker_delete(self):
522 def settings_issuetracker_delete(self):
523 _ = self.request.translate
523 _ = self.request.translate
524 self.load_default_context()
524 self.load_default_context()
525 uid = self.request.POST.get('uid')
525 uid = self.request.POST.get('uid')
526 try:
526 try:
527 IssueTrackerSettingsModel().delete_entries(uid)
527 IssueTrackerSettingsModel().delete_entries(uid)
528 except Exception:
528 except Exception:
529 log.exception('Failed to delete issue tracker setting %s', uid)
529 log.exception('Failed to delete issue tracker setting %s', uid)
530 raise HTTPNotFound()
530 raise HTTPNotFound()
531 h.flash(_('Removed issue tracker entry'), category='success')
531 h.flash(_('Removed issue tracker entry'), category='success')
532 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
532 raise HTTPFound(h.route_path('admin_settings_issuetracker'))
533
533
534 @LoginRequired()
534 @LoginRequired()
535 @HasPermissionAllDecorator('hg.admin')
535 @HasPermissionAllDecorator('hg.admin')
536 @view_config(
536 @view_config(
537 route_name='admin_settings_email', request_method='GET',
537 route_name='admin_settings_email', request_method='GET',
538 renderer='rhodecode:templates/admin/settings/settings.mako')
538 renderer='rhodecode:templates/admin/settings/settings.mako')
539 def settings_email(self):
539 def settings_email(self):
540 c = self.load_default_context()
540 c = self.load_default_context()
541 c.active = 'email'
541 c.active = 'email'
542 c.rhodecode_ini = rhodecode.CONFIG
542 c.rhodecode_ini = rhodecode.CONFIG
543
543
544 data = render('rhodecode:templates/admin/settings/settings.mako',
544 data = render('rhodecode:templates/admin/settings/settings.mako',
545 self._get_template_context(c), self.request)
545 self._get_template_context(c), self.request)
546 html = formencode.htmlfill.render(
546 html = formencode.htmlfill.render(
547 data,
547 data,
548 defaults=self._form_defaults(),
548 defaults=self._form_defaults(),
549 encoding="UTF-8",
549 encoding="UTF-8",
550 force_defaults=False
550 force_defaults=False
551 )
551 )
552 return Response(html)
552 return Response(html)
553
553
554 @LoginRequired()
554 @LoginRequired()
555 @HasPermissionAllDecorator('hg.admin')
555 @HasPermissionAllDecorator('hg.admin')
556 @CSRFRequired()
556 @CSRFRequired()
557 @view_config(
557 @view_config(
558 route_name='admin_settings_email_update', request_method='POST',
558 route_name='admin_settings_email_update', request_method='POST',
559 renderer='rhodecode:templates/admin/settings/settings.mako')
559 renderer='rhodecode:templates/admin/settings/settings.mako')
560 def settings_email_update(self):
560 def settings_email_update(self):
561 _ = self.request.translate
561 _ = self.request.translate
562 c = self.load_default_context()
562 c = self.load_default_context()
563 c.active = 'email'
563 c.active = 'email'
564
564
565 test_email = self.request.POST.get('test_email')
565 test_email = self.request.POST.get('test_email')
566
566
567 if not test_email:
567 if not test_email:
568 h.flash(_('Please enter email address'), category='error')
568 h.flash(_('Please enter email address'), category='error')
569 raise HTTPFound(h.route_path('admin_settings_email'))
569 raise HTTPFound(h.route_path('admin_settings_email'))
570
570
571 email_kwargs = {
571 email_kwargs = {
572 'date': datetime.datetime.now(),
572 'date': datetime.datetime.now(),
573 'user': c.rhodecode_user,
573 'user': c.rhodecode_user,
574 'rhodecode_version': c.rhodecode_version
574 'rhodecode_version': c.rhodecode_version
575 }
575 }
576
576
577 (subject, headers, email_body,
577 (subject, headers, email_body,
578 email_body_plaintext) = EmailNotificationModel().render_email(
578 email_body_plaintext) = EmailNotificationModel().render_email(
579 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
579 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
580
580
581 recipients = [test_email] if test_email else None
581 recipients = [test_email] if test_email else None
582
582
583 run_task(tasks.send_email, recipients, subject,
583 run_task(tasks.send_email, recipients, subject,
584 email_body_plaintext, email_body)
584 email_body_plaintext, email_body)
585
585
586 h.flash(_('Send email task created'), category='success')
586 h.flash(_('Send email task created'), category='success')
587 raise HTTPFound(h.route_path('admin_settings_email'))
587 raise HTTPFound(h.route_path('admin_settings_email'))
588
588
589 @LoginRequired()
589 @LoginRequired()
590 @HasPermissionAllDecorator('hg.admin')
590 @HasPermissionAllDecorator('hg.admin')
591 @view_config(
591 @view_config(
592 route_name='admin_settings_hooks', request_method='GET',
592 route_name='admin_settings_hooks', request_method='GET',
593 renderer='rhodecode:templates/admin/settings/settings.mako')
593 renderer='rhodecode:templates/admin/settings/settings.mako')
594 def settings_hooks(self):
594 def settings_hooks(self):
595 c = self.load_default_context()
595 c = self.load_default_context()
596 c.active = 'hooks'
596 c.active = 'hooks'
597
597
598 model = SettingsModel()
598 model = SettingsModel()
599 c.hooks = model.get_builtin_hooks()
599 c.hooks = model.get_builtin_hooks()
600 c.custom_hooks = model.get_custom_hooks()
600 c.custom_hooks = model.get_custom_hooks()
601
601
602 data = render('rhodecode:templates/admin/settings/settings.mako',
602 data = render('rhodecode:templates/admin/settings/settings.mako',
603 self._get_template_context(c), self.request)
603 self._get_template_context(c), self.request)
604 html = formencode.htmlfill.render(
604 html = formencode.htmlfill.render(
605 data,
605 data,
606 defaults=self._form_defaults(),
606 defaults=self._form_defaults(),
607 encoding="UTF-8",
607 encoding="UTF-8",
608 force_defaults=False
608 force_defaults=False
609 )
609 )
610 return Response(html)
610 return Response(html)
611
611
612 @LoginRequired()
612 @LoginRequired()
613 @HasPermissionAllDecorator('hg.admin')
613 @HasPermissionAllDecorator('hg.admin')
614 @CSRFRequired()
614 @CSRFRequired()
615 @view_config(
615 @view_config(
616 route_name='admin_settings_hooks_update', request_method='POST',
616 route_name='admin_settings_hooks_update', request_method='POST',
617 renderer='rhodecode:templates/admin/settings/settings.mako')
617 renderer='rhodecode:templates/admin/settings/settings.mako')
618 @view_config(
618 @view_config(
619 route_name='admin_settings_hooks_delete', request_method='POST',
619 route_name='admin_settings_hooks_delete', request_method='POST',
620 renderer='rhodecode:templates/admin/settings/settings.mako')
620 renderer='rhodecode:templates/admin/settings/settings.mako')
621 def settings_hooks_update(self):
621 def settings_hooks_update(self):
622 _ = self.request.translate
622 _ = self.request.translate
623 c = self.load_default_context()
623 c = self.load_default_context()
624 c.active = 'hooks'
624 c.active = 'hooks'
625 if c.visual.allow_custom_hooks_settings:
625 if c.visual.allow_custom_hooks_settings:
626 ui_key = self.request.POST.get('new_hook_ui_key')
626 ui_key = self.request.POST.get('new_hook_ui_key')
627 ui_value = self.request.POST.get('new_hook_ui_value')
627 ui_value = self.request.POST.get('new_hook_ui_value')
628
628
629 hook_id = self.request.POST.get('hook_id')
629 hook_id = self.request.POST.get('hook_id')
630 new_hook = False
630 new_hook = False
631
631
632 model = SettingsModel()
632 model = SettingsModel()
633 try:
633 try:
634 if ui_value and ui_key:
634 if ui_value and ui_key:
635 model.create_or_update_hook(ui_key, ui_value)
635 model.create_or_update_hook(ui_key, ui_value)
636 h.flash(_('Added new hook'), category='success')
636 h.flash(_('Added new hook'), category='success')
637 new_hook = True
637 new_hook = True
638 elif hook_id:
638 elif hook_id:
639 RhodeCodeUi.delete(hook_id)
639 RhodeCodeUi.delete(hook_id)
640 Session().commit()
640 Session().commit()
641
641
642 # check for edits
642 # check for edits
643 update = False
643 update = False
644 _d = self.request.POST.dict_of_lists()
644 _d = self.request.POST.dict_of_lists()
645 for k, v in zip(_d.get('hook_ui_key', []),
645 for k, v in zip(_d.get('hook_ui_key', []),
646 _d.get('hook_ui_value_new', [])):
646 _d.get('hook_ui_value_new', [])):
647 model.create_or_update_hook(k, v)
647 model.create_or_update_hook(k, v)
648 update = True
648 update = True
649
649
650 if update and not new_hook:
650 if update and not new_hook:
651 h.flash(_('Updated hooks'), category='success')
651 h.flash(_('Updated hooks'), category='success')
652 Session().commit()
652 Session().commit()
653 except Exception:
653 except Exception:
654 log.exception("Exception during hook creation")
654 log.exception("Exception during hook creation")
655 h.flash(_('Error occurred during hook creation'),
655 h.flash(_('Error occurred during hook creation'),
656 category='error')
656 category='error')
657
657
658 raise HTTPFound(h.route_path('admin_settings_hooks'))
658 raise HTTPFound(h.route_path('admin_settings_hooks'))
659
659
660 @LoginRequired()
660 @LoginRequired()
661 @HasPermissionAllDecorator('hg.admin')
661 @HasPermissionAllDecorator('hg.admin')
662 @view_config(
662 @view_config(
663 route_name='admin_settings_search', request_method='GET',
663 route_name='admin_settings_search', request_method='GET',
664 renderer='rhodecode:templates/admin/settings/settings.mako')
664 renderer='rhodecode:templates/admin/settings/settings.mako')
665 def settings_search(self):
665 def settings_search(self):
666 c = self.load_default_context()
666 c = self.load_default_context()
667 c.active = 'search'
667 c.active = 'search'
668
668
669 c.searcher = searcher_from_config(self.request.registry.settings)
669 c.searcher = searcher_from_config(self.request.registry.settings)
670 c.statistics = c.searcher.statistics(self.request.translate)
670 c.statistics = c.searcher.statistics(self.request.translate)
671
671
672 return self._get_template_context(c)
672 return self._get_template_context(c)
673
673
674 @LoginRequired()
674 @LoginRequired()
675 @HasPermissionAllDecorator('hg.admin')
675 @HasPermissionAllDecorator('hg.admin')
676 @view_config(
676 @view_config(
677 route_name='admin_settings_automation', request_method='GET',
677 route_name='admin_settings_automation', request_method='GET',
678 renderer='rhodecode:templates/admin/settings/settings.mako')
678 renderer='rhodecode:templates/admin/settings/settings.mako')
679 def settings_automation(self):
679 def settings_automation(self):
680 c = self.load_default_context()
680 c = self.load_default_context()
681 c.active = 'automation'
681 c.active = 'automation'
682
682
683 return self._get_template_context(c)
683 return self._get_template_context(c)
684
684
685 @LoginRequired()
685 @LoginRequired()
686 @HasPermissionAllDecorator('hg.admin')
686 @HasPermissionAllDecorator('hg.admin')
687 @view_config(
687 @view_config(
688 route_name='admin_settings_labs', request_method='GET',
688 route_name='admin_settings_labs', request_method='GET',
689 renderer='rhodecode:templates/admin/settings/settings.mako')
689 renderer='rhodecode:templates/admin/settings/settings.mako')
690 def settings_labs(self):
690 def settings_labs(self):
691 c = self.load_default_context()
691 c = self.load_default_context()
692 if not c.labs_active:
692 if not c.labs_active:
693 raise HTTPFound(h.route_path('admin_settings'))
693 raise HTTPFound(h.route_path('admin_settings'))
694
694
695 c.active = 'labs'
695 c.active = 'labs'
696 c.lab_settings = _LAB_SETTINGS
696 c.lab_settings = _LAB_SETTINGS
697
697
698 data = render('rhodecode:templates/admin/settings/settings.mako',
698 data = render('rhodecode:templates/admin/settings/settings.mako',
699 self._get_template_context(c), self.request)
699 self._get_template_context(c), self.request)
700 html = formencode.htmlfill.render(
700 html = formencode.htmlfill.render(
701 data,
701 data,
702 defaults=self._form_defaults(),
702 defaults=self._form_defaults(),
703 encoding="UTF-8",
703 encoding="UTF-8",
704 force_defaults=False
704 force_defaults=False
705 )
705 )
706 return Response(html)
706 return Response(html)
707
707
708 @LoginRequired()
708 @LoginRequired()
709 @HasPermissionAllDecorator('hg.admin')
709 @HasPermissionAllDecorator('hg.admin')
710 @CSRFRequired()
710 @CSRFRequired()
711 @view_config(
711 @view_config(
712 route_name='admin_settings_labs_update', request_method='POST',
712 route_name='admin_settings_labs_update', request_method='POST',
713 renderer='rhodecode:templates/admin/settings/settings.mako')
713 renderer='rhodecode:templates/admin/settings/settings.mako')
714 def settings_labs_update(self):
714 def settings_labs_update(self):
715 _ = self.request.translate
715 _ = self.request.translate
716 c = self.load_default_context()
716 c = self.load_default_context()
717 c.active = 'labs'
717 c.active = 'labs'
718
718
719 application_form = LabsSettingsForm(self.request.translate)()
719 application_form = LabsSettingsForm(self.request.translate)()
720 try:
720 try:
721 form_result = application_form.to_python(dict(self.request.POST))
721 form_result = application_form.to_python(dict(self.request.POST))
722 except formencode.Invalid as errors:
722 except formencode.Invalid as errors:
723 h.flash(
723 h.flash(
724 _("Some form inputs contain invalid data."),
724 _("Some form inputs contain invalid data."),
725 category='error')
725 category='error')
726 data = render('rhodecode:templates/admin/settings/settings.mako',
726 data = render('rhodecode:templates/admin/settings/settings.mako',
727 self._get_template_context(c), self.request)
727 self._get_template_context(c), self.request)
728 html = formencode.htmlfill.render(
728 html = formencode.htmlfill.render(
729 data,
729 data,
730 defaults=errors.value,
730 defaults=errors.value,
731 errors=errors.error_dict or {},
731 errors=errors.error_dict or {},
732 prefix_error=False,
732 prefix_error=False,
733 encoding="UTF-8",
733 encoding="UTF-8",
734 force_defaults=False
734 force_defaults=False
735 )
735 )
736 return Response(html)
736 return Response(html)
737
737
738 try:
738 try:
739 session = Session()
739 session = Session()
740 for setting in _LAB_SETTINGS:
740 for setting in _LAB_SETTINGS:
741 setting_name = setting.key[len('rhodecode_'):]
741 setting_name = setting.key[len('rhodecode_'):]
742 sett = SettingsModel().create_or_update_setting(
742 sett = SettingsModel().create_or_update_setting(
743 setting_name, form_result[setting.key], setting.type)
743 setting_name, form_result[setting.key], setting.type)
744 session.add(sett)
744 session.add(sett)
745
745
746 except Exception:
746 except Exception:
747 log.exception('Exception while updating lab settings')
747 log.exception('Exception while updating lab settings')
748 h.flash(_('Error occurred during updating labs settings'),
748 h.flash(_('Error occurred during updating labs settings'),
749 category='error')
749 category='error')
750 else:
750 else:
751 Session().commit()
751 Session().commit()
752 SettingsModel().invalidate_settings_cache()
752 SettingsModel().invalidate_settings_cache()
753 h.flash(_('Updated Labs settings'), category='success')
753 h.flash(_('Updated Labs settings'), category='success')
754 raise HTTPFound(h.route_path('admin_settings_labs'))
754 raise HTTPFound(h.route_path('admin_settings_labs'))
755
755
756 data = render('rhodecode:templates/admin/settings/settings.mako',
756 data = render('rhodecode:templates/admin/settings/settings.mako',
757 self._get_template_context(c), self.request)
757 self._get_template_context(c), self.request)
758 html = formencode.htmlfill.render(
758 html = formencode.htmlfill.render(
759 data,
759 data,
760 defaults=self._form_defaults(),
760 defaults=self._form_defaults(),
761 encoding="UTF-8",
761 encoding="UTF-8",
762 force_defaults=False
762 force_defaults=False
763 )
763 )
764 return Response(html)
764 return Response(html)
765
765
766
766
767 # :param key: name of the setting including the 'rhodecode_' prefix
767 # :param key: name of the setting including the 'rhodecode_' prefix
768 # :param type: the RhodeCodeSetting type to use.
768 # :param type: the RhodeCodeSetting type to use.
769 # :param group: the i18ned group in which we should dispaly this setting
769 # :param group: the i18ned group in which we should dispaly this setting
770 # :param label: the i18ned label we should display for this setting
770 # :param label: the i18ned label we should display for this setting
771 # :param help: the i18ned help we should dispaly for this setting
771 # :param help: the i18ned help we should dispaly for this setting
772 LabSetting = collections.namedtuple(
772 LabSetting = collections.namedtuple(
773 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
773 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
774
774
775
775
776 # This list has to be kept in sync with the form
776 # This list has to be kept in sync with the form
777 # rhodecode.model.forms.LabsSettingsForm.
777 # rhodecode.model.forms.LabsSettingsForm.
778 _LAB_SETTINGS = [
778 _LAB_SETTINGS = [
779
779
780 ]
780 ]
@@ -1,592 +1,592 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 The base Controller API
22 The base Controller API
23 Provides the BaseController class for subclassing. And usage in different
23 Provides the BaseController class for subclassing. And usage in different
24 controllers
24 controllers
25 """
25 """
26
26
27 import logging
27 import logging
28 import socket
28 import socket
29
29
30 import markupsafe
30 import markupsafe
31 import ipaddress
31 import ipaddress
32
32
33 from paste.auth.basic import AuthBasicAuthenticator
33 from paste.auth.basic import AuthBasicAuthenticator
34 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception
34 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception
35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
35 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
36
36
37 import rhodecode
37 import rhodecode
38 from rhodecode.apps._base import TemplateArgs
38 from rhodecode.apps._base import TemplateArgs
39 from rhodecode.authentication.base import VCS_TYPE
39 from rhodecode.authentication.base import VCS_TYPE
40 from rhodecode.lib import auth, utils2
40 from rhodecode.lib import auth, utils2
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib.auth import AuthUser, CookieStoreWrapper
42 from rhodecode.lib.auth import AuthUser, CookieStoreWrapper
43 from rhodecode.lib.exceptions import UserCreationError
43 from rhodecode.lib.exceptions import UserCreationError
44 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
44 from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes)
45 from rhodecode.lib.utils2 import (
45 from rhodecode.lib.utils2 import (
46 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
46 str2bool, safe_unicode, AttributeDict, safe_int, sha1, aslist, safe_str)
47 from rhodecode.model.db import Repository, User, ChangesetComment, UserBookmark
47 from rhodecode.model.db import Repository, User, ChangesetComment, UserBookmark
48 from rhodecode.model.notification import NotificationModel
48 from rhodecode.model.notification import NotificationModel
49 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
49 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 def _filter_proxy(ip):
54 def _filter_proxy(ip):
55 """
55 """
56 Passed in IP addresses in HEADERS can be in a special format of multiple
56 Passed in IP addresses in HEADERS can be in a special format of multiple
57 ips. Those comma separated IPs are passed from various proxies in the
57 ips. Those comma separated IPs are passed from various proxies in the
58 chain of request processing. The left-most being the original client.
58 chain of request processing. The left-most being the original client.
59 We only care about the first IP which came from the org. client.
59 We only care about the first IP which came from the org. client.
60
60
61 :param ip: ip string from headers
61 :param ip: ip string from headers
62 """
62 """
63 if ',' in ip:
63 if ',' in ip:
64 _ips = ip.split(',')
64 _ips = ip.split(',')
65 _first_ip = _ips[0].strip()
65 _first_ip = _ips[0].strip()
66 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
66 log.debug('Got multiple IPs %s, using %s', ','.join(_ips), _first_ip)
67 return _first_ip
67 return _first_ip
68 return ip
68 return ip
69
69
70
70
71 def _filter_port(ip):
71 def _filter_port(ip):
72 """
72 """
73 Removes a port from ip, there are 4 main cases to handle here.
73 Removes a port from ip, there are 4 main cases to handle here.
74 - ipv4 eg. 127.0.0.1
74 - ipv4 eg. 127.0.0.1
75 - ipv6 eg. ::1
75 - ipv6 eg. ::1
76 - ipv4+port eg. 127.0.0.1:8080
76 - ipv4+port eg. 127.0.0.1:8080
77 - ipv6+port eg. [::1]:8080
77 - ipv6+port eg. [::1]:8080
78
78
79 :param ip:
79 :param ip:
80 """
80 """
81 def is_ipv6(ip_addr):
81 def is_ipv6(ip_addr):
82 if hasattr(socket, 'inet_pton'):
82 if hasattr(socket, 'inet_pton'):
83 try:
83 try:
84 socket.inet_pton(socket.AF_INET6, ip_addr)
84 socket.inet_pton(socket.AF_INET6, ip_addr)
85 except socket.error:
85 except socket.error:
86 return False
86 return False
87 else:
87 else:
88 # fallback to ipaddress
88 # fallback to ipaddress
89 try:
89 try:
90 ipaddress.IPv6Address(safe_unicode(ip_addr))
90 ipaddress.IPv6Address(safe_unicode(ip_addr))
91 except Exception:
91 except Exception:
92 return False
92 return False
93 return True
93 return True
94
94
95 if ':' not in ip: # must be ipv4 pure ip
95 if ':' not in ip: # must be ipv4 pure ip
96 return ip
96 return ip
97
97
98 if '[' in ip and ']' in ip: # ipv6 with port
98 if '[' in ip and ']' in ip: # ipv6 with port
99 return ip.split(']')[0][1:].lower()
99 return ip.split(']')[0][1:].lower()
100
100
101 # must be ipv6 or ipv4 with port
101 # must be ipv6 or ipv4 with port
102 if is_ipv6(ip):
102 if is_ipv6(ip):
103 return ip
103 return ip
104 else:
104 else:
105 ip, _port = ip.split(':')[:2] # means ipv4+port
105 ip, _port = ip.split(':')[:2] # means ipv4+port
106 return ip
106 return ip
107
107
108
108
109 def get_ip_addr(environ):
109 def get_ip_addr(environ):
110 proxy_key = 'HTTP_X_REAL_IP'
110 proxy_key = 'HTTP_X_REAL_IP'
111 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
111 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
112 def_key = 'REMOTE_ADDR'
112 def_key = 'REMOTE_ADDR'
113 _filters = lambda x: _filter_port(_filter_proxy(x))
113 _filters = lambda x: _filter_port(_filter_proxy(x))
114
114
115 ip = environ.get(proxy_key)
115 ip = environ.get(proxy_key)
116 if ip:
116 if ip:
117 return _filters(ip)
117 return _filters(ip)
118
118
119 ip = environ.get(proxy_key2)
119 ip = environ.get(proxy_key2)
120 if ip:
120 if ip:
121 return _filters(ip)
121 return _filters(ip)
122
122
123 ip = environ.get(def_key, '0.0.0.0')
123 ip = environ.get(def_key, '0.0.0.0')
124 return _filters(ip)
124 return _filters(ip)
125
125
126
126
127 def get_server_ip_addr(environ, log_errors=True):
127 def get_server_ip_addr(environ, log_errors=True):
128 hostname = environ.get('SERVER_NAME')
128 hostname = environ.get('SERVER_NAME')
129 try:
129 try:
130 return socket.gethostbyname(hostname)
130 return socket.gethostbyname(hostname)
131 except Exception as e:
131 except Exception as e:
132 if log_errors:
132 if log_errors:
133 # in some cases this lookup is not possible, and we don't want to
133 # in some cases this lookup is not possible, and we don't want to
134 # make it an exception in logs
134 # make it an exception in logs
135 log.exception('Could not retrieve server ip address: %s', e)
135 log.exception('Could not retrieve server ip address: %s', e)
136 return hostname
136 return hostname
137
137
138
138
139 def get_server_port(environ):
139 def get_server_port(environ):
140 return environ.get('SERVER_PORT')
140 return environ.get('SERVER_PORT')
141
141
142
142
143 def get_access_path(environ):
143 def get_access_path(environ):
144 path = environ.get('PATH_INFO')
144 path = environ.get('PATH_INFO')
145 org_req = environ.get('pylons.original_request')
145 org_req = environ.get('pylons.original_request')
146 if org_req:
146 if org_req:
147 path = org_req.environ.get('PATH_INFO')
147 path = org_req.environ.get('PATH_INFO')
148 return path
148 return path
149
149
150
150
151 def get_user_agent(environ):
151 def get_user_agent(environ):
152 return environ.get('HTTP_USER_AGENT')
152 return environ.get('HTTP_USER_AGENT')
153
153
154
154
155 def vcs_operation_context(
155 def vcs_operation_context(
156 environ, repo_name, username, action, scm, check_locking=True,
156 environ, repo_name, username, action, scm, check_locking=True,
157 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
157 is_shadow_repo=False, check_branch_perms=False, detect_force_push=False):
158 """
158 """
159 Generate the context for a vcs operation, e.g. push or pull.
159 Generate the context for a vcs operation, e.g. push or pull.
160
160
161 This context is passed over the layers so that hooks triggered by the
161 This context is passed over the layers so that hooks triggered by the
162 vcs operation know details like the user, the user's IP address etc.
162 vcs operation know details like the user, the user's IP address etc.
163
163
164 :param check_locking: Allows to switch of the computation of the locking
164 :param check_locking: Allows to switch of the computation of the locking
165 data. This serves mainly the need of the simplevcs middleware to be
165 data. This serves mainly the need of the simplevcs middleware to be
166 able to disable this for certain operations.
166 able to disable this for certain operations.
167
167
168 """
168 """
169 # Tri-state value: False: unlock, None: nothing, True: lock
169 # Tri-state value: False: unlock, None: nothing, True: lock
170 make_lock = None
170 make_lock = None
171 locked_by = [None, None, None]
171 locked_by = [None, None, None]
172 is_anonymous = username == User.DEFAULT_USER
172 is_anonymous = username == User.DEFAULT_USER
173 user = User.get_by_username(username)
173 user = User.get_by_username(username)
174 if not is_anonymous and check_locking:
174 if not is_anonymous and check_locking:
175 log.debug('Checking locking on repository "%s"', repo_name)
175 log.debug('Checking locking on repository "%s"', repo_name)
176 repo = Repository.get_by_repo_name(repo_name)
176 repo = Repository.get_by_repo_name(repo_name)
177 make_lock, __, locked_by = repo.get_locking_state(
177 make_lock, __, locked_by = repo.get_locking_state(
178 action, user.user_id)
178 action, user.user_id)
179 user_id = user.user_id
179 user_id = user.user_id
180 settings_model = VcsSettingsModel(repo=repo_name)
180 settings_model = VcsSettingsModel(repo=repo_name)
181 ui_settings = settings_model.get_ui_settings()
181 ui_settings = settings_model.get_ui_settings()
182
182
183 # NOTE(marcink): This should be also in sync with
183 # NOTE(marcink): This should be also in sync with
184 # rhodecode/apps/ssh_support/lib/backends/base.py:update_environment scm_data
184 # rhodecode/apps/ssh_support/lib/backends/base.py:update_environment scm_data
185 store = [x for x in ui_settings if x.key == '/']
185 store = [x for x in ui_settings if x.key == '/']
186 repo_store = ''
186 repo_store = ''
187 if store:
187 if store:
188 repo_store = store[0].value
188 repo_store = store[0].value
189
189
190 scm_data = {
190 scm_data = {
191 'ip': get_ip_addr(environ),
191 'ip': get_ip_addr(environ),
192 'username': username,
192 'username': username,
193 'user_id': user_id,
193 'user_id': user_id,
194 'action': action,
194 'action': action,
195 'repository': repo_name,
195 'repository': repo_name,
196 'scm': scm,
196 'scm': scm,
197 'config': rhodecode.CONFIG['__file__'],
197 'config': rhodecode.CONFIG['__file__'],
198 'repo_store': repo_store,
198 'repo_store': repo_store,
199 'make_lock': make_lock,
199 'make_lock': make_lock,
200 'locked_by': locked_by,
200 'locked_by': locked_by,
201 'server_url': utils2.get_server_url(environ),
201 'server_url': utils2.get_server_url(environ),
202 'user_agent': get_user_agent(environ),
202 'user_agent': get_user_agent(environ),
203 'hooks': get_enabled_hook_classes(ui_settings),
203 'hooks': get_enabled_hook_classes(ui_settings),
204 'is_shadow_repo': is_shadow_repo,
204 'is_shadow_repo': is_shadow_repo,
205 'detect_force_push': detect_force_push,
205 'detect_force_push': detect_force_push,
206 'check_branch_perms': check_branch_perms,
206 'check_branch_perms': check_branch_perms,
207 }
207 }
208 return scm_data
208 return scm_data
209
209
210
210
211 class BasicAuth(AuthBasicAuthenticator):
211 class BasicAuth(AuthBasicAuthenticator):
212
212
213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
213 def __init__(self, realm, authfunc, registry, auth_http_code=None,
214 initial_call_detection=False, acl_repo_name=None):
214 initial_call_detection=False, acl_repo_name=None):
215 self.realm = realm
215 self.realm = realm
216 self.initial_call = initial_call_detection
216 self.initial_call = initial_call_detection
217 self.authfunc = authfunc
217 self.authfunc = authfunc
218 self.registry = registry
218 self.registry = registry
219 self.acl_repo_name = acl_repo_name
219 self.acl_repo_name = acl_repo_name
220 self._rc_auth_http_code = auth_http_code
220 self._rc_auth_http_code = auth_http_code
221
221
222 def _get_response_from_code(self, http_code):
222 def _get_response_from_code(self, http_code):
223 try:
223 try:
224 return get_exception(safe_int(http_code))
224 return get_exception(safe_int(http_code))
225 except Exception:
225 except Exception:
226 log.exception('Failed to fetch response for code %s', http_code)
226 log.exception('Failed to fetch response for code %s', http_code)
227 return HTTPForbidden
227 return HTTPForbidden
228
228
229 def get_rc_realm(self):
229 def get_rc_realm(self):
230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
230 return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
231
231
232 def build_authentication(self):
232 def build_authentication(self):
233 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
233 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
234 if self._rc_auth_http_code and not self.initial_call:
234 if self._rc_auth_http_code and not self.initial_call:
235 # return alternative HTTP code if alternative http return code
235 # return alternative HTTP code if alternative http return code
236 # is specified in RhodeCode config, but ONLY if it's not the
236 # is specified in RhodeCode config, but ONLY if it's not the
237 # FIRST call
237 # FIRST call
238 custom_response_klass = self._get_response_from_code(
238 custom_response_klass = self._get_response_from_code(
239 self._rc_auth_http_code)
239 self._rc_auth_http_code)
240 return custom_response_klass(headers=head)
240 return custom_response_klass(headers=head)
241 return HTTPUnauthorized(headers=head)
241 return HTTPUnauthorized(headers=head)
242
242
243 def authenticate(self, environ):
243 def authenticate(self, environ):
244 authorization = AUTHORIZATION(environ)
244 authorization = AUTHORIZATION(environ)
245 if not authorization:
245 if not authorization:
246 return self.build_authentication()
246 return self.build_authentication()
247 (authmeth, auth) = authorization.split(' ', 1)
247 (authmeth, auth) = authorization.split(' ', 1)
248 if 'basic' != authmeth.lower():
248 if 'basic' != authmeth.lower():
249 return self.build_authentication()
249 return self.build_authentication()
250 auth = auth.strip().decode('base64')
250 auth = auth.strip().decode('base64')
251 _parts = auth.split(':', 1)
251 _parts = auth.split(':', 1)
252 if len(_parts) == 2:
252 if len(_parts) == 2:
253 username, password = _parts
253 username, password = _parts
254 auth_data = self.authfunc(
254 auth_data = self.authfunc(
255 username, password, environ, VCS_TYPE,
255 username, password, environ, VCS_TYPE,
256 registry=self.registry, acl_repo_name=self.acl_repo_name)
256 registry=self.registry, acl_repo_name=self.acl_repo_name)
257 if auth_data:
257 if auth_data:
258 return {'username': username, 'auth_data': auth_data}
258 return {'username': username, 'auth_data': auth_data}
259 if username and password:
259 if username and password:
260 # we mark that we actually executed authentication once, at
260 # we mark that we actually executed authentication once, at
261 # that point we can use the alternative auth code
261 # that point we can use the alternative auth code
262 self.initial_call = False
262 self.initial_call = False
263
263
264 return self.build_authentication()
264 return self.build_authentication()
265
265
266 __call__ = authenticate
266 __call__ = authenticate
267
267
268
268
269 def calculate_version_hash(config):
269 def calculate_version_hash(config):
270 return sha1(
270 return sha1(
271 config.get('beaker.session.secret', '') +
271 config.get('beaker.session.secret', '') +
272 rhodecode.__version__)[:8]
272 rhodecode.__version__)[:8]
273
273
274
274
275 def get_current_lang(request):
275 def get_current_lang(request):
276 # NOTE(marcink): remove after pyramid move
276 # NOTE(marcink): remove after pyramid move
277 try:
277 try:
278 return translation.get_lang()[0]
278 return translation.get_lang()[0]
279 except:
279 except:
280 pass
280 pass
281
281
282 return getattr(request, '_LOCALE_', request.locale_name)
282 return getattr(request, '_LOCALE_', request.locale_name)
283
283
284
284
285 def attach_context_attributes(context, request, user_id=None):
285 def attach_context_attributes(context, request, user_id=None):
286 """
286 """
287 Attach variables into template context called `c`.
287 Attach variables into template context called `c`.
288 """
288 """
289 config = request.registry.settings
289 config = request.registry.settings
290
290
291 rc_config = SettingsModel().get_all_settings(cache=True)
291 rc_config = SettingsModel().get_all_settings(cache=True)
292
292 context.rc_config = rc_config
293 context.rhodecode_version = rhodecode.__version__
293 context.rhodecode_version = rhodecode.__version__
294 context.rhodecode_edition = config.get('rhodecode.edition')
294 context.rhodecode_edition = config.get('rhodecode.edition')
295 # unique secret + version does not leak the version but keep consistency
295 # unique secret + version does not leak the version but keep consistency
296 context.rhodecode_version_hash = calculate_version_hash(config)
296 context.rhodecode_version_hash = calculate_version_hash(config)
297
297
298 # Default language set for the incoming request
298 # Default language set for the incoming request
299 context.language = get_current_lang(request)
299 context.language = get_current_lang(request)
300
300
301 # Visual options
301 # Visual options
302 context.visual = AttributeDict({})
302 context.visual = AttributeDict({})
303
303
304 # DB stored Visual Items
304 # DB stored Visual Items
305 context.visual.show_public_icon = str2bool(
305 context.visual.show_public_icon = str2bool(
306 rc_config.get('rhodecode_show_public_icon'))
306 rc_config.get('rhodecode_show_public_icon'))
307 context.visual.show_private_icon = str2bool(
307 context.visual.show_private_icon = str2bool(
308 rc_config.get('rhodecode_show_private_icon'))
308 rc_config.get('rhodecode_show_private_icon'))
309 context.visual.stylify_metatags = str2bool(
309 context.visual.stylify_metatags = str2bool(
310 rc_config.get('rhodecode_stylify_metatags'))
310 rc_config.get('rhodecode_stylify_metatags'))
311 context.visual.dashboard_items = safe_int(
311 context.visual.dashboard_items = safe_int(
312 rc_config.get('rhodecode_dashboard_items', 100))
312 rc_config.get('rhodecode_dashboard_items', 100))
313 context.visual.admin_grid_items = safe_int(
313 context.visual.admin_grid_items = safe_int(
314 rc_config.get('rhodecode_admin_grid_items', 100))
314 rc_config.get('rhodecode_admin_grid_items', 100))
315 context.visual.show_revision_number = str2bool(
315 context.visual.show_revision_number = str2bool(
316 rc_config.get('rhodecode_show_revision_number', True))
316 rc_config.get('rhodecode_show_revision_number', True))
317 context.visual.show_sha_length = safe_int(
317 context.visual.show_sha_length = safe_int(
318 rc_config.get('rhodecode_show_sha_length', 100))
318 rc_config.get('rhodecode_show_sha_length', 100))
319 context.visual.repository_fields = str2bool(
319 context.visual.repository_fields = str2bool(
320 rc_config.get('rhodecode_repository_fields'))
320 rc_config.get('rhodecode_repository_fields'))
321 context.visual.show_version = str2bool(
321 context.visual.show_version = str2bool(
322 rc_config.get('rhodecode_show_version'))
322 rc_config.get('rhodecode_show_version'))
323 context.visual.use_gravatar = str2bool(
323 context.visual.use_gravatar = str2bool(
324 rc_config.get('rhodecode_use_gravatar'))
324 rc_config.get('rhodecode_use_gravatar'))
325 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
325 context.visual.gravatar_url = rc_config.get('rhodecode_gravatar_url')
326 context.visual.default_renderer = rc_config.get(
326 context.visual.default_renderer = rc_config.get(
327 'rhodecode_markup_renderer', 'rst')
327 'rhodecode_markup_renderer', 'rst')
328 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
328 context.visual.comment_types = ChangesetComment.COMMENT_TYPES
329 context.visual.rhodecode_support_url = \
329 context.visual.rhodecode_support_url = \
330 rc_config.get('rhodecode_support_url') or h.route_url('rhodecode_support')
330 rc_config.get('rhodecode_support_url') or h.route_url('rhodecode_support')
331
331
332 context.visual.affected_files_cut_off = 60
332 context.visual.affected_files_cut_off = 60
333
333
334 context.pre_code = rc_config.get('rhodecode_pre_code')
334 context.pre_code = rc_config.get('rhodecode_pre_code')
335 context.post_code = rc_config.get('rhodecode_post_code')
335 context.post_code = rc_config.get('rhodecode_post_code')
336 context.rhodecode_name = rc_config.get('rhodecode_title')
336 context.rhodecode_name = rc_config.get('rhodecode_title')
337 context.default_encodings = aslist(config.get('default_encoding'), sep=',')
337 context.default_encodings = aslist(config.get('default_encoding'), sep=',')
338 # if we have specified default_encoding in the request, it has more
338 # if we have specified default_encoding in the request, it has more
339 # priority
339 # priority
340 if request.GET.get('default_encoding'):
340 if request.GET.get('default_encoding'):
341 context.default_encodings.insert(0, request.GET.get('default_encoding'))
341 context.default_encodings.insert(0, request.GET.get('default_encoding'))
342 context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
342 context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl')
343 context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl')
343 context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl')
344
344
345 # INI stored
345 # INI stored
346 context.labs_active = str2bool(
346 context.labs_active = str2bool(
347 config.get('labs_settings_active', 'false'))
347 config.get('labs_settings_active', 'false'))
348 context.ssh_enabled = str2bool(
348 context.ssh_enabled = str2bool(
349 config.get('ssh.generate_authorized_keyfile', 'false'))
349 config.get('ssh.generate_authorized_keyfile', 'false'))
350 context.ssh_key_generator_enabled = str2bool(
350 context.ssh_key_generator_enabled = str2bool(
351 config.get('ssh.enable_ui_key_generator', 'true'))
351 config.get('ssh.enable_ui_key_generator', 'true'))
352
352
353 context.visual.allow_repo_location_change = str2bool(
353 context.visual.allow_repo_location_change = str2bool(
354 config.get('allow_repo_location_change', True))
354 config.get('allow_repo_location_change', True))
355 context.visual.allow_custom_hooks_settings = str2bool(
355 context.visual.allow_custom_hooks_settings = str2bool(
356 config.get('allow_custom_hooks_settings', True))
356 config.get('allow_custom_hooks_settings', True))
357 context.debug_style = str2bool(config.get('debug_style', False))
357 context.debug_style = str2bool(config.get('debug_style', False))
358
358
359 context.rhodecode_instanceid = config.get('instance_id')
359 context.rhodecode_instanceid = config.get('instance_id')
360
360
361 context.visual.cut_off_limit_diff = safe_int(
361 context.visual.cut_off_limit_diff = safe_int(
362 config.get('cut_off_limit_diff'))
362 config.get('cut_off_limit_diff'))
363 context.visual.cut_off_limit_file = safe_int(
363 context.visual.cut_off_limit_file = safe_int(
364 config.get('cut_off_limit_file'))
364 config.get('cut_off_limit_file'))
365
365
366 # AppEnlight
366 # AppEnlight
367 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
367 context.appenlight_enabled = str2bool(config.get('appenlight', 'false'))
368 context.appenlight_api_public_key = config.get(
368 context.appenlight_api_public_key = config.get(
369 'appenlight.api_public_key', '')
369 'appenlight.api_public_key', '')
370 context.appenlight_server_url = config.get('appenlight.server_url', '')
370 context.appenlight_server_url = config.get('appenlight.server_url', '')
371
371
372 diffmode = {
372 diffmode = {
373 "unified": "unified",
373 "unified": "unified",
374 "sideside": "sideside"
374 "sideside": "sideside"
375 }.get(request.GET.get('diffmode'))
375 }.get(request.GET.get('diffmode'))
376
376
377 is_api = hasattr(request, 'rpc_user')
377 is_api = hasattr(request, 'rpc_user')
378 session_attrs = {
378 session_attrs = {
379 # defaults
379 # defaults
380 "clone_url_format": "http",
380 "clone_url_format": "http",
381 "diffmode": "sideside"
381 "diffmode": "sideside"
382 }
382 }
383
383
384 if not is_api:
384 if not is_api:
385 # don't access pyramid session for API calls
385 # don't access pyramid session for API calls
386 if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'):
386 if diffmode and diffmode != request.session.get('rc_user_session_attr.diffmode'):
387 request.session['rc_user_session_attr.diffmode'] = diffmode
387 request.session['rc_user_session_attr.diffmode'] = diffmode
388
388
389 # session settings per user
389 # session settings per user
390
390
391 for k, v in request.session.items():
391 for k, v in request.session.items():
392 pref = 'rc_user_session_attr.'
392 pref = 'rc_user_session_attr.'
393 if k and k.startswith(pref):
393 if k and k.startswith(pref):
394 k = k[len(pref):]
394 k = k[len(pref):]
395 session_attrs[k] = v
395 session_attrs[k] = v
396
396
397 context.user_session_attrs = session_attrs
397 context.user_session_attrs = session_attrs
398
398
399 # JS template context
399 # JS template context
400 context.template_context = {
400 context.template_context = {
401 'repo_name': None,
401 'repo_name': None,
402 'repo_type': None,
402 'repo_type': None,
403 'repo_landing_commit': None,
403 'repo_landing_commit': None,
404 'rhodecode_user': {
404 'rhodecode_user': {
405 'username': None,
405 'username': None,
406 'email': None,
406 'email': None,
407 'notification_status': False
407 'notification_status': False
408 },
408 },
409 'session_attrs': session_attrs,
409 'session_attrs': session_attrs,
410 'visual': {
410 'visual': {
411 'default_renderer': None
411 'default_renderer': None
412 },
412 },
413 'commit_data': {
413 'commit_data': {
414 'commit_id': None
414 'commit_id': None
415 },
415 },
416 'pull_request_data': {'pull_request_id': None},
416 'pull_request_data': {'pull_request_id': None},
417 'timeago': {
417 'timeago': {
418 'refresh_time': 120 * 1000,
418 'refresh_time': 120 * 1000,
419 'cutoff_limit': 1000 * 60 * 60 * 24 * 7
419 'cutoff_limit': 1000 * 60 * 60 * 24 * 7
420 },
420 },
421 'pyramid_dispatch': {
421 'pyramid_dispatch': {
422
422
423 },
423 },
424 'extra': {'plugins': {}}
424 'extra': {'plugins': {}}
425 }
425 }
426 # END CONFIG VARS
426 # END CONFIG VARS
427 if is_api:
427 if is_api:
428 csrf_token = None
428 csrf_token = None
429 else:
429 else:
430 csrf_token = auth.get_csrf_token(session=request.session)
430 csrf_token = auth.get_csrf_token(session=request.session)
431
431
432 context.csrf_token = csrf_token
432 context.csrf_token = csrf_token
433 context.backends = rhodecode.BACKENDS.keys()
433 context.backends = rhodecode.BACKENDS.keys()
434 context.backends.sort()
434 context.backends.sort()
435 unread_count = 0
435 unread_count = 0
436 user_bookmark_list = []
436 user_bookmark_list = []
437 if user_id:
437 if user_id:
438 unread_count = NotificationModel().get_unread_cnt_for_user(user_id)
438 unread_count = NotificationModel().get_unread_cnt_for_user(user_id)
439 user_bookmark_list = UserBookmark.get_bookmarks_for_user(user_id)
439 user_bookmark_list = UserBookmark.get_bookmarks_for_user(user_id)
440 context.unread_notifications = unread_count
440 context.unread_notifications = unread_count
441 context.bookmark_items = user_bookmark_list
441 context.bookmark_items = user_bookmark_list
442
442
443 # web case
443 # web case
444 if hasattr(request, 'user'):
444 if hasattr(request, 'user'):
445 context.auth_user = request.user
445 context.auth_user = request.user
446 context.rhodecode_user = request.user
446 context.rhodecode_user = request.user
447
447
448 # api case
448 # api case
449 if hasattr(request, 'rpc_user'):
449 if hasattr(request, 'rpc_user'):
450 context.auth_user = request.rpc_user
450 context.auth_user = request.rpc_user
451 context.rhodecode_user = request.rpc_user
451 context.rhodecode_user = request.rpc_user
452
452
453 # attach the whole call context to the request
453 # attach the whole call context to the request
454 request.call_context = context
454 request.call_context = context
455
455
456
456
457 def get_auth_user(request):
457 def get_auth_user(request):
458 environ = request.environ
458 environ = request.environ
459 session = request.session
459 session = request.session
460
460
461 ip_addr = get_ip_addr(environ)
461 ip_addr = get_ip_addr(environ)
462 # make sure that we update permissions each time we call controller
462 # make sure that we update permissions each time we call controller
463 _auth_token = (request.GET.get('auth_token', '') or
463 _auth_token = (request.GET.get('auth_token', '') or
464 request.GET.get('api_key', ''))
464 request.GET.get('api_key', ''))
465
465
466 if _auth_token:
466 if _auth_token:
467 # when using API_KEY we assume user exists, and
467 # when using API_KEY we assume user exists, and
468 # doesn't need auth based on cookies.
468 # doesn't need auth based on cookies.
469 auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr)
469 auth_user = AuthUser(api_key=_auth_token, ip_addr=ip_addr)
470 authenticated = False
470 authenticated = False
471 else:
471 else:
472 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
472 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
473 try:
473 try:
474 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
474 auth_user = AuthUser(user_id=cookie_store.get('user_id', None),
475 ip_addr=ip_addr)
475 ip_addr=ip_addr)
476 except UserCreationError as e:
476 except UserCreationError as e:
477 h.flash(e, 'error')
477 h.flash(e, 'error')
478 # container auth or other auth functions that create users
478 # container auth or other auth functions that create users
479 # on the fly can throw this exception signaling that there's
479 # on the fly can throw this exception signaling that there's
480 # issue with user creation, explanation should be provided
480 # issue with user creation, explanation should be provided
481 # in Exception itself. We then create a simple blank
481 # in Exception itself. We then create a simple blank
482 # AuthUser
482 # AuthUser
483 auth_user = AuthUser(ip_addr=ip_addr)
483 auth_user = AuthUser(ip_addr=ip_addr)
484
484
485 # in case someone changes a password for user it triggers session
485 # in case someone changes a password for user it triggers session
486 # flush and forces a re-login
486 # flush and forces a re-login
487 if password_changed(auth_user, session):
487 if password_changed(auth_user, session):
488 session.invalidate()
488 session.invalidate()
489 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
489 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
490 auth_user = AuthUser(ip_addr=ip_addr)
490 auth_user = AuthUser(ip_addr=ip_addr)
491
491
492 authenticated = cookie_store.get('is_authenticated')
492 authenticated = cookie_store.get('is_authenticated')
493
493
494 if not auth_user.is_authenticated and auth_user.is_user_object:
494 if not auth_user.is_authenticated and auth_user.is_user_object:
495 # user is not authenticated and not empty
495 # user is not authenticated and not empty
496 auth_user.set_authenticated(authenticated)
496 auth_user.set_authenticated(authenticated)
497
497
498 return auth_user
498 return auth_user
499
499
500
500
501 def h_filter(s):
501 def h_filter(s):
502 """
502 """
503 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
503 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
504 we wrap this with additional functionality that converts None to empty
504 we wrap this with additional functionality that converts None to empty
505 strings
505 strings
506 """
506 """
507 if s is None:
507 if s is None:
508 return markupsafe.Markup()
508 return markupsafe.Markup()
509 return markupsafe.escape(s)
509 return markupsafe.escape(s)
510
510
511
511
512 def add_events_routes(config):
512 def add_events_routes(config):
513 """
513 """
514 Adds routing that can be used in events. Because some events are triggered
514 Adds routing that can be used in events. Because some events are triggered
515 outside of pyramid context, we need to bootstrap request with some
515 outside of pyramid context, we need to bootstrap request with some
516 routing registered
516 routing registered
517 """
517 """
518
518
519 from rhodecode.apps._base import ADMIN_PREFIX
519 from rhodecode.apps._base import ADMIN_PREFIX
520
520
521 config.add_route(name='home', pattern='/')
521 config.add_route(name='home', pattern='/')
522
522
523 config.add_route(name='login', pattern=ADMIN_PREFIX + '/login')
523 config.add_route(name='login', pattern=ADMIN_PREFIX + '/login')
524 config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout')
524 config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout')
525 config.add_route(name='repo_summary', pattern='/{repo_name}')
525 config.add_route(name='repo_summary', pattern='/{repo_name}')
526 config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary')
526 config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary')
527 config.add_route(name='repo_group_home', pattern='/{repo_group_name}')
527 config.add_route(name='repo_group_home', pattern='/{repo_group_name}')
528
528
529 config.add_route(name='pullrequest_show',
529 config.add_route(name='pullrequest_show',
530 pattern='/{repo_name}/pull-request/{pull_request_id}')
530 pattern='/{repo_name}/pull-request/{pull_request_id}')
531 config.add_route(name='pull_requests_global',
531 config.add_route(name='pull_requests_global',
532 pattern='/pull-request/{pull_request_id}')
532 pattern='/pull-request/{pull_request_id}')
533 config.add_route(name='repo_commit',
533 config.add_route(name='repo_commit',
534 pattern='/{repo_name}/changeset/{commit_id}')
534 pattern='/{repo_name}/changeset/{commit_id}')
535
535
536 config.add_route(name='repo_files',
536 config.add_route(name='repo_files',
537 pattern='/{repo_name}/files/{commit_id}/{f_path}')
537 pattern='/{repo_name}/files/{commit_id}/{f_path}')
538
538
539
539
540 def bootstrap_config(request):
540 def bootstrap_config(request):
541 import pyramid.testing
541 import pyramid.testing
542 registry = pyramid.testing.Registry('RcTestRegistry')
542 registry = pyramid.testing.Registry('RcTestRegistry')
543
543
544 config = pyramid.testing.setUp(registry=registry, request=request)
544 config = pyramid.testing.setUp(registry=registry, request=request)
545
545
546 # allow pyramid lookup in testing
546 # allow pyramid lookup in testing
547 config.include('pyramid_mako')
547 config.include('pyramid_mako')
548 config.include('rhodecode.lib.rc_beaker')
548 config.include('rhodecode.lib.rc_beaker')
549 config.include('rhodecode.lib.rc_cache')
549 config.include('rhodecode.lib.rc_cache')
550
550
551 add_events_routes(config)
551 add_events_routes(config)
552
552
553 return config
553 return config
554
554
555
555
556 def bootstrap_request(**kwargs):
556 def bootstrap_request(**kwargs):
557 import pyramid.testing
557 import pyramid.testing
558
558
559 class TestRequest(pyramid.testing.DummyRequest):
559 class TestRequest(pyramid.testing.DummyRequest):
560 application_url = kwargs.pop('application_url', 'http://example.com')
560 application_url = kwargs.pop('application_url', 'http://example.com')
561 host = kwargs.pop('host', 'example.com:80')
561 host = kwargs.pop('host', 'example.com:80')
562 domain = kwargs.pop('domain', 'example.com')
562 domain = kwargs.pop('domain', 'example.com')
563
563
564 def translate(self, msg):
564 def translate(self, msg):
565 return msg
565 return msg
566
566
567 def plularize(self, singular, plural, n):
567 def plularize(self, singular, plural, n):
568 return singular
568 return singular
569
569
570 def get_partial_renderer(self, tmpl_name):
570 def get_partial_renderer(self, tmpl_name):
571
571
572 from rhodecode.lib.partial_renderer import get_partial_renderer
572 from rhodecode.lib.partial_renderer import get_partial_renderer
573 return get_partial_renderer(request=self, tmpl_name=tmpl_name)
573 return get_partial_renderer(request=self, tmpl_name=tmpl_name)
574
574
575 _call_context = TemplateArgs()
575 _call_context = TemplateArgs()
576 _call_context.visual = TemplateArgs()
576 _call_context.visual = TemplateArgs()
577 _call_context.visual.show_sha_length = 12
577 _call_context.visual.show_sha_length = 12
578 _call_context.visual.show_revision_number = True
578 _call_context.visual.show_revision_number = True
579
579
580 @property
580 @property
581 def call_context(self):
581 def call_context(self):
582 return self._call_context
582 return self._call_context
583
583
584 class TestDummySession(pyramid.testing.DummySession):
584 class TestDummySession(pyramid.testing.DummySession):
585 def save(*arg, **kw):
585 def save(*arg, **kw):
586 pass
586 pass
587
587
588 request = TestRequest(**kwargs)
588 request = TestRequest(**kwargs)
589 request.session = TestDummySession()
589 request.session = TestDummySession()
590
590
591 return request
591 return request
592
592
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now