##// END OF EJS Templates
svn: moving svn http support out of labs settings.
lisaq -
r748:0147d45d default
parent child Browse files
Show More
@@ -1,806 +1,793 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.admin.navigation import navigation_list
40 from rhodecode.admin.navigation import navigation_list
41 from rhodecode.lib import auth
41 from rhodecode.lib import auth
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.celerylib import tasks, run_task
45 from rhodecode.lib.celerylib import tasks, run_task
46 from rhodecode.lib.utils import repo2db_mapper
46 from rhodecode.lib.utils import repo2db_mapper
47 from rhodecode.lib.utils2 import (
47 from rhodecode.lib.utils2 import (
48 str2bool, safe_unicode, AttributeDict, safe_int)
48 str2bool, safe_unicode, AttributeDict, safe_int)
49 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.compat import OrderedDict
50 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.ext_json import json
51 from rhodecode.lib.utils import jsonify
51 from rhodecode.lib.utils import jsonify
52
52
53 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.db import RhodeCodeUi, Repository
54 from rhodecode.model.forms import ApplicationSettingsForm, \
54 from rhodecode.model.forms import ApplicationSettingsForm, \
55 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
55 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 LabsSettingsForm, IssueTrackerPatternsForm
56 LabsSettingsForm, IssueTrackerPatternsForm
57
57
58 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.notification import EmailNotificationModel
59 from rhodecode.model.notification import EmailNotificationModel
60 from rhodecode.model.meta import Session
60 from rhodecode.model.meta import Session
61 from rhodecode.model.settings import (
61 from rhodecode.model.settings import (
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
63 SettingsModel)
63 SettingsModel)
64
64
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
66
66
67
67
68 log = logging.getLogger(__name__)
68 log = logging.getLogger(__name__)
69
69
70
70
71 class SettingsController(BaseController):
71 class SettingsController(BaseController):
72 """REST Controller styled on the Atom Publishing Protocol"""
72 """REST Controller styled on the Atom Publishing Protocol"""
73 # To properly map this controller, ensure your config/routing.py
73 # To properly map this controller, ensure your config/routing.py
74 # file has a resource setup:
74 # file has a resource setup:
75 # map.resource('setting', 'settings', controller='admin/settings',
75 # map.resource('setting', 'settings', controller='admin/settings',
76 # path_prefix='/admin', name_prefix='admin_')
76 # path_prefix='/admin', name_prefix='admin_')
77
77
78 @LoginRequired()
78 @LoginRequired()
79 def __before__(self):
79 def __before__(self):
80 super(SettingsController, self).__before__()
80 super(SettingsController, self).__before__()
81 c.labs_active = str2bool(
81 c.labs_active = str2bool(
82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
83 c.navlist = navigation_list(request)
83 c.navlist = navigation_list(request)
84
84
85 def _get_hg_ui_settings(self):
85 def _get_hg_ui_settings(self):
86 ret = RhodeCodeUi.query().all()
86 ret = RhodeCodeUi.query().all()
87
87
88 if not ret:
88 if not ret:
89 raise Exception('Could not get application ui settings !')
89 raise Exception('Could not get application ui settings !')
90 settings = {}
90 settings = {}
91 for each in ret:
91 for each in ret:
92 k = each.ui_key
92 k = each.ui_key
93 v = each.ui_value
93 v = each.ui_value
94 if k == '/':
94 if k == '/':
95 k = 'root_path'
95 k = 'root_path'
96
96
97 if k in ['push_ssl', 'publish']:
97 if k in ['push_ssl', 'publish']:
98 v = str2bool(v)
98 v = str2bool(v)
99
99
100 if k.find('.') != -1:
100 if k.find('.') != -1:
101 k = k.replace('.', '_')
101 k = k.replace('.', '_')
102
102
103 if each.ui_section in ['hooks', 'extensions']:
103 if each.ui_section in ['hooks', 'extensions']:
104 v = each.ui_active
104 v = each.ui_active
105
105
106 settings[each.ui_section + '_' + k] = v
106 settings[each.ui_section + '_' + k] = v
107 return settings
107 return settings
108
108
109 @HasPermissionAllDecorator('hg.admin')
109 @HasPermissionAllDecorator('hg.admin')
110 @auth.CSRFRequired()
110 @auth.CSRFRequired()
111 @jsonify
111 @jsonify
112 def delete_svn_pattern(self):
112 def delete_svn_pattern(self):
113 if not request.is_xhr:
113 if not request.is_xhr:
114 raise HTTPBadRequest()
114 raise HTTPBadRequest()
115
115
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
117 model = VcsSettingsModel()
117 model = VcsSettingsModel()
118 try:
118 try:
119 model.delete_global_svn_pattern(delete_pattern_id)
119 model.delete_global_svn_pattern(delete_pattern_id)
120 except SettingNotFound:
120 except SettingNotFound:
121 raise HTTPBadRequest()
121 raise HTTPBadRequest()
122
122
123 Session().commit()
123 Session().commit()
124 return True
124 return True
125
125
126 @HasPermissionAllDecorator('hg.admin')
126 @HasPermissionAllDecorator('hg.admin')
127 @auth.CSRFRequired()
127 @auth.CSRFRequired()
128 def settings_vcs_update(self):
128 def settings_vcs_update(self):
129 """POST /admin/settings: All items in the collection"""
129 """POST /admin/settings: All items in the collection"""
130 # url('admin_settings_vcs')
130 # url('admin_settings_vcs')
131 c.active = 'vcs'
131 c.active = 'vcs'
132
132
133 model = VcsSettingsModel()
133 model = VcsSettingsModel()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
136
136
137 application_form = ApplicationUiSettingsForm()()
137 application_form = ApplicationUiSettingsForm()()
138 try:
138 try:
139 form_result = application_form.to_python(dict(request.POST))
139 form_result = application_form.to_python(dict(request.POST))
140 except formencode.Invalid as errors:
140 except formencode.Invalid as errors:
141 h.flash(
141 h.flash(
142 _("Some form inputs contain invalid data."),
142 _("Some form inputs contain invalid data."),
143 category='error')
143 category='error')
144 return htmlfill.render(
144 return htmlfill.render(
145 render('admin/settings/settings.html'),
145 render('admin/settings/settings.html'),
146 defaults=errors.value,
146 defaults=errors.value,
147 errors=errors.error_dict or {},
147 errors=errors.error_dict or {},
148 prefix_error=False,
148 prefix_error=False,
149 encoding="UTF-8",
149 encoding="UTF-8",
150 force_defaults=False
150 force_defaults=False
151 )
151 )
152
152
153 try:
153 try:
154 model.update_global_ssl_setting(form_result['web_push_ssl'])
154 model.update_global_ssl_setting(form_result['web_push_ssl'])
155 if c.visual.allow_repo_location_change:
155 if c.visual.allow_repo_location_change:
156 model.update_global_path_setting(
156 model.update_global_path_setting(
157 form_result['paths_root_path'])
157 form_result['paths_root_path'])
158 model.update_global_hook_settings(form_result)
158 model.update_global_hook_settings(form_result)
159 model.create_global_svn_settings(form_result)
159 model.create_global_svn_settings(form_result)
160 model.create_or_update_global_hg_settings(form_result)
160 model.create_or_update_global_hg_settings(form_result)
161 model.create_or_update_global_pr_settings(form_result)
161 model.create_or_update_global_pr_settings(form_result)
162 except Exception:
162 except Exception:
163 log.exception("Exception while updating settings")
163 log.exception("Exception while updating settings")
164 h.flash(_('Error occurred during updating '
164 h.flash(_('Error occurred during updating '
165 'application settings'), category='error')
165 'application settings'), category='error')
166 else:
166 else:
167 Session().commit()
167 Session().commit()
168 h.flash(_('Updated VCS settings'), category='success')
168 h.flash(_('Updated VCS settings'), category='success')
169 return redirect(url('admin_settings_vcs'))
169 return redirect(url('admin_settings_vcs'))
170
170
171 return htmlfill.render(
171 return htmlfill.render(
172 render('admin/settings/settings.html'),
172 render('admin/settings/settings.html'),
173 defaults=self._form_defaults(),
173 defaults=self._form_defaults(),
174 encoding="UTF-8",
174 encoding="UTF-8",
175 force_defaults=False)
175 force_defaults=False)
176
176
177 @HasPermissionAllDecorator('hg.admin')
177 @HasPermissionAllDecorator('hg.admin')
178 def settings_vcs(self):
178 def settings_vcs(self):
179 """GET /admin/settings: All items in the collection"""
179 """GET /admin/settings: All items in the collection"""
180 # url('admin_settings_vcs')
180 # url('admin_settings_vcs')
181 c.active = 'vcs'
181 c.active = 'vcs'
182 model = VcsSettingsModel()
182 model = VcsSettingsModel()
183 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
183 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
184 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
184 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
185
185
186 return htmlfill.render(
186 return htmlfill.render(
187 render('admin/settings/settings.html'),
187 render('admin/settings/settings.html'),
188 defaults=self._form_defaults(),
188 defaults=self._form_defaults(),
189 encoding="UTF-8",
189 encoding="UTF-8",
190 force_defaults=False)
190 force_defaults=False)
191
191
192 @HasPermissionAllDecorator('hg.admin')
192 @HasPermissionAllDecorator('hg.admin')
193 @auth.CSRFRequired()
193 @auth.CSRFRequired()
194 def settings_mapping_update(self):
194 def settings_mapping_update(self):
195 """POST /admin/settings/mapping: All items in the collection"""
195 """POST /admin/settings/mapping: All items in the collection"""
196 # url('admin_settings_mapping')
196 # url('admin_settings_mapping')
197 c.active = 'mapping'
197 c.active = 'mapping'
198 rm_obsolete = request.POST.get('destroy', False)
198 rm_obsolete = request.POST.get('destroy', False)
199 invalidate_cache = request.POST.get('invalidate', False)
199 invalidate_cache = request.POST.get('invalidate', False)
200 log.debug(
200 log.debug(
201 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
201 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
202
202
203 if invalidate_cache:
203 if invalidate_cache:
204 log.debug('invalidating all repositories cache')
204 log.debug('invalidating all repositories cache')
205 for repo in Repository.get_all():
205 for repo in Repository.get_all():
206 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
206 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
207
207
208 filesystem_repos = ScmModel().repo_scan()
208 filesystem_repos = ScmModel().repo_scan()
209 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
209 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
210 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
210 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
211 h.flash(_('Repositories successfully '
211 h.flash(_('Repositories successfully '
212 'rescanned added: %s ; removed: %s') %
212 'rescanned added: %s ; removed: %s') %
213 (_repr(added), _repr(removed)),
213 (_repr(added), _repr(removed)),
214 category='success')
214 category='success')
215 return redirect(url('admin_settings_mapping'))
215 return redirect(url('admin_settings_mapping'))
216
216
217 @HasPermissionAllDecorator('hg.admin')
217 @HasPermissionAllDecorator('hg.admin')
218 def settings_mapping(self):
218 def settings_mapping(self):
219 """GET /admin/settings/mapping: All items in the collection"""
219 """GET /admin/settings/mapping: All items in the collection"""
220 # url('admin_settings_mapping')
220 # url('admin_settings_mapping')
221 c.active = 'mapping'
221 c.active = 'mapping'
222
222
223 return htmlfill.render(
223 return htmlfill.render(
224 render('admin/settings/settings.html'),
224 render('admin/settings/settings.html'),
225 defaults=self._form_defaults(),
225 defaults=self._form_defaults(),
226 encoding="UTF-8",
226 encoding="UTF-8",
227 force_defaults=False)
227 force_defaults=False)
228
228
229 @HasPermissionAllDecorator('hg.admin')
229 @HasPermissionAllDecorator('hg.admin')
230 @auth.CSRFRequired()
230 @auth.CSRFRequired()
231 def settings_global_update(self):
231 def settings_global_update(self):
232 """POST /admin/settings/global: All items in the collection"""
232 """POST /admin/settings/global: All items in the collection"""
233 # url('admin_settings_global')
233 # url('admin_settings_global')
234 c.active = 'global'
234 c.active = 'global'
235 application_form = ApplicationSettingsForm()()
235 application_form = ApplicationSettingsForm()()
236 try:
236 try:
237 form_result = application_form.to_python(dict(request.POST))
237 form_result = application_form.to_python(dict(request.POST))
238 except formencode.Invalid as errors:
238 except formencode.Invalid as errors:
239 return htmlfill.render(
239 return htmlfill.render(
240 render('admin/settings/settings.html'),
240 render('admin/settings/settings.html'),
241 defaults=errors.value,
241 defaults=errors.value,
242 errors=errors.error_dict or {},
242 errors=errors.error_dict or {},
243 prefix_error=False,
243 prefix_error=False,
244 encoding="UTF-8",
244 encoding="UTF-8",
245 force_defaults=False)
245 force_defaults=False)
246
246
247 try:
247 try:
248 settings = [
248 settings = [
249 ('title', 'rhodecode_title'),
249 ('title', 'rhodecode_title'),
250 ('realm', 'rhodecode_realm'),
250 ('realm', 'rhodecode_realm'),
251 ('pre_code', 'rhodecode_pre_code'),
251 ('pre_code', 'rhodecode_pre_code'),
252 ('post_code', 'rhodecode_post_code'),
252 ('post_code', 'rhodecode_post_code'),
253 ('captcha_public_key', 'rhodecode_captcha_public_key'),
253 ('captcha_public_key', 'rhodecode_captcha_public_key'),
254 ('captcha_private_key', 'rhodecode_captcha_private_key'),
254 ('captcha_private_key', 'rhodecode_captcha_private_key'),
255 ]
255 ]
256 for setting, form_key in settings:
256 for setting, form_key in settings:
257 sett = SettingsModel().create_or_update_setting(
257 sett = SettingsModel().create_or_update_setting(
258 setting, form_result[form_key])
258 setting, form_result[form_key])
259 Session().add(sett)
259 Session().add(sett)
260
260
261 Session().commit()
261 Session().commit()
262 SettingsModel().invalidate_settings_cache()
262 SettingsModel().invalidate_settings_cache()
263 h.flash(_('Updated application settings'), category='success')
263 h.flash(_('Updated application settings'), category='success')
264 except Exception:
264 except Exception:
265 log.exception("Exception while updating application settings")
265 log.exception("Exception while updating application settings")
266 h.flash(
266 h.flash(
267 _('Error occurred during updating application settings'),
267 _('Error occurred during updating application settings'),
268 category='error')
268 category='error')
269
269
270 return redirect(url('admin_settings_global'))
270 return redirect(url('admin_settings_global'))
271
271
272 @HasPermissionAllDecorator('hg.admin')
272 @HasPermissionAllDecorator('hg.admin')
273 def settings_global(self):
273 def settings_global(self):
274 """GET /admin/settings/global: All items in the collection"""
274 """GET /admin/settings/global: All items in the collection"""
275 # url('admin_settings_global')
275 # url('admin_settings_global')
276 c.active = 'global'
276 c.active = 'global'
277
277
278 return htmlfill.render(
278 return htmlfill.render(
279 render('admin/settings/settings.html'),
279 render('admin/settings/settings.html'),
280 defaults=self._form_defaults(),
280 defaults=self._form_defaults(),
281 encoding="UTF-8",
281 encoding="UTF-8",
282 force_defaults=False)
282 force_defaults=False)
283
283
284 @HasPermissionAllDecorator('hg.admin')
284 @HasPermissionAllDecorator('hg.admin')
285 @auth.CSRFRequired()
285 @auth.CSRFRequired()
286 def settings_visual_update(self):
286 def settings_visual_update(self):
287 """POST /admin/settings/visual: All items in the collection"""
287 """POST /admin/settings/visual: All items in the collection"""
288 # url('admin_settings_visual')
288 # url('admin_settings_visual')
289 c.active = 'visual'
289 c.active = 'visual'
290 application_form = ApplicationVisualisationForm()()
290 application_form = ApplicationVisualisationForm()()
291 try:
291 try:
292 form_result = application_form.to_python(dict(request.POST))
292 form_result = application_form.to_python(dict(request.POST))
293 except formencode.Invalid as errors:
293 except formencode.Invalid as errors:
294 return htmlfill.render(
294 return htmlfill.render(
295 render('admin/settings/settings.html'),
295 render('admin/settings/settings.html'),
296 defaults=errors.value,
296 defaults=errors.value,
297 errors=errors.error_dict or {},
297 errors=errors.error_dict or {},
298 prefix_error=False,
298 prefix_error=False,
299 encoding="UTF-8",
299 encoding="UTF-8",
300 force_defaults=False
300 force_defaults=False
301 )
301 )
302
302
303 try:
303 try:
304 settings = [
304 settings = [
305 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
305 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
306 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
306 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
307 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
307 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
308 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
308 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
309 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
309 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
310 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
310 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
311 ('show_version', 'rhodecode_show_version', 'bool'),
311 ('show_version', 'rhodecode_show_version', 'bool'),
312 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
312 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
313 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
313 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
314 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
314 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
315 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
315 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
316 ('support_url', 'rhodecode_support_url', 'unicode'),
316 ('support_url', 'rhodecode_support_url', 'unicode'),
317 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
317 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
318 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
318 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
319 ]
319 ]
320 for setting, form_key, type_ in settings:
320 for setting, form_key, type_ in settings:
321 sett = SettingsModel().create_or_update_setting(
321 sett = SettingsModel().create_or_update_setting(
322 setting, form_result[form_key], type_)
322 setting, form_result[form_key], type_)
323 Session().add(sett)
323 Session().add(sett)
324
324
325 Session().commit()
325 Session().commit()
326 SettingsModel().invalidate_settings_cache()
326 SettingsModel().invalidate_settings_cache()
327 h.flash(_('Updated visualisation settings'), category='success')
327 h.flash(_('Updated visualisation settings'), category='success')
328 except Exception:
328 except Exception:
329 log.exception("Exception updating visualization settings")
329 log.exception("Exception updating visualization settings")
330 h.flash(_('Error occurred during updating '
330 h.flash(_('Error occurred during updating '
331 'visualisation settings'),
331 'visualisation settings'),
332 category='error')
332 category='error')
333
333
334 return redirect(url('admin_settings_visual'))
334 return redirect(url('admin_settings_visual'))
335
335
336 @HasPermissionAllDecorator('hg.admin')
336 @HasPermissionAllDecorator('hg.admin')
337 def settings_visual(self):
337 def settings_visual(self):
338 """GET /admin/settings/visual: All items in the collection"""
338 """GET /admin/settings/visual: All items in the collection"""
339 # url('admin_settings_visual')
339 # url('admin_settings_visual')
340 c.active = 'visual'
340 c.active = 'visual'
341
341
342 return htmlfill.render(
342 return htmlfill.render(
343 render('admin/settings/settings.html'),
343 render('admin/settings/settings.html'),
344 defaults=self._form_defaults(),
344 defaults=self._form_defaults(),
345 encoding="UTF-8",
345 encoding="UTF-8",
346 force_defaults=False)
346 force_defaults=False)
347
347
348 @HasPermissionAllDecorator('hg.admin')
348 @HasPermissionAllDecorator('hg.admin')
349 @auth.CSRFRequired()
349 @auth.CSRFRequired()
350 def settings_issuetracker_test(self):
350 def settings_issuetracker_test(self):
351 if request.is_xhr:
351 if request.is_xhr:
352 return h.urlify_commit_message(
352 return h.urlify_commit_message(
353 request.POST.get('test_text', ''),
353 request.POST.get('test_text', ''),
354 'repo_group/test_repo1')
354 'repo_group/test_repo1')
355 else:
355 else:
356 raise HTTPBadRequest()
356 raise HTTPBadRequest()
357
357
358 @HasPermissionAllDecorator('hg.admin')
358 @HasPermissionAllDecorator('hg.admin')
359 @auth.CSRFRequired()
359 @auth.CSRFRequired()
360 def settings_issuetracker_delete(self):
360 def settings_issuetracker_delete(self):
361 uid = request.POST.get('uid')
361 uid = request.POST.get('uid')
362 IssueTrackerSettingsModel().delete_entries(uid)
362 IssueTrackerSettingsModel().delete_entries(uid)
363 h.flash(_('Removed issue tracker entry'), category='success')
363 h.flash(_('Removed issue tracker entry'), category='success')
364 return redirect(url('admin_settings_issuetracker'))
364 return redirect(url('admin_settings_issuetracker'))
365
365
366 @HasPermissionAllDecorator('hg.admin')
366 @HasPermissionAllDecorator('hg.admin')
367 def settings_issuetracker(self):
367 def settings_issuetracker(self):
368 """GET /admin/settings/issue-tracker: All items in the collection"""
368 """GET /admin/settings/issue-tracker: All items in the collection"""
369 # url('admin_settings_issuetracker')
369 # url('admin_settings_issuetracker')
370 c.active = 'issuetracker'
370 c.active = 'issuetracker'
371 defaults = SettingsModel().get_all_settings()
371 defaults = SettingsModel().get_all_settings()
372
372
373 entry_key = 'rhodecode_issuetracker_pat_'
373 entry_key = 'rhodecode_issuetracker_pat_'
374
374
375 c.issuetracker_entries = {}
375 c.issuetracker_entries = {}
376 for k, v in defaults.items():
376 for k, v in defaults.items():
377 if k.startswith(entry_key):
377 if k.startswith(entry_key):
378 uid = k[len(entry_key):]
378 uid = k[len(entry_key):]
379 c.issuetracker_entries[uid] = None
379 c.issuetracker_entries[uid] = None
380
380
381 for uid in c.issuetracker_entries:
381 for uid in c.issuetracker_entries:
382 c.issuetracker_entries[uid] = AttributeDict({
382 c.issuetracker_entries[uid] = AttributeDict({
383 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
383 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
384 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
384 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
385 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
385 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
386 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
386 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
387 })
387 })
388
388
389 return render('admin/settings/settings.html')
389 return render('admin/settings/settings.html')
390
390
391 @HasPermissionAllDecorator('hg.admin')
391 @HasPermissionAllDecorator('hg.admin')
392 @auth.CSRFRequired()
392 @auth.CSRFRequired()
393 def settings_issuetracker_save(self):
393 def settings_issuetracker_save(self):
394 settings_model = IssueTrackerSettingsModel()
394 settings_model = IssueTrackerSettingsModel()
395
395
396 form = IssueTrackerPatternsForm()().to_python(request.POST)
396 form = IssueTrackerPatternsForm()().to_python(request.POST)
397 for uid in form['delete_patterns']:
397 for uid in form['delete_patterns']:
398 settings_model.delete_entries(uid)
398 settings_model.delete_entries(uid)
399
399
400 for pattern in form['patterns']:
400 for pattern in form['patterns']:
401 for setting, value, type_ in pattern:
401 for setting, value, type_ in pattern:
402 sett = settings_model.create_or_update_setting(
402 sett = settings_model.create_or_update_setting(
403 setting, value, type_)
403 setting, value, type_)
404 Session().add(sett)
404 Session().add(sett)
405
405
406 Session().commit()
406 Session().commit()
407
407
408 SettingsModel().invalidate_settings_cache()
408 SettingsModel().invalidate_settings_cache()
409 h.flash(_('Updated issue tracker entries'), category='success')
409 h.flash(_('Updated issue tracker entries'), category='success')
410 return redirect(url('admin_settings_issuetracker'))
410 return redirect(url('admin_settings_issuetracker'))
411
411
412 @HasPermissionAllDecorator('hg.admin')
412 @HasPermissionAllDecorator('hg.admin')
413 @auth.CSRFRequired()
413 @auth.CSRFRequired()
414 def settings_email_update(self):
414 def settings_email_update(self):
415 """POST /admin/settings/email: All items in the collection"""
415 """POST /admin/settings/email: All items in the collection"""
416 # url('admin_settings_email')
416 # url('admin_settings_email')
417 c.active = 'email'
417 c.active = 'email'
418
418
419 test_email = request.POST.get('test_email')
419 test_email = request.POST.get('test_email')
420
420
421 if not test_email:
421 if not test_email:
422 h.flash(_('Please enter email address'), category='error')
422 h.flash(_('Please enter email address'), category='error')
423 return redirect(url('admin_settings_email'))
423 return redirect(url('admin_settings_email'))
424
424
425 email_kwargs = {
425 email_kwargs = {
426 'date': datetime.datetime.now(),
426 'date': datetime.datetime.now(),
427 'user': c.rhodecode_user,
427 'user': c.rhodecode_user,
428 'rhodecode_version': c.rhodecode_version
428 'rhodecode_version': c.rhodecode_version
429 }
429 }
430
430
431 (subject, headers, email_body,
431 (subject, headers, email_body,
432 email_body_plaintext) = EmailNotificationModel().render_email(
432 email_body_plaintext) = EmailNotificationModel().render_email(
433 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
433 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
434
434
435 recipients = [test_email] if test_email else None
435 recipients = [test_email] if test_email else None
436
436
437 run_task(tasks.send_email, recipients, subject,
437 run_task(tasks.send_email, recipients, subject,
438 email_body_plaintext, email_body)
438 email_body_plaintext, email_body)
439
439
440 h.flash(_('Send email task created'), category='success')
440 h.flash(_('Send email task created'), category='success')
441 return redirect(url('admin_settings_email'))
441 return redirect(url('admin_settings_email'))
442
442
443 @HasPermissionAllDecorator('hg.admin')
443 @HasPermissionAllDecorator('hg.admin')
444 def settings_email(self):
444 def settings_email(self):
445 """GET /admin/settings/email: All items in the collection"""
445 """GET /admin/settings/email: All items in the collection"""
446 # url('admin_settings_email')
446 # url('admin_settings_email')
447 c.active = 'email'
447 c.active = 'email'
448 c.rhodecode_ini = rhodecode.CONFIG
448 c.rhodecode_ini = rhodecode.CONFIG
449
449
450 return htmlfill.render(
450 return htmlfill.render(
451 render('admin/settings/settings.html'),
451 render('admin/settings/settings.html'),
452 defaults=self._form_defaults(),
452 defaults=self._form_defaults(),
453 encoding="UTF-8",
453 encoding="UTF-8",
454 force_defaults=False)
454 force_defaults=False)
455
455
456 @HasPermissionAllDecorator('hg.admin')
456 @HasPermissionAllDecorator('hg.admin')
457 @auth.CSRFRequired()
457 @auth.CSRFRequired()
458 def settings_hooks_update(self):
458 def settings_hooks_update(self):
459 """POST or DELETE /admin/settings/hooks: All items in the collection"""
459 """POST or DELETE /admin/settings/hooks: All items in the collection"""
460 # url('admin_settings_hooks')
460 # url('admin_settings_hooks')
461 c.active = 'hooks'
461 c.active = 'hooks'
462 if c.visual.allow_custom_hooks_settings:
462 if c.visual.allow_custom_hooks_settings:
463 ui_key = request.POST.get('new_hook_ui_key')
463 ui_key = request.POST.get('new_hook_ui_key')
464 ui_value = request.POST.get('new_hook_ui_value')
464 ui_value = request.POST.get('new_hook_ui_value')
465
465
466 hook_id = request.POST.get('hook_id')
466 hook_id = request.POST.get('hook_id')
467 new_hook = False
467 new_hook = False
468
468
469 model = SettingsModel()
469 model = SettingsModel()
470 try:
470 try:
471 if ui_value and ui_key:
471 if ui_value and ui_key:
472 model.create_or_update_hook(ui_key, ui_value)
472 model.create_or_update_hook(ui_key, ui_value)
473 h.flash(_('Added new hook'), category='success')
473 h.flash(_('Added new hook'), category='success')
474 new_hook = True
474 new_hook = True
475 elif hook_id:
475 elif hook_id:
476 RhodeCodeUi.delete(hook_id)
476 RhodeCodeUi.delete(hook_id)
477 Session().commit()
477 Session().commit()
478
478
479 # check for edits
479 # check for edits
480 update = False
480 update = False
481 _d = request.POST.dict_of_lists()
481 _d = request.POST.dict_of_lists()
482 for k, v in zip(_d.get('hook_ui_key', []),
482 for k, v in zip(_d.get('hook_ui_key', []),
483 _d.get('hook_ui_value_new', [])):
483 _d.get('hook_ui_value_new', [])):
484 model.create_or_update_hook(k, v)
484 model.create_or_update_hook(k, v)
485 update = True
485 update = True
486
486
487 if update and not new_hook:
487 if update and not new_hook:
488 h.flash(_('Updated hooks'), category='success')
488 h.flash(_('Updated hooks'), category='success')
489 Session().commit()
489 Session().commit()
490 except Exception:
490 except Exception:
491 log.exception("Exception during hook creation")
491 log.exception("Exception during hook creation")
492 h.flash(_('Error occurred during hook creation'),
492 h.flash(_('Error occurred during hook creation'),
493 category='error')
493 category='error')
494
494
495 return redirect(url('admin_settings_hooks'))
495 return redirect(url('admin_settings_hooks'))
496
496
497 @HasPermissionAllDecorator('hg.admin')
497 @HasPermissionAllDecorator('hg.admin')
498 def settings_hooks(self):
498 def settings_hooks(self):
499 """GET /admin/settings/hooks: All items in the collection"""
499 """GET /admin/settings/hooks: All items in the collection"""
500 # url('admin_settings_hooks')
500 # url('admin_settings_hooks')
501 c.active = 'hooks'
501 c.active = 'hooks'
502
502
503 model = SettingsModel()
503 model = SettingsModel()
504 c.hooks = model.get_builtin_hooks()
504 c.hooks = model.get_builtin_hooks()
505 c.custom_hooks = model.get_custom_hooks()
505 c.custom_hooks = model.get_custom_hooks()
506
506
507 return htmlfill.render(
507 return htmlfill.render(
508 render('admin/settings/settings.html'),
508 render('admin/settings/settings.html'),
509 defaults=self._form_defaults(),
509 defaults=self._form_defaults(),
510 encoding="UTF-8",
510 encoding="UTF-8",
511 force_defaults=False)
511 force_defaults=False)
512
512
513 @HasPermissionAllDecorator('hg.admin')
513 @HasPermissionAllDecorator('hg.admin')
514 def settings_search(self):
514 def settings_search(self):
515 """GET /admin/settings/search: All items in the collection"""
515 """GET /admin/settings/search: All items in the collection"""
516 # url('admin_settings_search')
516 # url('admin_settings_search')
517 c.active = 'search'
517 c.active = 'search'
518
518
519 from rhodecode.lib.index import searcher_from_config
519 from rhodecode.lib.index import searcher_from_config
520 searcher = searcher_from_config(config)
520 searcher = searcher_from_config(config)
521 c.statistics = searcher.statistics()
521 c.statistics = searcher.statistics()
522
522
523 return render('admin/settings/settings.html')
523 return render('admin/settings/settings.html')
524
524
525 @HasPermissionAllDecorator('hg.admin')
525 @HasPermissionAllDecorator('hg.admin')
526 def settings_system(self):
526 def settings_system(self):
527 """GET /admin/settings/system: All items in the collection"""
527 """GET /admin/settings/system: All items in the collection"""
528 # url('admin_settings_system')
528 # url('admin_settings_system')
529 snapshot = str2bool(request.GET.get('snapshot'))
529 snapshot = str2bool(request.GET.get('snapshot'))
530 c.active = 'system'
530 c.active = 'system'
531
531
532 defaults = self._form_defaults()
532 defaults = self._form_defaults()
533 c.rhodecode_ini = rhodecode.CONFIG
533 c.rhodecode_ini = rhodecode.CONFIG
534 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
534 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
535 server_info = ScmModel().get_server_info(request.environ)
535 server_info = ScmModel().get_server_info(request.environ)
536 for key, val in server_info.iteritems():
536 for key, val in server_info.iteritems():
537 setattr(c, key, val)
537 setattr(c, key, val)
538
538
539 if c.disk['percent'] > 90:
539 if c.disk['percent'] > 90:
540 h.flash(h.literal(_(
540 h.flash(h.literal(_(
541 'Critical: your disk space is very low <b>%s%%</b> used' %
541 'Critical: your disk space is very low <b>%s%%</b> used' %
542 c.disk['percent'])), 'error')
542 c.disk['percent'])), 'error')
543 elif c.disk['percent'] > 70:
543 elif c.disk['percent'] > 70:
544 h.flash(h.literal(_(
544 h.flash(h.literal(_(
545 'Warning: your disk space is running low <b>%s%%</b> used' %
545 'Warning: your disk space is running low <b>%s%%</b> used' %
546 c.disk['percent'])), 'warning')
546 c.disk['percent'])), 'warning')
547
547
548 try:
548 try:
549 c.uptime_age = h._age(
549 c.uptime_age = h._age(
550 h.time_to_datetime(c.boot_time), False, show_suffix=False)
550 h.time_to_datetime(c.boot_time), False, show_suffix=False)
551 except TypeError:
551 except TypeError:
552 c.uptime_age = c.boot_time
552 c.uptime_age = c.boot_time
553
553
554 try:
554 try:
555 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
555 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
556 h.format_byte_size_binary(c.memory['used']),
556 h.format_byte_size_binary(c.memory['used']),
557 h.format_byte_size_binary(c.memory['total']),
557 h.format_byte_size_binary(c.memory['total']),
558 c.memory['percent2'],
558 c.memory['percent2'],
559 c.memory['percent'],
559 c.memory['percent'],
560 ' %s' % c.memory['error'] if 'error' in c.memory else '')
560 ' %s' % c.memory['error'] if 'error' in c.memory else '')
561 except TypeError:
561 except TypeError:
562 c.system_memory = 'NOT AVAILABLE'
562 c.system_memory = 'NOT AVAILABLE'
563
563
564 rhodecode_ini_safe = rhodecode.CONFIG.copy()
564 rhodecode_ini_safe = rhodecode.CONFIG.copy()
565 blacklist = [
565 blacklist = [
566 'rhodecode_license_key',
566 'rhodecode_license_key',
567 'routes.map',
567 'routes.map',
568 'pylons.h',
568 'pylons.h',
569 'pylons.app_globals',
569 'pylons.app_globals',
570 'pylons.environ_config',
570 'pylons.environ_config',
571 'sqlalchemy.db1.url',
571 'sqlalchemy.db1.url',
572 ('app_conf', 'sqlalchemy.db1.url')
572 ('app_conf', 'sqlalchemy.db1.url')
573 ]
573 ]
574 for k in blacklist:
574 for k in blacklist:
575 if isinstance(k, tuple):
575 if isinstance(k, tuple):
576 section, key = k
576 section, key = k
577 if section in rhodecode_ini_safe:
577 if section in rhodecode_ini_safe:
578 rhodecode_ini_safe[section].pop(key, None)
578 rhodecode_ini_safe[section].pop(key, None)
579 else:
579 else:
580 rhodecode_ini_safe.pop(k, None)
580 rhodecode_ini_safe.pop(k, None)
581
581
582 c.rhodecode_ini_safe = rhodecode_ini_safe
582 c.rhodecode_ini_safe = rhodecode_ini_safe
583
583
584 # TODO: marcink, figure out how to allow only selected users to do this
584 # TODO: marcink, figure out how to allow only selected users to do this
585 c.allowed_to_snapshot = False
585 c.allowed_to_snapshot = False
586
586
587 if snapshot:
587 if snapshot:
588 if c.allowed_to_snapshot:
588 if c.allowed_to_snapshot:
589 return render('admin/settings/settings_system_snapshot.html')
589 return render('admin/settings/settings_system_snapshot.html')
590 else:
590 else:
591 h.flash('You are not allowed to do this', category='warning')
591 h.flash('You are not allowed to do this', category='warning')
592
592
593 return htmlfill.render(
593 return htmlfill.render(
594 render('admin/settings/settings.html'),
594 render('admin/settings/settings.html'),
595 defaults=defaults,
595 defaults=defaults,
596 encoding="UTF-8",
596 encoding="UTF-8",
597 force_defaults=False)
597 force_defaults=False)
598
598
599 @staticmethod
599 @staticmethod
600 def get_update_data(update_url):
600 def get_update_data(update_url):
601 """Return the JSON update data."""
601 """Return the JSON update data."""
602 ver = rhodecode.__version__
602 ver = rhodecode.__version__
603 log.debug('Checking for upgrade on `%s` server', update_url)
603 log.debug('Checking for upgrade on `%s` server', update_url)
604 opener = urllib2.build_opener()
604 opener = urllib2.build_opener()
605 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
605 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
606 response = opener.open(update_url)
606 response = opener.open(update_url)
607 response_data = response.read()
607 response_data = response.read()
608 data = json.loads(response_data)
608 data = json.loads(response_data)
609
609
610 return data
610 return data
611
611
612 @HasPermissionAllDecorator('hg.admin')
612 @HasPermissionAllDecorator('hg.admin')
613 def settings_system_update(self):
613 def settings_system_update(self):
614 """GET /admin/settings/system/updates: All items in the collection"""
614 """GET /admin/settings/system/updates: All items in the collection"""
615 # url('admin_settings_system_update')
615 # url('admin_settings_system_update')
616 defaults = self._form_defaults()
616 defaults = self._form_defaults()
617 update_url = defaults.get('rhodecode_update_url', '')
617 update_url = defaults.get('rhodecode_update_url', '')
618
618
619 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
619 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
620 try:
620 try:
621 data = self.get_update_data(update_url)
621 data = self.get_update_data(update_url)
622 except urllib2.URLError as e:
622 except urllib2.URLError as e:
623 log.exception("Exception contacting upgrade server")
623 log.exception("Exception contacting upgrade server")
624 return _err('Failed to contact upgrade server: %r' % e)
624 return _err('Failed to contact upgrade server: %r' % e)
625 except ValueError as e:
625 except ValueError as e:
626 log.exception("Bad data sent from update server")
626 log.exception("Bad data sent from update server")
627 return _err('Bad data sent from update server')
627 return _err('Bad data sent from update server')
628
628
629 latest = data['versions'][0]
629 latest = data['versions'][0]
630
630
631 c.update_url = update_url
631 c.update_url = update_url
632 c.latest_data = latest
632 c.latest_data = latest
633 c.latest_ver = latest['version']
633 c.latest_ver = latest['version']
634 c.cur_ver = rhodecode.__version__
634 c.cur_ver = rhodecode.__version__
635 c.should_upgrade = False
635 c.should_upgrade = False
636
636
637 if (packaging.version.Version(c.latest_ver) >
637 if (packaging.version.Version(c.latest_ver) >
638 packaging.version.Version(c.cur_ver)):
638 packaging.version.Version(c.cur_ver)):
639 c.should_upgrade = True
639 c.should_upgrade = True
640 c.important_notices = latest['general']
640 c.important_notices = latest['general']
641
641
642 return render('admin/settings/settings_system_update.html')
642 return render('admin/settings/settings_system_update.html')
643
643
644 @HasPermissionAllDecorator('hg.admin')
644 @HasPermissionAllDecorator('hg.admin')
645 def settings_supervisor(self):
645 def settings_supervisor(self):
646 c.rhodecode_ini = rhodecode.CONFIG
646 c.rhodecode_ini = rhodecode.CONFIG
647 c.active = 'supervisor'
647 c.active = 'supervisor'
648
648
649 c.supervisor_procs = OrderedDict([
649 c.supervisor_procs = OrderedDict([
650 (SUPERVISOR_MASTER, {}),
650 (SUPERVISOR_MASTER, {}),
651 ])
651 ])
652
652
653 c.log_size = 10240
653 c.log_size = 10240
654 supervisor = SupervisorModel()
654 supervisor = SupervisorModel()
655
655
656 _connection = supervisor.get_connection(
656 _connection = supervisor.get_connection(
657 c.rhodecode_ini.get('supervisor.uri'))
657 c.rhodecode_ini.get('supervisor.uri'))
658 c.connection_error = None
658 c.connection_error = None
659 try:
659 try:
660 _connection.supervisor.getAllProcessInfo()
660 _connection.supervisor.getAllProcessInfo()
661 except Exception as e:
661 except Exception as e:
662 c.connection_error = str(e)
662 c.connection_error = str(e)
663 log.exception("Exception reading supervisor data")
663 log.exception("Exception reading supervisor data")
664 return render('admin/settings/settings.html')
664 return render('admin/settings/settings.html')
665
665
666 groupid = c.rhodecode_ini.get('supervisor.group_id')
666 groupid = c.rhodecode_ini.get('supervisor.group_id')
667
667
668 # feed our group processes to the main
668 # feed our group processes to the main
669 for proc in supervisor.get_group_processes(_connection, groupid):
669 for proc in supervisor.get_group_processes(_connection, groupid):
670 c.supervisor_procs[proc['name']] = {}
670 c.supervisor_procs[proc['name']] = {}
671
671
672 for k in c.supervisor_procs.keys():
672 for k in c.supervisor_procs.keys():
673 try:
673 try:
674 # master process info
674 # master process info
675 if k == SUPERVISOR_MASTER:
675 if k == SUPERVISOR_MASTER:
676 _data = supervisor.get_master_state(_connection)
676 _data = supervisor.get_master_state(_connection)
677 _data['name'] = 'supervisor master'
677 _data['name'] = 'supervisor master'
678 _data['description'] = 'pid %s, id: %s, ver: %s' % (
678 _data['description'] = 'pid %s, id: %s, ver: %s' % (
679 _data['pid'], _data['id'], _data['ver'])
679 _data['pid'], _data['id'], _data['ver'])
680 c.supervisor_procs[k] = _data
680 c.supervisor_procs[k] = _data
681 else:
681 else:
682 procid = groupid + ":" + k
682 procid = groupid + ":" + k
683 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
683 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
684 except Exception as e:
684 except Exception as e:
685 log.exception("Exception reading supervisor data")
685 log.exception("Exception reading supervisor data")
686 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
686 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
687
687
688 return render('admin/settings/settings.html')
688 return render('admin/settings/settings.html')
689
689
690 @HasPermissionAllDecorator('hg.admin')
690 @HasPermissionAllDecorator('hg.admin')
691 def settings_supervisor_log(self, procid):
691 def settings_supervisor_log(self, procid):
692 import rhodecode
692 import rhodecode
693 c.rhodecode_ini = rhodecode.CONFIG
693 c.rhodecode_ini = rhodecode.CONFIG
694 c.active = 'supervisor_tail'
694 c.active = 'supervisor_tail'
695
695
696 supervisor = SupervisorModel()
696 supervisor = SupervisorModel()
697 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
697 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
698 groupid = c.rhodecode_ini.get('supervisor.group_id')
698 groupid = c.rhodecode_ini.get('supervisor.group_id')
699 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
699 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
700
700
701 c.log_size = 10240
701 c.log_size = 10240
702 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
702 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
703 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
703 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
704
704
705 return render('admin/settings/settings.html')
705 return render('admin/settings/settings.html')
706
706
707 @HasPermissionAllDecorator('hg.admin')
707 @HasPermissionAllDecorator('hg.admin')
708 @auth.CSRFRequired()
708 @auth.CSRFRequired()
709 def settings_labs_update(self):
709 def settings_labs_update(self):
710 """POST /admin/settings/labs: All items in the collection"""
710 """POST /admin/settings/labs: All items in the collection"""
711 # url('admin_settings/labs', method={'POST'})
711 # url('admin_settings/labs', method={'POST'})
712 c.active = 'labs'
712 c.active = 'labs'
713
713
714 application_form = LabsSettingsForm()()
714 application_form = LabsSettingsForm()()
715 try:
715 try:
716 form_result = application_form.to_python(dict(request.POST))
716 form_result = application_form.to_python(dict(request.POST))
717 except formencode.Invalid as errors:
717 except formencode.Invalid as errors:
718 h.flash(
718 h.flash(
719 _('Some form inputs contain invalid data.'),
719 _('Some form inputs contain invalid data.'),
720 category='error')
720 category='error')
721 return htmlfill.render(
721 return htmlfill.render(
722 render('admin/settings/settings.html'),
722 render('admin/settings/settings.html'),
723 defaults=errors.value,
723 defaults=errors.value,
724 errors=errors.error_dict or {},
724 errors=errors.error_dict or {},
725 prefix_error=False,
725 prefix_error=False,
726 encoding='UTF-8',
726 encoding='UTF-8',
727 force_defaults=False
727 force_defaults=False
728 )
728 )
729
729
730 try:
730 try:
731 session = Session()
731 session = Session()
732 for setting in _LAB_SETTINGS:
732 for setting in _LAB_SETTINGS:
733 setting_name = setting.key[len('rhodecode_'):]
733 setting_name = setting.key[len('rhodecode_'):]
734 sett = SettingsModel().create_or_update_setting(
734 sett = SettingsModel().create_or_update_setting(
735 setting_name, form_result[setting.key], setting.type)
735 setting_name, form_result[setting.key], setting.type)
736 session.add(sett)
736 session.add(sett)
737
737
738 except Exception:
738 except Exception:
739 log.exception('Exception while updating lab settings')
739 log.exception('Exception while updating lab settings')
740 h.flash(_('Error occurred during updating labs settings'),
740 h.flash(_('Error occurred during updating labs settings'),
741 category='error')
741 category='error')
742 else:
742 else:
743 Session().commit()
743 Session().commit()
744 SettingsModel().invalidate_settings_cache()
744 SettingsModel().invalidate_settings_cache()
745 h.flash(_('Updated Labs settings'), category='success')
745 h.flash(_('Updated Labs settings'), category='success')
746 return redirect(url('admin_settings_labs'))
746 return redirect(url('admin_settings_labs'))
747
747
748 return htmlfill.render(
748 return htmlfill.render(
749 render('admin/settings/settings.html'),
749 render('admin/settings/settings.html'),
750 defaults=self._form_defaults(),
750 defaults=self._form_defaults(),
751 encoding='UTF-8',
751 encoding='UTF-8',
752 force_defaults=False)
752 force_defaults=False)
753
753
754 @HasPermissionAllDecorator('hg.admin')
754 @HasPermissionAllDecorator('hg.admin')
755 def settings_labs(self):
755 def settings_labs(self):
756 """GET /admin/settings/labs: All items in the collection"""
756 """GET /admin/settings/labs: All items in the collection"""
757 # url('admin_settings_labs')
757 # url('admin_settings_labs')
758 if not c.labs_active:
758 if not c.labs_active:
759 redirect(url('admin_settings'))
759 redirect(url('admin_settings'))
760
760
761 c.active = 'labs'
761 c.active = 'labs'
762 c.lab_settings = _LAB_SETTINGS
762 c.lab_settings = _LAB_SETTINGS
763
763
764 return htmlfill.render(
764 return htmlfill.render(
765 render('admin/settings/settings.html'),
765 render('admin/settings/settings.html'),
766 defaults=self._form_defaults(),
766 defaults=self._form_defaults(),
767 encoding='UTF-8',
767 encoding='UTF-8',
768 force_defaults=False)
768 force_defaults=False)
769
769
770 def _form_defaults(self):
770 def _form_defaults(self):
771 defaults = SettingsModel().get_all_settings()
771 defaults = SettingsModel().get_all_settings()
772 defaults.update(self._get_hg_ui_settings())
772 defaults.update(self._get_hg_ui_settings())
773 defaults.update({
773 defaults.update({
774 'new_svn_branch': '',
774 'new_svn_branch': '',
775 'new_svn_tag': '',
775 'new_svn_tag': '',
776 })
776 })
777 return defaults
777 return defaults
778
778
779
779
780 # :param key: name of the setting including the 'rhodecode_' prefix
780 # :param key: name of the setting including the 'rhodecode_' prefix
781 # :param type: the RhodeCodeSetting type to use.
781 # :param type: the RhodeCodeSetting type to use.
782 # :param group: the i18ned group in which we should dispaly this setting
782 # :param group: the i18ned group in which we should dispaly this setting
783 # :param label: the i18ned label we should display for this setting
783 # :param label: the i18ned label we should display for this setting
784 # :param help: the i18ned help we should dispaly for this setting
784 # :param help: the i18ned help we should dispaly for this setting
785 LabSetting = collections.namedtuple(
785 LabSetting = collections.namedtuple(
786 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
786 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
787
787
788
788
789 # This list has to be kept in sync with the form
789 # This list has to be kept in sync with the form
790 # rhodecode.model.forms.LabsSettingsForm.
790 # rhodecode.model.forms.LabsSettingsForm.
791 _LAB_SETTINGS = [
791 _LAB_SETTINGS = [
792 LabSetting(
792
793 key='rhodecode_proxy_subversion_http_requests',
794 type='bool',
795 group=lazy_ugettext('Subversion HTTP Support'),
796 label=lazy_ugettext('Proxy subversion HTTP requests'),
797 help='' # Do not translate the empty string!
798 ),
799 LabSetting(
800 key='rhodecode_subversion_http_server_url',
801 type='str',
802 group=lazy_ugettext('Subversion HTTP Server URL'),
803 label='', # Do not translate the empty string!
804 help=lazy_ugettext('e.g. http://localhost:8080/')
805 ),
806 ]
793 ]
@@ -1,549 +1,547 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 this is forms validation classes
22 this is forms validation classes
23 http://formencode.org/module-formencode.validators.html
23 http://formencode.org/module-formencode.validators.html
24 for list off all availible validators
24 for list off all availible validators
25
25
26 we can create our own validators
26 we can create our own validators
27
27
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
29 pre_validators [] These validators will be applied before the schema
29 pre_validators [] These validators will be applied before the schema
30 chained_validators [] These validators will be applied after the schema
30 chained_validators [] These validators will be applied after the schema
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
35
35
36
36
37 <name> = formencode.validators.<name of validator>
37 <name> = formencode.validators.<name of validator>
38 <name> must equal form name
38 <name> must equal form name
39 list=[1,2,3,4,5]
39 list=[1,2,3,4,5]
40 for SELECT use formencode.All(OneOf(list), Int())
40 for SELECT use formencode.All(OneOf(list), Int())
41
41
42 """
42 """
43
43
44 import deform
44 import deform
45 import logging
45 import logging
46 import formencode
46 import formencode
47
47
48 from pkg_resources import resource_filename
48 from pkg_resources import resource_filename
49 from formencode import All, Pipe
49 from formencode import All, Pipe
50
50
51 from pylons.i18n.translation import _
51 from pylons.i18n.translation import _
52
52
53 from rhodecode import BACKENDS
53 from rhodecode import BACKENDS
54 from rhodecode.lib import helpers
54 from rhodecode.lib import helpers
55 from rhodecode.model import validators as v
55 from rhodecode.model import validators as v
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 deform_templates = resource_filename('deform', 'templates')
60 deform_templates = resource_filename('deform', 'templates')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
62 search_path = (rhodecode_templates, deform_templates)
62 search_path = (rhodecode_templates, deform_templates)
63
63
64
64
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
67 def __call__(self, template_name, **kw):
67 def __call__(self, template_name, **kw):
68 kw['h'] = helpers
68 kw['h'] = helpers
69 return self.load(template_name)(**kw)
69 return self.load(template_name)(**kw)
70
70
71
71
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
73 deform.Form.set_default_renderer(form_renderer)
73 deform.Form.set_default_renderer(form_renderer)
74
74
75
75
76 def LoginForm():
76 def LoginForm():
77 class _LoginForm(formencode.Schema):
77 class _LoginForm(formencode.Schema):
78 allow_extra_fields = True
78 allow_extra_fields = True
79 filter_extra_fields = True
79 filter_extra_fields = True
80 username = v.UnicodeString(
80 username = v.UnicodeString(
81 strip=True,
81 strip=True,
82 min=1,
82 min=1,
83 not_empty=True,
83 not_empty=True,
84 messages={
84 messages={
85 'empty': _(u'Please enter a login'),
85 'empty': _(u'Please enter a login'),
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
87 }
87 }
88 )
88 )
89
89
90 password = v.UnicodeString(
90 password = v.UnicodeString(
91 strip=False,
91 strip=False,
92 min=3,
92 min=3,
93 not_empty=True,
93 not_empty=True,
94 messages={
94 messages={
95 'empty': _(u'Please enter a password'),
95 'empty': _(u'Please enter a password'),
96 'tooShort': _(u'Enter %(min)i characters or more')}
96 'tooShort': _(u'Enter %(min)i characters or more')}
97 )
97 )
98
98
99 remember = v.StringBoolean(if_missing=False)
99 remember = v.StringBoolean(if_missing=False)
100
100
101 chained_validators = [v.ValidAuth()]
101 chained_validators = [v.ValidAuth()]
102 return _LoginForm
102 return _LoginForm
103
103
104
104
105 def UserForm(edit=False, available_languages=[], old_data={}):
105 def UserForm(edit=False, available_languages=[], old_data={}):
106 class _UserForm(formencode.Schema):
106 class _UserForm(formencode.Schema):
107 allow_extra_fields = True
107 allow_extra_fields = True
108 filter_extra_fields = True
108 filter_extra_fields = True
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
110 v.ValidUsername(edit, old_data))
110 v.ValidUsername(edit, old_data))
111 if edit:
111 if edit:
112 new_password = All(
112 new_password = All(
113 v.ValidPassword(),
113 v.ValidPassword(),
114 v.UnicodeString(strip=False, min=6, not_empty=False)
114 v.UnicodeString(strip=False, min=6, not_empty=False)
115 )
115 )
116 password_confirmation = All(
116 password_confirmation = All(
117 v.ValidPassword(),
117 v.ValidPassword(),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
119 )
119 )
120 admin = v.StringBoolean(if_missing=False)
120 admin = v.StringBoolean(if_missing=False)
121 else:
121 else:
122 password = All(
122 password = All(
123 v.ValidPassword(),
123 v.ValidPassword(),
124 v.UnicodeString(strip=False, min=6, not_empty=True)
124 v.UnicodeString(strip=False, min=6, not_empty=True)
125 )
125 )
126 password_confirmation = All(
126 password_confirmation = All(
127 v.ValidPassword(),
127 v.ValidPassword(),
128 v.UnicodeString(strip=False, min=6, not_empty=False)
128 v.UnicodeString(strip=False, min=6, not_empty=False)
129 )
129 )
130
130
131 password_change = v.StringBoolean(if_missing=False)
131 password_change = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
133
133
134 active = v.StringBoolean(if_missing=False)
134 active = v.StringBoolean(if_missing=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
138 extern_name = v.UnicodeString(strip=True)
138 extern_name = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
140 language = v.OneOf(available_languages, hideList=False,
140 language = v.OneOf(available_languages, hideList=False,
141 testValueList=True, if_missing=None)
141 testValueList=True, if_missing=None)
142 chained_validators = [v.ValidPasswordsMatch()]
142 chained_validators = [v.ValidPasswordsMatch()]
143 return _UserForm
143 return _UserForm
144
144
145
145
146 def UserGroupForm(edit=False, old_data=None, available_members=None,
146 def UserGroupForm(edit=False, old_data=None, available_members=None,
147 allow_disabled=False):
147 allow_disabled=False):
148 old_data = old_data or {}
148 old_data = old_data or {}
149 available_members = available_members or []
149 available_members = available_members or []
150
150
151 class _UserGroupForm(formencode.Schema):
151 class _UserGroupForm(formencode.Schema):
152 allow_extra_fields = True
152 allow_extra_fields = True
153 filter_extra_fields = True
153 filter_extra_fields = True
154
154
155 users_group_name = All(
155 users_group_name = All(
156 v.UnicodeString(strip=True, min=1, not_empty=True),
156 v.UnicodeString(strip=True, min=1, not_empty=True),
157 v.ValidUserGroup(edit, old_data)
157 v.ValidUserGroup(edit, old_data)
158 )
158 )
159 user_group_description = v.UnicodeString(strip=True, min=1,
159 user_group_description = v.UnicodeString(strip=True, min=1,
160 not_empty=False)
160 not_empty=False)
161
161
162 users_group_active = v.StringBoolean(if_missing=False)
162 users_group_active = v.StringBoolean(if_missing=False)
163
163
164 if edit:
164 if edit:
165 users_group_members = v.OneOf(
165 users_group_members = v.OneOf(
166 available_members, hideList=False, testValueList=True,
166 available_members, hideList=False, testValueList=True,
167 if_missing=None, not_empty=False
167 if_missing=None, not_empty=False
168 )
168 )
169 # this is user group owner
169 # this is user group owner
170 user = All(
170 user = All(
171 v.UnicodeString(not_empty=True),
171 v.UnicodeString(not_empty=True),
172 v.ValidRepoUser(allow_disabled))
172 v.ValidRepoUser(allow_disabled))
173 return _UserGroupForm
173 return _UserGroupForm
174
174
175
175
176 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
176 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
177 can_create_in_root=False, allow_disabled=False):
177 can_create_in_root=False, allow_disabled=False):
178 old_data = old_data or {}
178 old_data = old_data or {}
179 available_groups = available_groups or []
179 available_groups = available_groups or []
180
180
181 class _RepoGroupForm(formencode.Schema):
181 class _RepoGroupForm(formencode.Schema):
182 allow_extra_fields = True
182 allow_extra_fields = True
183 filter_extra_fields = False
183 filter_extra_fields = False
184
184
185 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
185 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
186 v.SlugifyName(),)
186 v.SlugifyName(),)
187 group_description = v.UnicodeString(strip=True, min=1,
187 group_description = v.UnicodeString(strip=True, min=1,
188 not_empty=False)
188 not_empty=False)
189 group_copy_permissions = v.StringBoolean(if_missing=False)
189 group_copy_permissions = v.StringBoolean(if_missing=False)
190
190
191 group_parent_id = v.OneOf(available_groups, hideList=False,
191 group_parent_id = v.OneOf(available_groups, hideList=False,
192 testValueList=True, not_empty=True)
192 testValueList=True, not_empty=True)
193 enable_locking = v.StringBoolean(if_missing=False)
193 enable_locking = v.StringBoolean(if_missing=False)
194 chained_validators = [
194 chained_validators = [
195 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
195 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
196
196
197 if edit:
197 if edit:
198 # this is repo group owner
198 # this is repo group owner
199 user = All(
199 user = All(
200 v.UnicodeString(not_empty=True),
200 v.UnicodeString(not_empty=True),
201 v.ValidRepoUser(allow_disabled))
201 v.ValidRepoUser(allow_disabled))
202
202
203 return _RepoGroupForm
203 return _RepoGroupForm
204
204
205
205
206 def RegisterForm(edit=False, old_data={}):
206 def RegisterForm(edit=False, old_data={}):
207 class _RegisterForm(formencode.Schema):
207 class _RegisterForm(formencode.Schema):
208 allow_extra_fields = True
208 allow_extra_fields = True
209 filter_extra_fields = True
209 filter_extra_fields = True
210 username = All(
210 username = All(
211 v.ValidUsername(edit, old_data),
211 v.ValidUsername(edit, old_data),
212 v.UnicodeString(strip=True, min=1, not_empty=True)
212 v.UnicodeString(strip=True, min=1, not_empty=True)
213 )
213 )
214 password = All(
214 password = All(
215 v.ValidPassword(),
215 v.ValidPassword(),
216 v.UnicodeString(strip=False, min=6, not_empty=True)
216 v.UnicodeString(strip=False, min=6, not_empty=True)
217 )
217 )
218 password_confirmation = All(
218 password_confirmation = All(
219 v.ValidPassword(),
219 v.ValidPassword(),
220 v.UnicodeString(strip=False, min=6, not_empty=True)
220 v.UnicodeString(strip=False, min=6, not_empty=True)
221 )
221 )
222 active = v.StringBoolean(if_missing=False)
222 active = v.StringBoolean(if_missing=False)
223 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
223 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
224 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
224 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
225 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
225 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
226
226
227 chained_validators = [v.ValidPasswordsMatch()]
227 chained_validators = [v.ValidPasswordsMatch()]
228
228
229 return _RegisterForm
229 return _RegisterForm
230
230
231
231
232 def PasswordResetForm():
232 def PasswordResetForm():
233 class _PasswordResetForm(formencode.Schema):
233 class _PasswordResetForm(formencode.Schema):
234 allow_extra_fields = True
234 allow_extra_fields = True
235 filter_extra_fields = True
235 filter_extra_fields = True
236 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
236 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
237 return _PasswordResetForm
237 return _PasswordResetForm
238
238
239
239
240 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
240 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
241 allow_disabled=False):
241 allow_disabled=False):
242 old_data = old_data or {}
242 old_data = old_data or {}
243 repo_groups = repo_groups or []
243 repo_groups = repo_groups or []
244 landing_revs = landing_revs or []
244 landing_revs = landing_revs or []
245 supported_backends = BACKENDS.keys()
245 supported_backends = BACKENDS.keys()
246
246
247 class _RepoForm(formencode.Schema):
247 class _RepoForm(formencode.Schema):
248 allow_extra_fields = True
248 allow_extra_fields = True
249 filter_extra_fields = False
249 filter_extra_fields = False
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
250 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
251 v.SlugifyName())
251 v.SlugifyName())
252 repo_group = All(v.CanWriteGroup(old_data),
252 repo_group = All(v.CanWriteGroup(old_data),
253 v.OneOf(repo_groups, hideList=True))
253 v.OneOf(repo_groups, hideList=True))
254 repo_type = v.OneOf(supported_backends, required=False,
254 repo_type = v.OneOf(supported_backends, required=False,
255 if_missing=old_data.get('repo_type'))
255 if_missing=old_data.get('repo_type'))
256 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
256 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
257 repo_private = v.StringBoolean(if_missing=False)
257 repo_private = v.StringBoolean(if_missing=False)
258 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
258 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
259 repo_copy_permissions = v.StringBoolean(if_missing=False)
259 repo_copy_permissions = v.StringBoolean(if_missing=False)
260 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
260 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
261
261
262 repo_enable_statistics = v.StringBoolean(if_missing=False)
262 repo_enable_statistics = v.StringBoolean(if_missing=False)
263 repo_enable_downloads = v.StringBoolean(if_missing=False)
263 repo_enable_downloads = v.StringBoolean(if_missing=False)
264 repo_enable_locking = v.StringBoolean(if_missing=False)
264 repo_enable_locking = v.StringBoolean(if_missing=False)
265
265
266 if edit:
266 if edit:
267 # this is repo owner
267 # this is repo owner
268 user = All(
268 user = All(
269 v.UnicodeString(not_empty=True),
269 v.UnicodeString(not_empty=True),
270 v.ValidRepoUser(allow_disabled))
270 v.ValidRepoUser(allow_disabled))
271 clone_uri_change = v.UnicodeString(
271 clone_uri_change = v.UnicodeString(
272 not_empty=False, if_missing=v.Missing)
272 not_empty=False, if_missing=v.Missing)
273
273
274 chained_validators = [v.ValidCloneUri(),
274 chained_validators = [v.ValidCloneUri(),
275 v.ValidRepoName(edit, old_data)]
275 v.ValidRepoName(edit, old_data)]
276 return _RepoForm
276 return _RepoForm
277
277
278
278
279 def RepoPermsForm():
279 def RepoPermsForm():
280 class _RepoPermsForm(formencode.Schema):
280 class _RepoPermsForm(formencode.Schema):
281 allow_extra_fields = True
281 allow_extra_fields = True
282 filter_extra_fields = False
282 filter_extra_fields = False
283 chained_validators = [v.ValidPerms(type_='repo')]
283 chained_validators = [v.ValidPerms(type_='repo')]
284 return _RepoPermsForm
284 return _RepoPermsForm
285
285
286
286
287 def RepoGroupPermsForm(valid_recursive_choices):
287 def RepoGroupPermsForm(valid_recursive_choices):
288 class _RepoGroupPermsForm(formencode.Schema):
288 class _RepoGroupPermsForm(formencode.Schema):
289 allow_extra_fields = True
289 allow_extra_fields = True
290 filter_extra_fields = False
290 filter_extra_fields = False
291 recursive = v.OneOf(valid_recursive_choices)
291 recursive = v.OneOf(valid_recursive_choices)
292 chained_validators = [v.ValidPerms(type_='repo_group')]
292 chained_validators = [v.ValidPerms(type_='repo_group')]
293 return _RepoGroupPermsForm
293 return _RepoGroupPermsForm
294
294
295
295
296 def UserGroupPermsForm():
296 def UserGroupPermsForm():
297 class _UserPermsForm(formencode.Schema):
297 class _UserPermsForm(formencode.Schema):
298 allow_extra_fields = True
298 allow_extra_fields = True
299 filter_extra_fields = False
299 filter_extra_fields = False
300 chained_validators = [v.ValidPerms(type_='user_group')]
300 chained_validators = [v.ValidPerms(type_='user_group')]
301 return _UserPermsForm
301 return _UserPermsForm
302
302
303
303
304 def RepoFieldForm():
304 def RepoFieldForm():
305 class _RepoFieldForm(formencode.Schema):
305 class _RepoFieldForm(formencode.Schema):
306 filter_extra_fields = True
306 filter_extra_fields = True
307 allow_extra_fields = True
307 allow_extra_fields = True
308
308
309 new_field_key = All(v.FieldKey(),
309 new_field_key = All(v.FieldKey(),
310 v.UnicodeString(strip=True, min=3, not_empty=True))
310 v.UnicodeString(strip=True, min=3, not_empty=True))
311 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
311 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
312 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
312 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
313 if_missing='str')
313 if_missing='str')
314 new_field_label = v.UnicodeString(not_empty=False)
314 new_field_label = v.UnicodeString(not_empty=False)
315 new_field_desc = v.UnicodeString(not_empty=False)
315 new_field_desc = v.UnicodeString(not_empty=False)
316
316
317 return _RepoFieldForm
317 return _RepoFieldForm
318
318
319
319
320 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
320 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
321 repo_groups=[], landing_revs=[]):
321 repo_groups=[], landing_revs=[]):
322 class _RepoForkForm(formencode.Schema):
322 class _RepoForkForm(formencode.Schema):
323 allow_extra_fields = True
323 allow_extra_fields = True
324 filter_extra_fields = False
324 filter_extra_fields = False
325 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
325 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
326 v.SlugifyName())
326 v.SlugifyName())
327 repo_group = All(v.CanWriteGroup(),
327 repo_group = All(v.CanWriteGroup(),
328 v.OneOf(repo_groups, hideList=True))
328 v.OneOf(repo_groups, hideList=True))
329 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
329 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
330 description = v.UnicodeString(strip=True, min=1, not_empty=True)
330 description = v.UnicodeString(strip=True, min=1, not_empty=True)
331 private = v.StringBoolean(if_missing=False)
331 private = v.StringBoolean(if_missing=False)
332 copy_permissions = v.StringBoolean(if_missing=False)
332 copy_permissions = v.StringBoolean(if_missing=False)
333 fork_parent_id = v.UnicodeString()
333 fork_parent_id = v.UnicodeString()
334 chained_validators = [v.ValidForkName(edit, old_data)]
334 chained_validators = [v.ValidForkName(edit, old_data)]
335 landing_rev = v.OneOf(landing_revs, hideList=True)
335 landing_rev = v.OneOf(landing_revs, hideList=True)
336
336
337 return _RepoForkForm
337 return _RepoForkForm
338
338
339
339
340 def ApplicationSettingsForm():
340 def ApplicationSettingsForm():
341 class _ApplicationSettingsForm(formencode.Schema):
341 class _ApplicationSettingsForm(formencode.Schema):
342 allow_extra_fields = True
342 allow_extra_fields = True
343 filter_extra_fields = False
343 filter_extra_fields = False
344 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
344 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
345 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
345 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
346 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
346 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
347 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
347 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
348 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
348 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
349 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
349 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
350
350
351 return _ApplicationSettingsForm
351 return _ApplicationSettingsForm
352
352
353
353
354 def ApplicationVisualisationForm():
354 def ApplicationVisualisationForm():
355 class _ApplicationVisualisationForm(formencode.Schema):
355 class _ApplicationVisualisationForm(formencode.Schema):
356 allow_extra_fields = True
356 allow_extra_fields = True
357 filter_extra_fields = False
357 filter_extra_fields = False
358 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
358 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
359 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
359 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
360 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
360 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
361
361
362 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
362 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
363 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
363 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
364 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
364 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
365 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
365 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
366 rhodecode_show_version = v.StringBoolean(if_missing=False)
366 rhodecode_show_version = v.StringBoolean(if_missing=False)
367 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
367 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
368 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
368 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
369 rhodecode_gravatar_url = v.UnicodeString(min=3)
369 rhodecode_gravatar_url = v.UnicodeString(min=3)
370 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
370 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
371 rhodecode_support_url = v.UnicodeString()
371 rhodecode_support_url = v.UnicodeString()
372 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
372 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
373 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
373 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
374
374
375 return _ApplicationVisualisationForm
375 return _ApplicationVisualisationForm
376
376
377
377
378 class _BaseVcsSettingsForm(formencode.Schema):
378 class _BaseVcsSettingsForm(formencode.Schema):
379 allow_extra_fields = True
379 allow_extra_fields = True
380 filter_extra_fields = False
380 filter_extra_fields = False
381 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
381 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
382 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
382 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
383 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
383 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
384
384
385 extensions_largefiles = v.StringBoolean(if_missing=False)
385 extensions_largefiles = v.StringBoolean(if_missing=False)
386 phases_publish = v.StringBoolean(if_missing=False)
386 phases_publish = v.StringBoolean(if_missing=False)
387
387
388 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
388 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
389 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
389 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
390 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
390 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
391
391
392 rhodecode_proxy_subversion_http_requests = v.StringBoolean(if_missing=False)
393 rhodecode_subversion_http_server_url = v.UnicodeString(
394 strip=True, if_missing=None)
392
395
393 def ApplicationUiSettingsForm():
396 def ApplicationUiSettingsForm():
394 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
397 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
395 web_push_ssl = v.StringBoolean(if_missing=False)
398 web_push_ssl = v.StringBoolean(if_missing=False)
396 paths_root_path = All(
399 paths_root_path = All(
397 v.ValidPath(),
400 v.ValidPath(),
398 v.UnicodeString(strip=True, min=1, not_empty=True)
401 v.UnicodeString(strip=True, min=1, not_empty=True)
399 )
402 )
400 extensions_hgsubversion = v.StringBoolean(if_missing=False)
403 extensions_hgsubversion = v.StringBoolean(if_missing=False)
401 extensions_hggit = v.StringBoolean(if_missing=False)
404 extensions_hggit = v.StringBoolean(if_missing=False)
402 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
405 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
403 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
406 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
404
407
405 return _ApplicationUiSettingsForm
408 return _ApplicationUiSettingsForm
406
409
407
410
408 def RepoVcsSettingsForm(repo_name):
411 def RepoVcsSettingsForm(repo_name):
409 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
412 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
410 inherit_global_settings = v.StringBoolean(if_missing=False)
413 inherit_global_settings = v.StringBoolean(if_missing=False)
411 new_svn_branch = v.ValidSvnPattern(
414 new_svn_branch = v.ValidSvnPattern(
412 section='vcs_svn_branch', repo_name=repo_name)
415 section='vcs_svn_branch', repo_name=repo_name)
413 new_svn_tag = v.ValidSvnPattern(
416 new_svn_tag = v.ValidSvnPattern(
414 section='vcs_svn_tag', repo_name=repo_name)
417 section='vcs_svn_tag', repo_name=repo_name)
415
418
416 return _RepoVcsSettingsForm
419 return _RepoVcsSettingsForm
417
420
418
421
419 def LabsSettingsForm():
422 def LabsSettingsForm():
420 class _LabSettingsForm(formencode.Schema):
423 class _LabSettingsForm(formencode.Schema):
421 allow_extra_fields = True
424 allow_extra_fields = True
422 filter_extra_fields = False
425 filter_extra_fields = False
423
426
424 rhodecode_proxy_subversion_http_requests = v.StringBoolean(
425 if_missing=False)
426 rhodecode_subversion_http_server_url = v.UnicodeString(
427 strip=True, if_missing=None)
428
429 return _LabSettingsForm
427 return _LabSettingsForm
430
428
431
429
432 def ApplicationPermissionsForm(register_choices, extern_activate_choices):
430 def ApplicationPermissionsForm(register_choices, extern_activate_choices):
433 class _DefaultPermissionsForm(formencode.Schema):
431 class _DefaultPermissionsForm(formencode.Schema):
434 allow_extra_fields = True
432 allow_extra_fields = True
435 filter_extra_fields = True
433 filter_extra_fields = True
436
434
437 anonymous = v.StringBoolean(if_missing=False)
435 anonymous = v.StringBoolean(if_missing=False)
438 default_register = v.OneOf(register_choices)
436 default_register = v.OneOf(register_choices)
439 default_register_message = v.UnicodeString()
437 default_register_message = v.UnicodeString()
440 default_extern_activate = v.OneOf(extern_activate_choices)
438 default_extern_activate = v.OneOf(extern_activate_choices)
441
439
442 return _DefaultPermissionsForm
440 return _DefaultPermissionsForm
443
441
444
442
445 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
443 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
446 user_group_perms_choices):
444 user_group_perms_choices):
447 class _ObjectPermissionsForm(formencode.Schema):
445 class _ObjectPermissionsForm(formencode.Schema):
448 allow_extra_fields = True
446 allow_extra_fields = True
449 filter_extra_fields = True
447 filter_extra_fields = True
450 overwrite_default_repo = v.StringBoolean(if_missing=False)
448 overwrite_default_repo = v.StringBoolean(if_missing=False)
451 overwrite_default_group = v.StringBoolean(if_missing=False)
449 overwrite_default_group = v.StringBoolean(if_missing=False)
452 overwrite_default_user_group = v.StringBoolean(if_missing=False)
450 overwrite_default_user_group = v.StringBoolean(if_missing=False)
453 default_repo_perm = v.OneOf(repo_perms_choices)
451 default_repo_perm = v.OneOf(repo_perms_choices)
454 default_group_perm = v.OneOf(group_perms_choices)
452 default_group_perm = v.OneOf(group_perms_choices)
455 default_user_group_perm = v.OneOf(user_group_perms_choices)
453 default_user_group_perm = v.OneOf(user_group_perms_choices)
456
454
457 return _ObjectPermissionsForm
455 return _ObjectPermissionsForm
458
456
459
457
460 def UserPermissionsForm(create_choices, create_on_write_choices,
458 def UserPermissionsForm(create_choices, create_on_write_choices,
461 repo_group_create_choices, user_group_create_choices,
459 repo_group_create_choices, user_group_create_choices,
462 fork_choices, inherit_default_permissions_choices):
460 fork_choices, inherit_default_permissions_choices):
463 class _DefaultPermissionsForm(formencode.Schema):
461 class _DefaultPermissionsForm(formencode.Schema):
464 allow_extra_fields = True
462 allow_extra_fields = True
465 filter_extra_fields = True
463 filter_extra_fields = True
466
464
467 anonymous = v.StringBoolean(if_missing=False)
465 anonymous = v.StringBoolean(if_missing=False)
468
466
469 default_repo_create = v.OneOf(create_choices)
467 default_repo_create = v.OneOf(create_choices)
470 default_repo_create_on_write = v.OneOf(create_on_write_choices)
468 default_repo_create_on_write = v.OneOf(create_on_write_choices)
471 default_user_group_create = v.OneOf(user_group_create_choices)
469 default_user_group_create = v.OneOf(user_group_create_choices)
472 default_repo_group_create = v.OneOf(repo_group_create_choices)
470 default_repo_group_create = v.OneOf(repo_group_create_choices)
473 default_fork_create = v.OneOf(fork_choices)
471 default_fork_create = v.OneOf(fork_choices)
474 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
472 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
475
473
476 return _DefaultPermissionsForm
474 return _DefaultPermissionsForm
477
475
478
476
479 def UserIndividualPermissionsForm():
477 def UserIndividualPermissionsForm():
480 class _DefaultPermissionsForm(formencode.Schema):
478 class _DefaultPermissionsForm(formencode.Schema):
481 allow_extra_fields = True
479 allow_extra_fields = True
482 filter_extra_fields = True
480 filter_extra_fields = True
483
481
484 inherit_default_permissions = v.StringBoolean(if_missing=False)
482 inherit_default_permissions = v.StringBoolean(if_missing=False)
485
483
486 return _DefaultPermissionsForm
484 return _DefaultPermissionsForm
487
485
488
486
489 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
487 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
490 class _DefaultsForm(formencode.Schema):
488 class _DefaultsForm(formencode.Schema):
491 allow_extra_fields = True
489 allow_extra_fields = True
492 filter_extra_fields = True
490 filter_extra_fields = True
493 default_repo_type = v.OneOf(supported_backends)
491 default_repo_type = v.OneOf(supported_backends)
494 default_repo_private = v.StringBoolean(if_missing=False)
492 default_repo_private = v.StringBoolean(if_missing=False)
495 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
493 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
496 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
494 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
497 default_repo_enable_locking = v.StringBoolean(if_missing=False)
495 default_repo_enable_locking = v.StringBoolean(if_missing=False)
498
496
499 return _DefaultsForm
497 return _DefaultsForm
500
498
501
499
502 def AuthSettingsForm():
500 def AuthSettingsForm():
503 class _AuthSettingsForm(formencode.Schema):
501 class _AuthSettingsForm(formencode.Schema):
504 allow_extra_fields = True
502 allow_extra_fields = True
505 filter_extra_fields = True
503 filter_extra_fields = True
506 auth_plugins = All(v.ValidAuthPlugins(),
504 auth_plugins = All(v.ValidAuthPlugins(),
507 v.UniqueListFromString()(not_empty=True))
505 v.UniqueListFromString()(not_empty=True))
508
506
509 return _AuthSettingsForm
507 return _AuthSettingsForm
510
508
511
509
512 def UserExtraEmailForm():
510 def UserExtraEmailForm():
513 class _UserExtraEmailForm(formencode.Schema):
511 class _UserExtraEmailForm(formencode.Schema):
514 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
512 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
515 return _UserExtraEmailForm
513 return _UserExtraEmailForm
516
514
517
515
518 def UserExtraIpForm():
516 def UserExtraIpForm():
519 class _UserExtraIpForm(formencode.Schema):
517 class _UserExtraIpForm(formencode.Schema):
520 ip = v.ValidIp()(not_empty=True)
518 ip = v.ValidIp()(not_empty=True)
521 return _UserExtraIpForm
519 return _UserExtraIpForm
522
520
523
521
524 def PullRequestForm(repo_id):
522 def PullRequestForm(repo_id):
525 class _PullRequestForm(formencode.Schema):
523 class _PullRequestForm(formencode.Schema):
526 allow_extra_fields = True
524 allow_extra_fields = True
527 filter_extra_fields = True
525 filter_extra_fields = True
528
526
529 user = v.UnicodeString(strip=True, required=True)
527 user = v.UnicodeString(strip=True, required=True)
530 source_repo = v.UnicodeString(strip=True, required=True)
528 source_repo = v.UnicodeString(strip=True, required=True)
531 source_ref = v.UnicodeString(strip=True, required=True)
529 source_ref = v.UnicodeString(strip=True, required=True)
532 target_repo = v.UnicodeString(strip=True, required=True)
530 target_repo = v.UnicodeString(strip=True, required=True)
533 target_ref = v.UnicodeString(strip=True, required=True)
531 target_ref = v.UnicodeString(strip=True, required=True)
534 revisions = All(#v.NotReviewedRevisions(repo_id)(),
532 revisions = All(#v.NotReviewedRevisions(repo_id)(),
535 v.UniqueList()(not_empty=True))
533 v.UniqueList()(not_empty=True))
536 review_members = v.UniqueList(convert=int)(not_empty=True)
534 review_members = v.UniqueList(convert=int)(not_empty=True)
537
535
538 pullrequest_title = v.UnicodeString(strip=True, required=True)
536 pullrequest_title = v.UnicodeString(strip=True, required=True)
539 pullrequest_desc = v.UnicodeString(strip=True, required=False)
537 pullrequest_desc = v.UnicodeString(strip=True, required=False)
540
538
541 return _PullRequestForm
539 return _PullRequestForm
542
540
543
541
544 def IssueTrackerPatternsForm():
542 def IssueTrackerPatternsForm():
545 class _IssueTrackerPatternsForm(formencode.Schema):
543 class _IssueTrackerPatternsForm(formencode.Schema):
546 allow_extra_fields = True
544 allow_extra_fields = True
547 filter_extra_fields = False
545 filter_extra_fields = False
548 chained_validators = [v.ValidPattern()]
546 chained_validators = [v.ValidPattern()]
549 return _IssueTrackerPatternsForm
547 return _IssueTrackerPatternsForm
@@ -1,698 +1,716 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):
204 def invalidate_settings_cache(self):
205 namespace = 'rhodecode_settings'
205 namespace = 'rhodecode_settings'
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 caches.clear_cache_manager(cache_manager)
207 caches.clear_cache_manager(cache_manager)
208
208
209 def get_all_settings(self, cache=False):
209 def get_all_settings(self, cache=False):
210 def _compute():
210 def _compute():
211 q = self._get_settings_query()
211 q = self._get_settings_query()
212 if not q:
212 if not q:
213 raise Exception('Could not get application settings !')
213 raise Exception('Could not get application settings !')
214
214
215 settings = {
215 settings = {
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 for result in q
217 for result in q
218 }
218 }
219 return settings
219 return settings
220
220
221 if cache:
221 if cache:
222 log.debug('Fetching app settings using cache')
222 log.debug('Fetching app settings using cache')
223 repo = self._get_repo(self.repo) if self.repo else None
223 repo = self._get_repo(self.repo) if self.repo else None
224 namespace = 'rhodecode_settings'
224 namespace = 'rhodecode_settings'
225 cache_manager = caches.get_cache_manager(
225 cache_manager = caches.get_cache_manager(
226 'sql_cache_short', namespace)
226 'sql_cache_short', namespace)
227 _cache_key = (
227 _cache_key = (
228 "get_repo_{}_settings".format(repo.repo_id)
228 "get_repo_{}_settings".format(repo.repo_id)
229 if repo else "get_app_settings")
229 if repo else "get_app_settings")
230
230
231 return cache_manager.get(_cache_key, createfunc=_compute)
231 return cache_manager.get(_cache_key, createfunc=_compute)
232
232
233 else:
233 else:
234 return _compute()
234 return _compute()
235
235
236 def get_auth_settings(self):
236 def get_auth_settings(self):
237 q = self._get_settings_query()
237 q = self._get_settings_query()
238 q = q.filter(
238 q = q.filter(
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
240 rows = q.all()
240 rows = q.all()
241 auth_settings = {
241 auth_settings = {
242 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}
243 return auth_settings
243 return auth_settings
244
244
245 def get_auth_plugins(self):
245 def get_auth_plugins(self):
246 auth_plugins = self.get_setting_by_name("auth_plugins")
246 auth_plugins = self.get_setting_by_name("auth_plugins")
247 return auth_plugins.app_settings_value
247 return auth_plugins.app_settings_value
248
248
249 def get_default_repo_settings(self, strip_prefix=False):
249 def get_default_repo_settings(self, strip_prefix=False):
250 q = self._get_settings_query()
250 q = self._get_settings_query()
251 q = q.filter(
251 q = q.filter(
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
253 rows = q.all()
253 rows = q.all()
254
254
255 result = {}
255 result = {}
256 for row in rows:
256 for row in rows:
257 key = row.app_settings_name
257 key = row.app_settings_name
258 if strip_prefix:
258 if strip_prefix:
259 key = remove_prefix(key, prefix='default_')
259 key = remove_prefix(key, prefix='default_')
260 result.update({key: row.app_settings_value})
260 result.update({key: row.app_settings_value})
261 return result
261 return result
262
262
263 def get_repo(self):
263 def get_repo(self):
264 repo = self._get_repo(self.repo)
264 repo = self._get_repo(self.repo)
265 if not repo:
265 if not repo:
266 raise Exception(
266 raise Exception(
267 'Repository {} cannot be found'.format(self.repo))
267 'Repository {} cannot be found'.format(self.repo))
268 return repo
268 return repo
269
269
270 def _filter_by_repo(self, model, query):
270 def _filter_by_repo(self, model, query):
271 if self.repo:
271 if self.repo:
272 repo = self.get_repo()
272 repo = self.get_repo()
273 query = query.filter(model.repository_id == repo.repo_id)
273 query = query.filter(model.repository_id == repo.repo_id)
274 return query
274 return query
275
275
276 def _get_hooks(self, query):
276 def _get_hooks(self, query):
277 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
277 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
278 query = self._filter_by_repo(RepoRhodeCodeUi, query)
278 query = self._filter_by_repo(RepoRhodeCodeUi, query)
279 return query.all()
279 return query.all()
280
280
281 def _get_settings_query(self):
281 def _get_settings_query(self):
282 q = self.SettingsDbModel.query()
282 q = self.SettingsDbModel.query()
283 return self._filter_by_repo(RepoRhodeCodeSetting, q)
283 return self._filter_by_repo(RepoRhodeCodeSetting, q)
284
284
285 def list_enabled_social_plugins(self, settings):
285 def list_enabled_social_plugins(self, settings):
286 enabled = []
286 enabled = []
287 for plug in SOCIAL_PLUGINS_LIST:
287 for plug in SOCIAL_PLUGINS_LIST:
288 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
288 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
289 )):
289 )):
290 enabled.append(plug)
290 enabled.append(plug)
291 return enabled
291 return enabled
292
292
293
293
294 def assert_repo_settings(func):
294 def assert_repo_settings(func):
295 @wraps(func)
295 @wraps(func)
296 def _wrapper(self, *args, **kwargs):
296 def _wrapper(self, *args, **kwargs):
297 if not self.repo_settings:
297 if not self.repo_settings:
298 raise Exception('Repository is not specified')
298 raise Exception('Repository is not specified')
299 return func(self, *args, **kwargs)
299 return func(self, *args, **kwargs)
300 return _wrapper
300 return _wrapper
301
301
302
302
303 class IssueTrackerSettingsModel(object):
303 class IssueTrackerSettingsModel(object):
304 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
304 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
305 SETTINGS_PREFIX = 'issuetracker_'
305 SETTINGS_PREFIX = 'issuetracker_'
306
306
307 def __init__(self, sa=None, repo=None):
307 def __init__(self, sa=None, repo=None):
308 self.global_settings = SettingsModel(sa=sa)
308 self.global_settings = SettingsModel(sa=sa)
309 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
310
310
311 @property
311 @property
312 def inherit_global_settings(self):
312 def inherit_global_settings(self):
313 if not self.repo_settings:
313 if not self.repo_settings:
314 return True
314 return True
315 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
315 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
316 return setting.app_settings_value if setting else True
316 return setting.app_settings_value if setting else True
317
317
318 @inherit_global_settings.setter
318 @inherit_global_settings.setter
319 def inherit_global_settings(self, value):
319 def inherit_global_settings(self, value):
320 if self.repo_settings:
320 if self.repo_settings:
321 settings = self.repo_settings.create_or_update_setting(
321 settings = self.repo_settings.create_or_update_setting(
322 self.INHERIT_SETTINGS, value, type_='bool')
322 self.INHERIT_SETTINGS, value, type_='bool')
323 Session().add(settings)
323 Session().add(settings)
324
324
325 def _get_keyname(self, key, uid, prefix=''):
325 def _get_keyname(self, key, uid, prefix=''):
326 return '{0}{1}{2}_{3}'.format(
326 return '{0}{1}{2}_{3}'.format(
327 prefix, self.SETTINGS_PREFIX, key, uid)
327 prefix, self.SETTINGS_PREFIX, key, uid)
328
328
329 def _make_dict_for_settings(self, qs):
329 def _make_dict_for_settings(self, qs):
330 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
330 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
331
331
332 issuetracker_entries = {}
332 issuetracker_entries = {}
333 # create keys
333 # create keys
334 for k, v in qs.items():
334 for k, v in qs.items():
335 if k.startswith(prefix_match):
335 if k.startswith(prefix_match):
336 uid = k[len(prefix_match):]
336 uid = k[len(prefix_match):]
337 issuetracker_entries[uid] = None
337 issuetracker_entries[uid] = None
338
338
339 # populate
339 # populate
340 for uid in issuetracker_entries:
340 for uid in issuetracker_entries:
341 issuetracker_entries[uid] = AttributeDict({
341 issuetracker_entries[uid] = AttributeDict({
342 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
342 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
343 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
343 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
344 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
344 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
345 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
345 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
346 })
346 })
347 return issuetracker_entries
347 return issuetracker_entries
348
348
349 def get_global_settings(self, cache=False):
349 def get_global_settings(self, cache=False):
350 """
350 """
351 Returns list of global issue tracker settings
351 Returns list of global issue tracker settings
352 """
352 """
353 defaults = self.global_settings.get_all_settings(cache=cache)
353 defaults = self.global_settings.get_all_settings(cache=cache)
354 settings = self._make_dict_for_settings(defaults)
354 settings = self._make_dict_for_settings(defaults)
355 return settings
355 return settings
356
356
357 def get_repo_settings(self, cache=False):
357 def get_repo_settings(self, cache=False):
358 """
358 """
359 Returns list of issue tracker settings per repository
359 Returns list of issue tracker settings per repository
360 """
360 """
361 if not self.repo_settings:
361 if not self.repo_settings:
362 raise Exception('Repository is not specified')
362 raise Exception('Repository is not specified')
363 all_settings = self.repo_settings.get_all_settings(cache=cache)
363 all_settings = self.repo_settings.get_all_settings(cache=cache)
364 settings = self._make_dict_for_settings(all_settings)
364 settings = self._make_dict_for_settings(all_settings)
365 return settings
365 return settings
366
366
367 def get_settings(self, cache=False):
367 def get_settings(self, cache=False):
368 if self.inherit_global_settings:
368 if self.inherit_global_settings:
369 return self.get_global_settings(cache=cache)
369 return self.get_global_settings(cache=cache)
370 else:
370 else:
371 return self.get_repo_settings(cache=cache)
371 return self.get_repo_settings(cache=cache)
372
372
373 def delete_entries(self, uid):
373 def delete_entries(self, uid):
374 if self.repo_settings:
374 if self.repo_settings:
375 all_patterns = self.get_repo_settings()
375 all_patterns = self.get_repo_settings()
376 settings_model = self.repo_settings
376 settings_model = self.repo_settings
377 else:
377 else:
378 all_patterns = self.get_global_settings()
378 all_patterns = self.get_global_settings()
379 settings_model = self.global_settings
379 settings_model = self.global_settings
380 entries = all_patterns.get(uid)
380 entries = all_patterns.get(uid)
381
381
382 for del_key in entries:
382 for del_key in entries:
383 setting_name = self._get_keyname(del_key, uid)
383 setting_name = self._get_keyname(del_key, uid)
384 entry = settings_model.get_setting_by_name(setting_name)
384 entry = settings_model.get_setting_by_name(setting_name)
385 if entry:
385 if entry:
386 Session().delete(entry)
386 Session().delete(entry)
387
387
388 Session().commit()
388 Session().commit()
389
389
390 def create_or_update_setting(
390 def create_or_update_setting(
391 self, name, val=Optional(''), type_=Optional('unicode')):
391 self, name, val=Optional(''), type_=Optional('unicode')):
392 if self.repo_settings:
392 if self.repo_settings:
393 setting = self.repo_settings.create_or_update_setting(
393 setting = self.repo_settings.create_or_update_setting(
394 name, val, type_)
394 name, val, type_)
395 else:
395 else:
396 setting = self.global_settings.create_or_update_setting(
396 setting = self.global_settings.create_or_update_setting(
397 name, val, type_)
397 name, val, type_)
398 return setting
398 return setting
399
399
400
400
401 class VcsSettingsModel(object):
401 class VcsSettingsModel(object):
402
402
403 INHERIT_SETTINGS = 'inherit_vcs_settings'
403 INHERIT_SETTINGS = 'inherit_vcs_settings'
404 GENERAL_SETTINGS = (
404 GENERAL_SETTINGS = (
405 'use_outdated_comments', 'pr_merge_enabled',
405 'use_outdated_comments', 'pr_merge_enabled',
406 'hg_use_rebase_for_merging')
406 'hg_use_rebase_for_merging')
407 HOOKS_SETTINGS = (
407 HOOKS_SETTINGS = (
408 ('hooks', 'changegroup.repo_size'),
408 ('hooks', 'changegroup.repo_size'),
409 ('hooks', 'changegroup.push_logger'),
409 ('hooks', 'changegroup.push_logger'),
410 ('hooks', 'outgoing.pull_logger'))
410 ('hooks', 'outgoing.pull_logger'))
411 HG_SETTINGS = (
411 HG_SETTINGS = (
412 ('extensions', 'largefiles'), ('phases', 'publish'))
412 ('extensions', 'largefiles'), ('phases', 'publish'))
413 GLOBAL_HG_SETTINGS = HG_SETTINGS + (('extensions', 'hgsubversion'), )
413 GLOBAL_HG_SETTINGS = HG_SETTINGS + (('extensions', 'hgsubversion'), )
414 GLOBAL_SVN_SETTINGS = (
415 'rhodecode_proxy_subversion_http_requests',
416 'rhodecode_subversion_http_server_url')
414 SVN_BRANCH_SECTION = 'vcs_svn_branch'
417 SVN_BRANCH_SECTION = 'vcs_svn_branch'
415 SVN_TAG_SECTION = 'vcs_svn_tag'
418 SVN_TAG_SECTION = 'vcs_svn_tag'
416 SSL_SETTING = ('web', 'push_ssl')
419 SSL_SETTING = ('web', 'push_ssl')
417 PATH_SETTING = ('paths', '/')
420 PATH_SETTING = ('paths', '/')
418
421
419 def __init__(self, sa=None, repo=None):
422 def __init__(self, sa=None, repo=None):
420 self.global_settings = SettingsModel(sa=sa)
423 self.global_settings = SettingsModel(sa=sa)
421 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
424 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
422 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
425 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
423 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
426 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
424
427
425 @property
428 @property
426 @assert_repo_settings
429 @assert_repo_settings
427 def inherit_global_settings(self):
430 def inherit_global_settings(self):
428 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
431 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
429 return setting.app_settings_value if setting else True
432 return setting.app_settings_value if setting else True
430
433
431 @inherit_global_settings.setter
434 @inherit_global_settings.setter
432 @assert_repo_settings
435 @assert_repo_settings
433 def inherit_global_settings(self, value):
436 def inherit_global_settings(self, value):
434 self.repo_settings.create_or_update_setting(
437 self.repo_settings.create_or_update_setting(
435 self.INHERIT_SETTINGS, value, type_='bool')
438 self.INHERIT_SETTINGS, value, type_='bool')
436
439
437 def get_global_svn_branch_patterns(self):
440 def get_global_svn_branch_patterns(self):
438 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
441 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
439
442
440 @assert_repo_settings
443 @assert_repo_settings
441 def get_repo_svn_branch_patterns(self):
444 def get_repo_svn_branch_patterns(self):
442 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
445 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
443
446
444 def get_global_svn_tag_patterns(self):
447 def get_global_svn_tag_patterns(self):
445 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
448 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
446
449
447 @assert_repo_settings
450 @assert_repo_settings
448 def get_repo_svn_tag_patterns(self):
451 def get_repo_svn_tag_patterns(self):
449 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
452 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
450
453
451 def get_global_settings(self):
454 def get_global_settings(self):
452 return self._collect_all_settings(global_=True)
455 return self._collect_all_settings(global_=True)
453
456
454 @assert_repo_settings
457 @assert_repo_settings
455 def get_repo_settings(self):
458 def get_repo_settings(self):
456 return self._collect_all_settings(global_=False)
459 return self._collect_all_settings(global_=False)
457
460
458 @assert_repo_settings
461 @assert_repo_settings
459 def create_or_update_repo_settings(
462 def create_or_update_repo_settings(
460 self, data, inherit_global_settings=False):
463 self, data, inherit_global_settings=False):
461 from rhodecode.model.scm import ScmModel
464 from rhodecode.model.scm import ScmModel
462
465
463 self.inherit_global_settings = inherit_global_settings
466 self.inherit_global_settings = inherit_global_settings
464
467
465 repo = self.repo_settings.get_repo()
468 repo = self.repo_settings.get_repo()
466 if not inherit_global_settings:
469 if not inherit_global_settings:
467 if repo.repo_type == 'svn':
470 if repo.repo_type == 'svn':
468 self.create_repo_svn_settings(data)
471 self.create_repo_svn_settings(data)
469 else:
472 else:
470 self.create_or_update_repo_hook_settings(data)
473 self.create_or_update_repo_hook_settings(data)
471 self.create_or_update_repo_pr_settings(data)
474 self.create_or_update_repo_pr_settings(data)
472
475
473 if repo.repo_type == 'hg':
476 if repo.repo_type == 'hg':
474 self.create_or_update_repo_hg_settings(data)
477 self.create_or_update_repo_hg_settings(data)
475
478
476 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
479 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
477
480
478 @assert_repo_settings
481 @assert_repo_settings
479 def create_or_update_repo_hook_settings(self, data):
482 def create_or_update_repo_hook_settings(self, data):
480 for section, key in self.HOOKS_SETTINGS:
483 for section, key in self.HOOKS_SETTINGS:
481 data_key = self._get_form_ui_key(section, key)
484 data_key = self._get_form_ui_key(section, key)
482 if data_key not in data:
485 if data_key not in data:
483 raise ValueError(
486 raise ValueError(
484 'The given data does not contain {} key'.format(data_key))
487 'The given data does not contain {} key'.format(data_key))
485
488
486 active = data.get(data_key)
489 active = data.get(data_key)
487 repo_setting = self.repo_settings.get_ui_by_section_and_key(
490 repo_setting = self.repo_settings.get_ui_by_section_and_key(
488 section, key)
491 section, key)
489 if not repo_setting:
492 if not repo_setting:
490 global_setting = self.global_settings.\
493 global_setting = self.global_settings.\
491 get_ui_by_section_and_key(section, key)
494 get_ui_by_section_and_key(section, key)
492 self.repo_settings.create_ui_section_value(
495 self.repo_settings.create_ui_section_value(
493 section, global_setting.ui_value, key=key, active=active)
496 section, global_setting.ui_value, key=key, active=active)
494 else:
497 else:
495 repo_setting.ui_active = active
498 repo_setting.ui_active = active
496 Session().add(repo_setting)
499 Session().add(repo_setting)
497
500
498 def update_global_hook_settings(self, data):
501 def update_global_hook_settings(self, data):
499 for section, key in self.HOOKS_SETTINGS:
502 for section, key in self.HOOKS_SETTINGS:
500 data_key = self._get_form_ui_key(section, key)
503 data_key = self._get_form_ui_key(section, key)
501 if data_key not in data:
504 if data_key not in data:
502 raise ValueError(
505 raise ValueError(
503 'The given data does not contain {} key'.format(data_key))
506 'The given data does not contain {} key'.format(data_key))
504 active = data.get(data_key)
507 active = data.get(data_key)
505 repo_setting = self.global_settings.get_ui_by_section_and_key(
508 repo_setting = self.global_settings.get_ui_by_section_and_key(
506 section, key)
509 section, key)
507 repo_setting.ui_active = active
510 repo_setting.ui_active = active
508 Session().add(repo_setting)
511 Session().add(repo_setting)
509
512
510 @assert_repo_settings
513 @assert_repo_settings
511 def create_or_update_repo_pr_settings(self, data):
514 def create_or_update_repo_pr_settings(self, data):
512 return self._create_or_update_general_settings(
515 return self._create_or_update_general_settings(
513 self.repo_settings, data)
516 self.repo_settings, data)
514
517
515 def create_or_update_global_pr_settings(self, data):
518 def create_or_update_global_pr_settings(self, data):
516 return self._create_or_update_general_settings(
519 return self._create_or_update_general_settings(
517 self.global_settings, data)
520 self.global_settings, data)
518
521
519 @assert_repo_settings
522 @assert_repo_settings
520 def create_repo_svn_settings(self, data):
523 def create_repo_svn_settings(self, data):
521 return self._create_svn_settings(self.repo_settings, data)
524 return self._create_svn_settings(self.repo_settings, data)
522
525
523 def create_global_svn_settings(self, data):
526 def create_global_svn_settings(self, data):
524 return self._create_svn_settings(self.global_settings, data)
527 return self._create_svn_settings(self.global_settings, data)
525
528
526 @assert_repo_settings
529 @assert_repo_settings
527 def create_or_update_repo_hg_settings(self, data):
530 def create_or_update_repo_hg_settings(self, data):
528 largefiles, phases = self.HG_SETTINGS
531 largefiles, phases = self.HG_SETTINGS
529 largefiles_key, phases_key = self._get_hg_settings(
532 largefiles_key, phases_key = self._get_hg_settings(
530 self.HG_SETTINGS, data)
533 self.HG_SETTINGS, data)
531 self._create_or_update_ui(
534 self._create_or_update_ui(
532 self.repo_settings, *largefiles, value='',
535 self.repo_settings, *largefiles, value='',
533 active=data[largefiles_key])
536 active=data[largefiles_key])
534 self._create_or_update_ui(
537 self._create_or_update_ui(
535 self.repo_settings, *phases, value=safe_str(data[phases_key]))
538 self.repo_settings, *phases, value=safe_str(data[phases_key]))
536
539
537 def create_or_update_global_hg_settings(self, data):
540 def create_or_update_global_hg_settings(self, data):
538 largefiles, phases, subversion = self.GLOBAL_HG_SETTINGS
541 largefiles, phases, subversion = self.GLOBAL_HG_SETTINGS
539 largefiles_key, phases_key, subversion_key = self._get_hg_settings(
542 largefiles_key, phases_key, subversion_key = self._get_hg_settings(
540 self.GLOBAL_HG_SETTINGS, data)
543 self.GLOBAL_HG_SETTINGS, data)
541 self._create_or_update_ui(
544 self._create_or_update_ui(
542 self.global_settings, *largefiles, value='',
545 self.global_settings, *largefiles, value='',
543 active=data[largefiles_key])
546 active=data[largefiles_key])
544 self._create_or_update_ui(
547 self._create_or_update_ui(
545 self.global_settings, *phases, value=safe_str(data[phases_key]))
548 self.global_settings, *phases, value=safe_str(data[phases_key]))
546 self._create_or_update_ui(
549 self._create_or_update_ui(
547 self.global_settings, *subversion, active=data[subversion_key])
550 self.global_settings, *subversion, active=data[subversion_key])
548
551
552 def create_or_update_global_svn_settings(self, data):
553 rhodecode_proxy_subversion_http_requests,
554 rhodecode_subversion_http_server_url = self.GLOBAL_SVN_SETTINGS
555 rhodecode_proxy_subversion_http_requests_key,
556 rhodecode_subversion_http_server_url_key = self._get_svn_settings(
557 self.GLOBAL_SVN_SETTINGS, data)
558 self._create_or_update_ui(
559 self.global_settings,
560 *rhodecode_proxy_subversion_http_requests,
561 value=safe_str(data[rhodecode_proxy_subversion_http_requests_key]))
562 self._create_or_update_ui(
563 self.global_settings,
564 *rhodecode_subversion_http_server_url,
565 active=data[rhodecode_subversion_http_server_url_key])
566
549 def update_global_ssl_setting(self, value):
567 def update_global_ssl_setting(self, value):
550 self._create_or_update_ui(
568 self._create_or_update_ui(
551 self.global_settings, *self.SSL_SETTING, value=value)
569 self.global_settings, *self.SSL_SETTING, value=value)
552
570
553 def update_global_path_setting(self, value):
571 def update_global_path_setting(self, value):
554 self._create_or_update_ui(
572 self._create_or_update_ui(
555 self.global_settings, *self.PATH_SETTING, value=value)
573 self.global_settings, *self.PATH_SETTING, value=value)
556
574
557 @assert_repo_settings
575 @assert_repo_settings
558 def delete_repo_svn_pattern(self, id_):
576 def delete_repo_svn_pattern(self, id_):
559 self.repo_settings.delete_ui(id_)
577 self.repo_settings.delete_ui(id_)
560
578
561 def delete_global_svn_pattern(self, id_):
579 def delete_global_svn_pattern(self, id_):
562 self.global_settings.delete_ui(id_)
580 self.global_settings.delete_ui(id_)
563
581
564 @assert_repo_settings
582 @assert_repo_settings
565 def get_repo_ui_settings(self, section=None, key=None):
583 def get_repo_ui_settings(self, section=None, key=None):
566 global_uis = self.global_settings.get_ui(section, key)
584 global_uis = self.global_settings.get_ui(section, key)
567 repo_uis = self.repo_settings.get_ui(section, key)
585 repo_uis = self.repo_settings.get_ui(section, key)
568 filtered_repo_uis = self._filter_ui_settings(repo_uis)
586 filtered_repo_uis = self._filter_ui_settings(repo_uis)
569 filtered_repo_uis_keys = [
587 filtered_repo_uis_keys = [
570 (s.section, s.key) for s in filtered_repo_uis]
588 (s.section, s.key) for s in filtered_repo_uis]
571
589
572 def _is_global_ui_filtered(ui):
590 def _is_global_ui_filtered(ui):
573 return (
591 return (
574 (ui.section, ui.key) in filtered_repo_uis_keys
592 (ui.section, ui.key) in filtered_repo_uis_keys
575 or ui.section in self._svn_sections)
593 or ui.section in self._svn_sections)
576
594
577 filtered_global_uis = [
595 filtered_global_uis = [
578 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
596 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
579
597
580 return filtered_global_uis + filtered_repo_uis
598 return filtered_global_uis + filtered_repo_uis
581
599
582 def get_global_ui_settings(self, section=None, key=None):
600 def get_global_ui_settings(self, section=None, key=None):
583 return self.global_settings.get_ui(section, key)
601 return self.global_settings.get_ui(section, key)
584
602
585 def get_ui_settings(self, section=None, key=None):
603 def get_ui_settings(self, section=None, key=None):
586 if not self.repo_settings or self.inherit_global_settings:
604 if not self.repo_settings or self.inherit_global_settings:
587 return self.get_global_ui_settings(section, key)
605 return self.get_global_ui_settings(section, key)
588 else:
606 else:
589 return self.get_repo_ui_settings(section, key)
607 return self.get_repo_ui_settings(section, key)
590
608
591 def get_svn_patterns(self, section=None):
609 def get_svn_patterns(self, section=None):
592 if not self.repo_settings:
610 if not self.repo_settings:
593 return self.get_global_ui_settings(section)
611 return self.get_global_ui_settings(section)
594 else:
612 else:
595 return self.get_repo_ui_settings(section)
613 return self.get_repo_ui_settings(section)
596
614
597 @assert_repo_settings
615 @assert_repo_settings
598 def get_repo_general_settings(self):
616 def get_repo_general_settings(self):
599 global_settings = self.global_settings.get_all_settings()
617 global_settings = self.global_settings.get_all_settings()
600 repo_settings = self.repo_settings.get_all_settings()
618 repo_settings = self.repo_settings.get_all_settings()
601 filtered_repo_settings = self._filter_general_settings(repo_settings)
619 filtered_repo_settings = self._filter_general_settings(repo_settings)
602 global_settings.update(filtered_repo_settings)
620 global_settings.update(filtered_repo_settings)
603 return global_settings
621 return global_settings
604
622
605 def get_global_general_settings(self):
623 def get_global_general_settings(self):
606 return self.global_settings.get_all_settings()
624 return self.global_settings.get_all_settings()
607
625
608 def get_general_settings(self):
626 def get_general_settings(self):
609 if not self.repo_settings or self.inherit_global_settings:
627 if not self.repo_settings or self.inherit_global_settings:
610 return self.get_global_general_settings()
628 return self.get_global_general_settings()
611 else:
629 else:
612 return self.get_repo_general_settings()
630 return self.get_repo_general_settings()
613
631
614 def get_repos_location(self):
632 def get_repos_location(self):
615 return self.global_settings.get_ui_by_key('/').ui_value
633 return self.global_settings.get_ui_by_key('/').ui_value
616
634
617 def _filter_ui_settings(self, settings):
635 def _filter_ui_settings(self, settings):
618 filtered_settings = [
636 filtered_settings = [
619 s for s in settings if self._should_keep_setting(s)]
637 s for s in settings if self._should_keep_setting(s)]
620 return filtered_settings
638 return filtered_settings
621
639
622 def _should_keep_setting(self, setting):
640 def _should_keep_setting(self, setting):
623 keep = (
641 keep = (
624 (setting.section, setting.key) in self._ui_settings or
642 (setting.section, setting.key) in self._ui_settings or
625 setting.section in self._svn_sections)
643 setting.section in self._svn_sections)
626 return keep
644 return keep
627
645
628 def _filter_general_settings(self, settings):
646 def _filter_general_settings(self, settings):
629 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
647 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
630 return {
648 return {
631 k: settings[k]
649 k: settings[k]
632 for k in settings if k in keys}
650 for k in settings if k in keys}
633
651
634 def _collect_all_settings(self, global_=False):
652 def _collect_all_settings(self, global_=False):
635 settings = self.global_settings if global_ else self.repo_settings
653 settings = self.global_settings if global_ else self.repo_settings
636 result = {}
654 result = {}
637
655
638 for section, key in self._ui_settings:
656 for section, key in self._ui_settings:
639 ui = settings.get_ui_by_section_and_key(section, key)
657 ui = settings.get_ui_by_section_and_key(section, key)
640 result_key = self._get_form_ui_key(section, key)
658 result_key = self._get_form_ui_key(section, key)
641 if ui:
659 if ui:
642 if section in ('hooks', 'extensions'):
660 if section in ('hooks', 'extensions'):
643 result[result_key] = ui.ui_active
661 result[result_key] = ui.ui_active
644 else:
662 else:
645 result[result_key] = ui.ui_value
663 result[result_key] = ui.ui_value
646
664
647 for name in self.GENERAL_SETTINGS:
665 for name in self.GENERAL_SETTINGS:
648 setting = settings.get_setting_by_name(name)
666 setting = settings.get_setting_by_name(name)
649 if setting:
667 if setting:
650 result_key = 'rhodecode_{}'.format(name)
668 result_key = 'rhodecode_{}'.format(name)
651 result[result_key] = setting.app_settings_value
669 result[result_key] = setting.app_settings_value
652
670
653 return result
671 return result
654
672
655 def _get_form_ui_key(self, section, key):
673 def _get_form_ui_key(self, section, key):
656 return '{section}_{key}'.format(
674 return '{section}_{key}'.format(
657 section=section, key=key.replace('.', '_'))
675 section=section, key=key.replace('.', '_'))
658
676
659 def _create_or_update_ui(
677 def _create_or_update_ui(
660 self, settings, section, key, value=None, active=None):
678 self, settings, section, key, value=None, active=None):
661 ui = settings.get_ui_by_section_and_key(section, key)
679 ui = settings.get_ui_by_section_and_key(section, key)
662 if not ui:
680 if not ui:
663 active = True if active is None else active
681 active = True if active is None else active
664 settings.create_ui_section_value(
682 settings.create_ui_section_value(
665 section, value, key=key, active=active)
683 section, value, key=key, active=active)
666 else:
684 else:
667 if active is not None:
685 if active is not None:
668 ui.ui_active = active
686 ui.ui_active = active
669 if value is not None:
687 if value is not None:
670 ui.ui_value = value
688 ui.ui_value = value
671 Session().add(ui)
689 Session().add(ui)
672
690
673 def _create_svn_settings(self, settings, data):
691 def _create_svn_settings(self, settings, data):
674 svn_settings = {
692 svn_settings = {
675 'new_svn_branch': self.SVN_BRANCH_SECTION,
693 'new_svn_branch': self.SVN_BRANCH_SECTION,
676 'new_svn_tag': self.SVN_TAG_SECTION
694 'new_svn_tag': self.SVN_TAG_SECTION
677 }
695 }
678 for key in svn_settings:
696 for key in svn_settings:
679 if data.get(key):
697 if data.get(key):
680 settings.create_ui_section_value(svn_settings[key], data[key])
698 settings.create_ui_section_value(svn_settings[key], data[key])
681
699
682 def _create_or_update_general_settings(self, settings, data):
700 def _create_or_update_general_settings(self, settings, data):
683 for name in self.GENERAL_SETTINGS:
701 for name in self.GENERAL_SETTINGS:
684 data_key = 'rhodecode_{}'.format(name)
702 data_key = 'rhodecode_{}'.format(name)
685 if data_key not in data:
703 if data_key not in data:
686 raise ValueError(
704 raise ValueError(
687 'The given data does not contain {} key'.format(data_key))
705 'The given data does not contain {} key'.format(data_key))
688 setting = settings.create_or_update_setting(
706 setting = settings.create_or_update_setting(
689 name, data[data_key], 'bool')
707 name, data[data_key], 'bool')
690 Session().add(setting)
708 Session().add(setting)
691
709
692 def _get_hg_settings(self, settings, data):
710 def _get_hg_settings(self, settings, data):
693 data_keys = [self._get_form_ui_key(*s) for s in settings]
711 data_keys = [self._get_form_ui_key(*s) for s in settings]
694 for data_key in data_keys:
712 for data_key in data_keys:
695 if data_key not in data:
713 if data_key not in data:
696 raise ValueError(
714 raise ValueError(
697 'The given data does not contain {} key'.format(data_key))
715 'The given data does not contain {} key'.format(data_key))
698 return data_keys
716 return data_keys
@@ -1,244 +1,266 b''
1 ## snippet for displaying vcs settings
1 ## snippet for displaying vcs settings
2 ## usage:
2 ## usage:
3 ## <%namespace name="vcss" file="/base/vcssettings.html"/>
3 ## <%namespace name="vcss" file="/base/vcssettings.html"/>
4 ## ${vcss.vcs_settings_fields()}
4 ## ${vcss.vcs_settings_fields()}
5
5
6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
7 % if display_globals:
7 % if display_globals:
8 <div class="panel panel-default">
8 <div class="panel panel-default">
9 <div class="panel-heading" id="general">
9 <div class="panel-heading" id="general">
10 <h3 class="panel-title">${_('General')}</h3>
10 <h3 class="panel-title">${_('General')}</h3>
11 </div>
11 </div>
12 <div class="panel-body">
12 <div class="panel-body">
13 <div class="field">
13 <div class="field">
14 <div class="checkbox">
14 <div class="checkbox">
15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
17 </div>
17 </div>
18 <div class="label">
18 <div class="label">
19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
20 </div>
20 </div>
21 </div>
21 </div>
22 </div>
22 </div>
23 </div>
23 </div>
24 % endif
24 % endif
25
25
26 % if display_globals:
26 % if display_globals:
27 <div class="panel panel-default">
27 <div class="panel panel-default">
28 <div class="panel-heading">
28 <div class="panel-heading">
29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
30 </div>
30 </div>
31 <div class="panel-body">
31 <div class="panel-body">
32 <div class="field">
32 <div class="field">
33 <div class="inputx locked_input">
33 <div class="inputx locked_input">
34 %if allow_repo_location_change:
34 %if allow_repo_location_change:
35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
36 <span id="path_unlock" class="tooltip"
36 <span id="path_unlock" class="tooltip"
37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
39 </span>
39 </span>
40 %else:
40 %else:
41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
42 ## form still requires this but we cannot internally change it anyway
42 ## form still requires this but we cannot internally change it anyway
43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
44 %endif
44 %endif
45 </div>
45 </div>
46 </div>
46 </div>
47 <div class="label">
47 <div class="label">
48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
49 </div>
49 </div>
50 </div>
50 </div>
51 </div>
51 </div>
52 % endif
52 % endif
53
53
54 % if display_globals or repo_type in ['git', 'hg']:
54 % if display_globals or repo_type in ['git', 'hg']:
55 <div class="panel panel-default">
55 <div class="panel panel-default">
56 <div class="panel-heading" id="general">
56 <div class="panel-heading" id="general">
57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
58 </div>
58 </div>
59 <div class="panel-body">
59 <div class="panel-body">
60 <div class="field">
60 <div class="field">
61 <div class="checkbox">
61 <div class="checkbox">
62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
64 </div>
64 </div>
65
65
66 <div class="label">
66 <div class="label">
67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
68 </div>
68 </div>
69 <div class="checkbox">
69 <div class="checkbox">
70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
72 </div>
72 </div>
73 <div class="label">
73 <div class="label">
74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
75 </div>
75 </div>
76 <div class="checkbox">
76 <div class="checkbox">
77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
79 </div>
79 </div>
80 <div class="label">
80 <div class="label">
81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
82 </div>
82 </div>
83 </div>
83 </div>
84 </div>
84 </div>
85 </div>
85 </div>
86 % endif
86 % endif
87
87
88 % if display_globals or repo_type in ['hg']:
88 % if display_globals or repo_type in ['hg']:
89 <div class="panel panel-default">
89 <div class="panel panel-default">
90 <div class="panel-heading">
90 <div class="panel-heading">
91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
92 </div>
92 </div>
93 <div class="panel-body">
93 <div class="panel-body">
94 <div class="checkbox">
94 <div class="checkbox">
95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
97 </div>
97 </div>
98 <div class="label">
98 <div class="label">
99 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
99 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
100 </div>
100 </div>
101 <div class="checkbox">
101 <div class="checkbox">
102 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
102 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
103 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
103 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
104 </div>
104 </div>
105 <div class="label">
105 <div class="label">
106 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
106 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
107 </div>
107 </div>
108 % if display_globals:
108 % if display_globals:
109 <div class="checkbox">
109 <div class="checkbox">
110 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
110 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
111 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
111 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
112 </div>
112 </div>
113 <div class="label">
113 <div class="label">
114 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
114 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
115 </div>
115 </div>
116 % endif
116 % endif
117 </div>
117 </div>
118 </div>
118 </div>
119 % endif
119 % endif
120
120
121 % if display_globals or repo_type in ['svn']:
121 % if display_globals or repo_type in ['svn']:
122 <div class="panel panel-default">
122 <div class="panel panel-default">
123 <div class="panel-heading">
123 <div class="panel-heading">
124 <h3 class="panel-title">${_('Subversion Settings')}</h3>
124 <h3 class="panel-title">${_('Subversion Settings')}</h3>
125 </div>
125 </div>
126 <div class="panel-body">
126 <div class="panel-body">
127 <div class="field">
127 <div class="field">
128 <div class="content" >
128 <div class="content" >
129 <label>${_('Subversion HTTP Support')}</label><br/>
130 </div>
131 <div class="checkbox">
132 ${h.checkbox('rhodecode_proxy_subversion_http_requests' + suffix, 'True', **kwargs)}
133 <label for="rhodecode_proxy_subversion_http_requests${suffix}">${_('Proxy subversion HTTP requests')}</label>
134 </div>
135 </div>
136 <div class="field">
137 <div class="label">
138 <label for="rhodecode_subversion_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
139 </div>
140 <div class="input">
141 ${h.text('rhodecode_subversion_http_server_url',size=59)}
142 </div>
143 </div>
144 <div class="field">
145 <div class="label">
146 <span class="help-block">${_('e.g. http://localhost:8080/')}</span>
147 </div>
148 </div>
149 <div class="field">
150 <div class="content" >
129 <label>${_('Repository patterns')}</label><br/>
151 <label>${_('Repository patterns')}</label><br/>
130 </div>
152 </div>
131 </div>
153 </div>
132 <div class="label">
154 <div class="label">
133 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
155 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
134 </div>
156 </div>
135
157
136 <div class="field branch_patterns">
158 <div class="field branch_patterns">
137 <div class="input" >
159 <div class="input" >
138 <label>${_('Branches')}:</label><br/>
160 <label>${_('Branches')}:</label><br/>
139 </div>
161 </div>
140 % if svn_branch_patterns:
162 % if svn_branch_patterns:
141 % for branch in svn_branch_patterns:
163 % for branch in svn_branch_patterns:
142 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
164 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
143 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
165 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
144 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
166 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
145 % if kwargs.get('disabled') != 'disabled':
167 % if kwargs.get('disabled') != 'disabled':
146 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
168 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
147 ${_('Delete')}
169 ${_('Delete')}
148 </span>
170 </span>
149 % endif
171 % endif
150 </div>
172 </div>
151 % endfor
173 % endfor
152 %endif
174 %endif
153 </div>
175 </div>
154 % if kwargs.get('disabled') != 'disabled':
176 % if kwargs.get('disabled') != 'disabled':
155 <div class="field branch_patterns">
177 <div class="field branch_patterns">
156 <div class="input" >
178 <div class="input" >
157 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
179 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
158 </div>
180 </div>
159 </div>
181 </div>
160 % endif
182 % endif
161 <div class="field tag_patterns">
183 <div class="field tag_patterns">
162 <div class="input" >
184 <div class="input" >
163 <label>${_('Tags')}:</label><br/>
185 <label>${_('Tags')}:</label><br/>
164 </div>
186 </div>
165 % if svn_tag_patterns:
187 % if svn_tag_patterns:
166 % for tag in svn_tag_patterns:
188 % for tag in svn_tag_patterns:
167 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
189 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
168 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
190 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
169 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
191 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
170 % if kwargs.get('disabled') != 'disabled':
192 % if kwargs.get('disabled') != 'disabled':
171 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
193 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
172 ${_('Delete')}
194 ${_('Delete')}
173 </span>
195 </span>
174 %endif
196 %endif
175 </div>
197 </div>
176 % endfor
198 % endfor
177 % endif
199 % endif
178 </div>
200 </div>
179 % if kwargs.get('disabled') != 'disabled':
201 % if kwargs.get('disabled') != 'disabled':
180 <div class="field tag_patterns">
202 <div class="field tag_patterns">
181 <div class="input" >
203 <div class="input" >
182 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
204 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
183 </div>
205 </div>
184 </div>
206 </div>
185 %endif
207 %endif
186 </div>
208 </div>
187 </div>
209 </div>
188 % else:
210 % else:
189 ${h.hidden('new_svn_branch' + suffix, '')}
211 ${h.hidden('new_svn_branch' + suffix, '')}
190 ${h.hidden('new_svn_tag' + suffix, '')}
212 ${h.hidden('new_svn_tag' + suffix, '')}
191 % endif
213 % endif
192
214
193 % if display_globals or repo_type in ['hg', 'git']:
215 % if display_globals or repo_type in ['hg', 'git']:
194 <div class="panel panel-default">
216 <div class="panel panel-default">
195 <div class="panel-heading">
217 <div class="panel-heading">
196 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
218 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
197 </div>
219 </div>
198 <div class="panel-body">
220 <div class="panel-body">
199 <div class="checkbox">
221 <div class="checkbox">
200 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
222 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
201 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
223 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
202 </div>
224 </div>
203 <div class="label">
225 <div class="label">
204 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
226 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
205 </div>
227 </div>
206 <div class="checkbox">
228 <div class="checkbox">
207 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
229 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
208 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
230 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
209 </div>
231 </div>
210 <div class="label">
232 <div class="label">
211 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
233 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
212 </div>
234 </div>
213 </div>
235 </div>
214 </div>
236 </div>
215 % endif
237 % endif
216
238
217 ## This condition has to be adapted if we add more labs settings for
239 ## This condition has to be adapted if we add more labs settings for
218 ## VCS types other than 'hg'
240 ## VCS types other than 'hg'
219 % if c.labs_active and (display_globals or repo_type in ['hg']):
241 % if c.labs_active and (display_globals or repo_type in ['hg']):
220 <div class="panel panel-danger">
242 <div class="panel panel-danger">
221 <div class="panel-heading">
243 <div class="panel-heading">
222 <h3 class="panel-title">${_('Labs settings')}: ${_('These features are considered experimental and may not work as expected.')}</h3>
244 <h3 class="panel-title">${_('Labs settings')}: ${_('These features are considered experimental and may not work as expected.')}</h3>
223 </div>
245 </div>
224 <div class="panel-body">
246 <div class="panel-body">
225 <div class="fields">
247 <div class="fields">
226
248
227 <div class="field">
249 <div class="field">
228 <div class="label">
250 <div class="label">
229 <label>${_('Mercurial server-side merge')}:</label>
251 <label>${_('Mercurial server-side merge')}:</label>
230 </div>
252 </div>
231 <div class="checkboxes">
253 <div class="checkboxes">
232 <div class="checkbox">
254 <div class="checkbox">
233 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
255 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
234 <label for="rhodecode_hg_use_rebase_for_merging${suffix}">${_('Use rebase instead of creating a merge commit when merging via web interface')}</label>
256 <label for="rhodecode_hg_use_rebase_for_merging${suffix}">${_('Use rebase instead of creating a merge commit when merging via web interface')}</label>
235 </div>
257 </div>
236 <!-- <p class="help-block">Help message here</p> -->
258 <!-- <p class="help-block">Help message here</p> -->
237 </div>
259 </div>
238 </div>
260 </div>
239
261
240 </div>
262 </div>
241 </div>
263 </div>
242 </div>
264 </div>
243 % endif
265 % endif
244 </%def>
266 </%def>
General Comments 0
You need to be logged in to leave comments. Login now