##// END OF EJS Templates
settings: use invalidate after updating settings.
marcink -
r276:7f18164f default
parent child Browse files
Show More
@@ -1,852 +1,854 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
22 """
23 settings controller for rhodecode admin
23 settings controller for rhodecode admin
24 """
24 """
25
25
26 import collections
26 import collections
27 import logging
27 import logging
28 import urllib2
28 import urllib2
29
29
30 import datetime
30 import datetime
31 import formencode
31 import formencode
32 from formencode import htmlfill
32 from formencode import htmlfill
33 import packaging.version
33 import packaging.version
34 from pylons import request, tmpl_context as c, url, config
34 from pylons import request, tmpl_context as c, url, config
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _, lazy_ugettext
36 from pylons.i18n.translation import _, lazy_ugettext
37 from webob.exc import HTTPBadRequest
37 from webob.exc import HTTPBadRequest
38
38
39 import rhodecode
39 import rhodecode
40 from rhodecode.lib import auth
40 from rhodecode.lib import auth
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
42 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.celerylib import tasks, run_task
44 from rhodecode.lib.celerylib import tasks, run_task
45 from rhodecode.lib.utils import repo2db_mapper
45 from rhodecode.lib.utils import repo2db_mapper
46 from rhodecode.lib.utils2 import (
46 from rhodecode.lib.utils2 import (
47 str2bool, safe_unicode, AttributeDict, safe_int)
47 str2bool, safe_unicode, AttributeDict, safe_int)
48 from rhodecode.lib.compat import OrderedDict
48 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.ext_json import json
49 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.utils import jsonify
50 from rhodecode.lib.utils import jsonify
51
51
52 from rhodecode.model.db import RhodeCodeUi, Repository
52 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.forms import ApplicationSettingsForm, \
53 from rhodecode.model.forms import ApplicationSettingsForm, \
54 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
54 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
55 LabsSettingsForm, IssueTrackerPatternsForm
55 LabsSettingsForm, IssueTrackerPatternsForm
56
56
57 from rhodecode.model.scm import ScmModel
57 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.notification import EmailNotificationModel
58 from rhodecode.model.notification import EmailNotificationModel
59 from rhodecode.model.meta import Session
59 from rhodecode.model.meta import Session
60 from rhodecode.model.settings import (
60 from rhodecode.model.settings import (
61 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
61 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 SettingsModel)
62 SettingsModel)
63 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
63 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
64
64
65
65
66 log = logging.getLogger(__name__)
66 log = logging.getLogger(__name__)
67
67
68
68
69 class SettingsController(BaseController):
69 class SettingsController(BaseController):
70 """REST Controller styled on the Atom Publishing Protocol"""
70 """REST Controller styled on the Atom Publishing Protocol"""
71 # To properly map this controller, ensure your config/routing.py
71 # To properly map this controller, ensure your config/routing.py
72 # file has a resource setup:
72 # file has a resource setup:
73 # map.resource('setting', 'settings', controller='admin/settings',
73 # map.resource('setting', 'settings', controller='admin/settings',
74 # path_prefix='/admin', name_prefix='admin_')
74 # path_prefix='/admin', name_prefix='admin_')
75
75
76 @LoginRequired()
76 @LoginRequired()
77 def __before__(self):
77 def __before__(self):
78 super(SettingsController, self).__before__()
78 super(SettingsController, self).__before__()
79 c.labs_active = str2bool(
79 c.labs_active = str2bool(
80 rhodecode.CONFIG.get('labs_settings_active', 'false'))
80 rhodecode.CONFIG.get('labs_settings_active', 'false'))
81 c.navlist = navigation.get_navlist(request)
81 c.navlist = navigation.get_navlist(request)
82
82
83 def _get_hg_ui_settings(self):
83 def _get_hg_ui_settings(self):
84 ret = RhodeCodeUi.query().all()
84 ret = RhodeCodeUi.query().all()
85
85
86 if not ret:
86 if not ret:
87 raise Exception('Could not get application ui settings !')
87 raise Exception('Could not get application ui settings !')
88 settings = {}
88 settings = {}
89 for each in ret:
89 for each in ret:
90 k = each.ui_key
90 k = each.ui_key
91 v = each.ui_value
91 v = each.ui_value
92 if k == '/':
92 if k == '/':
93 k = 'root_path'
93 k = 'root_path'
94
94
95 if k in ['push_ssl', 'publish']:
95 if k in ['push_ssl', 'publish']:
96 v = str2bool(v)
96 v = str2bool(v)
97
97
98 if k.find('.') != -1:
98 if k.find('.') != -1:
99 k = k.replace('.', '_')
99 k = k.replace('.', '_')
100
100
101 if each.ui_section in ['hooks', 'extensions']:
101 if each.ui_section in ['hooks', 'extensions']:
102 v = each.ui_active
102 v = each.ui_active
103
103
104 settings[each.ui_section + '_' + k] = v
104 settings[each.ui_section + '_' + k] = v
105 return settings
105 return settings
106
106
107 @HasPermissionAllDecorator('hg.admin')
107 @HasPermissionAllDecorator('hg.admin')
108 @auth.CSRFRequired()
108 @auth.CSRFRequired()
109 @jsonify
109 @jsonify
110 def delete_svn_pattern(self):
110 def delete_svn_pattern(self):
111 if not request.is_xhr:
111 if not request.is_xhr:
112 raise HTTPBadRequest()
112 raise HTTPBadRequest()
113
113
114 delete_pattern_id = request.POST.get('delete_svn_pattern')
114 delete_pattern_id = request.POST.get('delete_svn_pattern')
115 model = VcsSettingsModel()
115 model = VcsSettingsModel()
116 try:
116 try:
117 model.delete_global_svn_pattern(delete_pattern_id)
117 model.delete_global_svn_pattern(delete_pattern_id)
118 except SettingNotFound:
118 except SettingNotFound:
119 raise HTTPBadRequest()
119 raise HTTPBadRequest()
120
120
121 Session().commit()
121 Session().commit()
122 return True
122 return True
123
123
124 @HasPermissionAllDecorator('hg.admin')
124 @HasPermissionAllDecorator('hg.admin')
125 @auth.CSRFRequired()
125 @auth.CSRFRequired()
126 def settings_vcs_update(self):
126 def settings_vcs_update(self):
127 """POST /admin/settings: All items in the collection"""
127 """POST /admin/settings: All items in the collection"""
128 # url('admin_settings_vcs')
128 # url('admin_settings_vcs')
129 c.active = 'vcs'
129 c.active = 'vcs'
130
130
131 model = VcsSettingsModel()
131 model = VcsSettingsModel()
132 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
132 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
133 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
133 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
134
134
135 application_form = ApplicationUiSettingsForm()()
135 application_form = ApplicationUiSettingsForm()()
136 try:
136 try:
137 form_result = application_form.to_python(dict(request.POST))
137 form_result = application_form.to_python(dict(request.POST))
138 except formencode.Invalid as errors:
138 except formencode.Invalid as errors:
139 h.flash(
139 h.flash(
140 _("Some form inputs contain invalid data."),
140 _("Some form inputs contain invalid data."),
141 category='error')
141 category='error')
142 return htmlfill.render(
142 return htmlfill.render(
143 render('admin/settings/settings.html'),
143 render('admin/settings/settings.html'),
144 defaults=errors.value,
144 defaults=errors.value,
145 errors=errors.error_dict or {},
145 errors=errors.error_dict or {},
146 prefix_error=False,
146 prefix_error=False,
147 encoding="UTF-8",
147 encoding="UTF-8",
148 force_defaults=False
148 force_defaults=False
149 )
149 )
150
150
151 try:
151 try:
152 model.update_global_ssl_setting(form_result['web_push_ssl'])
152 model.update_global_ssl_setting(form_result['web_push_ssl'])
153 if c.visual.allow_repo_location_change:
153 if c.visual.allow_repo_location_change:
154 model.update_global_path_setting(
154 model.update_global_path_setting(
155 form_result['paths_root_path'])
155 form_result['paths_root_path'])
156 model.update_global_hook_settings(form_result)
156 model.update_global_hook_settings(form_result)
157 model.create_global_svn_settings(form_result)
157 model.create_global_svn_settings(form_result)
158 model.create_or_update_global_hg_settings(form_result)
158 model.create_or_update_global_hg_settings(form_result)
159 model.create_or_update_global_pr_settings(form_result)
159 model.create_or_update_global_pr_settings(form_result)
160 except Exception:
160 except Exception:
161 log.exception("Exception while updating settings")
161 log.exception("Exception while updating settings")
162 h.flash(_('Error occurred during updating '
162 h.flash(_('Error occurred during updating '
163 'application settings'), category='error')
163 'application settings'), category='error')
164 else:
164 else:
165 Session().commit()
165 Session().commit()
166 h.flash(_('Updated VCS settings'), category='success')
166 h.flash(_('Updated VCS settings'), category='success')
167 return redirect(url('admin_settings_vcs'))
167 return redirect(url('admin_settings_vcs'))
168
168
169 return htmlfill.render(
169 return htmlfill.render(
170 render('admin/settings/settings.html'),
170 render('admin/settings/settings.html'),
171 defaults=self._form_defaults(),
171 defaults=self._form_defaults(),
172 encoding="UTF-8",
172 encoding="UTF-8",
173 force_defaults=False)
173 force_defaults=False)
174
174
175 @HasPermissionAllDecorator('hg.admin')
175 @HasPermissionAllDecorator('hg.admin')
176 def settings_vcs(self):
176 def settings_vcs(self):
177 """GET /admin/settings: All items in the collection"""
177 """GET /admin/settings: All items in the collection"""
178 # url('admin_settings_vcs')
178 # url('admin_settings_vcs')
179 c.active = 'vcs'
179 c.active = 'vcs'
180 model = VcsSettingsModel()
180 model = VcsSettingsModel()
181 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
181 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
182 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
182 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
183
183
184 return htmlfill.render(
184 return htmlfill.render(
185 render('admin/settings/settings.html'),
185 render('admin/settings/settings.html'),
186 defaults=self._form_defaults(),
186 defaults=self._form_defaults(),
187 encoding="UTF-8",
187 encoding="UTF-8",
188 force_defaults=False)
188 force_defaults=False)
189
189
190 @HasPermissionAllDecorator('hg.admin')
190 @HasPermissionAllDecorator('hg.admin')
191 @auth.CSRFRequired()
191 @auth.CSRFRequired()
192 def settings_mapping_update(self):
192 def settings_mapping_update(self):
193 """POST /admin/settings/mapping: All items in the collection"""
193 """POST /admin/settings/mapping: All items in the collection"""
194 # url('admin_settings_mapping')
194 # url('admin_settings_mapping')
195 c.active = 'mapping'
195 c.active = 'mapping'
196 rm_obsolete = request.POST.get('destroy', False)
196 rm_obsolete = request.POST.get('destroy', False)
197 invalidate_cache = request.POST.get('invalidate', False)
197 invalidate_cache = request.POST.get('invalidate', False)
198 log.debug(
198 log.debug(
199 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
199 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
200
200
201 if invalidate_cache:
201 if invalidate_cache:
202 log.debug('invalidating all repositories cache')
202 log.debug('invalidating all repositories cache')
203 for repo in Repository.get_all():
203 for repo in Repository.get_all():
204 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
204 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
205
205
206 filesystem_repos = ScmModel().repo_scan()
206 filesystem_repos = ScmModel().repo_scan()
207 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
207 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
208 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
208 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
209 h.flash(_('Repositories successfully '
209 h.flash(_('Repositories successfully '
210 'rescanned added: %s ; removed: %s') %
210 'rescanned added: %s ; removed: %s') %
211 (_repr(added), _repr(removed)),
211 (_repr(added), _repr(removed)),
212 category='success')
212 category='success')
213 return redirect(url('admin_settings_mapping'))
213 return redirect(url('admin_settings_mapping'))
214
214
215 @HasPermissionAllDecorator('hg.admin')
215 @HasPermissionAllDecorator('hg.admin')
216 def settings_mapping(self):
216 def settings_mapping(self):
217 """GET /admin/settings/mapping: All items in the collection"""
217 """GET /admin/settings/mapping: All items in the collection"""
218 # url('admin_settings_mapping')
218 # url('admin_settings_mapping')
219 c.active = 'mapping'
219 c.active = 'mapping'
220
220
221 return htmlfill.render(
221 return htmlfill.render(
222 render('admin/settings/settings.html'),
222 render('admin/settings/settings.html'),
223 defaults=self._form_defaults(),
223 defaults=self._form_defaults(),
224 encoding="UTF-8",
224 encoding="UTF-8",
225 force_defaults=False)
225 force_defaults=False)
226
226
227 @HasPermissionAllDecorator('hg.admin')
227 @HasPermissionAllDecorator('hg.admin')
228 @auth.CSRFRequired()
228 @auth.CSRFRequired()
229 def settings_global_update(self):
229 def settings_global_update(self):
230 """POST /admin/settings/global: All items in the collection"""
230 """POST /admin/settings/global: All items in the collection"""
231 # url('admin_settings_global')
231 # url('admin_settings_global')
232 c.active = 'global'
232 c.active = 'global'
233 application_form = ApplicationSettingsForm()()
233 application_form = ApplicationSettingsForm()()
234 try:
234 try:
235 form_result = application_form.to_python(dict(request.POST))
235 form_result = application_form.to_python(dict(request.POST))
236 except formencode.Invalid as errors:
236 except formencode.Invalid as errors:
237 return htmlfill.render(
237 return htmlfill.render(
238 render('admin/settings/settings.html'),
238 render('admin/settings/settings.html'),
239 defaults=errors.value,
239 defaults=errors.value,
240 errors=errors.error_dict or {},
240 errors=errors.error_dict or {},
241 prefix_error=False,
241 prefix_error=False,
242 encoding="UTF-8",
242 encoding="UTF-8",
243 force_defaults=False)
243 force_defaults=False)
244
244
245 try:
245 try:
246 settings = [
246 settings = [
247 ('title', 'rhodecode_title'),
247 ('title', 'rhodecode_title'),
248 ('realm', 'rhodecode_realm'),
248 ('realm', 'rhodecode_realm'),
249 ('pre_code', 'rhodecode_pre_code'),
249 ('pre_code', 'rhodecode_pre_code'),
250 ('post_code', 'rhodecode_post_code'),
250 ('post_code', 'rhodecode_post_code'),
251 ('captcha_public_key', 'rhodecode_captcha_public_key'),
251 ('captcha_public_key', 'rhodecode_captcha_public_key'),
252 ('captcha_private_key', 'rhodecode_captcha_private_key'),
252 ('captcha_private_key', 'rhodecode_captcha_private_key'),
253 ]
253 ]
254 for setting, form_key in settings:
254 for setting, form_key in settings:
255 sett = SettingsModel().create_or_update_setting(
255 sett = SettingsModel().create_or_update_setting(
256 setting, form_result[form_key])
256 setting, form_result[form_key])
257 Session().add(sett)
257 Session().add(sett)
258
258
259 Session().commit()
259 Session().commit()
260 SettingsModel().invalidate_settings_cache()
260 h.flash(_('Updated application settings'), category='success')
261 h.flash(_('Updated application settings'), category='success')
261
262 except Exception:
262 except Exception:
263 log.exception("Exception while updating application settings")
263 log.exception("Exception while updating application settings")
264 h.flash(
264 h.flash(
265 _('Error occurred during updating application settings'),
265 _('Error occurred during updating application settings'),
266 category='error')
266 category='error')
267
267
268 return redirect(url('admin_settings_global'))
268 return redirect(url('admin_settings_global'))
269
269
270 @HasPermissionAllDecorator('hg.admin')
270 @HasPermissionAllDecorator('hg.admin')
271 def settings_global(self):
271 def settings_global(self):
272 """GET /admin/settings/global: All items in the collection"""
272 """GET /admin/settings/global: All items in the collection"""
273 # url('admin_settings_global')
273 # url('admin_settings_global')
274 c.active = 'global'
274 c.active = 'global'
275
275
276 return htmlfill.render(
276 return htmlfill.render(
277 render('admin/settings/settings.html'),
277 render('admin/settings/settings.html'),
278 defaults=self._form_defaults(),
278 defaults=self._form_defaults(),
279 encoding="UTF-8",
279 encoding="UTF-8",
280 force_defaults=False)
280 force_defaults=False)
281
281
282 @HasPermissionAllDecorator('hg.admin')
282 @HasPermissionAllDecorator('hg.admin')
283 @auth.CSRFRequired()
283 @auth.CSRFRequired()
284 def settings_visual_update(self):
284 def settings_visual_update(self):
285 """POST /admin/settings/visual: All items in the collection"""
285 """POST /admin/settings/visual: All items in the collection"""
286 # url('admin_settings_visual')
286 # url('admin_settings_visual')
287 c.active = 'visual'
287 c.active = 'visual'
288 application_form = ApplicationVisualisationForm()()
288 application_form = ApplicationVisualisationForm()()
289 try:
289 try:
290 form_result = application_form.to_python(dict(request.POST))
290 form_result = application_form.to_python(dict(request.POST))
291 except formencode.Invalid as errors:
291 except formencode.Invalid as errors:
292 return htmlfill.render(
292 return htmlfill.render(
293 render('admin/settings/settings.html'),
293 render('admin/settings/settings.html'),
294 defaults=errors.value,
294 defaults=errors.value,
295 errors=errors.error_dict or {},
295 errors=errors.error_dict or {},
296 prefix_error=False,
296 prefix_error=False,
297 encoding="UTF-8",
297 encoding="UTF-8",
298 force_defaults=False
298 force_defaults=False
299 )
299 )
300
300
301 try:
301 try:
302 settings = [
302 settings = [
303 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
303 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
304 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
304 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
305 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
305 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
306 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
306 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
307 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
307 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
308 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
308 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
309 ('show_version', 'rhodecode_show_version', 'bool'),
309 ('show_version', 'rhodecode_show_version', 'bool'),
310 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
310 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
311 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
311 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
312 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
312 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
313 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
313 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
314 ('support_url', 'rhodecode_support_url', 'unicode'),
314 ('support_url', 'rhodecode_support_url', 'unicode'),
315 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
315 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
316 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
316 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
317 ]
317 ]
318 for setting, form_key, type_ in settings:
318 for setting, form_key, type_ in settings:
319 sett = SettingsModel().create_or_update_setting(
319 sett = SettingsModel().create_or_update_setting(
320 setting, form_result[form_key], type_)
320 setting, form_result[form_key], type_)
321 Session().add(sett)
321 Session().add(sett)
322
322
323 Session().commit()
323 Session().commit()
324
324 SettingsModel().invalidate_settings_cache()
325 h.flash(_('Updated visualisation settings'), category='success')
325 h.flash(_('Updated visualisation settings'), category='success')
326 except Exception:
326 except Exception:
327 log.exception("Exception updating visualization settings")
327 log.exception("Exception updating visualization settings")
328 h.flash(_('Error occurred during updating '
328 h.flash(_('Error occurred during updating '
329 'visualisation settings'),
329 'visualisation settings'),
330 category='error')
330 category='error')
331
331
332 return redirect(url('admin_settings_visual'))
332 return redirect(url('admin_settings_visual'))
333
333
334 @HasPermissionAllDecorator('hg.admin')
334 @HasPermissionAllDecorator('hg.admin')
335 def settings_visual(self):
335 def settings_visual(self):
336 """GET /admin/settings/visual: All items in the collection"""
336 """GET /admin/settings/visual: All items in the collection"""
337 # url('admin_settings_visual')
337 # url('admin_settings_visual')
338 c.active = 'visual'
338 c.active = 'visual'
339
339
340 return htmlfill.render(
340 return htmlfill.render(
341 render('admin/settings/settings.html'),
341 render('admin/settings/settings.html'),
342 defaults=self._form_defaults(),
342 defaults=self._form_defaults(),
343 encoding="UTF-8",
343 encoding="UTF-8",
344 force_defaults=False)
344 force_defaults=False)
345
345
346 @HasPermissionAllDecorator('hg.admin')
346 @HasPermissionAllDecorator('hg.admin')
347 @auth.CSRFRequired()
347 @auth.CSRFRequired()
348 def settings_issuetracker_test(self):
348 def settings_issuetracker_test(self):
349 if request.is_xhr:
349 if request.is_xhr:
350 return h.urlify_commit_message(
350 return h.urlify_commit_message(
351 request.POST.get('test_text', ''),
351 request.POST.get('test_text', ''),
352 'repo_group/test_repo1')
352 'repo_group/test_repo1')
353 else:
353 else:
354 raise HTTPBadRequest()
354 raise HTTPBadRequest()
355
355
356 @HasPermissionAllDecorator('hg.admin')
356 @HasPermissionAllDecorator('hg.admin')
357 @auth.CSRFRequired()
357 @auth.CSRFRequired()
358 def settings_issuetracker_delete(self):
358 def settings_issuetracker_delete(self):
359 uid = request.POST.get('uid')
359 uid = request.POST.get('uid')
360 IssueTrackerSettingsModel().delete_entries(uid)
360 IssueTrackerSettingsModel().delete_entries(uid)
361 h.flash(_('Removed issue tracker entry'), category='success')
361 h.flash(_('Removed issue tracker entry'), category='success')
362 return redirect(url('admin_settings_issuetracker'))
362 return redirect(url('admin_settings_issuetracker'))
363
363
364 @HasPermissionAllDecorator('hg.admin')
364 @HasPermissionAllDecorator('hg.admin')
365 def settings_issuetracker(self):
365 def settings_issuetracker(self):
366 """GET /admin/settings/issue-tracker: All items in the collection"""
366 """GET /admin/settings/issue-tracker: All items in the collection"""
367 # url('admin_settings_issuetracker')
367 # url('admin_settings_issuetracker')
368 c.active = 'issuetracker'
368 c.active = 'issuetracker'
369 defaults = SettingsModel().get_all_settings()
369 defaults = SettingsModel().get_all_settings()
370
370
371 entry_key = 'rhodecode_issuetracker_pat_'
371 entry_key = 'rhodecode_issuetracker_pat_'
372
372
373 c.issuetracker_entries = {}
373 c.issuetracker_entries = {}
374 for k, v in defaults.items():
374 for k, v in defaults.items():
375 if k.startswith(entry_key):
375 if k.startswith(entry_key):
376 uid = k[len(entry_key):]
376 uid = k[len(entry_key):]
377 c.issuetracker_entries[uid] = None
377 c.issuetracker_entries[uid] = None
378
378
379 for uid in c.issuetracker_entries:
379 for uid in c.issuetracker_entries:
380 c.issuetracker_entries[uid] = AttributeDict({
380 c.issuetracker_entries[uid] = AttributeDict({
381 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
381 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
382 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
382 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
383 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
383 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
384 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
384 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
385 })
385 })
386
386
387 return render('admin/settings/settings.html')
387 return render('admin/settings/settings.html')
388
388
389 @HasPermissionAllDecorator('hg.admin')
389 @HasPermissionAllDecorator('hg.admin')
390 @auth.CSRFRequired()
390 @auth.CSRFRequired()
391 def settings_issuetracker_save(self):
391 def settings_issuetracker_save(self):
392 settings_model = IssueTrackerSettingsModel()
392 settings_model = IssueTrackerSettingsModel()
393
393
394 form = IssueTrackerPatternsForm()().to_python(request.POST)
394 form = IssueTrackerPatternsForm()().to_python(request.POST)
395 for uid in form['delete_patterns']:
395 for uid in form['delete_patterns']:
396 settings_model.delete_entries(uid)
396 settings_model.delete_entries(uid)
397
397
398 for pattern in form['patterns']:
398 for pattern in form['patterns']:
399 for setting, value, type_ in pattern:
399 for setting, value, type_ in pattern:
400 sett = settings_model.create_or_update_setting(
400 sett = settings_model.create_or_update_setting(
401 setting, value, type_)
401 setting, value, type_)
402 Session().add(sett)
402 Session().add(sett)
403
403
404 Session().commit()
404 Session().commit()
405
405
406 SettingsModel().invalidate_settings_cache()
406 h.flash(_('Updated issue tracker entries'), category='success')
407 h.flash(_('Updated issue tracker entries'), category='success')
407 return redirect(url('admin_settings_issuetracker'))
408 return redirect(url('admin_settings_issuetracker'))
408
409
409 @HasPermissionAllDecorator('hg.admin')
410 @HasPermissionAllDecorator('hg.admin')
410 @auth.CSRFRequired()
411 @auth.CSRFRequired()
411 def settings_email_update(self):
412 def settings_email_update(self):
412 """POST /admin/settings/email: All items in the collection"""
413 """POST /admin/settings/email: All items in the collection"""
413 # url('admin_settings_email')
414 # url('admin_settings_email')
414 c.active = 'email'
415 c.active = 'email'
415
416
416 test_email = request.POST.get('test_email')
417 test_email = request.POST.get('test_email')
417
418
418 if not test_email:
419 if not test_email:
419 h.flash(_('Please enter email address'), category='error')
420 h.flash(_('Please enter email address'), category='error')
420 return redirect(url('admin_settings_email'))
421 return redirect(url('admin_settings_email'))
421
422
422 email_kwargs = {
423 email_kwargs = {
423 'date': datetime.datetime.now(),
424 'date': datetime.datetime.now(),
424 'user': c.rhodecode_user,
425 'user': c.rhodecode_user,
425 'rhodecode_version': c.rhodecode_version
426 'rhodecode_version': c.rhodecode_version
426 }
427 }
427
428
428 (subject, headers, email_body,
429 (subject, headers, email_body,
429 email_body_plaintext) = EmailNotificationModel().render_email(
430 email_body_plaintext) = EmailNotificationModel().render_email(
430 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
431 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
431
432
432 recipients = [test_email] if test_email else None
433 recipients = [test_email] if test_email else None
433
434
434 run_task(tasks.send_email, recipients, subject,
435 run_task(tasks.send_email, recipients, subject,
435 email_body_plaintext, email_body)
436 email_body_plaintext, email_body)
436
437
437 h.flash(_('Send email task created'), category='success')
438 h.flash(_('Send email task created'), category='success')
438 return redirect(url('admin_settings_email'))
439 return redirect(url('admin_settings_email'))
439
440
440 @HasPermissionAllDecorator('hg.admin')
441 @HasPermissionAllDecorator('hg.admin')
441 def settings_email(self):
442 def settings_email(self):
442 """GET /admin/settings/email: All items in the collection"""
443 """GET /admin/settings/email: All items in the collection"""
443 # url('admin_settings_email')
444 # url('admin_settings_email')
444 c.active = 'email'
445 c.active = 'email'
445 c.rhodecode_ini = rhodecode.CONFIG
446 c.rhodecode_ini = rhodecode.CONFIG
446
447
447 return htmlfill.render(
448 return htmlfill.render(
448 render('admin/settings/settings.html'),
449 render('admin/settings/settings.html'),
449 defaults=self._form_defaults(),
450 defaults=self._form_defaults(),
450 encoding="UTF-8",
451 encoding="UTF-8",
451 force_defaults=False)
452 force_defaults=False)
452
453
453 @HasPermissionAllDecorator('hg.admin')
454 @HasPermissionAllDecorator('hg.admin')
454 @auth.CSRFRequired()
455 @auth.CSRFRequired()
455 def settings_hooks_update(self):
456 def settings_hooks_update(self):
456 """POST or DELETE /admin/settings/hooks: All items in the collection"""
457 """POST or DELETE /admin/settings/hooks: All items in the collection"""
457 # url('admin_settings_hooks')
458 # url('admin_settings_hooks')
458 c.active = 'hooks'
459 c.active = 'hooks'
459 if c.visual.allow_custom_hooks_settings:
460 if c.visual.allow_custom_hooks_settings:
460 ui_key = request.POST.get('new_hook_ui_key')
461 ui_key = request.POST.get('new_hook_ui_key')
461 ui_value = request.POST.get('new_hook_ui_value')
462 ui_value = request.POST.get('new_hook_ui_value')
462
463
463 hook_id = request.POST.get('hook_id')
464 hook_id = request.POST.get('hook_id')
464 new_hook = False
465 new_hook = False
465
466
466 model = SettingsModel()
467 model = SettingsModel()
467 try:
468 try:
468 if ui_value and ui_key:
469 if ui_value and ui_key:
469 model.create_or_update_hook(ui_key, ui_value)
470 model.create_or_update_hook(ui_key, ui_value)
470 h.flash(_('Added new hook'), category='success')
471 h.flash(_('Added new hook'), category='success')
471 new_hook = True
472 new_hook = True
472 elif hook_id:
473 elif hook_id:
473 RhodeCodeUi.delete(hook_id)
474 RhodeCodeUi.delete(hook_id)
474 Session().commit()
475 Session().commit()
475
476
476 # check for edits
477 # check for edits
477 update = False
478 update = False
478 _d = request.POST.dict_of_lists()
479 _d = request.POST.dict_of_lists()
479 for k, v in zip(_d.get('hook_ui_key', []),
480 for k, v in zip(_d.get('hook_ui_key', []),
480 _d.get('hook_ui_value_new', [])):
481 _d.get('hook_ui_value_new', [])):
481 model.create_or_update_hook(k, v)
482 model.create_or_update_hook(k, v)
482 update = True
483 update = True
483
484
484 if update and not new_hook:
485 if update and not new_hook:
485 h.flash(_('Updated hooks'), category='success')
486 h.flash(_('Updated hooks'), category='success')
486 Session().commit()
487 Session().commit()
487 except Exception:
488 except Exception:
488 log.exception("Exception during hook creation")
489 log.exception("Exception during hook creation")
489 h.flash(_('Error occurred during hook creation'),
490 h.flash(_('Error occurred during hook creation'),
490 category='error')
491 category='error')
491
492
492 return redirect(url('admin_settings_hooks'))
493 return redirect(url('admin_settings_hooks'))
493
494
494 @HasPermissionAllDecorator('hg.admin')
495 @HasPermissionAllDecorator('hg.admin')
495 def settings_hooks(self):
496 def settings_hooks(self):
496 """GET /admin/settings/hooks: All items in the collection"""
497 """GET /admin/settings/hooks: All items in the collection"""
497 # url('admin_settings_hooks')
498 # url('admin_settings_hooks')
498 c.active = 'hooks'
499 c.active = 'hooks'
499
500
500 model = SettingsModel()
501 model = SettingsModel()
501 c.hooks = model.get_builtin_hooks()
502 c.hooks = model.get_builtin_hooks()
502 c.custom_hooks = model.get_custom_hooks()
503 c.custom_hooks = model.get_custom_hooks()
503
504
504 return htmlfill.render(
505 return htmlfill.render(
505 render('admin/settings/settings.html'),
506 render('admin/settings/settings.html'),
506 defaults=self._form_defaults(),
507 defaults=self._form_defaults(),
507 encoding="UTF-8",
508 encoding="UTF-8",
508 force_defaults=False)
509 force_defaults=False)
509
510
510 @HasPermissionAllDecorator('hg.admin')
511 @HasPermissionAllDecorator('hg.admin')
511 def settings_search(self):
512 def settings_search(self):
512 """GET /admin/settings/search: All items in the collection"""
513 """GET /admin/settings/search: All items in the collection"""
513 # url('admin_settings_search')
514 # url('admin_settings_search')
514 c.active = 'search'
515 c.active = 'search'
515
516
516 from rhodecode.lib.index import searcher_from_config
517 from rhodecode.lib.index import searcher_from_config
517 searcher = searcher_from_config(config)
518 searcher = searcher_from_config(config)
518 c.statistics = searcher.statistics()
519 c.statistics = searcher.statistics()
519
520
520 return render('admin/settings/settings.html')
521 return render('admin/settings/settings.html')
521
522
522 @HasPermissionAllDecorator('hg.admin')
523 @HasPermissionAllDecorator('hg.admin')
523 def settings_system(self):
524 def settings_system(self):
524 """GET /admin/settings/system: All items in the collection"""
525 """GET /admin/settings/system: All items in the collection"""
525 # url('admin_settings_system')
526 # url('admin_settings_system')
526 c.active = 'system'
527 c.active = 'system'
527
528
528 defaults = self._form_defaults()
529 defaults = self._form_defaults()
529 c.rhodecode_ini = rhodecode.CONFIG
530 c.rhodecode_ini = rhodecode.CONFIG
530 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
531 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
531 server_info = ScmModel().get_server_info(request.environ)
532 server_info = ScmModel().get_server_info(request.environ)
532 for key, val in server_info.iteritems():
533 for key, val in server_info.iteritems():
533 setattr(c, key, val)
534 setattr(c, key, val)
534
535
535 if c.disk['percent'] > 90:
536 if c.disk['percent'] > 90:
536 h.flash(h.literal(_(
537 h.flash(h.literal(_(
537 'Critical: your disk space is very low <b>%s%%</b> used' %
538 'Critical: your disk space is very low <b>%s%%</b> used' %
538 c.disk['percent'])), 'error')
539 c.disk['percent'])), 'error')
539 elif c.disk['percent'] > 70:
540 elif c.disk['percent'] > 70:
540 h.flash(h.literal(_(
541 h.flash(h.literal(_(
541 'Warning: your disk space is running low <b>%s%%</b> used' %
542 'Warning: your disk space is running low <b>%s%%</b> used' %
542 c.disk['percent'])), 'warning')
543 c.disk['percent'])), 'warning')
543
544
544 try:
545 try:
545 c.uptime_age = h._age(
546 c.uptime_age = h._age(
546 h.time_to_datetime(c.boot_time), False, show_suffix=False)
547 h.time_to_datetime(c.boot_time), False, show_suffix=False)
547 except TypeError:
548 except TypeError:
548 c.uptime_age = c.boot_time
549 c.uptime_age = c.boot_time
549
550
550 try:
551 try:
551 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
552 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
552 h.format_byte_size_binary(c.memory['used']),
553 h.format_byte_size_binary(c.memory['used']),
553 h.format_byte_size_binary(c.memory['total']),
554 h.format_byte_size_binary(c.memory['total']),
554 c.memory['percent2'],
555 c.memory['percent2'],
555 c.memory['percent'],
556 c.memory['percent'],
556 ' %s' % c.memory['error'] if 'error' in c.memory else '')
557 ' %s' % c.memory['error'] if 'error' in c.memory else '')
557 except TypeError:
558 except TypeError:
558 c.system_memory = 'NOT AVAILABLE'
559 c.system_memory = 'NOT AVAILABLE'
559
560
560 return htmlfill.render(
561 return htmlfill.render(
561 render('admin/settings/settings.html'),
562 render('admin/settings/settings.html'),
562 defaults=defaults,
563 defaults=defaults,
563 encoding="UTF-8",
564 encoding="UTF-8",
564 force_defaults=False)
565 force_defaults=False)
565
566
566 @staticmethod
567 @staticmethod
567 def get_update_data(update_url):
568 def get_update_data(update_url):
568 """Return the JSON update data."""
569 """Return the JSON update data."""
569 ver = rhodecode.__version__
570 ver = rhodecode.__version__
570 log.debug('Checking for upgrade on `%s` server', update_url)
571 log.debug('Checking for upgrade on `%s` server', update_url)
571 opener = urllib2.build_opener()
572 opener = urllib2.build_opener()
572 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
573 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
573 response = opener.open(update_url)
574 response = opener.open(update_url)
574 response_data = response.read()
575 response_data = response.read()
575 data = json.loads(response_data)
576 data = json.loads(response_data)
576
577
577 return data
578 return data
578
579
579 @HasPermissionAllDecorator('hg.admin')
580 @HasPermissionAllDecorator('hg.admin')
580 def settings_system_update(self):
581 def settings_system_update(self):
581 """GET /admin/settings/system/updates: All items in the collection"""
582 """GET /admin/settings/system/updates: All items in the collection"""
582 # url('admin_settings_system_update')
583 # url('admin_settings_system_update')
583 defaults = self._form_defaults()
584 defaults = self._form_defaults()
584 update_url = defaults.get('rhodecode_update_url', '')
585 update_url = defaults.get('rhodecode_update_url', '')
585
586
586 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
587 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
587 try:
588 try:
588 data = self.get_update_data(update_url)
589 data = self.get_update_data(update_url)
589 except urllib2.URLError as e:
590 except urllib2.URLError as e:
590 log.exception("Exception contacting upgrade server")
591 log.exception("Exception contacting upgrade server")
591 return _err('Failed to contact upgrade server: %r' % e)
592 return _err('Failed to contact upgrade server: %r' % e)
592 except ValueError as e:
593 except ValueError as e:
593 log.exception("Bad data sent from update server")
594 log.exception("Bad data sent from update server")
594 return _err('Bad data sent from update server')
595 return _err('Bad data sent from update server')
595
596
596 latest = data['versions'][0]
597 latest = data['versions'][0]
597
598
598 c.update_url = update_url
599 c.update_url = update_url
599 c.latest_data = latest
600 c.latest_data = latest
600 c.latest_ver = latest['version']
601 c.latest_ver = latest['version']
601 c.cur_ver = rhodecode.__version__
602 c.cur_ver = rhodecode.__version__
602 c.should_upgrade = False
603 c.should_upgrade = False
603
604
604 if (packaging.version.Version(c.latest_ver) >
605 if (packaging.version.Version(c.latest_ver) >
605 packaging.version.Version(c.cur_ver)):
606 packaging.version.Version(c.cur_ver)):
606 c.should_upgrade = True
607 c.should_upgrade = True
607 c.important_notices = latest['general']
608 c.important_notices = latest['general']
608
609
609 return render('admin/settings/settings_system_update.html')
610 return render('admin/settings/settings_system_update.html')
610
611
611 @HasPermissionAllDecorator('hg.admin')
612 @HasPermissionAllDecorator('hg.admin')
612 def settings_supervisor(self):
613 def settings_supervisor(self):
613 c.rhodecode_ini = rhodecode.CONFIG
614 c.rhodecode_ini = rhodecode.CONFIG
614 c.active = 'supervisor'
615 c.active = 'supervisor'
615
616
616 c.supervisor_procs = OrderedDict([
617 c.supervisor_procs = OrderedDict([
617 (SUPERVISOR_MASTER, {}),
618 (SUPERVISOR_MASTER, {}),
618 ])
619 ])
619
620
620 c.log_size = 10240
621 c.log_size = 10240
621 supervisor = SupervisorModel()
622 supervisor = SupervisorModel()
622
623
623 _connection = supervisor.get_connection(
624 _connection = supervisor.get_connection(
624 c.rhodecode_ini.get('supervisor.uri'))
625 c.rhodecode_ini.get('supervisor.uri'))
625 c.connection_error = None
626 c.connection_error = None
626 try:
627 try:
627 _connection.supervisor.getAllProcessInfo()
628 _connection.supervisor.getAllProcessInfo()
628 except Exception as e:
629 except Exception as e:
629 c.connection_error = str(e)
630 c.connection_error = str(e)
630 log.exception("Exception reading supervisor data")
631 log.exception("Exception reading supervisor data")
631 return render('admin/settings/settings.html')
632 return render('admin/settings/settings.html')
632
633
633 groupid = c.rhodecode_ini.get('supervisor.group_id')
634 groupid = c.rhodecode_ini.get('supervisor.group_id')
634
635
635 # feed our group processes to the main
636 # feed our group processes to the main
636 for proc in supervisor.get_group_processes(_connection, groupid):
637 for proc in supervisor.get_group_processes(_connection, groupid):
637 c.supervisor_procs[proc['name']] = {}
638 c.supervisor_procs[proc['name']] = {}
638
639
639 for k in c.supervisor_procs.keys():
640 for k in c.supervisor_procs.keys():
640 try:
641 try:
641 # master process info
642 # master process info
642 if k == SUPERVISOR_MASTER:
643 if k == SUPERVISOR_MASTER:
643 _data = supervisor.get_master_state(_connection)
644 _data = supervisor.get_master_state(_connection)
644 _data['name'] = 'supervisor master'
645 _data['name'] = 'supervisor master'
645 _data['description'] = 'pid %s, id: %s, ver: %s' % (
646 _data['description'] = 'pid %s, id: %s, ver: %s' % (
646 _data['pid'], _data['id'], _data['ver'])
647 _data['pid'], _data['id'], _data['ver'])
647 c.supervisor_procs[k] = _data
648 c.supervisor_procs[k] = _data
648 else:
649 else:
649 procid = groupid + ":" + k
650 procid = groupid + ":" + k
650 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
651 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
651 except Exception as e:
652 except Exception as e:
652 log.exception("Exception reading supervisor data")
653 log.exception("Exception reading supervisor data")
653 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
654 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
654
655
655 return render('admin/settings/settings.html')
656 return render('admin/settings/settings.html')
656
657
657 @HasPermissionAllDecorator('hg.admin')
658 @HasPermissionAllDecorator('hg.admin')
658 def settings_supervisor_log(self, procid):
659 def settings_supervisor_log(self, procid):
659 import rhodecode
660 import rhodecode
660 c.rhodecode_ini = rhodecode.CONFIG
661 c.rhodecode_ini = rhodecode.CONFIG
661 c.active = 'supervisor_tail'
662 c.active = 'supervisor_tail'
662
663
663 supervisor = SupervisorModel()
664 supervisor = SupervisorModel()
664 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
665 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
665 groupid = c.rhodecode_ini.get('supervisor.group_id')
666 groupid = c.rhodecode_ini.get('supervisor.group_id')
666 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
667 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
667
668
668 c.log_size = 10240
669 c.log_size = 10240
669 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
670 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
670 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
671 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
671
672
672 return render('admin/settings/settings.html')
673 return render('admin/settings/settings.html')
673
674
674 @HasPermissionAllDecorator('hg.admin')
675 @HasPermissionAllDecorator('hg.admin')
675 @auth.CSRFRequired()
676 @auth.CSRFRequired()
676 def settings_labs_update(self):
677 def settings_labs_update(self):
677 """POST /admin/settings/labs: All items in the collection"""
678 """POST /admin/settings/labs: All items in the collection"""
678 # url('admin_settings/labs', method={'POST'})
679 # url('admin_settings/labs', method={'POST'})
679 c.active = 'labs'
680 c.active = 'labs'
680
681
681 application_form = LabsSettingsForm()()
682 application_form = LabsSettingsForm()()
682 try:
683 try:
683 form_result = application_form.to_python(dict(request.POST))
684 form_result = application_form.to_python(dict(request.POST))
684 except formencode.Invalid as errors:
685 except formencode.Invalid as errors:
685 h.flash(
686 h.flash(
686 _('Some form inputs contain invalid data.'),
687 _('Some form inputs contain invalid data.'),
687 category='error')
688 category='error')
688 return htmlfill.render(
689 return htmlfill.render(
689 render('admin/settings/settings.html'),
690 render('admin/settings/settings.html'),
690 defaults=errors.value,
691 defaults=errors.value,
691 errors=errors.error_dict or {},
692 errors=errors.error_dict or {},
692 prefix_error=False,
693 prefix_error=False,
693 encoding='UTF-8',
694 encoding='UTF-8',
694 force_defaults=False
695 force_defaults=False
695 )
696 )
696
697
697 try:
698 try:
698 session = Session()
699 session = Session()
699 for setting in _LAB_SETTINGS:
700 for setting in _LAB_SETTINGS:
700 setting_name = setting.key[len('rhodecode_'):]
701 setting_name = setting.key[len('rhodecode_'):]
701 sett = SettingsModel().create_or_update_setting(
702 sett = SettingsModel().create_or_update_setting(
702 setting_name, form_result[setting.key], setting.type)
703 setting_name, form_result[setting.key], setting.type)
703 session.add(sett)
704 session.add(sett)
704
705
705 except Exception:
706 except Exception:
706 log.exception('Exception while updating lab settings')
707 log.exception('Exception while updating lab settings')
707 h.flash(_('Error occurred during updating labs settings'),
708 h.flash(_('Error occurred during updating labs settings'),
708 category='error')
709 category='error')
709 else:
710 else:
710 Session().commit()
711 Session().commit()
712 SettingsModel().invalidate_settings_cache()
711 h.flash(_('Updated Labs settings'), category='success')
713 h.flash(_('Updated Labs settings'), category='success')
712 return redirect(url('admin_settings_labs'))
714 return redirect(url('admin_settings_labs'))
713
715
714 return htmlfill.render(
716 return htmlfill.render(
715 render('admin/settings/settings.html'),
717 render('admin/settings/settings.html'),
716 defaults=self._form_defaults(),
718 defaults=self._form_defaults(),
717 encoding='UTF-8',
719 encoding='UTF-8',
718 force_defaults=False)
720 force_defaults=False)
719
721
720 @HasPermissionAllDecorator('hg.admin')
722 @HasPermissionAllDecorator('hg.admin')
721 def settings_labs(self):
723 def settings_labs(self):
722 """GET /admin/settings/labs: All items in the collection"""
724 """GET /admin/settings/labs: All items in the collection"""
723 # url('admin_settings_labs')
725 # url('admin_settings_labs')
724 if not c.labs_active:
726 if not c.labs_active:
725 redirect(url('admin_settings'))
727 redirect(url('admin_settings'))
726
728
727 c.active = 'labs'
729 c.active = 'labs'
728 c.lab_settings = _LAB_SETTINGS
730 c.lab_settings = _LAB_SETTINGS
729
731
730 return htmlfill.render(
732 return htmlfill.render(
731 render('admin/settings/settings.html'),
733 render('admin/settings/settings.html'),
732 defaults=self._form_defaults(),
734 defaults=self._form_defaults(),
733 encoding='UTF-8',
735 encoding='UTF-8',
734 force_defaults=False)
736 force_defaults=False)
735
737
736 def _form_defaults(self):
738 def _form_defaults(self):
737 defaults = SettingsModel().get_all_settings()
739 defaults = SettingsModel().get_all_settings()
738 defaults.update(self._get_hg_ui_settings())
740 defaults.update(self._get_hg_ui_settings())
739 defaults.update({
741 defaults.update({
740 'new_svn_branch': '',
742 'new_svn_branch': '',
741 'new_svn_tag': '',
743 'new_svn_tag': '',
742 })
744 })
743 return defaults
745 return defaults
744
746
745
747
746 # :param key: name of the setting including the 'rhodecode_' prefix
748 # :param key: name of the setting including the 'rhodecode_' prefix
747 # :param type: the RhodeCodeSetting type to use.
749 # :param type: the RhodeCodeSetting type to use.
748 # :param group: the i18ned group in which we should dispaly this setting
750 # :param group: the i18ned group in which we should dispaly this setting
749 # :param label: the i18ned label we should display for this setting
751 # :param label: the i18ned label we should display for this setting
750 # :param help: the i18ned help we should dispaly for this setting
752 # :param help: the i18ned help we should dispaly for this setting
751 LabSetting = collections.namedtuple(
753 LabSetting = collections.namedtuple(
752 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
754 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
753
755
754
756
755 # This list has to be kept in sync with the form
757 # This list has to be kept in sync with the form
756 # rhodecode.model.forms.LabsSettingsForm.
758 # rhodecode.model.forms.LabsSettingsForm.
757 _LAB_SETTINGS = [
759 _LAB_SETTINGS = [
758 LabSetting(
760 LabSetting(
759 key='rhodecode_hg_use_rebase_for_merging',
761 key='rhodecode_hg_use_rebase_for_merging',
760 type='bool',
762 type='bool',
761 group=lazy_ugettext('Mercurial server-side merge'),
763 group=lazy_ugettext('Mercurial server-side merge'),
762 label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'),
764 label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'),
763 help='' # Do not translate the empty string!
765 help='' # Do not translate the empty string!
764 ),
766 ),
765 LabSetting(
767 LabSetting(
766 key='rhodecode_proxy_subversion_http_requests',
768 key='rhodecode_proxy_subversion_http_requests',
767 type='bool',
769 type='bool',
768 group=lazy_ugettext('Subversion HTTP Support'),
770 group=lazy_ugettext('Subversion HTTP Support'),
769 label=lazy_ugettext('Proxy subversion HTTP requests'),
771 label=lazy_ugettext('Proxy subversion HTTP requests'),
770 help='' # Do not translate the empty string!
772 help='' # Do not translate the empty string!
771 ),
773 ),
772 LabSetting(
774 LabSetting(
773 key='rhodecode_subversion_http_server_url',
775 key='rhodecode_subversion_http_server_url',
774 type='str',
776 type='str',
775 group=lazy_ugettext('Subversion HTTP Server URL'),
777 group=lazy_ugettext('Subversion HTTP Server URL'),
776 label='', # Do not translate the empty string!
778 label='', # Do not translate the empty string!
777 help=lazy_ugettext('e.g. http://localhost:8080/')
779 help=lazy_ugettext('e.g. http://localhost:8080/')
778 ),
780 ),
779 ]
781 ]
780
782
781
783
782 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
784 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
783
785
784
786
785 class NavEntry(object):
787 class NavEntry(object):
786
788
787 def __init__(self, key, name, view_name, pyramid=False):
789 def __init__(self, key, name, view_name, pyramid=False):
788 self.key = key
790 self.key = key
789 self.name = name
791 self.name = name
790 self.view_name = view_name
792 self.view_name = view_name
791 self.pyramid = pyramid
793 self.pyramid = pyramid
792
794
793 def generate_url(self, request):
795 def generate_url(self, request):
794 if self.pyramid:
796 if self.pyramid:
795 if hasattr(request, 'route_path'):
797 if hasattr(request, 'route_path'):
796 return request.route_path(self.view_name)
798 return request.route_path(self.view_name)
797 else:
799 else:
798 # TODO: johbo: Remove this after migrating to pyramid.
800 # TODO: johbo: Remove this after migrating to pyramid.
799 # We need the pyramid request here to generate URLs to pyramid
801 # We need the pyramid request here to generate URLs to pyramid
800 # views from within pylons views.
802 # views from within pylons views.
801 from pyramid.threadlocal import get_current_request
803 from pyramid.threadlocal import get_current_request
802 pyramid_request = get_current_request()
804 pyramid_request = get_current_request()
803 return pyramid_request.route_path(self.view_name)
805 return pyramid_request.route_path(self.view_name)
804 else:
806 else:
805 return url(self.view_name)
807 return url(self.view_name)
806
808
807
809
808 class NavigationRegistry(object):
810 class NavigationRegistry(object):
809
811
810 _base_entries = [
812 _base_entries = [
811 NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'),
813 NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'),
812 NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'),
814 NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'),
813 NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'),
815 NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'),
814 NavEntry('mapping', lazy_ugettext('Remap and Rescan'),
816 NavEntry('mapping', lazy_ugettext('Remap and Rescan'),
815 'admin_settings_mapping'),
817 'admin_settings_mapping'),
816 NavEntry('issuetracker', lazy_ugettext('Issue Tracker'),
818 NavEntry('issuetracker', lazy_ugettext('Issue Tracker'),
817 'admin_settings_issuetracker'),
819 'admin_settings_issuetracker'),
818 NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'),
820 NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'),
819 NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'),
821 NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'),
820 NavEntry('search', lazy_ugettext('Full Text Search'),
822 NavEntry('search', lazy_ugettext('Full Text Search'),
821 'admin_settings_search'),
823 'admin_settings_search'),
822 NavEntry('system', lazy_ugettext('System Info'),
824 NavEntry('system', lazy_ugettext('System Info'),
823 'admin_settings_system'),
825 'admin_settings_system'),
824 NavEntry('open_source', lazy_ugettext('Open Source Licenses'),
826 NavEntry('open_source', lazy_ugettext('Open Source Licenses'),
825 'admin_settings_open_source', pyramid=True),
827 'admin_settings_open_source', pyramid=True),
826 # TODO: marcink: we disable supervisor now until the supervisor stats
828 # TODO: marcink: we disable supervisor now until the supervisor stats
827 # page is fixed in the nix configuration
829 # page is fixed in the nix configuration
828 # NavEntry('supervisor', lazy_ugettext('Supervisor'),
830 # NavEntry('supervisor', lazy_ugettext('Supervisor'),
829 # 'admin_settings_supervisor'),
831 # 'admin_settings_supervisor'),
830 ]
832 ]
831
833
832 def __init__(self):
834 def __init__(self):
833 self._registered_entries = collections.OrderedDict([
835 self._registered_entries = collections.OrderedDict([
834 (item.key, item) for item in self.__class__._base_entries
836 (item.key, item) for item in self.__class__._base_entries
835 ])
837 ])
836
838
837 # Add the labs entry when it's activated.
839 # Add the labs entry when it's activated.
838 labs_active = str2bool(
840 labs_active = str2bool(
839 rhodecode.CONFIG.get('labs_settings_active', 'false'))
841 rhodecode.CONFIG.get('labs_settings_active', 'false'))
840 if labs_active:
842 if labs_active:
841 self.add_entry(
843 self.add_entry(
842 NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs'))
844 NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs'))
843
845
844 def add_entry(self, entry):
846 def add_entry(self, entry):
845 self._registered_entries[entry.key] = entry
847 self._registered_entries[entry.key] = entry
846
848
847 def get_navlist(self, request):
849 def get_navlist(self, request):
848 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
850 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
849 for i in self._registered_entries.values()]
851 for i in self._registered_entries.values()]
850 return navlist
852 return navlist
851
853
852 navigation = NavigationRegistry()
854 navigation = NavigationRegistry()
@@ -1,220 +1,226 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2015-2016 RhodeCode GmbH
3 # Copyright (C) 2015-2016 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 beaker
22 import beaker
23 import logging
23 import logging
24
24
25 from beaker.cache import _cache_decorate, cache_regions, region_invalidate
25 from beaker.cache import _cache_decorate, cache_regions, region_invalidate
26
26
27 from rhodecode.lib.utils import safe_str, md5
27 from rhodecode.lib.utils import safe_str, md5
28 from rhodecode.model.db import Session, CacheKey, IntegrityError
28 from rhodecode.model.db import Session, CacheKey, IntegrityError
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32 FILE_TREE = 'cache_file_tree'
32 FILE_TREE = 'cache_file_tree'
33 FILE_TREE_META = 'cache_file_tree_metadata'
33 FILE_TREE_META = 'cache_file_tree_metadata'
34 FILE_SEARCH_TREE_META = 'cache_file_search_metadata'
34 FILE_SEARCH_TREE_META = 'cache_file_search_metadata'
35 SUMMARY_STATS = 'cache_summary_stats'
35 SUMMARY_STATS = 'cache_summary_stats'
36
36
37 # This list of caches gets purged when invalidation happens
37 # This list of caches gets purged when invalidation happens
38 USED_REPO_CACHES = (FILE_TREE, FILE_TREE_META, FILE_TREE_META)
38 USED_REPO_CACHES = (FILE_TREE, FILE_TREE_META, FILE_TREE_META)
39
39
40 DEFAULT_CACHE_MANAGER_CONFIG = {
40 DEFAULT_CACHE_MANAGER_CONFIG = {
41 'type': 'memorylru_base',
41 'type': 'memorylru_base',
42 'max_items': 10240,
42 'max_items': 10240,
43 'key_length': 256,
43 'key_length': 256,
44 'enabled': True
44 'enabled': True
45 }
45 }
46
46
47
47
48 def configure_cache_region(
48 def configure_cache_region(
49 region_name, region_kw, default_cache_kw, default_expire=60):
49 region_name, region_kw, default_cache_kw, default_expire=60):
50 default_type = default_cache_kw.get('type', 'memory')
50 default_type = default_cache_kw.get('type', 'memory')
51 default_lock_dir = default_cache_kw.get('lock_dir')
51 default_lock_dir = default_cache_kw.get('lock_dir')
52 default_data_dir = default_cache_kw.get('data_dir')
52 default_data_dir = default_cache_kw.get('data_dir')
53
53
54 region_kw['lock_dir'] = region_kw.get('lock_dir', default_lock_dir)
54 region_kw['lock_dir'] = region_kw.get('lock_dir', default_lock_dir)
55 region_kw['data_dir'] = region_kw.get('data_dir', default_data_dir)
55 region_kw['data_dir'] = region_kw.get('data_dir', default_data_dir)
56 region_kw['type'] = region_kw.get('type', default_type)
56 region_kw['type'] = region_kw.get('type', default_type)
57 region_kw['expire'] = int(region_kw.get('expire', default_expire))
57 region_kw['expire'] = int(region_kw.get('expire', default_expire))
58
58
59 beaker.cache.cache_regions[region_name] = region_kw
59 beaker.cache.cache_regions[region_name] = region_kw
60
60
61
61
62 def get_cache_manager(region_name, cache_name, custom_ttl=None):
62 def get_cache_manager(region_name, cache_name, custom_ttl=None):
63 """
63 """
64 Creates a Beaker cache manager. Such instance can be used like that::
64 Creates a Beaker cache manager. Such instance can be used like that::
65
65
66 _namespace = caches.get_repo_namespace_key(caches.XXX, repo_name)
66 _namespace = caches.get_repo_namespace_key(caches.XXX, repo_name)
67 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
67 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
68 _cache_key = caches.compute_key_from_params(repo_name, commit.raw_id)
68 _cache_key = caches.compute_key_from_params(repo_name, commit.raw_id)
69 def heavy_compute():
69 def heavy_compute():
70 ...
70 ...
71 result = cache_manager.get(_cache_key, createfunc=heavy_compute)
71 result = cache_manager.get(_cache_key, createfunc=heavy_compute)
72
72
73 :param region_name: region from ini file
73 :param region_name: region from ini file
74 :param cache_name: custom cache name, usually prefix+repo_name. eg
74 :param cache_name: custom cache name, usually prefix+repo_name. eg
75 file_switcher_repo1
75 file_switcher_repo1
76 :param custom_ttl: override .ini file timeout on this cache
76 :param custom_ttl: override .ini file timeout on this cache
77 :return: instance of cache manager
77 :return: instance of cache manager
78 """
78 """
79
79
80 cache_config = cache_regions.get(region_name, DEFAULT_CACHE_MANAGER_CONFIG)
80 cache_config = cache_regions.get(region_name, DEFAULT_CACHE_MANAGER_CONFIG)
81 if custom_ttl:
81 if custom_ttl:
82 log.debug('Updating region %s with custom ttl: %s',
82 log.debug('Updating region %s with custom ttl: %s',
83 region_name, custom_ttl)
83 region_name, custom_ttl)
84 cache_config.update({'expire': custom_ttl})
84 cache_config.update({'expire': custom_ttl})
85
85
86 return beaker.cache.Cache._get_cache(cache_name, cache_config)
86 return beaker.cache.Cache._get_cache(cache_name, cache_config)
87
87
88
88
89 def clear_cache_manager(cache_manager):
89 def clear_cache_manager(cache_manager):
90 """
91 namespace = 'foobar'
92 cache_manager = get_cache_manager('repo_cache_long', namespace)
93 clear_cache_manager(cache_manager)
94 """
95
90 log.debug('Clearing all values for cache manager %s', cache_manager)
96 log.debug('Clearing all values for cache manager %s', cache_manager)
91 cache_manager.clear()
97 cache_manager.clear()
92
98
93
99
94 def clear_repo_caches(repo_name):
100 def clear_repo_caches(repo_name):
95 # invalidate cache manager for this repo
101 # invalidate cache manager for this repo
96 for prefix in USED_REPO_CACHES:
102 for prefix in USED_REPO_CACHES:
97 namespace = get_repo_namespace_key(prefix, repo_name)
103 namespace = get_repo_namespace_key(prefix, repo_name)
98 cache_manager = get_cache_manager('repo_cache_long', namespace)
104 cache_manager = get_cache_manager('repo_cache_long', namespace)
99 clear_cache_manager(cache_manager)
105 clear_cache_manager(cache_manager)
100
106
101
107
102 def compute_key_from_params(*args):
108 def compute_key_from_params(*args):
103 """
109 """
104 Helper to compute key from given params to be used in cache manager
110 Helper to compute key from given params to be used in cache manager
105 """
111 """
106 return md5("_".join(map(safe_str, args)))
112 return md5("_".join(map(safe_str, args)))
107
113
108
114
109 def get_repo_namespace_key(prefix, repo_name):
115 def get_repo_namespace_key(prefix, repo_name):
110 return '{0}_{1}'.format(prefix, compute_key_from_params(repo_name))
116 return '{0}_{1}'.format(prefix, compute_key_from_params(repo_name))
111
117
112
118
113 def conditional_cache(region, prefix, condition, func):
119 def conditional_cache(region, prefix, condition, func):
114 """
120 """
115 Conditional caching function use like::
121 Conditional caching function use like::
116 def _c(arg):
122 def _c(arg):
117 # heavy computation function
123 # heavy computation function
118 return data
124 return data
119
125
120 # depending on the condition the compute is wrapped in cache or not
126 # depending on the condition the compute is wrapped in cache or not
121 compute = conditional_cache('short_term', 'cache_desc',
127 compute = conditional_cache('short_term', 'cache_desc',
122 condition=True, func=func)
128 condition=True, func=func)
123 return compute(arg)
129 return compute(arg)
124
130
125 :param region: name of cache region
131 :param region: name of cache region
126 :param prefix: cache region prefix
132 :param prefix: cache region prefix
127 :param condition: condition for cache to be triggered, and
133 :param condition: condition for cache to be triggered, and
128 return data cached
134 return data cached
129 :param func: wrapped heavy function to compute
135 :param func: wrapped heavy function to compute
130
136
131 """
137 """
132 wrapped = func
138 wrapped = func
133 if condition:
139 if condition:
134 log.debug('conditional_cache: True, wrapping call of '
140 log.debug('conditional_cache: True, wrapping call of '
135 'func: %s into %s region cache', region, func)
141 'func: %s into %s region cache', region, func)
136 cached_region = _cache_decorate((prefix,), None, None, region)
142 cached_region = _cache_decorate((prefix,), None, None, region)
137 wrapped = cached_region(func)
143 wrapped = cached_region(func)
138 return wrapped
144 return wrapped
139
145
140
146
141 class ActiveRegionCache(object):
147 class ActiveRegionCache(object):
142 def __init__(self, context):
148 def __init__(self, context):
143 self.context = context
149 self.context = context
144
150
145 def invalidate(self, *args, **kwargs):
151 def invalidate(self, *args, **kwargs):
146 return False
152 return False
147
153
148 def compute(self):
154 def compute(self):
149 log.debug('Context cache: getting obj %s from cache', self.context)
155 log.debug('Context cache: getting obj %s from cache', self.context)
150 return self.context.compute_func(self.context.cache_key)
156 return self.context.compute_func(self.context.cache_key)
151
157
152
158
153 class FreshRegionCache(ActiveRegionCache):
159 class FreshRegionCache(ActiveRegionCache):
154 def invalidate(self):
160 def invalidate(self):
155 log.debug('Context cache: invalidating cache for %s', self.context)
161 log.debug('Context cache: invalidating cache for %s', self.context)
156 region_invalidate(
162 region_invalidate(
157 self.context.compute_func, None, self.context.cache_key)
163 self.context.compute_func, None, self.context.cache_key)
158 return True
164 return True
159
165
160
166
161 class InvalidationContext(object):
167 class InvalidationContext(object):
162 def __repr__(self):
168 def __repr__(self):
163 return '<InvalidationContext:{}[{}]>'.format(
169 return '<InvalidationContext:{}[{}]>'.format(
164 self.repo_name, self.cache_type)
170 self.repo_name, self.cache_type)
165
171
166 def __init__(self, compute_func, repo_name, cache_type,
172 def __init__(self, compute_func, repo_name, cache_type,
167 raise_exception=False):
173 raise_exception=False):
168 self.compute_func = compute_func
174 self.compute_func = compute_func
169 self.repo_name = repo_name
175 self.repo_name = repo_name
170 self.cache_type = cache_type
176 self.cache_type = cache_type
171 self.cache_key = compute_key_from_params(
177 self.cache_key = compute_key_from_params(
172 repo_name, cache_type)
178 repo_name, cache_type)
173 self.raise_exception = raise_exception
179 self.raise_exception = raise_exception
174
180
175 def get_cache_obj(self):
181 def get_cache_obj(self):
176 cache_key = CacheKey.get_cache_key(
182 cache_key = CacheKey.get_cache_key(
177 self.repo_name, self.cache_type)
183 self.repo_name, self.cache_type)
178 cache_obj = CacheKey.get_active_cache(cache_key)
184 cache_obj = CacheKey.get_active_cache(cache_key)
179 if not cache_obj:
185 if not cache_obj:
180 cache_obj = CacheKey(cache_key, self.repo_name)
186 cache_obj = CacheKey(cache_key, self.repo_name)
181 return cache_obj
187 return cache_obj
182
188
183 def __enter__(self):
189 def __enter__(self):
184 """
190 """
185 Test if current object is valid, and return CacheRegion function
191 Test if current object is valid, and return CacheRegion function
186 that does invalidation and calculation
192 that does invalidation and calculation
187 """
193 """
188
194
189 self.cache_obj = self.get_cache_obj()
195 self.cache_obj = self.get_cache_obj()
190 if self.cache_obj.cache_active:
196 if self.cache_obj.cache_active:
191 # means our cache obj is existing and marked as it's
197 # means our cache obj is existing and marked as it's
192 # cache is not outdated, we return BaseInvalidator
198 # cache is not outdated, we return BaseInvalidator
193 self.skip_cache_active_change = True
199 self.skip_cache_active_change = True
194 return ActiveRegionCache(self)
200 return ActiveRegionCache(self)
195
201
196 # the key is either not existing or set to False, we return
202 # the key is either not existing or set to False, we return
197 # the real invalidator which re-computes value. We additionally set
203 # the real invalidator which re-computes value. We additionally set
198 # the flag to actually update the Database objects
204 # the flag to actually update the Database objects
199 self.skip_cache_active_change = False
205 self.skip_cache_active_change = False
200 return FreshRegionCache(self)
206 return FreshRegionCache(self)
201
207
202 def __exit__(self, exc_type, exc_val, exc_tb):
208 def __exit__(self, exc_type, exc_val, exc_tb):
203
209
204 if self.skip_cache_active_change:
210 if self.skip_cache_active_change:
205 return
211 return
206
212
207 try:
213 try:
208 self.cache_obj.cache_active = True
214 self.cache_obj.cache_active = True
209 Session().add(self.cache_obj)
215 Session().add(self.cache_obj)
210 Session().commit()
216 Session().commit()
211 except IntegrityError:
217 except IntegrityError:
212 # if we catch integrity error, it means we inserted this object
218 # if we catch integrity error, it means we inserted this object
213 # assumption is that's really an edge race-condition case and
219 # assumption is that's really an edge race-condition case and
214 # it's safe is to skip it
220 # it's safe is to skip it
215 Session().rollback()
221 Session().rollback()
216 except Exception:
222 except Exception:
217 log.exception('Failed to commit on cache key update')
223 log.exception('Failed to commit on cache key update')
218 Session().rollback()
224 Session().rollback()
219 if self.raise_exception:
225 if self.raise_exception:
220 raise
226 raise
@@ -1,690 +1,696 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 hashlib
21 import hashlib
22 import logging
22 import logging
23 from collections import namedtuple
23 from collections import namedtuple
24 from functools import wraps
24 from functools import wraps
25
25
26 from rhodecode.lib import caches
26 from rhodecode.lib import caches
27 from rhodecode.lib.caching_query import FromCache
27 from rhodecode.lib.caching_query import FromCache
28 from rhodecode.lib.utils2 import (
28 from rhodecode.lib.utils2 import (
29 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
29 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
30 from rhodecode.model import BaseModel
30 from rhodecode.model import BaseModel
31 from rhodecode.model.db import (
31 from rhodecode.model.db import (
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
33 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
34
34
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 UiSetting = namedtuple(
39 UiSetting = namedtuple(
40 'UiSetting', ['section', 'key', 'value', 'active'])
40 'UiSetting', ['section', 'key', 'value', 'active'])
41
41
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
43
43
44
44
45 class SettingNotFound(Exception):
45 class SettingNotFound(Exception):
46 def __init__(self):
46 def __init__(self):
47 super(SettingNotFound, self).__init__('Setting is not found')
47 super(SettingNotFound, self).__init__('Setting is not found')
48
48
49
49
50 class SettingsModel(BaseModel):
50 class SettingsModel(BaseModel):
51 BUILTIN_HOOKS = (
51 BUILTIN_HOOKS = (
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PULL,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PULL,
54 RhodeCodeUi.HOOK_PRE_PULL)
54 RhodeCodeUi.HOOK_PRE_PULL)
55 HOOKS_SECTION = 'hooks'
55 HOOKS_SECTION = 'hooks'
56
56
57 def __init__(self, sa=None, repo=None):
57 def __init__(self, sa=None, repo=None):
58 self.repo = repo
58 self.repo = repo
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
60 self.SettingsDbModel = (
60 self.SettingsDbModel = (
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
62 super(SettingsModel, self).__init__(sa)
62 super(SettingsModel, self).__init__(sa)
63
63
64 def get_ui_by_key(self, key):
64 def get_ui_by_key(self, key):
65 q = self.UiDbModel.query()
65 q = self.UiDbModel.query()
66 q = q.filter(self.UiDbModel.ui_key == key)
66 q = q.filter(self.UiDbModel.ui_key == key)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
68 return q.scalar()
68 return q.scalar()
69
69
70 def get_ui_by_section(self, section):
70 def get_ui_by_section(self, section):
71 q = self.UiDbModel.query()
71 q = self.UiDbModel.query()
72 q = q.filter(self.UiDbModel.ui_section == section)
72 q = q.filter(self.UiDbModel.ui_section == section)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
74 return q.all()
74 return q.all()
75
75
76 def get_ui_by_section_and_key(self, section, key):
76 def get_ui_by_section_and_key(self, section, key):
77 q = self.UiDbModel.query()
77 q = self.UiDbModel.query()
78 q = q.filter(self.UiDbModel.ui_section == section)
78 q = q.filter(self.UiDbModel.ui_section == section)
79 q = q.filter(self.UiDbModel.ui_key == key)
79 q = q.filter(self.UiDbModel.ui_key == key)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
81 return q.scalar()
81 return q.scalar()
82
82
83 def get_ui(self, section=None, key=None):
83 def get_ui(self, section=None, key=None):
84 q = self.UiDbModel.query()
84 q = self.UiDbModel.query()
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
86
86
87 if section:
87 if section:
88 q = q.filter(self.UiDbModel.ui_section == section)
88 q = q.filter(self.UiDbModel.ui_section == section)
89 if key:
89 if key:
90 q = q.filter(self.UiDbModel.ui_key == key)
90 q = q.filter(self.UiDbModel.ui_key == key)
91
91
92 # TODO: mikhail: add caching
92 # TODO: mikhail: add caching
93 result = [
93 result = [
94 UiSetting(
94 UiSetting(
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
96 value=safe_str(r.ui_value), active=r.ui_active
96 value=safe_str(r.ui_value), active=r.ui_active
97 )
97 )
98 for r in q.all()
98 for r in q.all()
99 ]
99 ]
100 return result
100 return result
101
101
102 def get_builtin_hooks(self):
102 def get_builtin_hooks(self):
103 q = self.UiDbModel.query()
103 q = self.UiDbModel.query()
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
105 return self._get_hooks(q)
105 return self._get_hooks(q)
106
106
107 def get_custom_hooks(self):
107 def get_custom_hooks(self):
108 q = self.UiDbModel.query()
108 q = self.UiDbModel.query()
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
110 return self._get_hooks(q)
110 return self._get_hooks(q)
111
111
112 def create_ui_section_value(self, section, val, key=None, active=True):
112 def create_ui_section_value(self, section, val, key=None, active=True):
113 new_ui = self.UiDbModel()
113 new_ui = self.UiDbModel()
114 new_ui.ui_section = section
114 new_ui.ui_section = section
115 new_ui.ui_value = val
115 new_ui.ui_value = val
116 new_ui.ui_active = active
116 new_ui.ui_active = active
117
117
118 if self.repo:
118 if self.repo:
119 repo = self._get_repo(self.repo)
119 repo = self._get_repo(self.repo)
120 repository_id = repo.repo_id
120 repository_id = repo.repo_id
121 new_ui.repository_id = repository_id
121 new_ui.repository_id = repository_id
122
122
123 if not key:
123 if not key:
124 # keys are unique so they need appended info
124 # keys are unique so they need appended info
125 if self.repo:
125 if self.repo:
126 key = hashlib.sha1(
126 key = hashlib.sha1(
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
128 else:
128 else:
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
130
130
131 new_ui.ui_key = key
131 new_ui.ui_key = key
132
132
133 Session().add(new_ui)
133 Session().add(new_ui)
134 return new_ui
134 return new_ui
135
135
136 def create_or_update_hook(self, key, value):
136 def create_or_update_hook(self, key, value):
137 ui = (
137 ui = (
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
139 self.UiDbModel())
139 self.UiDbModel())
140 ui.ui_section = self.HOOKS_SECTION
140 ui.ui_section = self.HOOKS_SECTION
141 ui.ui_active = True
141 ui.ui_active = True
142 ui.ui_key = key
142 ui.ui_key = key
143 ui.ui_value = value
143 ui.ui_value = value
144
144
145 if self.repo:
145 if self.repo:
146 repo = self._get_repo(self.repo)
146 repo = self._get_repo(self.repo)
147 repository_id = repo.repo_id
147 repository_id = repo.repo_id
148 ui.repository_id = repository_id
148 ui.repository_id = repository_id
149
149
150 Session().add(ui)
150 Session().add(ui)
151 return ui
151 return ui
152
152
153 def delete_ui(self, id_):
153 def delete_ui(self, id_):
154 ui = self.UiDbModel.get(id_)
154 ui = self.UiDbModel.get(id_)
155 if not ui:
155 if not ui:
156 raise SettingNotFound()
156 raise SettingNotFound()
157 Session().delete(ui)
157 Session().delete(ui)
158
158
159 def get_setting_by_name(self, name):
159 def get_setting_by_name(self, name):
160 q = self._get_settings_query()
160 q = self._get_settings_query()
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
162 return q.scalar()
162 return q.scalar()
163
163
164 def create_or_update_setting(
164 def create_or_update_setting(
165 self, name, val=Optional(''), type_=Optional('unicode')):
165 self, name, val=Optional(''), type_=Optional('unicode')):
166 """
166 """
167 Creates or updates RhodeCode setting. If updates is triggered it will
167 Creates or updates RhodeCode setting. If updates is triggered it will
168 only update parameters that are explicityl set Optional instance will
168 only update parameters that are explicityl set Optional instance will
169 be skipped
169 be skipped
170
170
171 :param name:
171 :param name:
172 :param val:
172 :param val:
173 :param type_:
173 :param type_:
174 :return:
174 :return:
175 """
175 """
176
176
177 res = self.get_setting_by_name(name)
177 res = self.get_setting_by_name(name)
178 repo = self._get_repo(self.repo) if self.repo else None
178 repo = self._get_repo(self.repo) if self.repo else None
179
179
180 if not res:
180 if not res:
181 val = Optional.extract(val)
181 val = Optional.extract(val)
182 type_ = Optional.extract(type_)
182 type_ = Optional.extract(type_)
183
183
184 args = (
184 args = (
185 (repo.repo_id, name, val, type_)
185 (repo.repo_id, name, val, type_)
186 if repo else (name, val, type_))
186 if repo else (name, val, type_))
187 res = self.SettingsDbModel(*args)
187 res = self.SettingsDbModel(*args)
188
188
189 else:
189 else:
190 if self.repo:
190 if self.repo:
191 res.repository_id = repo.repo_id
191 res.repository_id = repo.repo_id
192
192
193 res.app_settings_name = name
193 res.app_settings_name = name
194 if not isinstance(type_, Optional):
194 if not isinstance(type_, Optional):
195 # update if set
195 # update if set
196 res.app_settings_type = type_
196 res.app_settings_type = type_
197 if not isinstance(val, Optional):
197 if not isinstance(val, Optional):
198 # update if set
198 # update if set
199 res.app_settings_value = val
199 res.app_settings_value = val
200
200
201 Session.add(res)
201 Session.add(res)
202 return res
202 return res
203
203
204 def invalidate_settings_cache(self):
205 namespace = 'rhodecode_settings'
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 caches.clear_cache_manager(cache_manager)
208
204 def get_all_settings(self, cache=False):
209 def get_all_settings(self, cache=False):
205 def _compute():
210 def _compute():
206 q = self._get_settings_query()
211 q = self._get_settings_query()
207 if not q:
212 if not q:
208 raise Exception('Could not get application settings !')
213 raise Exception('Could not get application settings !')
209
214
210 settings = {
215 settings = {
211 'rhodecode_' + result.app_settings_name: result.app_settings_value
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
212 for result in q
217 for result in q
213 }
218 }
214 return settings
219 return settings
215
220
216 if cache:
221 if cache:
222 log.debug('Fetching app settings using cache')
217 repo = self._get_repo(self.repo) if self.repo else None
223 repo = self._get_repo(self.repo) if self.repo else None
218 namespace = 'rhodecode_settings'
224 namespace = 'rhodecode_settings'
219 cache_manager = caches.get_cache_manager(
225 cache_manager = caches.get_cache_manager(
220 'sql_cache_short', namespace)
226 'sql_cache_short', namespace)
221 _cache_key = (
227 _cache_key = (
222 "get_repo_{}_settings".format(repo.repo_id)
228 "get_repo_{}_settings".format(repo.repo_id)
223 if repo else "get_app_settings")
229 if repo else "get_app_settings")
224
230
225 return cache_manager.get(_cache_key, createfunc=_compute)
231 return cache_manager.get(_cache_key, createfunc=_compute)
226
232
227 else:
233 else:
228 return _compute()
234 return _compute()
229
235
230 def get_auth_settings(self):
236 def get_auth_settings(self):
231 q = self._get_settings_query()
237 q = self._get_settings_query()
232 q = q.filter(
238 q = q.filter(
233 self.SettingsDbModel.app_settings_name.startswith('auth_'))
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
234 rows = q.all()
240 rows = q.all()
235 auth_settings = {
241 auth_settings = {
236 row.app_settings_name: row.app_settings_value for row in rows}
242 row.app_settings_name: row.app_settings_value for row in rows}
237 return auth_settings
243 return auth_settings
238
244
239 def get_auth_plugins(self):
245 def get_auth_plugins(self):
240 auth_plugins = self.get_setting_by_name("auth_plugins")
246 auth_plugins = self.get_setting_by_name("auth_plugins")
241 return auth_plugins.app_settings_value
247 return auth_plugins.app_settings_value
242
248
243 def get_default_repo_settings(self, strip_prefix=False):
249 def get_default_repo_settings(self, strip_prefix=False):
244 q = self._get_settings_query()
250 q = self._get_settings_query()
245 q = q.filter(
251 q = q.filter(
246 self.SettingsDbModel.app_settings_name.startswith('default_'))
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
247 rows = q.all()
253 rows = q.all()
248
254
249 result = {}
255 result = {}
250 for row in rows:
256 for row in rows:
251 key = row.app_settings_name
257 key = row.app_settings_name
252 if strip_prefix:
258 if strip_prefix:
253 key = remove_prefix(key, prefix='default_')
259 key = remove_prefix(key, prefix='default_')
254 result.update({key: row.app_settings_value})
260 result.update({key: row.app_settings_value})
255 return result
261 return result
256
262
257 def get_repo(self):
263 def get_repo(self):
258 repo = self._get_repo(self.repo)
264 repo = self._get_repo(self.repo)
259 if not repo:
265 if not repo:
260 raise Exception(
266 raise Exception(
261 'Repository {} cannot be found'.format(self.repo))
267 'Repository {} cannot be found'.format(self.repo))
262 return repo
268 return repo
263
269
264 def _filter_by_repo(self, model, query):
270 def _filter_by_repo(self, model, query):
265 if self.repo:
271 if self.repo:
266 repo = self.get_repo()
272 repo = self.get_repo()
267 query = query.filter(model.repository_id == repo.repo_id)
273 query = query.filter(model.repository_id == repo.repo_id)
268 return query
274 return query
269
275
270 def _get_hooks(self, query):
276 def _get_hooks(self, query):
271 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
277 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
272 query = self._filter_by_repo(RepoRhodeCodeUi, query)
278 query = self._filter_by_repo(RepoRhodeCodeUi, query)
273 return query.all()
279 return query.all()
274
280
275 def _get_settings_query(self):
281 def _get_settings_query(self):
276 q = self.SettingsDbModel.query()
282 q = self.SettingsDbModel.query()
277 return self._filter_by_repo(RepoRhodeCodeSetting, q)
283 return self._filter_by_repo(RepoRhodeCodeSetting, q)
278
284
279 def list_enabled_social_plugins(self, settings):
285 def list_enabled_social_plugins(self, settings):
280 enabled = []
286 enabled = []
281 for plug in SOCIAL_PLUGINS_LIST:
287 for plug in SOCIAL_PLUGINS_LIST:
282 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
288 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
283 )):
289 )):
284 enabled.append(plug)
290 enabled.append(plug)
285 return enabled
291 return enabled
286
292
287
293
288 def assert_repo_settings(func):
294 def assert_repo_settings(func):
289 @wraps(func)
295 @wraps(func)
290 def _wrapper(self, *args, **kwargs):
296 def _wrapper(self, *args, **kwargs):
291 if not self.repo_settings:
297 if not self.repo_settings:
292 raise Exception('Repository is not specified')
298 raise Exception('Repository is not specified')
293 return func(self, *args, **kwargs)
299 return func(self, *args, **kwargs)
294 return _wrapper
300 return _wrapper
295
301
296
302
297 class IssueTrackerSettingsModel(object):
303 class IssueTrackerSettingsModel(object):
298 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
304 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
299 SETTINGS_PREFIX = 'issuetracker_'
305 SETTINGS_PREFIX = 'issuetracker_'
300
306
301 def __init__(self, sa=None, repo=None):
307 def __init__(self, sa=None, repo=None):
302 self.global_settings = SettingsModel(sa=sa)
308 self.global_settings = SettingsModel(sa=sa)
303 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
309 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
304
310
305 @property
311 @property
306 def inherit_global_settings(self):
312 def inherit_global_settings(self):
307 if not self.repo_settings:
313 if not self.repo_settings:
308 return True
314 return True
309 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
315 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
310 return setting.app_settings_value if setting else True
316 return setting.app_settings_value if setting else True
311
317
312 @inherit_global_settings.setter
318 @inherit_global_settings.setter
313 def inherit_global_settings(self, value):
319 def inherit_global_settings(self, value):
314 if self.repo_settings:
320 if self.repo_settings:
315 settings = self.repo_settings.create_or_update_setting(
321 settings = self.repo_settings.create_or_update_setting(
316 self.INHERIT_SETTINGS, value, type_='bool')
322 self.INHERIT_SETTINGS, value, type_='bool')
317 Session().add(settings)
323 Session().add(settings)
318
324
319 def _get_keyname(self, key, uid, prefix=''):
325 def _get_keyname(self, key, uid, prefix=''):
320 return '{0}{1}{2}_{3}'.format(
326 return '{0}{1}{2}_{3}'.format(
321 prefix, self.SETTINGS_PREFIX, key, uid)
327 prefix, self.SETTINGS_PREFIX, key, uid)
322
328
323 def _make_dict_for_settings(self, qs):
329 def _make_dict_for_settings(self, qs):
324 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
330 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
325
331
326 issuetracker_entries = {}
332 issuetracker_entries = {}
327 # create keys
333 # create keys
328 for k, v in qs.items():
334 for k, v in qs.items():
329 if k.startswith(prefix_match):
335 if k.startswith(prefix_match):
330 uid = k[len(prefix_match):]
336 uid = k[len(prefix_match):]
331 issuetracker_entries[uid] = None
337 issuetracker_entries[uid] = None
332
338
333 # populate
339 # populate
334 for uid in issuetracker_entries:
340 for uid in issuetracker_entries:
335 issuetracker_entries[uid] = AttributeDict({
341 issuetracker_entries[uid] = AttributeDict({
336 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
342 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
337 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
343 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
338 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
344 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
339 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
345 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
340 })
346 })
341 return issuetracker_entries
347 return issuetracker_entries
342
348
343 def get_global_settings(self, cache=False):
349 def get_global_settings(self, cache=False):
344 """
350 """
345 Returns list of global issue tracker settings
351 Returns list of global issue tracker settings
346 """
352 """
347 defaults = self.global_settings.get_all_settings(cache=cache)
353 defaults = self.global_settings.get_all_settings(cache=cache)
348 settings = self._make_dict_for_settings(defaults)
354 settings = self._make_dict_for_settings(defaults)
349 return settings
355 return settings
350
356
351 def get_repo_settings(self, cache=False):
357 def get_repo_settings(self, cache=False):
352 """
358 """
353 Returns list of issue tracker settings per repository
359 Returns list of issue tracker settings per repository
354 """
360 """
355 if not self.repo_settings:
361 if not self.repo_settings:
356 raise Exception('Repository is not specified')
362 raise Exception('Repository is not specified')
357 all_settings = self.repo_settings.get_all_settings(cache=cache)
363 all_settings = self.repo_settings.get_all_settings(cache=cache)
358 settings = self._make_dict_for_settings(all_settings)
364 settings = self._make_dict_for_settings(all_settings)
359 return settings
365 return settings
360
366
361 def get_settings(self, cache=False):
367 def get_settings(self, cache=False):
362 if self.inherit_global_settings:
368 if self.inherit_global_settings:
363 return self.get_global_settings(cache=cache)
369 return self.get_global_settings(cache=cache)
364 else:
370 else:
365 return self.get_repo_settings(cache=cache)
371 return self.get_repo_settings(cache=cache)
366
372
367 def delete_entries(self, uid):
373 def delete_entries(self, uid):
368 if self.repo_settings:
374 if self.repo_settings:
369 all_patterns = self.get_repo_settings()
375 all_patterns = self.get_repo_settings()
370 settings_model = self.repo_settings
376 settings_model = self.repo_settings
371 else:
377 else:
372 all_patterns = self.get_global_settings()
378 all_patterns = self.get_global_settings()
373 settings_model = self.global_settings
379 settings_model = self.global_settings
374 entries = all_patterns.get(uid)
380 entries = all_patterns.get(uid)
375
381
376 for del_key in entries:
382 for del_key in entries:
377 setting_name = self._get_keyname(del_key, uid)
383 setting_name = self._get_keyname(del_key, uid)
378 entry = settings_model.get_setting_by_name(setting_name)
384 entry = settings_model.get_setting_by_name(setting_name)
379 if entry:
385 if entry:
380 Session().delete(entry)
386 Session().delete(entry)
381
387
382 Session().commit()
388 Session().commit()
383
389
384 def create_or_update_setting(
390 def create_or_update_setting(
385 self, name, val=Optional(''), type_=Optional('unicode')):
391 self, name, val=Optional(''), type_=Optional('unicode')):
386 if self.repo_settings:
392 if self.repo_settings:
387 setting = self.repo_settings.create_or_update_setting(
393 setting = self.repo_settings.create_or_update_setting(
388 name, val, type_)
394 name, val, type_)
389 else:
395 else:
390 setting = self.global_settings.create_or_update_setting(
396 setting = self.global_settings.create_or_update_setting(
391 name, val, type_)
397 name, val, type_)
392 return setting
398 return setting
393
399
394
400
395 class VcsSettingsModel(object):
401 class VcsSettingsModel(object):
396
402
397 INHERIT_SETTINGS = 'inherit_vcs_settings'
403 INHERIT_SETTINGS = 'inherit_vcs_settings'
398 GENERAL_SETTINGS = ('use_outdated_comments', 'pr_merge_enabled')
404 GENERAL_SETTINGS = ('use_outdated_comments', 'pr_merge_enabled')
399 HOOKS_SETTINGS = (
405 HOOKS_SETTINGS = (
400 ('hooks', 'changegroup.repo_size'),
406 ('hooks', 'changegroup.repo_size'),
401 ('hooks', 'changegroup.push_logger'),
407 ('hooks', 'changegroup.push_logger'),
402 ('hooks', 'outgoing.pull_logger'))
408 ('hooks', 'outgoing.pull_logger'))
403 HG_SETTINGS = (
409 HG_SETTINGS = (
404 ('extensions', 'largefiles'), ('phases', 'publish'))
410 ('extensions', 'largefiles'), ('phases', 'publish'))
405 GLOBAL_HG_SETTINGS = HG_SETTINGS + (('extensions', 'hgsubversion'), )
411 GLOBAL_HG_SETTINGS = HG_SETTINGS + (('extensions', 'hgsubversion'), )
406 SVN_BRANCH_SECTION = 'vcs_svn_branch'
412 SVN_BRANCH_SECTION = 'vcs_svn_branch'
407 SVN_TAG_SECTION = 'vcs_svn_tag'
413 SVN_TAG_SECTION = 'vcs_svn_tag'
408 SSL_SETTING = ('web', 'push_ssl')
414 SSL_SETTING = ('web', 'push_ssl')
409 PATH_SETTING = ('paths', '/')
415 PATH_SETTING = ('paths', '/')
410
416
411 def __init__(self, sa=None, repo=None):
417 def __init__(self, sa=None, repo=None):
412 self.global_settings = SettingsModel(sa=sa)
418 self.global_settings = SettingsModel(sa=sa)
413 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
419 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
414 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
420 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
415 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
421 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
416
422
417 @property
423 @property
418 @assert_repo_settings
424 @assert_repo_settings
419 def inherit_global_settings(self):
425 def inherit_global_settings(self):
420 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
426 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
421 return setting.app_settings_value if setting else True
427 return setting.app_settings_value if setting else True
422
428
423 @inherit_global_settings.setter
429 @inherit_global_settings.setter
424 @assert_repo_settings
430 @assert_repo_settings
425 def inherit_global_settings(self, value):
431 def inherit_global_settings(self, value):
426 self.repo_settings.create_or_update_setting(
432 self.repo_settings.create_or_update_setting(
427 self.INHERIT_SETTINGS, value, type_='bool')
433 self.INHERIT_SETTINGS, value, type_='bool')
428
434
429 def get_global_svn_branch_patterns(self):
435 def get_global_svn_branch_patterns(self):
430 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
436 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
431
437
432 @assert_repo_settings
438 @assert_repo_settings
433 def get_repo_svn_branch_patterns(self):
439 def get_repo_svn_branch_patterns(self):
434 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
440 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
435
441
436 def get_global_svn_tag_patterns(self):
442 def get_global_svn_tag_patterns(self):
437 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
443 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
438
444
439 @assert_repo_settings
445 @assert_repo_settings
440 def get_repo_svn_tag_patterns(self):
446 def get_repo_svn_tag_patterns(self):
441 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
447 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
442
448
443 def get_global_settings(self):
449 def get_global_settings(self):
444 return self._collect_all_settings(global_=True)
450 return self._collect_all_settings(global_=True)
445
451
446 @assert_repo_settings
452 @assert_repo_settings
447 def get_repo_settings(self):
453 def get_repo_settings(self):
448 return self._collect_all_settings(global_=False)
454 return self._collect_all_settings(global_=False)
449
455
450 @assert_repo_settings
456 @assert_repo_settings
451 def create_or_update_repo_settings(
457 def create_or_update_repo_settings(
452 self, data, inherit_global_settings=False):
458 self, data, inherit_global_settings=False):
453 from rhodecode.model.scm import ScmModel
459 from rhodecode.model.scm import ScmModel
454
460
455 self.inherit_global_settings = inherit_global_settings
461 self.inherit_global_settings = inherit_global_settings
456
462
457 repo = self.repo_settings.get_repo()
463 repo = self.repo_settings.get_repo()
458 if not inherit_global_settings:
464 if not inherit_global_settings:
459 if repo.repo_type == 'svn':
465 if repo.repo_type == 'svn':
460 self.create_repo_svn_settings(data)
466 self.create_repo_svn_settings(data)
461 else:
467 else:
462 self.create_or_update_repo_hook_settings(data)
468 self.create_or_update_repo_hook_settings(data)
463 self.create_or_update_repo_pr_settings(data)
469 self.create_or_update_repo_pr_settings(data)
464
470
465 if repo.repo_type == 'hg':
471 if repo.repo_type == 'hg':
466 self.create_or_update_repo_hg_settings(data)
472 self.create_or_update_repo_hg_settings(data)
467
473
468 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
474 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
469
475
470 @assert_repo_settings
476 @assert_repo_settings
471 def create_or_update_repo_hook_settings(self, data):
477 def create_or_update_repo_hook_settings(self, data):
472 for section, key in self.HOOKS_SETTINGS:
478 for section, key in self.HOOKS_SETTINGS:
473 data_key = self._get_form_ui_key(section, key)
479 data_key = self._get_form_ui_key(section, key)
474 if data_key not in data:
480 if data_key not in data:
475 raise ValueError(
481 raise ValueError(
476 'The given data does not contain {} key'.format(data_key))
482 'The given data does not contain {} key'.format(data_key))
477
483
478 active = data.get(data_key)
484 active = data.get(data_key)
479 repo_setting = self.repo_settings.get_ui_by_section_and_key(
485 repo_setting = self.repo_settings.get_ui_by_section_and_key(
480 section, key)
486 section, key)
481 if not repo_setting:
487 if not repo_setting:
482 global_setting = self.global_settings.\
488 global_setting = self.global_settings.\
483 get_ui_by_section_and_key(section, key)
489 get_ui_by_section_and_key(section, key)
484 self.repo_settings.create_ui_section_value(
490 self.repo_settings.create_ui_section_value(
485 section, global_setting.ui_value, key=key, active=active)
491 section, global_setting.ui_value, key=key, active=active)
486 else:
492 else:
487 repo_setting.ui_active = active
493 repo_setting.ui_active = active
488 Session().add(repo_setting)
494 Session().add(repo_setting)
489
495
490 def update_global_hook_settings(self, data):
496 def update_global_hook_settings(self, data):
491 for section, key in self.HOOKS_SETTINGS:
497 for section, key in self.HOOKS_SETTINGS:
492 data_key = self._get_form_ui_key(section, key)
498 data_key = self._get_form_ui_key(section, key)
493 if data_key not in data:
499 if data_key not in data:
494 raise ValueError(
500 raise ValueError(
495 'The given data does not contain {} key'.format(data_key))
501 'The given data does not contain {} key'.format(data_key))
496 active = data.get(data_key)
502 active = data.get(data_key)
497 repo_setting = self.global_settings.get_ui_by_section_and_key(
503 repo_setting = self.global_settings.get_ui_by_section_and_key(
498 section, key)
504 section, key)
499 repo_setting.ui_active = active
505 repo_setting.ui_active = active
500 Session().add(repo_setting)
506 Session().add(repo_setting)
501
507
502 @assert_repo_settings
508 @assert_repo_settings
503 def create_or_update_repo_pr_settings(self, data):
509 def create_or_update_repo_pr_settings(self, data):
504 return self._create_or_update_general_settings(
510 return self._create_or_update_general_settings(
505 self.repo_settings, data)
511 self.repo_settings, data)
506
512
507 def create_or_update_global_pr_settings(self, data):
513 def create_or_update_global_pr_settings(self, data):
508 return self._create_or_update_general_settings(
514 return self._create_or_update_general_settings(
509 self.global_settings, data)
515 self.global_settings, data)
510
516
511 @assert_repo_settings
517 @assert_repo_settings
512 def create_repo_svn_settings(self, data):
518 def create_repo_svn_settings(self, data):
513 return self._create_svn_settings(self.repo_settings, data)
519 return self._create_svn_settings(self.repo_settings, data)
514
520
515 def create_global_svn_settings(self, data):
521 def create_global_svn_settings(self, data):
516 return self._create_svn_settings(self.global_settings, data)
522 return self._create_svn_settings(self.global_settings, data)
517
523
518 @assert_repo_settings
524 @assert_repo_settings
519 def create_or_update_repo_hg_settings(self, data):
525 def create_or_update_repo_hg_settings(self, data):
520 largefiles, phases = self.HG_SETTINGS
526 largefiles, phases = self.HG_SETTINGS
521 largefiles_key, phases_key = self._get_hg_settings(
527 largefiles_key, phases_key = self._get_hg_settings(
522 self.HG_SETTINGS, data)
528 self.HG_SETTINGS, data)
523 self._create_or_update_ui(
529 self._create_or_update_ui(
524 self.repo_settings, *largefiles, value='',
530 self.repo_settings, *largefiles, value='',
525 active=data[largefiles_key])
531 active=data[largefiles_key])
526 self._create_or_update_ui(
532 self._create_or_update_ui(
527 self.repo_settings, *phases, value=safe_str(data[phases_key]))
533 self.repo_settings, *phases, value=safe_str(data[phases_key]))
528
534
529 def create_or_update_global_hg_settings(self, data):
535 def create_or_update_global_hg_settings(self, data):
530 largefiles, phases, subversion = self.GLOBAL_HG_SETTINGS
536 largefiles, phases, subversion = self.GLOBAL_HG_SETTINGS
531 largefiles_key, phases_key, subversion_key = self._get_hg_settings(
537 largefiles_key, phases_key, subversion_key = self._get_hg_settings(
532 self.GLOBAL_HG_SETTINGS, data)
538 self.GLOBAL_HG_SETTINGS, data)
533 self._create_or_update_ui(
539 self._create_or_update_ui(
534 self.global_settings, *largefiles, value='',
540 self.global_settings, *largefiles, value='',
535 active=data[largefiles_key])
541 active=data[largefiles_key])
536 self._create_or_update_ui(
542 self._create_or_update_ui(
537 self.global_settings, *phases, value=safe_str(data[phases_key]))
543 self.global_settings, *phases, value=safe_str(data[phases_key]))
538 self._create_or_update_ui(
544 self._create_or_update_ui(
539 self.global_settings, *subversion, active=data[subversion_key])
545 self.global_settings, *subversion, active=data[subversion_key])
540
546
541 def update_global_ssl_setting(self, value):
547 def update_global_ssl_setting(self, value):
542 self._create_or_update_ui(
548 self._create_or_update_ui(
543 self.global_settings, *self.SSL_SETTING, value=value)
549 self.global_settings, *self.SSL_SETTING, value=value)
544
550
545 def update_global_path_setting(self, value):
551 def update_global_path_setting(self, value):
546 self._create_or_update_ui(
552 self._create_or_update_ui(
547 self.global_settings, *self.PATH_SETTING, value=value)
553 self.global_settings, *self.PATH_SETTING, value=value)
548
554
549 @assert_repo_settings
555 @assert_repo_settings
550 def delete_repo_svn_pattern(self, id_):
556 def delete_repo_svn_pattern(self, id_):
551 self.repo_settings.delete_ui(id_)
557 self.repo_settings.delete_ui(id_)
552
558
553 def delete_global_svn_pattern(self, id_):
559 def delete_global_svn_pattern(self, id_):
554 self.global_settings.delete_ui(id_)
560 self.global_settings.delete_ui(id_)
555
561
556 @assert_repo_settings
562 @assert_repo_settings
557 def get_repo_ui_settings(self, section=None, key=None):
563 def get_repo_ui_settings(self, section=None, key=None):
558 global_uis = self.global_settings.get_ui(section, key)
564 global_uis = self.global_settings.get_ui(section, key)
559 repo_uis = self.repo_settings.get_ui(section, key)
565 repo_uis = self.repo_settings.get_ui(section, key)
560 filtered_repo_uis = self._filter_ui_settings(repo_uis)
566 filtered_repo_uis = self._filter_ui_settings(repo_uis)
561 filtered_repo_uis_keys = [
567 filtered_repo_uis_keys = [
562 (s.section, s.key) for s in filtered_repo_uis]
568 (s.section, s.key) for s in filtered_repo_uis]
563
569
564 def _is_global_ui_filtered(ui):
570 def _is_global_ui_filtered(ui):
565 return (
571 return (
566 (ui.section, ui.key) in filtered_repo_uis_keys
572 (ui.section, ui.key) in filtered_repo_uis_keys
567 or ui.section in self._svn_sections)
573 or ui.section in self._svn_sections)
568
574
569 filtered_global_uis = [
575 filtered_global_uis = [
570 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
576 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
571
577
572 return filtered_global_uis + filtered_repo_uis
578 return filtered_global_uis + filtered_repo_uis
573
579
574 def get_global_ui_settings(self, section=None, key=None):
580 def get_global_ui_settings(self, section=None, key=None):
575 return self.global_settings.get_ui(section, key)
581 return self.global_settings.get_ui(section, key)
576
582
577 def get_ui_settings(self, section=None, key=None):
583 def get_ui_settings(self, section=None, key=None):
578 if not self.repo_settings or self.inherit_global_settings:
584 if not self.repo_settings or self.inherit_global_settings:
579 return self.get_global_ui_settings(section, key)
585 return self.get_global_ui_settings(section, key)
580 else:
586 else:
581 return self.get_repo_ui_settings(section, key)
587 return self.get_repo_ui_settings(section, key)
582
588
583 def get_svn_patterns(self, section=None):
589 def get_svn_patterns(self, section=None):
584 if not self.repo_settings:
590 if not self.repo_settings:
585 return self.get_global_ui_settings(section)
591 return self.get_global_ui_settings(section)
586 else:
592 else:
587 return self.get_repo_ui_settings(section)
593 return self.get_repo_ui_settings(section)
588
594
589 @assert_repo_settings
595 @assert_repo_settings
590 def get_repo_general_settings(self):
596 def get_repo_general_settings(self):
591 global_settings = self.global_settings.get_all_settings()
597 global_settings = self.global_settings.get_all_settings()
592 repo_settings = self.repo_settings.get_all_settings()
598 repo_settings = self.repo_settings.get_all_settings()
593 filtered_repo_settings = self._filter_general_settings(repo_settings)
599 filtered_repo_settings = self._filter_general_settings(repo_settings)
594 global_settings.update(filtered_repo_settings)
600 global_settings.update(filtered_repo_settings)
595 return global_settings
601 return global_settings
596
602
597 def get_global_general_settings(self):
603 def get_global_general_settings(self):
598 return self.global_settings.get_all_settings()
604 return self.global_settings.get_all_settings()
599
605
600 def get_general_settings(self):
606 def get_general_settings(self):
601 if not self.repo_settings or self.inherit_global_settings:
607 if not self.repo_settings or self.inherit_global_settings:
602 return self.get_global_general_settings()
608 return self.get_global_general_settings()
603 else:
609 else:
604 return self.get_repo_general_settings()
610 return self.get_repo_general_settings()
605
611
606 def get_repos_location(self):
612 def get_repos_location(self):
607 return self.global_settings.get_ui_by_key('/').ui_value
613 return self.global_settings.get_ui_by_key('/').ui_value
608
614
609 def _filter_ui_settings(self, settings):
615 def _filter_ui_settings(self, settings):
610 filtered_settings = [
616 filtered_settings = [
611 s for s in settings if self._should_keep_setting(s)]
617 s for s in settings if self._should_keep_setting(s)]
612 return filtered_settings
618 return filtered_settings
613
619
614 def _should_keep_setting(self, setting):
620 def _should_keep_setting(self, setting):
615 keep = (
621 keep = (
616 (setting.section, setting.key) in self._ui_settings or
622 (setting.section, setting.key) in self._ui_settings or
617 setting.section in self._svn_sections)
623 setting.section in self._svn_sections)
618 return keep
624 return keep
619
625
620 def _filter_general_settings(self, settings):
626 def _filter_general_settings(self, settings):
621 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
627 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
622 return {
628 return {
623 k: settings[k]
629 k: settings[k]
624 for k in settings if k in keys}
630 for k in settings if k in keys}
625
631
626 def _collect_all_settings(self, global_=False):
632 def _collect_all_settings(self, global_=False):
627 settings = self.global_settings if global_ else self.repo_settings
633 settings = self.global_settings if global_ else self.repo_settings
628 result = {}
634 result = {}
629
635
630 for section, key in self._ui_settings:
636 for section, key in self._ui_settings:
631 ui = settings.get_ui_by_section_and_key(section, key)
637 ui = settings.get_ui_by_section_and_key(section, key)
632 result_key = self._get_form_ui_key(section, key)
638 result_key = self._get_form_ui_key(section, key)
633 if ui:
639 if ui:
634 if section in ('hooks', 'extensions'):
640 if section in ('hooks', 'extensions'):
635 result[result_key] = ui.ui_active
641 result[result_key] = ui.ui_active
636 else:
642 else:
637 result[result_key] = ui.ui_value
643 result[result_key] = ui.ui_value
638
644
639 for name in self.GENERAL_SETTINGS:
645 for name in self.GENERAL_SETTINGS:
640 setting = settings.get_setting_by_name(name)
646 setting = settings.get_setting_by_name(name)
641 if setting:
647 if setting:
642 result_key = 'rhodecode_{}'.format(name)
648 result_key = 'rhodecode_{}'.format(name)
643 result[result_key] = setting.app_settings_value
649 result[result_key] = setting.app_settings_value
644
650
645 return result
651 return result
646
652
647 def _get_form_ui_key(self, section, key):
653 def _get_form_ui_key(self, section, key):
648 return '{section}_{key}'.format(
654 return '{section}_{key}'.format(
649 section=section, key=key.replace('.', '_'))
655 section=section, key=key.replace('.', '_'))
650
656
651 def _create_or_update_ui(
657 def _create_or_update_ui(
652 self, settings, section, key, value=None, active=None):
658 self, settings, section, key, value=None, active=None):
653 ui = settings.get_ui_by_section_and_key(section, key)
659 ui = settings.get_ui_by_section_and_key(section, key)
654 if not ui:
660 if not ui:
655 active = True if active is None else active
661 active = True if active is None else active
656 settings.create_ui_section_value(
662 settings.create_ui_section_value(
657 section, value, key=key, active=active)
663 section, value, key=key, active=active)
658 else:
664 else:
659 if active is not None:
665 if active is not None:
660 ui.ui_active = active
666 ui.ui_active = active
661 if value is not None:
667 if value is not None:
662 ui.ui_value = value
668 ui.ui_value = value
663 Session().add(ui)
669 Session().add(ui)
664
670
665 def _create_svn_settings(self, settings, data):
671 def _create_svn_settings(self, settings, data):
666 svn_settings = {
672 svn_settings = {
667 'new_svn_branch': self.SVN_BRANCH_SECTION,
673 'new_svn_branch': self.SVN_BRANCH_SECTION,
668 'new_svn_tag': self.SVN_TAG_SECTION
674 'new_svn_tag': self.SVN_TAG_SECTION
669 }
675 }
670 for key in svn_settings:
676 for key in svn_settings:
671 if data.get(key):
677 if data.get(key):
672 settings.create_ui_section_value(svn_settings[key], data[key])
678 settings.create_ui_section_value(svn_settings[key], data[key])
673
679
674 def _create_or_update_general_settings(self, settings, data):
680 def _create_or_update_general_settings(self, settings, data):
675 for name in self.GENERAL_SETTINGS:
681 for name in self.GENERAL_SETTINGS:
676 data_key = 'rhodecode_{}'.format(name)
682 data_key = 'rhodecode_{}'.format(name)
677 if data_key not in data:
683 if data_key not in data:
678 raise ValueError(
684 raise ValueError(
679 'The given data does not contain {} key'.format(data_key))
685 'The given data does not contain {} key'.format(data_key))
680 setting = settings.create_or_update_setting(
686 setting = settings.create_or_update_setting(
681 name, data[data_key], 'bool')
687 name, data[data_key], 'bool')
682 Session().add(setting)
688 Session().add(setting)
683
689
684 def _get_hg_settings(self, settings, data):
690 def _get_hg_settings(self, settings, data):
685 data_keys = [self._get_form_ui_key(*s) for s in settings]
691 data_keys = [self._get_form_ui_key(*s) for s in settings]
686 for data_key in data_keys:
692 for data_key in data_keys:
687 if data_key not in data:
693 if data_key not in data:
688 raise ValueError(
694 raise ValueError(
689 'The given data does not contain {} key'.format(data_key))
695 'The given data does not contain {} key'.format(data_key))
690 return data_keys
696 return data_keys
General Comments 0
You need to be logged in to leave comments. Login now