##// END OF EJS Templates
svn-support: Only show 'generate config' button if config generation is enabled.
Martin Bornhold -
r1022:79b4d791 default
parent child Browse files
Show More
@@ -1,797 +1,803 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 pyramid.threadlocal import get_current_registry
37 from webob.exc import HTTPBadRequest
38 from webob.exc import HTTPBadRequest
38
39
39 import rhodecode
40 import rhodecode
40 from rhodecode.admin.navigation import navigation_list
41 from rhodecode.admin.navigation import navigation_list
41 from rhodecode.lib import auth
42 from rhodecode.lib import auth
42 from rhodecode.lib import helpers as h
43 from rhodecode.lib import helpers as h
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.celerylib import tasks, run_task
46 from rhodecode.lib.celerylib import tasks, run_task
46 from rhodecode.lib.utils import repo2db_mapper
47 from rhodecode.lib.utils import repo2db_mapper
47 from rhodecode.lib.utils2 import (
48 from rhodecode.lib.utils2 import (
48 str2bool, safe_unicode, AttributeDict, safe_int)
49 str2bool, safe_unicode, AttributeDict, safe_int)
49 from rhodecode.lib.compat import OrderedDict
50 from rhodecode.lib.compat import OrderedDict
50 from rhodecode.lib.ext_json import json
51 from rhodecode.lib.ext_json import json
51 from rhodecode.lib.utils import jsonify
52 from rhodecode.lib.utils import jsonify
52
53
53 from rhodecode.model.db import RhodeCodeUi, Repository
54 from rhodecode.model.db import RhodeCodeUi, Repository
54 from rhodecode.model.forms import ApplicationSettingsForm, \
55 from rhodecode.model.forms import ApplicationSettingsForm, \
55 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
56 LabsSettingsForm, IssueTrackerPatternsForm
57 LabsSettingsForm, IssueTrackerPatternsForm
57
58
58 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.notification import EmailNotificationModel
60 from rhodecode.model.notification import EmailNotificationModel
60 from rhodecode.model.meta import Session
61 from rhodecode.model.meta import Session
61 from rhodecode.model.settings import (
62 from rhodecode.model.settings import (
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
63 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
63 SettingsModel)
64 SettingsModel)
64
65
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
66 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
67 from rhodecode.svn_support.config_keys import generate_config
66
68
67
69
68 log = logging.getLogger(__name__)
70 log = logging.getLogger(__name__)
69
71
70
72
71 class SettingsController(BaseController):
73 class SettingsController(BaseController):
72 """REST Controller styled on the Atom Publishing Protocol"""
74 """REST Controller styled on the Atom Publishing Protocol"""
73 # To properly map this controller, ensure your config/routing.py
75 # To properly map this controller, ensure your config/routing.py
74 # file has a resource setup:
76 # file has a resource setup:
75 # map.resource('setting', 'settings', controller='admin/settings',
77 # map.resource('setting', 'settings', controller='admin/settings',
76 # path_prefix='/admin', name_prefix='admin_')
78 # path_prefix='/admin', name_prefix='admin_')
77
79
78 @LoginRequired()
80 @LoginRequired()
79 def __before__(self):
81 def __before__(self):
80 super(SettingsController, self).__before__()
82 super(SettingsController, self).__before__()
81 c.labs_active = str2bool(
83 c.labs_active = str2bool(
82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
84 rhodecode.CONFIG.get('labs_settings_active', 'true'))
83 c.navlist = navigation_list(request)
85 c.navlist = navigation_list(request)
84
86
85 def _get_hg_ui_settings(self):
87 def _get_hg_ui_settings(self):
86 ret = RhodeCodeUi.query().all()
88 ret = RhodeCodeUi.query().all()
87
89
88 if not ret:
90 if not ret:
89 raise Exception('Could not get application ui settings !')
91 raise Exception('Could not get application ui settings !')
90 settings = {}
92 settings = {}
91 for each in ret:
93 for each in ret:
92 k = each.ui_key
94 k = each.ui_key
93 v = each.ui_value
95 v = each.ui_value
94 if k == '/':
96 if k == '/':
95 k = 'root_path'
97 k = 'root_path'
96
98
97 if k in ['push_ssl', 'publish']:
99 if k in ['push_ssl', 'publish']:
98 v = str2bool(v)
100 v = str2bool(v)
99
101
100 if k.find('.') != -1:
102 if k.find('.') != -1:
101 k = k.replace('.', '_')
103 k = k.replace('.', '_')
102
104
103 if each.ui_section in ['hooks', 'extensions']:
105 if each.ui_section in ['hooks', 'extensions']:
104 v = each.ui_active
106 v = each.ui_active
105
107
106 settings[each.ui_section + '_' + k] = v
108 settings[each.ui_section + '_' + k] = v
107 return settings
109 return settings
108
110
109 @HasPermissionAllDecorator('hg.admin')
111 @HasPermissionAllDecorator('hg.admin')
110 @auth.CSRFRequired()
112 @auth.CSRFRequired()
111 @jsonify
113 @jsonify
112 def delete_svn_pattern(self):
114 def delete_svn_pattern(self):
113 if not request.is_xhr:
115 if not request.is_xhr:
114 raise HTTPBadRequest()
116 raise HTTPBadRequest()
115
117
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
118 delete_pattern_id = request.POST.get('delete_svn_pattern')
117 model = VcsSettingsModel()
119 model = VcsSettingsModel()
118 try:
120 try:
119 model.delete_global_svn_pattern(delete_pattern_id)
121 model.delete_global_svn_pattern(delete_pattern_id)
120 except SettingNotFound:
122 except SettingNotFound:
121 raise HTTPBadRequest()
123 raise HTTPBadRequest()
122
124
123 Session().commit()
125 Session().commit()
124 return True
126 return True
125
127
126 @HasPermissionAllDecorator('hg.admin')
128 @HasPermissionAllDecorator('hg.admin')
127 @auth.CSRFRequired()
129 @auth.CSRFRequired()
128 def settings_vcs_update(self):
130 def settings_vcs_update(self):
129 """POST /admin/settings: All items in the collection"""
131 """POST /admin/settings: All items in the collection"""
130 # url('admin_settings_vcs')
132 # url('admin_settings_vcs')
131 c.active = 'vcs'
133 c.active = 'vcs'
132
134
133 model = VcsSettingsModel()
135 model = VcsSettingsModel()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
136 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
137 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
136
138
137 application_form = ApplicationUiSettingsForm()()
139 application_form = ApplicationUiSettingsForm()()
138
140
139 try:
141 try:
140 form_result = application_form.to_python(dict(request.POST))
142 form_result = application_form.to_python(dict(request.POST))
141 except formencode.Invalid as errors:
143 except formencode.Invalid as errors:
142 h.flash(
144 h.flash(
143 _("Some form inputs contain invalid data."),
145 _("Some form inputs contain invalid data."),
144 category='error')
146 category='error')
145 return htmlfill.render(
147 return htmlfill.render(
146 render('admin/settings/settings.html'),
148 render('admin/settings/settings.html'),
147 defaults=errors.value,
149 defaults=errors.value,
148 errors=errors.error_dict or {},
150 errors=errors.error_dict or {},
149 prefix_error=False,
151 prefix_error=False,
150 encoding="UTF-8",
152 encoding="UTF-8",
151 force_defaults=False
153 force_defaults=False
152 )
154 )
153
155
154 try:
156 try:
155 if c.visual.allow_repo_location_change:
157 if c.visual.allow_repo_location_change:
156 model.update_global_path_setting(
158 model.update_global_path_setting(
157 form_result['paths_root_path'])
159 form_result['paths_root_path'])
158
160
159 model.update_global_ssl_setting(form_result['web_push_ssl'])
161 model.update_global_ssl_setting(form_result['web_push_ssl'])
160 model.update_global_hook_settings(form_result)
162 model.update_global_hook_settings(form_result)
161
163
162 model.create_or_update_global_svn_settings(form_result)
164 model.create_or_update_global_svn_settings(form_result)
163 model.create_or_update_global_hg_settings(form_result)
165 model.create_or_update_global_hg_settings(form_result)
164 model.create_or_update_global_pr_settings(form_result)
166 model.create_or_update_global_pr_settings(form_result)
165 except Exception:
167 except Exception:
166 log.exception("Exception while updating settings")
168 log.exception("Exception while updating settings")
167 h.flash(_('Error occurred during updating '
169 h.flash(_('Error occurred during updating '
168 'application settings'), category='error')
170 'application settings'), category='error')
169 else:
171 else:
170 Session().commit()
172 Session().commit()
171 h.flash(_('Updated VCS settings'), category='success')
173 h.flash(_('Updated VCS settings'), category='success')
172 return redirect(url('admin_settings_vcs'))
174 return redirect(url('admin_settings_vcs'))
173
175
174 return htmlfill.render(
176 return htmlfill.render(
175 render('admin/settings/settings.html'),
177 render('admin/settings/settings.html'),
176 defaults=self._form_defaults(),
178 defaults=self._form_defaults(),
177 encoding="UTF-8",
179 encoding="UTF-8",
178 force_defaults=False)
180 force_defaults=False)
179
181
180 @HasPermissionAllDecorator('hg.admin')
182 @HasPermissionAllDecorator('hg.admin')
181 def settings_vcs(self):
183 def settings_vcs(self):
182 """GET /admin/settings: All items in the collection"""
184 """GET /admin/settings: All items in the collection"""
183 # url('admin_settings_vcs')
185 # url('admin_settings_vcs')
184 c.active = 'vcs'
186 c.active = 'vcs'
185 model = VcsSettingsModel()
187 model = VcsSettingsModel()
186 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
188 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
187 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
189 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
188
190
191 # TODO: Replace with request.registry after migrating to pyramid.
192 pyramid_settings = get_current_registry().settings
193 c.svn_proxy_generate_config = pyramid_settings[generate_config]
194
189 return htmlfill.render(
195 return htmlfill.render(
190 render('admin/settings/settings.html'),
196 render('admin/settings/settings.html'),
191 defaults=self._form_defaults(),
197 defaults=self._form_defaults(),
192 encoding="UTF-8",
198 encoding="UTF-8",
193 force_defaults=False)
199 force_defaults=False)
194
200
195 @HasPermissionAllDecorator('hg.admin')
201 @HasPermissionAllDecorator('hg.admin')
196 @auth.CSRFRequired()
202 @auth.CSRFRequired()
197 def settings_mapping_update(self):
203 def settings_mapping_update(self):
198 """POST /admin/settings/mapping: All items in the collection"""
204 """POST /admin/settings/mapping: All items in the collection"""
199 # url('admin_settings_mapping')
205 # url('admin_settings_mapping')
200 c.active = 'mapping'
206 c.active = 'mapping'
201 rm_obsolete = request.POST.get('destroy', False)
207 rm_obsolete = request.POST.get('destroy', False)
202 invalidate_cache = request.POST.get('invalidate', False)
208 invalidate_cache = request.POST.get('invalidate', False)
203 log.debug(
209 log.debug(
204 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
210 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
205
211
206 if invalidate_cache:
212 if invalidate_cache:
207 log.debug('invalidating all repositories cache')
213 log.debug('invalidating all repositories cache')
208 for repo in Repository.get_all():
214 for repo in Repository.get_all():
209 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
215 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
210
216
211 filesystem_repos = ScmModel().repo_scan()
217 filesystem_repos = ScmModel().repo_scan()
212 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
218 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
213 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
219 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
214 h.flash(_('Repositories successfully '
220 h.flash(_('Repositories successfully '
215 'rescanned added: %s ; removed: %s') %
221 'rescanned added: %s ; removed: %s') %
216 (_repr(added), _repr(removed)),
222 (_repr(added), _repr(removed)),
217 category='success')
223 category='success')
218 return redirect(url('admin_settings_mapping'))
224 return redirect(url('admin_settings_mapping'))
219
225
220 @HasPermissionAllDecorator('hg.admin')
226 @HasPermissionAllDecorator('hg.admin')
221 def settings_mapping(self):
227 def settings_mapping(self):
222 """GET /admin/settings/mapping: All items in the collection"""
228 """GET /admin/settings/mapping: All items in the collection"""
223 # url('admin_settings_mapping')
229 # url('admin_settings_mapping')
224 c.active = 'mapping'
230 c.active = 'mapping'
225
231
226 return htmlfill.render(
232 return htmlfill.render(
227 render('admin/settings/settings.html'),
233 render('admin/settings/settings.html'),
228 defaults=self._form_defaults(),
234 defaults=self._form_defaults(),
229 encoding="UTF-8",
235 encoding="UTF-8",
230 force_defaults=False)
236 force_defaults=False)
231
237
232 @HasPermissionAllDecorator('hg.admin')
238 @HasPermissionAllDecorator('hg.admin')
233 @auth.CSRFRequired()
239 @auth.CSRFRequired()
234 def settings_global_update(self):
240 def settings_global_update(self):
235 """POST /admin/settings/global: All items in the collection"""
241 """POST /admin/settings/global: All items in the collection"""
236 # url('admin_settings_global')
242 # url('admin_settings_global')
237 c.active = 'global'
243 c.active = 'global'
238 application_form = ApplicationSettingsForm()()
244 application_form = ApplicationSettingsForm()()
239 try:
245 try:
240 form_result = application_form.to_python(dict(request.POST))
246 form_result = application_form.to_python(dict(request.POST))
241 except formencode.Invalid as errors:
247 except formencode.Invalid as errors:
242 return htmlfill.render(
248 return htmlfill.render(
243 render('admin/settings/settings.html'),
249 render('admin/settings/settings.html'),
244 defaults=errors.value,
250 defaults=errors.value,
245 errors=errors.error_dict or {},
251 errors=errors.error_dict or {},
246 prefix_error=False,
252 prefix_error=False,
247 encoding="UTF-8",
253 encoding="UTF-8",
248 force_defaults=False)
254 force_defaults=False)
249
255
250 try:
256 try:
251 settings = [
257 settings = [
252 ('title', 'rhodecode_title'),
258 ('title', 'rhodecode_title'),
253 ('realm', 'rhodecode_realm'),
259 ('realm', 'rhodecode_realm'),
254 ('pre_code', 'rhodecode_pre_code'),
260 ('pre_code', 'rhodecode_pre_code'),
255 ('post_code', 'rhodecode_post_code'),
261 ('post_code', 'rhodecode_post_code'),
256 ('captcha_public_key', 'rhodecode_captcha_public_key'),
262 ('captcha_public_key', 'rhodecode_captcha_public_key'),
257 ('captcha_private_key', 'rhodecode_captcha_private_key'),
263 ('captcha_private_key', 'rhodecode_captcha_private_key'),
258 ]
264 ]
259 for setting, form_key in settings:
265 for setting, form_key in settings:
260 sett = SettingsModel().create_or_update_setting(
266 sett = SettingsModel().create_or_update_setting(
261 setting, form_result[form_key])
267 setting, form_result[form_key])
262 Session().add(sett)
268 Session().add(sett)
263
269
264 Session().commit()
270 Session().commit()
265 SettingsModel().invalidate_settings_cache()
271 SettingsModel().invalidate_settings_cache()
266 h.flash(_('Updated application settings'), category='success')
272 h.flash(_('Updated application settings'), category='success')
267 except Exception:
273 except Exception:
268 log.exception("Exception while updating application settings")
274 log.exception("Exception while updating application settings")
269 h.flash(
275 h.flash(
270 _('Error occurred during updating application settings'),
276 _('Error occurred during updating application settings'),
271 category='error')
277 category='error')
272
278
273 return redirect(url('admin_settings_global'))
279 return redirect(url('admin_settings_global'))
274
280
275 @HasPermissionAllDecorator('hg.admin')
281 @HasPermissionAllDecorator('hg.admin')
276 def settings_global(self):
282 def settings_global(self):
277 """GET /admin/settings/global: All items in the collection"""
283 """GET /admin/settings/global: All items in the collection"""
278 # url('admin_settings_global')
284 # url('admin_settings_global')
279 c.active = 'global'
285 c.active = 'global'
280
286
281 return htmlfill.render(
287 return htmlfill.render(
282 render('admin/settings/settings.html'),
288 render('admin/settings/settings.html'),
283 defaults=self._form_defaults(),
289 defaults=self._form_defaults(),
284 encoding="UTF-8",
290 encoding="UTF-8",
285 force_defaults=False)
291 force_defaults=False)
286
292
287 @HasPermissionAllDecorator('hg.admin')
293 @HasPermissionAllDecorator('hg.admin')
288 @auth.CSRFRequired()
294 @auth.CSRFRequired()
289 def settings_visual_update(self):
295 def settings_visual_update(self):
290 """POST /admin/settings/visual: All items in the collection"""
296 """POST /admin/settings/visual: All items in the collection"""
291 # url('admin_settings_visual')
297 # url('admin_settings_visual')
292 c.active = 'visual'
298 c.active = 'visual'
293 application_form = ApplicationVisualisationForm()()
299 application_form = ApplicationVisualisationForm()()
294 try:
300 try:
295 form_result = application_form.to_python(dict(request.POST))
301 form_result = application_form.to_python(dict(request.POST))
296 except formencode.Invalid as errors:
302 except formencode.Invalid as errors:
297 return htmlfill.render(
303 return htmlfill.render(
298 render('admin/settings/settings.html'),
304 render('admin/settings/settings.html'),
299 defaults=errors.value,
305 defaults=errors.value,
300 errors=errors.error_dict or {},
306 errors=errors.error_dict or {},
301 prefix_error=False,
307 prefix_error=False,
302 encoding="UTF-8",
308 encoding="UTF-8",
303 force_defaults=False
309 force_defaults=False
304 )
310 )
305
311
306 try:
312 try:
307 settings = [
313 settings = [
308 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
314 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
309 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
315 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
310 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
316 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
311 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
317 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
312 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
318 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
313 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
319 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
314 ('show_version', 'rhodecode_show_version', 'bool'),
320 ('show_version', 'rhodecode_show_version', 'bool'),
315 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
321 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
316 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
322 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
317 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
323 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
318 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
324 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
319 ('support_url', 'rhodecode_support_url', 'unicode'),
325 ('support_url', 'rhodecode_support_url', 'unicode'),
320 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
326 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
321 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
327 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
322 ]
328 ]
323 for setting, form_key, type_ in settings:
329 for setting, form_key, type_ in settings:
324 sett = SettingsModel().create_or_update_setting(
330 sett = SettingsModel().create_or_update_setting(
325 setting, form_result[form_key], type_)
331 setting, form_result[form_key], type_)
326 Session().add(sett)
332 Session().add(sett)
327
333
328 Session().commit()
334 Session().commit()
329 SettingsModel().invalidate_settings_cache()
335 SettingsModel().invalidate_settings_cache()
330 h.flash(_('Updated visualisation settings'), category='success')
336 h.flash(_('Updated visualisation settings'), category='success')
331 except Exception:
337 except Exception:
332 log.exception("Exception updating visualization settings")
338 log.exception("Exception updating visualization settings")
333 h.flash(_('Error occurred during updating '
339 h.flash(_('Error occurred during updating '
334 'visualisation settings'),
340 'visualisation settings'),
335 category='error')
341 category='error')
336
342
337 return redirect(url('admin_settings_visual'))
343 return redirect(url('admin_settings_visual'))
338
344
339 @HasPermissionAllDecorator('hg.admin')
345 @HasPermissionAllDecorator('hg.admin')
340 def settings_visual(self):
346 def settings_visual(self):
341 """GET /admin/settings/visual: All items in the collection"""
347 """GET /admin/settings/visual: All items in the collection"""
342 # url('admin_settings_visual')
348 # url('admin_settings_visual')
343 c.active = 'visual'
349 c.active = 'visual'
344
350
345 return htmlfill.render(
351 return htmlfill.render(
346 render('admin/settings/settings.html'),
352 render('admin/settings/settings.html'),
347 defaults=self._form_defaults(),
353 defaults=self._form_defaults(),
348 encoding="UTF-8",
354 encoding="UTF-8",
349 force_defaults=False)
355 force_defaults=False)
350
356
351 @HasPermissionAllDecorator('hg.admin')
357 @HasPermissionAllDecorator('hg.admin')
352 @auth.CSRFRequired()
358 @auth.CSRFRequired()
353 def settings_issuetracker_test(self):
359 def settings_issuetracker_test(self):
354 if request.is_xhr:
360 if request.is_xhr:
355 return h.urlify_commit_message(
361 return h.urlify_commit_message(
356 request.POST.get('test_text', ''),
362 request.POST.get('test_text', ''),
357 'repo_group/test_repo1')
363 'repo_group/test_repo1')
358 else:
364 else:
359 raise HTTPBadRequest()
365 raise HTTPBadRequest()
360
366
361 @HasPermissionAllDecorator('hg.admin')
367 @HasPermissionAllDecorator('hg.admin')
362 @auth.CSRFRequired()
368 @auth.CSRFRequired()
363 def settings_issuetracker_delete(self):
369 def settings_issuetracker_delete(self):
364 uid = request.POST.get('uid')
370 uid = request.POST.get('uid')
365 IssueTrackerSettingsModel().delete_entries(uid)
371 IssueTrackerSettingsModel().delete_entries(uid)
366 h.flash(_('Removed issue tracker entry'), category='success')
372 h.flash(_('Removed issue tracker entry'), category='success')
367 return redirect(url('admin_settings_issuetracker'))
373 return redirect(url('admin_settings_issuetracker'))
368
374
369 @HasPermissionAllDecorator('hg.admin')
375 @HasPermissionAllDecorator('hg.admin')
370 def settings_issuetracker(self):
376 def settings_issuetracker(self):
371 """GET /admin/settings/issue-tracker: All items in the collection"""
377 """GET /admin/settings/issue-tracker: All items in the collection"""
372 # url('admin_settings_issuetracker')
378 # url('admin_settings_issuetracker')
373 c.active = 'issuetracker'
379 c.active = 'issuetracker'
374 defaults = SettingsModel().get_all_settings()
380 defaults = SettingsModel().get_all_settings()
375
381
376 entry_key = 'rhodecode_issuetracker_pat_'
382 entry_key = 'rhodecode_issuetracker_pat_'
377
383
378 c.issuetracker_entries = {}
384 c.issuetracker_entries = {}
379 for k, v in defaults.items():
385 for k, v in defaults.items():
380 if k.startswith(entry_key):
386 if k.startswith(entry_key):
381 uid = k[len(entry_key):]
387 uid = k[len(entry_key):]
382 c.issuetracker_entries[uid] = None
388 c.issuetracker_entries[uid] = None
383
389
384 for uid in c.issuetracker_entries:
390 for uid in c.issuetracker_entries:
385 c.issuetracker_entries[uid] = AttributeDict({
391 c.issuetracker_entries[uid] = AttributeDict({
386 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
392 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
387 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
393 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
388 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
394 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
389 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
395 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
390 })
396 })
391
397
392 return render('admin/settings/settings.html')
398 return render('admin/settings/settings.html')
393
399
394 @HasPermissionAllDecorator('hg.admin')
400 @HasPermissionAllDecorator('hg.admin')
395 @auth.CSRFRequired()
401 @auth.CSRFRequired()
396 def settings_issuetracker_save(self):
402 def settings_issuetracker_save(self):
397 settings_model = IssueTrackerSettingsModel()
403 settings_model = IssueTrackerSettingsModel()
398
404
399 form = IssueTrackerPatternsForm()().to_python(request.POST)
405 form = IssueTrackerPatternsForm()().to_python(request.POST)
400 if form:
406 if form:
401 for uid in form.get('delete_patterns', []):
407 for uid in form.get('delete_patterns', []):
402 settings_model.delete_entries(uid)
408 settings_model.delete_entries(uid)
403
409
404 for pattern in form.get('patterns', []):
410 for pattern in form.get('patterns', []):
405 for setting, value, type_ in pattern:
411 for setting, value, type_ in pattern:
406 sett = settings_model.create_or_update_setting(
412 sett = settings_model.create_or_update_setting(
407 setting, value, type_)
413 setting, value, type_)
408 Session().add(sett)
414 Session().add(sett)
409
415
410 Session().commit()
416 Session().commit()
411
417
412 SettingsModel().invalidate_settings_cache()
418 SettingsModel().invalidate_settings_cache()
413 h.flash(_('Updated issue tracker entries'), category='success')
419 h.flash(_('Updated issue tracker entries'), category='success')
414 return redirect(url('admin_settings_issuetracker'))
420 return redirect(url('admin_settings_issuetracker'))
415
421
416 @HasPermissionAllDecorator('hg.admin')
422 @HasPermissionAllDecorator('hg.admin')
417 @auth.CSRFRequired()
423 @auth.CSRFRequired()
418 def settings_email_update(self):
424 def settings_email_update(self):
419 """POST /admin/settings/email: All items in the collection"""
425 """POST /admin/settings/email: All items in the collection"""
420 # url('admin_settings_email')
426 # url('admin_settings_email')
421 c.active = 'email'
427 c.active = 'email'
422
428
423 test_email = request.POST.get('test_email')
429 test_email = request.POST.get('test_email')
424
430
425 if not test_email:
431 if not test_email:
426 h.flash(_('Please enter email address'), category='error')
432 h.flash(_('Please enter email address'), category='error')
427 return redirect(url('admin_settings_email'))
433 return redirect(url('admin_settings_email'))
428
434
429 email_kwargs = {
435 email_kwargs = {
430 'date': datetime.datetime.now(),
436 'date': datetime.datetime.now(),
431 'user': c.rhodecode_user,
437 'user': c.rhodecode_user,
432 'rhodecode_version': c.rhodecode_version
438 'rhodecode_version': c.rhodecode_version
433 }
439 }
434
440
435 (subject, headers, email_body,
441 (subject, headers, email_body,
436 email_body_plaintext) = EmailNotificationModel().render_email(
442 email_body_plaintext) = EmailNotificationModel().render_email(
437 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
443 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
438
444
439 recipients = [test_email] if test_email else None
445 recipients = [test_email] if test_email else None
440
446
441 run_task(tasks.send_email, recipients, subject,
447 run_task(tasks.send_email, recipients, subject,
442 email_body_plaintext, email_body)
448 email_body_plaintext, email_body)
443
449
444 h.flash(_('Send email task created'), category='success')
450 h.flash(_('Send email task created'), category='success')
445 return redirect(url('admin_settings_email'))
451 return redirect(url('admin_settings_email'))
446
452
447 @HasPermissionAllDecorator('hg.admin')
453 @HasPermissionAllDecorator('hg.admin')
448 def settings_email(self):
454 def settings_email(self):
449 """GET /admin/settings/email: All items in the collection"""
455 """GET /admin/settings/email: All items in the collection"""
450 # url('admin_settings_email')
456 # url('admin_settings_email')
451 c.active = 'email'
457 c.active = 'email'
452 c.rhodecode_ini = rhodecode.CONFIG
458 c.rhodecode_ini = rhodecode.CONFIG
453
459
454 return htmlfill.render(
460 return htmlfill.render(
455 render('admin/settings/settings.html'),
461 render('admin/settings/settings.html'),
456 defaults=self._form_defaults(),
462 defaults=self._form_defaults(),
457 encoding="UTF-8",
463 encoding="UTF-8",
458 force_defaults=False)
464 force_defaults=False)
459
465
460 @HasPermissionAllDecorator('hg.admin')
466 @HasPermissionAllDecorator('hg.admin')
461 @auth.CSRFRequired()
467 @auth.CSRFRequired()
462 def settings_hooks_update(self):
468 def settings_hooks_update(self):
463 """POST or DELETE /admin/settings/hooks: All items in the collection"""
469 """POST or DELETE /admin/settings/hooks: All items in the collection"""
464 # url('admin_settings_hooks')
470 # url('admin_settings_hooks')
465 c.active = 'hooks'
471 c.active = 'hooks'
466 if c.visual.allow_custom_hooks_settings:
472 if c.visual.allow_custom_hooks_settings:
467 ui_key = request.POST.get('new_hook_ui_key')
473 ui_key = request.POST.get('new_hook_ui_key')
468 ui_value = request.POST.get('new_hook_ui_value')
474 ui_value = request.POST.get('new_hook_ui_value')
469
475
470 hook_id = request.POST.get('hook_id')
476 hook_id = request.POST.get('hook_id')
471 new_hook = False
477 new_hook = False
472
478
473 model = SettingsModel()
479 model = SettingsModel()
474 try:
480 try:
475 if ui_value and ui_key:
481 if ui_value and ui_key:
476 model.create_or_update_hook(ui_key, ui_value)
482 model.create_or_update_hook(ui_key, ui_value)
477 h.flash(_('Added new hook'), category='success')
483 h.flash(_('Added new hook'), category='success')
478 new_hook = True
484 new_hook = True
479 elif hook_id:
485 elif hook_id:
480 RhodeCodeUi.delete(hook_id)
486 RhodeCodeUi.delete(hook_id)
481 Session().commit()
487 Session().commit()
482
488
483 # check for edits
489 # check for edits
484 update = False
490 update = False
485 _d = request.POST.dict_of_lists()
491 _d = request.POST.dict_of_lists()
486 for k, v in zip(_d.get('hook_ui_key', []),
492 for k, v in zip(_d.get('hook_ui_key', []),
487 _d.get('hook_ui_value_new', [])):
493 _d.get('hook_ui_value_new', [])):
488 model.create_or_update_hook(k, v)
494 model.create_or_update_hook(k, v)
489 update = True
495 update = True
490
496
491 if update and not new_hook:
497 if update and not new_hook:
492 h.flash(_('Updated hooks'), category='success')
498 h.flash(_('Updated hooks'), category='success')
493 Session().commit()
499 Session().commit()
494 except Exception:
500 except Exception:
495 log.exception("Exception during hook creation")
501 log.exception("Exception during hook creation")
496 h.flash(_('Error occurred during hook creation'),
502 h.flash(_('Error occurred during hook creation'),
497 category='error')
503 category='error')
498
504
499 return redirect(url('admin_settings_hooks'))
505 return redirect(url('admin_settings_hooks'))
500
506
501 @HasPermissionAllDecorator('hg.admin')
507 @HasPermissionAllDecorator('hg.admin')
502 def settings_hooks(self):
508 def settings_hooks(self):
503 """GET /admin/settings/hooks: All items in the collection"""
509 """GET /admin/settings/hooks: All items in the collection"""
504 # url('admin_settings_hooks')
510 # url('admin_settings_hooks')
505 c.active = 'hooks'
511 c.active = 'hooks'
506
512
507 model = SettingsModel()
513 model = SettingsModel()
508 c.hooks = model.get_builtin_hooks()
514 c.hooks = model.get_builtin_hooks()
509 c.custom_hooks = model.get_custom_hooks()
515 c.custom_hooks = model.get_custom_hooks()
510
516
511 return htmlfill.render(
517 return htmlfill.render(
512 render('admin/settings/settings.html'),
518 render('admin/settings/settings.html'),
513 defaults=self._form_defaults(),
519 defaults=self._form_defaults(),
514 encoding="UTF-8",
520 encoding="UTF-8",
515 force_defaults=False)
521 force_defaults=False)
516
522
517 @HasPermissionAllDecorator('hg.admin')
523 @HasPermissionAllDecorator('hg.admin')
518 def settings_search(self):
524 def settings_search(self):
519 """GET /admin/settings/search: All items in the collection"""
525 """GET /admin/settings/search: All items in the collection"""
520 # url('admin_settings_search')
526 # url('admin_settings_search')
521 c.active = 'search'
527 c.active = 'search'
522
528
523 from rhodecode.lib.index import searcher_from_config
529 from rhodecode.lib.index import searcher_from_config
524 searcher = searcher_from_config(config)
530 searcher = searcher_from_config(config)
525 c.statistics = searcher.statistics()
531 c.statistics = searcher.statistics()
526
532
527 return render('admin/settings/settings.html')
533 return render('admin/settings/settings.html')
528
534
529 @HasPermissionAllDecorator('hg.admin')
535 @HasPermissionAllDecorator('hg.admin')
530 def settings_system(self):
536 def settings_system(self):
531 """GET /admin/settings/system: All items in the collection"""
537 """GET /admin/settings/system: All items in the collection"""
532 # url('admin_settings_system')
538 # url('admin_settings_system')
533 snapshot = str2bool(request.GET.get('snapshot'))
539 snapshot = str2bool(request.GET.get('snapshot'))
534 c.active = 'system'
540 c.active = 'system'
535
541
536 defaults = self._form_defaults()
542 defaults = self._form_defaults()
537 c.rhodecode_ini = rhodecode.CONFIG
543 c.rhodecode_ini = rhodecode.CONFIG
538 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
544 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
539 server_info = ScmModel().get_server_info(request.environ)
545 server_info = ScmModel().get_server_info(request.environ)
540 for key, val in server_info.iteritems():
546 for key, val in server_info.iteritems():
541 setattr(c, key, val)
547 setattr(c, key, val)
542
548
543 if c.disk['percent'] > 90:
549 if c.disk['percent'] > 90:
544 h.flash(h.literal(_(
550 h.flash(h.literal(_(
545 'Critical: your disk space is very low <b>%s%%</b> used' %
551 'Critical: your disk space is very low <b>%s%%</b> used' %
546 c.disk['percent'])), 'error')
552 c.disk['percent'])), 'error')
547 elif c.disk['percent'] > 70:
553 elif c.disk['percent'] > 70:
548 h.flash(h.literal(_(
554 h.flash(h.literal(_(
549 'Warning: your disk space is running low <b>%s%%</b> used' %
555 'Warning: your disk space is running low <b>%s%%</b> used' %
550 c.disk['percent'])), 'warning')
556 c.disk['percent'])), 'warning')
551
557
552 try:
558 try:
553 c.uptime_age = h._age(
559 c.uptime_age = h._age(
554 h.time_to_datetime(c.boot_time), False, show_suffix=False)
560 h.time_to_datetime(c.boot_time), False, show_suffix=False)
555 except TypeError:
561 except TypeError:
556 c.uptime_age = c.boot_time
562 c.uptime_age = c.boot_time
557
563
558 try:
564 try:
559 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
565 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
560 h.format_byte_size_binary(c.memory['used']),
566 h.format_byte_size_binary(c.memory['used']),
561 h.format_byte_size_binary(c.memory['total']),
567 h.format_byte_size_binary(c.memory['total']),
562 c.memory['percent2'],
568 c.memory['percent2'],
563 c.memory['percent'],
569 c.memory['percent'],
564 ' %s' % c.memory['error'] if 'error' in c.memory else '')
570 ' %s' % c.memory['error'] if 'error' in c.memory else '')
565 except TypeError:
571 except TypeError:
566 c.system_memory = 'NOT AVAILABLE'
572 c.system_memory = 'NOT AVAILABLE'
567
573
568 rhodecode_ini_safe = rhodecode.CONFIG.copy()
574 rhodecode_ini_safe = rhodecode.CONFIG.copy()
569 blacklist = [
575 blacklist = [
570 'rhodecode_license_key',
576 'rhodecode_license_key',
571 'routes.map',
577 'routes.map',
572 'pylons.h',
578 'pylons.h',
573 'pylons.app_globals',
579 'pylons.app_globals',
574 'pylons.environ_config',
580 'pylons.environ_config',
575 'sqlalchemy.db1.url',
581 'sqlalchemy.db1.url',
576 ('app_conf', 'sqlalchemy.db1.url')
582 ('app_conf', 'sqlalchemy.db1.url')
577 ]
583 ]
578 for k in blacklist:
584 for k in blacklist:
579 if isinstance(k, tuple):
585 if isinstance(k, tuple):
580 section, key = k
586 section, key = k
581 if section in rhodecode_ini_safe:
587 if section in rhodecode_ini_safe:
582 rhodecode_ini_safe[section].pop(key, None)
588 rhodecode_ini_safe[section].pop(key, None)
583 else:
589 else:
584 rhodecode_ini_safe.pop(k, None)
590 rhodecode_ini_safe.pop(k, None)
585
591
586 c.rhodecode_ini_safe = rhodecode_ini_safe
592 c.rhodecode_ini_safe = rhodecode_ini_safe
587
593
588 # TODO: marcink, figure out how to allow only selected users to do this
594 # TODO: marcink, figure out how to allow only selected users to do this
589 c.allowed_to_snapshot = False
595 c.allowed_to_snapshot = False
590
596
591 if snapshot:
597 if snapshot:
592 if c.allowed_to_snapshot:
598 if c.allowed_to_snapshot:
593 return render('admin/settings/settings_system_snapshot.html')
599 return render('admin/settings/settings_system_snapshot.html')
594 else:
600 else:
595 h.flash('You are not allowed to do this', category='warning')
601 h.flash('You are not allowed to do this', category='warning')
596
602
597 return htmlfill.render(
603 return htmlfill.render(
598 render('admin/settings/settings.html'),
604 render('admin/settings/settings.html'),
599 defaults=defaults,
605 defaults=defaults,
600 encoding="UTF-8",
606 encoding="UTF-8",
601 force_defaults=False)
607 force_defaults=False)
602
608
603 @staticmethod
609 @staticmethod
604 def get_update_data(update_url):
610 def get_update_data(update_url):
605 """Return the JSON update data."""
611 """Return the JSON update data."""
606 ver = rhodecode.__version__
612 ver = rhodecode.__version__
607 log.debug('Checking for upgrade on `%s` server', update_url)
613 log.debug('Checking for upgrade on `%s` server', update_url)
608 opener = urllib2.build_opener()
614 opener = urllib2.build_opener()
609 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
615 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
610 response = opener.open(update_url)
616 response = opener.open(update_url)
611 response_data = response.read()
617 response_data = response.read()
612 data = json.loads(response_data)
618 data = json.loads(response_data)
613
619
614 return data
620 return data
615
621
616 @HasPermissionAllDecorator('hg.admin')
622 @HasPermissionAllDecorator('hg.admin')
617 def settings_system_update(self):
623 def settings_system_update(self):
618 """GET /admin/settings/system/updates: All items in the collection"""
624 """GET /admin/settings/system/updates: All items in the collection"""
619 # url('admin_settings_system_update')
625 # url('admin_settings_system_update')
620 defaults = self._form_defaults()
626 defaults = self._form_defaults()
621 update_url = defaults.get('rhodecode_update_url', '')
627 update_url = defaults.get('rhodecode_update_url', '')
622
628
623 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
629 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
624 try:
630 try:
625 data = self.get_update_data(update_url)
631 data = self.get_update_data(update_url)
626 except urllib2.URLError as e:
632 except urllib2.URLError as e:
627 log.exception("Exception contacting upgrade server")
633 log.exception("Exception contacting upgrade server")
628 return _err('Failed to contact upgrade server: %r' % e)
634 return _err('Failed to contact upgrade server: %r' % e)
629 except ValueError as e:
635 except ValueError as e:
630 log.exception("Bad data sent from update server")
636 log.exception("Bad data sent from update server")
631 return _err('Bad data sent from update server')
637 return _err('Bad data sent from update server')
632
638
633 latest = data['versions'][0]
639 latest = data['versions'][0]
634
640
635 c.update_url = update_url
641 c.update_url = update_url
636 c.latest_data = latest
642 c.latest_data = latest
637 c.latest_ver = latest['version']
643 c.latest_ver = latest['version']
638 c.cur_ver = rhodecode.__version__
644 c.cur_ver = rhodecode.__version__
639 c.should_upgrade = False
645 c.should_upgrade = False
640
646
641 if (packaging.version.Version(c.latest_ver) >
647 if (packaging.version.Version(c.latest_ver) >
642 packaging.version.Version(c.cur_ver)):
648 packaging.version.Version(c.cur_ver)):
643 c.should_upgrade = True
649 c.should_upgrade = True
644 c.important_notices = latest['general']
650 c.important_notices = latest['general']
645
651
646 return render('admin/settings/settings_system_update.html')
652 return render('admin/settings/settings_system_update.html')
647
653
648 @HasPermissionAllDecorator('hg.admin')
654 @HasPermissionAllDecorator('hg.admin')
649 def settings_supervisor(self):
655 def settings_supervisor(self):
650 c.rhodecode_ini = rhodecode.CONFIG
656 c.rhodecode_ini = rhodecode.CONFIG
651 c.active = 'supervisor'
657 c.active = 'supervisor'
652
658
653 c.supervisor_procs = OrderedDict([
659 c.supervisor_procs = OrderedDict([
654 (SUPERVISOR_MASTER, {}),
660 (SUPERVISOR_MASTER, {}),
655 ])
661 ])
656
662
657 c.log_size = 10240
663 c.log_size = 10240
658 supervisor = SupervisorModel()
664 supervisor = SupervisorModel()
659
665
660 _connection = supervisor.get_connection(
666 _connection = supervisor.get_connection(
661 c.rhodecode_ini.get('supervisor.uri'))
667 c.rhodecode_ini.get('supervisor.uri'))
662 c.connection_error = None
668 c.connection_error = None
663 try:
669 try:
664 _connection.supervisor.getAllProcessInfo()
670 _connection.supervisor.getAllProcessInfo()
665 except Exception as e:
671 except Exception as e:
666 c.connection_error = str(e)
672 c.connection_error = str(e)
667 log.exception("Exception reading supervisor data")
673 log.exception("Exception reading supervisor data")
668 return render('admin/settings/settings.html')
674 return render('admin/settings/settings.html')
669
675
670 groupid = c.rhodecode_ini.get('supervisor.group_id')
676 groupid = c.rhodecode_ini.get('supervisor.group_id')
671
677
672 # feed our group processes to the main
678 # feed our group processes to the main
673 for proc in supervisor.get_group_processes(_connection, groupid):
679 for proc in supervisor.get_group_processes(_connection, groupid):
674 c.supervisor_procs[proc['name']] = {}
680 c.supervisor_procs[proc['name']] = {}
675
681
676 for k in c.supervisor_procs.keys():
682 for k in c.supervisor_procs.keys():
677 try:
683 try:
678 # master process info
684 # master process info
679 if k == SUPERVISOR_MASTER:
685 if k == SUPERVISOR_MASTER:
680 _data = supervisor.get_master_state(_connection)
686 _data = supervisor.get_master_state(_connection)
681 _data['name'] = 'supervisor master'
687 _data['name'] = 'supervisor master'
682 _data['description'] = 'pid %s, id: %s, ver: %s' % (
688 _data['description'] = 'pid %s, id: %s, ver: %s' % (
683 _data['pid'], _data['id'], _data['ver'])
689 _data['pid'], _data['id'], _data['ver'])
684 c.supervisor_procs[k] = _data
690 c.supervisor_procs[k] = _data
685 else:
691 else:
686 procid = groupid + ":" + k
692 procid = groupid + ":" + k
687 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
693 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
688 except Exception as e:
694 except Exception as e:
689 log.exception("Exception reading supervisor data")
695 log.exception("Exception reading supervisor data")
690 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
696 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
691
697
692 return render('admin/settings/settings.html')
698 return render('admin/settings/settings.html')
693
699
694 @HasPermissionAllDecorator('hg.admin')
700 @HasPermissionAllDecorator('hg.admin')
695 def settings_supervisor_log(self, procid):
701 def settings_supervisor_log(self, procid):
696 import rhodecode
702 import rhodecode
697 c.rhodecode_ini = rhodecode.CONFIG
703 c.rhodecode_ini = rhodecode.CONFIG
698 c.active = 'supervisor_tail'
704 c.active = 'supervisor_tail'
699
705
700 supervisor = SupervisorModel()
706 supervisor = SupervisorModel()
701 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
707 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
702 groupid = c.rhodecode_ini.get('supervisor.group_id')
708 groupid = c.rhodecode_ini.get('supervisor.group_id')
703 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
709 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
704
710
705 c.log_size = 10240
711 c.log_size = 10240
706 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
712 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
707 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
713 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
708
714
709 return render('admin/settings/settings.html')
715 return render('admin/settings/settings.html')
710
716
711 @HasPermissionAllDecorator('hg.admin')
717 @HasPermissionAllDecorator('hg.admin')
712 @auth.CSRFRequired()
718 @auth.CSRFRequired()
713 def settings_labs_update(self):
719 def settings_labs_update(self):
714 """POST /admin/settings/labs: All items in the collection"""
720 """POST /admin/settings/labs: All items in the collection"""
715 # url('admin_settings/labs', method={'POST'})
721 # url('admin_settings/labs', method={'POST'})
716 c.active = 'labs'
722 c.active = 'labs'
717
723
718 application_form = LabsSettingsForm()()
724 application_form = LabsSettingsForm()()
719 try:
725 try:
720 form_result = application_form.to_python(dict(request.POST))
726 form_result = application_form.to_python(dict(request.POST))
721 except formencode.Invalid as errors:
727 except formencode.Invalid as errors:
722 h.flash(
728 h.flash(
723 _('Some form inputs contain invalid data.'),
729 _('Some form inputs contain invalid data.'),
724 category='error')
730 category='error')
725 return htmlfill.render(
731 return htmlfill.render(
726 render('admin/settings/settings.html'),
732 render('admin/settings/settings.html'),
727 defaults=errors.value,
733 defaults=errors.value,
728 errors=errors.error_dict or {},
734 errors=errors.error_dict or {},
729 prefix_error=False,
735 prefix_error=False,
730 encoding='UTF-8',
736 encoding='UTF-8',
731 force_defaults=False
737 force_defaults=False
732 )
738 )
733
739
734 try:
740 try:
735 session = Session()
741 session = Session()
736 for setting in _LAB_SETTINGS:
742 for setting in _LAB_SETTINGS:
737 setting_name = setting.key[len('rhodecode_'):]
743 setting_name = setting.key[len('rhodecode_'):]
738 sett = SettingsModel().create_or_update_setting(
744 sett = SettingsModel().create_or_update_setting(
739 setting_name, form_result[setting.key], setting.type)
745 setting_name, form_result[setting.key], setting.type)
740 session.add(sett)
746 session.add(sett)
741
747
742 except Exception:
748 except Exception:
743 log.exception('Exception while updating lab settings')
749 log.exception('Exception while updating lab settings')
744 h.flash(_('Error occurred during updating labs settings'),
750 h.flash(_('Error occurred during updating labs settings'),
745 category='error')
751 category='error')
746 else:
752 else:
747 Session().commit()
753 Session().commit()
748 SettingsModel().invalidate_settings_cache()
754 SettingsModel().invalidate_settings_cache()
749 h.flash(_('Updated Labs settings'), category='success')
755 h.flash(_('Updated Labs settings'), category='success')
750 return redirect(url('admin_settings_labs'))
756 return redirect(url('admin_settings_labs'))
751
757
752 return htmlfill.render(
758 return htmlfill.render(
753 render('admin/settings/settings.html'),
759 render('admin/settings/settings.html'),
754 defaults=self._form_defaults(),
760 defaults=self._form_defaults(),
755 encoding='UTF-8',
761 encoding='UTF-8',
756 force_defaults=False)
762 force_defaults=False)
757
763
758 @HasPermissionAllDecorator('hg.admin')
764 @HasPermissionAllDecorator('hg.admin')
759 def settings_labs(self):
765 def settings_labs(self):
760 """GET /admin/settings/labs: All items in the collection"""
766 """GET /admin/settings/labs: All items in the collection"""
761 # url('admin_settings_labs')
767 # url('admin_settings_labs')
762 if not c.labs_active:
768 if not c.labs_active:
763 redirect(url('admin_settings'))
769 redirect(url('admin_settings'))
764
770
765 c.active = 'labs'
771 c.active = 'labs'
766 c.lab_settings = _LAB_SETTINGS
772 c.lab_settings = _LAB_SETTINGS
767
773
768 return htmlfill.render(
774 return htmlfill.render(
769 render('admin/settings/settings.html'),
775 render('admin/settings/settings.html'),
770 defaults=self._form_defaults(),
776 defaults=self._form_defaults(),
771 encoding='UTF-8',
777 encoding='UTF-8',
772 force_defaults=False)
778 force_defaults=False)
773
779
774 def _form_defaults(self):
780 def _form_defaults(self):
775 defaults = SettingsModel().get_all_settings()
781 defaults = SettingsModel().get_all_settings()
776 defaults.update(self._get_hg_ui_settings())
782 defaults.update(self._get_hg_ui_settings())
777 defaults.update({
783 defaults.update({
778 'new_svn_branch': '',
784 'new_svn_branch': '',
779 'new_svn_tag': '',
785 'new_svn_tag': '',
780 })
786 })
781 return defaults
787 return defaults
782
788
783
789
784 # :param key: name of the setting including the 'rhodecode_' prefix
790 # :param key: name of the setting including the 'rhodecode_' prefix
785 # :param type: the RhodeCodeSetting type to use.
791 # :param type: the RhodeCodeSetting type to use.
786 # :param group: the i18ned group in which we should dispaly this setting
792 # :param group: the i18ned group in which we should dispaly this setting
787 # :param label: the i18ned label we should display for this setting
793 # :param label: the i18ned label we should display for this setting
788 # :param help: the i18ned help we should dispaly for this setting
794 # :param help: the i18ned help we should dispaly for this setting
789 LabSetting = collections.namedtuple(
795 LabSetting = collections.namedtuple(
790 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
796 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
791
797
792
798
793 # This list has to be kept in sync with the form
799 # This list has to be kept in sync with the form
794 # rhodecode.model.forms.LabsSettingsForm.
800 # rhodecode.model.forms.LabsSettingsForm.
795 _LAB_SETTINGS = [
801 _LAB_SETTINGS = [
796
802
797 ]
803 ]
@@ -1,270 +1,272 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 ## LABS for HG
119 ## LABS for HG
120 % if c.labs_active:
120 % if c.labs_active:
121 <div class="panel panel-danger">
121 <div class="panel panel-danger">
122 <div class="panel-heading">
122 <div class="panel-heading">
123 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
123 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
124 </div>
124 </div>
125 <div class="panel-body">
125 <div class="panel-body">
126
126
127 <div class="checkbox">
127 <div class="checkbox">
128 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
128 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
129 <label for="rhodecode_hg_use_rebase_for_merging{suffix}">${_('Use rebase as merge strategy')}</label>
129 <label for="rhodecode_hg_use_rebase_for_merging{suffix}">${_('Use rebase as merge strategy')}</label>
130 </div>
130 </div>
131 <div class="label">
131 <div class="label">
132 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
132 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
133 </div>
133 </div>
134
134
135 </div>
135 </div>
136 </div>
136 </div>
137 % endif
137 % endif
138
138
139 % endif
139 % endif
140
140
141 % if display_globals:
141 % if display_globals:
142 <div class="panel panel-default">
142 <div class="panel panel-default">
143 <div class="panel-heading">
143 <div class="panel-heading">
144 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
144 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
145 </div>
145 </div>
146 <div class="panel-body">
146 <div class="panel-body">
147 <div class="field">
147 <div class="field">
148 <div class="checkbox">
148 <div class="checkbox">
149 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
149 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
150 <label for="vcs_svn_proxy_http_requests_enabled{suffix}">${_('Proxy subversion HTTP requests')}</label>
150 <label for="vcs_svn_proxy_http_requests_enabled{suffix}">${_('Proxy subversion HTTP requests')}</label>
151 </div>
151 </div>
152 <div class="label">
152 <div class="label">
153 <span class="help-block">${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}</span>
153 <span class="help-block">${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}</span>
154 </div>
154 </div>
155 </div>
155 </div>
156 <div class="field">
156 <div class="field">
157 <div class="label">
157 <div class="label">
158 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
158 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
159 </div>
159 </div>
160 <div class="input">
160 <div class="input">
161 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
161 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
162 </div>
162 </div>
163 </div>
163 </div>
164 % if c.svn_proxy_generate_config:
164 <div class="buttons">
165 <div class="buttons">
165 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
166 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
166 </div>
167 </div>
168 % endif
167 </div>
169 </div>
168 </div>
170 </div>
169 % endif
171 % endif
170
172
171 % if display_globals or repo_type in ['svn']:
173 % if display_globals or repo_type in ['svn']:
172 <div class="panel panel-default">
174 <div class="panel panel-default">
173 <div class="panel-heading">
175 <div class="panel-heading">
174 <h3 class="panel-title">${_('Subversion Settings')}</h3>
176 <h3 class="panel-title">${_('Subversion Settings')}</h3>
175 </div>
177 </div>
176 <div class="panel-body">
178 <div class="panel-body">
177 <div class="field">
179 <div class="field">
178 <div class="content" >
180 <div class="content" >
179 <label>${_('Repository patterns')}</label><br/>
181 <label>${_('Repository patterns')}</label><br/>
180 </div>
182 </div>
181 </div>
183 </div>
182 <div class="label">
184 <div class="label">
183 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
185 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
184 </div>
186 </div>
185
187
186 <div class="field branch_patterns">
188 <div class="field branch_patterns">
187 <div class="input" >
189 <div class="input" >
188 <label>${_('Branches')}:</label><br/>
190 <label>${_('Branches')}:</label><br/>
189 </div>
191 </div>
190 % if svn_branch_patterns:
192 % if svn_branch_patterns:
191 % for branch in svn_branch_patterns:
193 % for branch in svn_branch_patterns:
192 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
194 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
193 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
195 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
194 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
196 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
195 % if kwargs.get('disabled') != 'disabled':
197 % if kwargs.get('disabled') != 'disabled':
196 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
198 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
197 ${_('Delete')}
199 ${_('Delete')}
198 </span>
200 </span>
199 % endif
201 % endif
200 </div>
202 </div>
201 % endfor
203 % endfor
202 %endif
204 %endif
203 </div>
205 </div>
204 % if kwargs.get('disabled') != 'disabled':
206 % if kwargs.get('disabled') != 'disabled':
205 <div class="field branch_patterns">
207 <div class="field branch_patterns">
206 <div class="input" >
208 <div class="input" >
207 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
209 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
208 </div>
210 </div>
209 </div>
211 </div>
210 % endif
212 % endif
211 <div class="field tag_patterns">
213 <div class="field tag_patterns">
212 <div class="input" >
214 <div class="input" >
213 <label>${_('Tags')}:</label><br/>
215 <label>${_('Tags')}:</label><br/>
214 </div>
216 </div>
215 % if svn_tag_patterns:
217 % if svn_tag_patterns:
216 % for tag in svn_tag_patterns:
218 % for tag in svn_tag_patterns:
217 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
219 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
218 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
220 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
219 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
221 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
220 % if kwargs.get('disabled') != 'disabled':
222 % if kwargs.get('disabled') != 'disabled':
221 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
223 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
222 ${_('Delete')}
224 ${_('Delete')}
223 </span>
225 </span>
224 %endif
226 %endif
225 </div>
227 </div>
226 % endfor
228 % endfor
227 % endif
229 % endif
228 </div>
230 </div>
229 % if kwargs.get('disabled') != 'disabled':
231 % if kwargs.get('disabled') != 'disabled':
230 <div class="field tag_patterns">
232 <div class="field tag_patterns">
231 <div class="input" >
233 <div class="input" >
232 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
234 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
233 </div>
235 </div>
234 </div>
236 </div>
235 %endif
237 %endif
236 </div>
238 </div>
237 </div>
239 </div>
238 % else:
240 % else:
239 ${h.hidden('new_svn_branch' + suffix, '')}
241 ${h.hidden('new_svn_branch' + suffix, '')}
240 ${h.hidden('new_svn_tag' + suffix, '')}
242 ${h.hidden('new_svn_tag' + suffix, '')}
241 % endif
243 % endif
242
244
243
245
244
246
245
247
246 % if display_globals or repo_type in ['hg', 'git']:
248 % if display_globals or repo_type in ['hg', 'git']:
247 <div class="panel panel-default">
249 <div class="panel panel-default">
248 <div class="panel-heading">
250 <div class="panel-heading">
249 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
251 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
250 </div>
252 </div>
251 <div class="panel-body">
253 <div class="panel-body">
252 <div class="checkbox">
254 <div class="checkbox">
253 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
255 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
254 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
256 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
255 </div>
257 </div>
256 <div class="label">
258 <div class="label">
257 <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>
259 <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>
258 </div>
260 </div>
259 <div class="checkbox">
261 <div class="checkbox">
260 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
262 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
261 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
263 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
262 </div>
264 </div>
263 <div class="label">
265 <div class="label">
264 <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>
266 <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>
265 </div>
267 </div>
266 </div>
268 </div>
267 </div>
269 </div>
268 % endif
270 % endif
269
271
270 </%def>
272 </%def>
General Comments 0
You need to be logged in to leave comments. Login now