##// END OF EJS Templates
admin: Move admin settings navigation to admin module.
Martin Bornhold -
r295:392597a3 default
parent child Browse files
Show More
@@ -0,0 +1,106 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import logging
23 import collections
24 from pylons import url
25 from pylons.i18n.translation import lazy_ugettext
26 from zope.interface import implementer
27
28 import rhodecode
29 from rhodecode.admin.interfaces import IAdminNavigationRegistry
30 from rhodecode.lib.utils2 import str2bool
31
32
33 log = logging.getLogger(__name__)
34
35 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
36
37
38 class NavEntry(object):
39
40 def __init__(self, key, name, view_name, pyramid=False):
41 self.key = key
42 self.name = name
43 self.view_name = view_name
44 self.pyramid = pyramid
45
46 def generate_url(self, request):
47 if self.pyramid:
48 if hasattr(request, 'route_path'):
49 return request.route_path(self.view_name)
50 else:
51 # TODO: johbo: Remove this after migrating to pyramid.
52 # We need the pyramid request here to generate URLs to pyramid
53 # views from within pylons views.
54 from pyramid.threadlocal import get_current_request
55 pyramid_request = get_current_request()
56 return pyramid_request.route_path(self.view_name)
57 else:
58 return url(self.view_name)
59
60
61 @implementer(IAdminNavigationRegistry)
62 class NavigationRegistry(object):
63
64 _base_entries = [
65 NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'),
66 NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'),
67 NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'),
68 NavEntry('mapping', lazy_ugettext('Remap and Rescan'),
69 'admin_settings_mapping'),
70 NavEntry('issuetracker', lazy_ugettext('Issue Tracker'),
71 'admin_settings_issuetracker'),
72 NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'),
73 NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'),
74 NavEntry('search', lazy_ugettext('Full Text Search'),
75 'admin_settings_search'),
76 NavEntry('system', lazy_ugettext('System Info'),
77 'admin_settings_system'),
78 NavEntry('open_source', lazy_ugettext('Open Source Licenses'),
79 'admin_settings_open_source', pyramid=True),
80 # TODO: marcink: we disable supervisor now until the supervisor stats
81 # page is fixed in the nix configuration
82 # NavEntry('supervisor', lazy_ugettext('Supervisor'),
83 # 'admin_settings_supervisor'),
84 ]
85
86 def __init__(self):
87 self._registered_entries = collections.OrderedDict([
88 (item.key, item) for item in self.__class__._base_entries
89 ])
90
91 # Add the labs entry when it's activated.
92 labs_active = str2bool(
93 rhodecode.CONFIG.get('labs_settings_active', 'false'))
94 if labs_active:
95 self.add_entry(
96 NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs'))
97
98 def add_entry(self, entry):
99 self._registered_entries[entry.key] = entry
100
101 def get_navlist(self, request):
102 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
103 for i in self._registered_entries.values()]
104 return navlist
105
106 navigation = NavigationRegistry()
@@ -1,885 +1,813 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
40 from rhodecode.lib import auth
41 from rhodecode.lib import auth
41 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.celerylib import tasks, run_task
45 from rhodecode.lib.celerylib import tasks, run_task
45 from rhodecode.lib.utils import repo2db_mapper
46 from rhodecode.lib.utils import repo2db_mapper
46 from rhodecode.lib.utils2 import (
47 from rhodecode.lib.utils2 import (
47 str2bool, safe_unicode, AttributeDict, safe_int)
48 str2bool, safe_unicode, AttributeDict, safe_int)
48 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.ext_json import json
50 from rhodecode.lib.utils import jsonify
51 from rhodecode.lib.utils import jsonify
51
52
52 from rhodecode.model.db import RhodeCodeUi, Repository, User
53 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.forms import ApplicationSettingsForm, \
54 from rhodecode.model.forms import ApplicationSettingsForm, \
54 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
55 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
55 LabsSettingsForm, IssueTrackerPatternsForm
56 LabsSettingsForm, IssueTrackerPatternsForm
56
57
57 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.notification import EmailNotificationModel
59 from rhodecode.model.notification import EmailNotificationModel
59 from rhodecode.model.meta import Session
60 from rhodecode.model.meta import Session
60 from rhodecode.model.settings import (
61 from rhodecode.model.settings import (
61 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 SettingsModel)
63 SettingsModel)
63
64
64 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
65
66
66
67
67 log = logging.getLogger(__name__)
68 log = logging.getLogger(__name__)
68
69
69
70
70 class SettingsController(BaseController):
71 class SettingsController(BaseController):
71 """REST Controller styled on the Atom Publishing Protocol"""
72 """REST Controller styled on the Atom Publishing Protocol"""
72 # To properly map this controller, ensure your config/routing.py
73 # To properly map this controller, ensure your config/routing.py
73 # file has a resource setup:
74 # file has a resource setup:
74 # map.resource('setting', 'settings', controller='admin/settings',
75 # map.resource('setting', 'settings', controller='admin/settings',
75 # path_prefix='/admin', name_prefix='admin_')
76 # path_prefix='/admin', name_prefix='admin_')
76
77
77 @LoginRequired()
78 @LoginRequired()
78 def __before__(self):
79 def __before__(self):
79 super(SettingsController, self).__before__()
80 super(SettingsController, self).__before__()
80 c.labs_active = str2bool(
81 c.labs_active = str2bool(
81 rhodecode.CONFIG.get('labs_settings_active', 'false'))
82 rhodecode.CONFIG.get('labs_settings_active', 'false'))
82 c.navlist = navigation.get_navlist(request)
83 c.navlist = navigation.get_navlist(request)
83
84
84 def _get_hg_ui_settings(self):
85 def _get_hg_ui_settings(self):
85 ret = RhodeCodeUi.query().all()
86 ret = RhodeCodeUi.query().all()
86
87
87 if not ret:
88 if not ret:
88 raise Exception('Could not get application ui settings !')
89 raise Exception('Could not get application ui settings !')
89 settings = {}
90 settings = {}
90 for each in ret:
91 for each in ret:
91 k = each.ui_key
92 k = each.ui_key
92 v = each.ui_value
93 v = each.ui_value
93 if k == '/':
94 if k == '/':
94 k = 'root_path'
95 k = 'root_path'
95
96
96 if k in ['push_ssl', 'publish']:
97 if k in ['push_ssl', 'publish']:
97 v = str2bool(v)
98 v = str2bool(v)
98
99
99 if k.find('.') != -1:
100 if k.find('.') != -1:
100 k = k.replace('.', '_')
101 k = k.replace('.', '_')
101
102
102 if each.ui_section in ['hooks', 'extensions']:
103 if each.ui_section in ['hooks', 'extensions']:
103 v = each.ui_active
104 v = each.ui_active
104
105
105 settings[each.ui_section + '_' + k] = v
106 settings[each.ui_section + '_' + k] = v
106 return settings
107 return settings
107
108
108 @HasPermissionAllDecorator('hg.admin')
109 @HasPermissionAllDecorator('hg.admin')
109 @auth.CSRFRequired()
110 @auth.CSRFRequired()
110 @jsonify
111 @jsonify
111 def delete_svn_pattern(self):
112 def delete_svn_pattern(self):
112 if not request.is_xhr:
113 if not request.is_xhr:
113 raise HTTPBadRequest()
114 raise HTTPBadRequest()
114
115
115 delete_pattern_id = request.POST.get('delete_svn_pattern')
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
116 model = VcsSettingsModel()
117 model = VcsSettingsModel()
117 try:
118 try:
118 model.delete_global_svn_pattern(delete_pattern_id)
119 model.delete_global_svn_pattern(delete_pattern_id)
119 except SettingNotFound:
120 except SettingNotFound:
120 raise HTTPBadRequest()
121 raise HTTPBadRequest()
121
122
122 Session().commit()
123 Session().commit()
123 return True
124 return True
124
125
125 @HasPermissionAllDecorator('hg.admin')
126 @HasPermissionAllDecorator('hg.admin')
126 @auth.CSRFRequired()
127 @auth.CSRFRequired()
127 def settings_vcs_update(self):
128 def settings_vcs_update(self):
128 """POST /admin/settings: All items in the collection"""
129 """POST /admin/settings: All items in the collection"""
129 # url('admin_settings_vcs')
130 # url('admin_settings_vcs')
130 c.active = 'vcs'
131 c.active = 'vcs'
131
132
132 model = VcsSettingsModel()
133 model = VcsSettingsModel()
133 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
134 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
135
136
136 application_form = ApplicationUiSettingsForm()()
137 application_form = ApplicationUiSettingsForm()()
137 try:
138 try:
138 form_result = application_form.to_python(dict(request.POST))
139 form_result = application_form.to_python(dict(request.POST))
139 except formencode.Invalid as errors:
140 except formencode.Invalid as errors:
140 h.flash(
141 h.flash(
141 _("Some form inputs contain invalid data."),
142 _("Some form inputs contain invalid data."),
142 category='error')
143 category='error')
143 return htmlfill.render(
144 return htmlfill.render(
144 render('admin/settings/settings.html'),
145 render('admin/settings/settings.html'),
145 defaults=errors.value,
146 defaults=errors.value,
146 errors=errors.error_dict or {},
147 errors=errors.error_dict or {},
147 prefix_error=False,
148 prefix_error=False,
148 encoding="UTF-8",
149 encoding="UTF-8",
149 force_defaults=False
150 force_defaults=False
150 )
151 )
151
152
152 try:
153 try:
153 model.update_global_ssl_setting(form_result['web_push_ssl'])
154 model.update_global_ssl_setting(form_result['web_push_ssl'])
154 if c.visual.allow_repo_location_change:
155 if c.visual.allow_repo_location_change:
155 model.update_global_path_setting(
156 model.update_global_path_setting(
156 form_result['paths_root_path'])
157 form_result['paths_root_path'])
157 model.update_global_hook_settings(form_result)
158 model.update_global_hook_settings(form_result)
158 model.create_global_svn_settings(form_result)
159 model.create_global_svn_settings(form_result)
159 model.create_or_update_global_hg_settings(form_result)
160 model.create_or_update_global_hg_settings(form_result)
160 model.create_or_update_global_pr_settings(form_result)
161 model.create_or_update_global_pr_settings(form_result)
161 except Exception:
162 except Exception:
162 log.exception("Exception while updating settings")
163 log.exception("Exception while updating settings")
163 h.flash(_('Error occurred during updating '
164 h.flash(_('Error occurred during updating '
164 'application settings'), category='error')
165 'application settings'), category='error')
165 else:
166 else:
166 Session().commit()
167 Session().commit()
167 h.flash(_('Updated VCS settings'), category='success')
168 h.flash(_('Updated VCS settings'), category='success')
168 return redirect(url('admin_settings_vcs'))
169 return redirect(url('admin_settings_vcs'))
169
170
170 return htmlfill.render(
171 return htmlfill.render(
171 render('admin/settings/settings.html'),
172 render('admin/settings/settings.html'),
172 defaults=self._form_defaults(),
173 defaults=self._form_defaults(),
173 encoding="UTF-8",
174 encoding="UTF-8",
174 force_defaults=False)
175 force_defaults=False)
175
176
176 @HasPermissionAllDecorator('hg.admin')
177 @HasPermissionAllDecorator('hg.admin')
177 def settings_vcs(self):
178 def settings_vcs(self):
178 """GET /admin/settings: All items in the collection"""
179 """GET /admin/settings: All items in the collection"""
179 # url('admin_settings_vcs')
180 # url('admin_settings_vcs')
180 c.active = 'vcs'
181 c.active = 'vcs'
181 model = VcsSettingsModel()
182 model = VcsSettingsModel()
182 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
183 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
183 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
184 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
184
185
185 return htmlfill.render(
186 return htmlfill.render(
186 render('admin/settings/settings.html'),
187 render('admin/settings/settings.html'),
187 defaults=self._form_defaults(),
188 defaults=self._form_defaults(),
188 encoding="UTF-8",
189 encoding="UTF-8",
189 force_defaults=False)
190 force_defaults=False)
190
191
191 @HasPermissionAllDecorator('hg.admin')
192 @HasPermissionAllDecorator('hg.admin')
192 @auth.CSRFRequired()
193 @auth.CSRFRequired()
193 def settings_mapping_update(self):
194 def settings_mapping_update(self):
194 """POST /admin/settings/mapping: All items in the collection"""
195 """POST /admin/settings/mapping: All items in the collection"""
195 # url('admin_settings_mapping')
196 # url('admin_settings_mapping')
196 c.active = 'mapping'
197 c.active = 'mapping'
197 rm_obsolete = request.POST.get('destroy', False)
198 rm_obsolete = request.POST.get('destroy', False)
198 invalidate_cache = request.POST.get('invalidate', False)
199 invalidate_cache = request.POST.get('invalidate', False)
199 log.debug(
200 log.debug(
200 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
201 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
201
202
202 if invalidate_cache:
203 if invalidate_cache:
203 log.debug('invalidating all repositories cache')
204 log.debug('invalidating all repositories cache')
204 for repo in Repository.get_all():
205 for repo in Repository.get_all():
205 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
206 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
206
207
207 filesystem_repos = ScmModel().repo_scan()
208 filesystem_repos = ScmModel().repo_scan()
208 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
209 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
209 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
210 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
210 h.flash(_('Repositories successfully '
211 h.flash(_('Repositories successfully '
211 'rescanned added: %s ; removed: %s') %
212 'rescanned added: %s ; removed: %s') %
212 (_repr(added), _repr(removed)),
213 (_repr(added), _repr(removed)),
213 category='success')
214 category='success')
214 return redirect(url('admin_settings_mapping'))
215 return redirect(url('admin_settings_mapping'))
215
216
216 @HasPermissionAllDecorator('hg.admin')
217 @HasPermissionAllDecorator('hg.admin')
217 def settings_mapping(self):
218 def settings_mapping(self):
218 """GET /admin/settings/mapping: All items in the collection"""
219 """GET /admin/settings/mapping: All items in the collection"""
219 # url('admin_settings_mapping')
220 # url('admin_settings_mapping')
220 c.active = 'mapping'
221 c.active = 'mapping'
221
222
222 return htmlfill.render(
223 return htmlfill.render(
223 render('admin/settings/settings.html'),
224 render('admin/settings/settings.html'),
224 defaults=self._form_defaults(),
225 defaults=self._form_defaults(),
225 encoding="UTF-8",
226 encoding="UTF-8",
226 force_defaults=False)
227 force_defaults=False)
227
228
228 @HasPermissionAllDecorator('hg.admin')
229 @HasPermissionAllDecorator('hg.admin')
229 @auth.CSRFRequired()
230 @auth.CSRFRequired()
230 def settings_global_update(self):
231 def settings_global_update(self):
231 """POST /admin/settings/global: All items in the collection"""
232 """POST /admin/settings/global: All items in the collection"""
232 # url('admin_settings_global')
233 # url('admin_settings_global')
233 c.active = 'global'
234 c.active = 'global'
234 application_form = ApplicationSettingsForm()()
235 application_form = ApplicationSettingsForm()()
235 try:
236 try:
236 form_result = application_form.to_python(dict(request.POST))
237 form_result = application_form.to_python(dict(request.POST))
237 except formencode.Invalid as errors:
238 except formencode.Invalid as errors:
238 return htmlfill.render(
239 return htmlfill.render(
239 render('admin/settings/settings.html'),
240 render('admin/settings/settings.html'),
240 defaults=errors.value,
241 defaults=errors.value,
241 errors=errors.error_dict or {},
242 errors=errors.error_dict or {},
242 prefix_error=False,
243 prefix_error=False,
243 encoding="UTF-8",
244 encoding="UTF-8",
244 force_defaults=False)
245 force_defaults=False)
245
246
246 try:
247 try:
247 settings = [
248 settings = [
248 ('title', 'rhodecode_title'),
249 ('title', 'rhodecode_title'),
249 ('realm', 'rhodecode_realm'),
250 ('realm', 'rhodecode_realm'),
250 ('pre_code', 'rhodecode_pre_code'),
251 ('pre_code', 'rhodecode_pre_code'),
251 ('post_code', 'rhodecode_post_code'),
252 ('post_code', 'rhodecode_post_code'),
252 ('captcha_public_key', 'rhodecode_captcha_public_key'),
253 ('captcha_public_key', 'rhodecode_captcha_public_key'),
253 ('captcha_private_key', 'rhodecode_captcha_private_key'),
254 ('captcha_private_key', 'rhodecode_captcha_private_key'),
254 ]
255 ]
255 for setting, form_key in settings:
256 for setting, form_key in settings:
256 sett = SettingsModel().create_or_update_setting(
257 sett = SettingsModel().create_or_update_setting(
257 setting, form_result[form_key])
258 setting, form_result[form_key])
258 Session().add(sett)
259 Session().add(sett)
259
260
260 Session().commit()
261 Session().commit()
261 SettingsModel().invalidate_settings_cache()
262 SettingsModel().invalidate_settings_cache()
262 h.flash(_('Updated application settings'), category='success')
263 h.flash(_('Updated application settings'), category='success')
263 except Exception:
264 except Exception:
264 log.exception("Exception while updating application settings")
265 log.exception("Exception while updating application settings")
265 h.flash(
266 h.flash(
266 _('Error occurred during updating application settings'),
267 _('Error occurred during updating application settings'),
267 category='error')
268 category='error')
268
269
269 return redirect(url('admin_settings_global'))
270 return redirect(url('admin_settings_global'))
270
271
271 @HasPermissionAllDecorator('hg.admin')
272 @HasPermissionAllDecorator('hg.admin')
272 def settings_global(self):
273 def settings_global(self):
273 """GET /admin/settings/global: All items in the collection"""
274 """GET /admin/settings/global: All items in the collection"""
274 # url('admin_settings_global')
275 # url('admin_settings_global')
275 c.active = 'global'
276 c.active = 'global'
276
277
277 return htmlfill.render(
278 return htmlfill.render(
278 render('admin/settings/settings.html'),
279 render('admin/settings/settings.html'),
279 defaults=self._form_defaults(),
280 defaults=self._form_defaults(),
280 encoding="UTF-8",
281 encoding="UTF-8",
281 force_defaults=False)
282 force_defaults=False)
282
283
283 @HasPermissionAllDecorator('hg.admin')
284 @HasPermissionAllDecorator('hg.admin')
284 @auth.CSRFRequired()
285 @auth.CSRFRequired()
285 def settings_visual_update(self):
286 def settings_visual_update(self):
286 """POST /admin/settings/visual: All items in the collection"""
287 """POST /admin/settings/visual: All items in the collection"""
287 # url('admin_settings_visual')
288 # url('admin_settings_visual')
288 c.active = 'visual'
289 c.active = 'visual'
289 application_form = ApplicationVisualisationForm()()
290 application_form = ApplicationVisualisationForm()()
290 try:
291 try:
291 form_result = application_form.to_python(dict(request.POST))
292 form_result = application_form.to_python(dict(request.POST))
292 except formencode.Invalid as errors:
293 except formencode.Invalid as errors:
293 return htmlfill.render(
294 return htmlfill.render(
294 render('admin/settings/settings.html'),
295 render('admin/settings/settings.html'),
295 defaults=errors.value,
296 defaults=errors.value,
296 errors=errors.error_dict or {},
297 errors=errors.error_dict or {},
297 prefix_error=False,
298 prefix_error=False,
298 encoding="UTF-8",
299 encoding="UTF-8",
299 force_defaults=False
300 force_defaults=False
300 )
301 )
301
302
302 try:
303 try:
303 settings = [
304 settings = [
304 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
305 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
305 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
306 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
306 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
307 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
307 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
308 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
308 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
309 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
309 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
310 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
310 ('show_version', 'rhodecode_show_version', 'bool'),
311 ('show_version', 'rhodecode_show_version', 'bool'),
311 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
312 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
312 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
313 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
313 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
314 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
314 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
315 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
315 ('support_url', 'rhodecode_support_url', 'unicode'),
316 ('support_url', 'rhodecode_support_url', 'unicode'),
316 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
317 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
317 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
318 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
318 ]
319 ]
319 for setting, form_key, type_ in settings:
320 for setting, form_key, type_ in settings:
320 sett = SettingsModel().create_or_update_setting(
321 sett = SettingsModel().create_or_update_setting(
321 setting, form_result[form_key], type_)
322 setting, form_result[form_key], type_)
322 Session().add(sett)
323 Session().add(sett)
323
324
324 Session().commit()
325 Session().commit()
325 SettingsModel().invalidate_settings_cache()
326 SettingsModel().invalidate_settings_cache()
326 h.flash(_('Updated visualisation settings'), category='success')
327 h.flash(_('Updated visualisation settings'), category='success')
327 except Exception:
328 except Exception:
328 log.exception("Exception updating visualization settings")
329 log.exception("Exception updating visualization settings")
329 h.flash(_('Error occurred during updating '
330 h.flash(_('Error occurred during updating '
330 'visualisation settings'),
331 'visualisation settings'),
331 category='error')
332 category='error')
332
333
333 return redirect(url('admin_settings_visual'))
334 return redirect(url('admin_settings_visual'))
334
335
335 @HasPermissionAllDecorator('hg.admin')
336 @HasPermissionAllDecorator('hg.admin')
336 def settings_visual(self):
337 def settings_visual(self):
337 """GET /admin/settings/visual: All items in the collection"""
338 """GET /admin/settings/visual: All items in the collection"""
338 # url('admin_settings_visual')
339 # url('admin_settings_visual')
339 c.active = 'visual'
340 c.active = 'visual'
340
341
341 return htmlfill.render(
342 return htmlfill.render(
342 render('admin/settings/settings.html'),
343 render('admin/settings/settings.html'),
343 defaults=self._form_defaults(),
344 defaults=self._form_defaults(),
344 encoding="UTF-8",
345 encoding="UTF-8",
345 force_defaults=False)
346 force_defaults=False)
346
347
347 @HasPermissionAllDecorator('hg.admin')
348 @HasPermissionAllDecorator('hg.admin')
348 @auth.CSRFRequired()
349 @auth.CSRFRequired()
349 def settings_issuetracker_test(self):
350 def settings_issuetracker_test(self):
350 if request.is_xhr:
351 if request.is_xhr:
351 return h.urlify_commit_message(
352 return h.urlify_commit_message(
352 request.POST.get('test_text', ''),
353 request.POST.get('test_text', ''),
353 'repo_group/test_repo1')
354 'repo_group/test_repo1')
354 else:
355 else:
355 raise HTTPBadRequest()
356 raise HTTPBadRequest()
356
357
357 @HasPermissionAllDecorator('hg.admin')
358 @HasPermissionAllDecorator('hg.admin')
358 @auth.CSRFRequired()
359 @auth.CSRFRequired()
359 def settings_issuetracker_delete(self):
360 def settings_issuetracker_delete(self):
360 uid = request.POST.get('uid')
361 uid = request.POST.get('uid')
361 IssueTrackerSettingsModel().delete_entries(uid)
362 IssueTrackerSettingsModel().delete_entries(uid)
362 h.flash(_('Removed issue tracker entry'), category='success')
363 h.flash(_('Removed issue tracker entry'), category='success')
363 return redirect(url('admin_settings_issuetracker'))
364 return redirect(url('admin_settings_issuetracker'))
364
365
365 @HasPermissionAllDecorator('hg.admin')
366 @HasPermissionAllDecorator('hg.admin')
366 def settings_issuetracker(self):
367 def settings_issuetracker(self):
367 """GET /admin/settings/issue-tracker: All items in the collection"""
368 """GET /admin/settings/issue-tracker: All items in the collection"""
368 # url('admin_settings_issuetracker')
369 # url('admin_settings_issuetracker')
369 c.active = 'issuetracker'
370 c.active = 'issuetracker'
370 defaults = SettingsModel().get_all_settings()
371 defaults = SettingsModel().get_all_settings()
371
372
372 entry_key = 'rhodecode_issuetracker_pat_'
373 entry_key = 'rhodecode_issuetracker_pat_'
373
374
374 c.issuetracker_entries = {}
375 c.issuetracker_entries = {}
375 for k, v in defaults.items():
376 for k, v in defaults.items():
376 if k.startswith(entry_key):
377 if k.startswith(entry_key):
377 uid = k[len(entry_key):]
378 uid = k[len(entry_key):]
378 c.issuetracker_entries[uid] = None
379 c.issuetracker_entries[uid] = None
379
380
380 for uid in c.issuetracker_entries:
381 for uid in c.issuetracker_entries:
381 c.issuetracker_entries[uid] = AttributeDict({
382 c.issuetracker_entries[uid] = AttributeDict({
382 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
383 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
383 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
384 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
384 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
385 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
385 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
386 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
386 })
387 })
387
388
388 return render('admin/settings/settings.html')
389 return render('admin/settings/settings.html')
389
390
390 @HasPermissionAllDecorator('hg.admin')
391 @HasPermissionAllDecorator('hg.admin')
391 @auth.CSRFRequired()
392 @auth.CSRFRequired()
392 def settings_issuetracker_save(self):
393 def settings_issuetracker_save(self):
393 settings_model = IssueTrackerSettingsModel()
394 settings_model = IssueTrackerSettingsModel()
394
395
395 form = IssueTrackerPatternsForm()().to_python(request.POST)
396 form = IssueTrackerPatternsForm()().to_python(request.POST)
396 for uid in form['delete_patterns']:
397 for uid in form['delete_patterns']:
397 settings_model.delete_entries(uid)
398 settings_model.delete_entries(uid)
398
399
399 for pattern in form['patterns']:
400 for pattern in form['patterns']:
400 for setting, value, type_ in pattern:
401 for setting, value, type_ in pattern:
401 sett = settings_model.create_or_update_setting(
402 sett = settings_model.create_or_update_setting(
402 setting, value, type_)
403 setting, value, type_)
403 Session().add(sett)
404 Session().add(sett)
404
405
405 Session().commit()
406 Session().commit()
406
407
407 SettingsModel().invalidate_settings_cache()
408 SettingsModel().invalidate_settings_cache()
408 h.flash(_('Updated issue tracker entries'), category='success')
409 h.flash(_('Updated issue tracker entries'), category='success')
409 return redirect(url('admin_settings_issuetracker'))
410 return redirect(url('admin_settings_issuetracker'))
410
411
411 @HasPermissionAllDecorator('hg.admin')
412 @HasPermissionAllDecorator('hg.admin')
412 @auth.CSRFRequired()
413 @auth.CSRFRequired()
413 def settings_email_update(self):
414 def settings_email_update(self):
414 """POST /admin/settings/email: All items in the collection"""
415 """POST /admin/settings/email: All items in the collection"""
415 # url('admin_settings_email')
416 # url('admin_settings_email')
416 c.active = 'email'
417 c.active = 'email'
417
418
418 test_email = request.POST.get('test_email')
419 test_email = request.POST.get('test_email')
419
420
420 if not test_email:
421 if not test_email:
421 h.flash(_('Please enter email address'), category='error')
422 h.flash(_('Please enter email address'), category='error')
422 return redirect(url('admin_settings_email'))
423 return redirect(url('admin_settings_email'))
423
424
424 email_kwargs = {
425 email_kwargs = {
425 'date': datetime.datetime.now(),
426 'date': datetime.datetime.now(),
426 'user': c.rhodecode_user,
427 'user': c.rhodecode_user,
427 'rhodecode_version': c.rhodecode_version
428 'rhodecode_version': c.rhodecode_version
428 }
429 }
429
430
430 (subject, headers, email_body,
431 (subject, headers, email_body,
431 email_body_plaintext) = EmailNotificationModel().render_email(
432 email_body_plaintext) = EmailNotificationModel().render_email(
432 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
433 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
433
434
434 recipients = [test_email] if test_email else None
435 recipients = [test_email] if test_email else None
435
436
436 run_task(tasks.send_email, recipients, subject,
437 run_task(tasks.send_email, recipients, subject,
437 email_body_plaintext, email_body)
438 email_body_plaintext, email_body)
438
439
439 h.flash(_('Send email task created'), category='success')
440 h.flash(_('Send email task created'), category='success')
440 return redirect(url('admin_settings_email'))
441 return redirect(url('admin_settings_email'))
441
442
442 @HasPermissionAllDecorator('hg.admin')
443 @HasPermissionAllDecorator('hg.admin')
443 def settings_email(self):
444 def settings_email(self):
444 """GET /admin/settings/email: All items in the collection"""
445 """GET /admin/settings/email: All items in the collection"""
445 # url('admin_settings_email')
446 # url('admin_settings_email')
446 c.active = 'email'
447 c.active = 'email'
447 c.rhodecode_ini = rhodecode.CONFIG
448 c.rhodecode_ini = rhodecode.CONFIG
448
449
449 return htmlfill.render(
450 return htmlfill.render(
450 render('admin/settings/settings.html'),
451 render('admin/settings/settings.html'),
451 defaults=self._form_defaults(),
452 defaults=self._form_defaults(),
452 encoding="UTF-8",
453 encoding="UTF-8",
453 force_defaults=False)
454 force_defaults=False)
454
455
455 @HasPermissionAllDecorator('hg.admin')
456 @HasPermissionAllDecorator('hg.admin')
456 @auth.CSRFRequired()
457 @auth.CSRFRequired()
457 def settings_hooks_update(self):
458 def settings_hooks_update(self):
458 """POST or DELETE /admin/settings/hooks: All items in the collection"""
459 """POST or DELETE /admin/settings/hooks: All items in the collection"""
459 # url('admin_settings_hooks')
460 # url('admin_settings_hooks')
460 c.active = 'hooks'
461 c.active = 'hooks'
461 if c.visual.allow_custom_hooks_settings:
462 if c.visual.allow_custom_hooks_settings:
462 ui_key = request.POST.get('new_hook_ui_key')
463 ui_key = request.POST.get('new_hook_ui_key')
463 ui_value = request.POST.get('new_hook_ui_value')
464 ui_value = request.POST.get('new_hook_ui_value')
464
465
465 hook_id = request.POST.get('hook_id')
466 hook_id = request.POST.get('hook_id')
466 new_hook = False
467 new_hook = False
467
468
468 model = SettingsModel()
469 model = SettingsModel()
469 try:
470 try:
470 if ui_value and ui_key:
471 if ui_value and ui_key:
471 model.create_or_update_hook(ui_key, ui_value)
472 model.create_or_update_hook(ui_key, ui_value)
472 h.flash(_('Added new hook'), category='success')
473 h.flash(_('Added new hook'), category='success')
473 new_hook = True
474 new_hook = True
474 elif hook_id:
475 elif hook_id:
475 RhodeCodeUi.delete(hook_id)
476 RhodeCodeUi.delete(hook_id)
476 Session().commit()
477 Session().commit()
477
478
478 # check for edits
479 # check for edits
479 update = False
480 update = False
480 _d = request.POST.dict_of_lists()
481 _d = request.POST.dict_of_lists()
481 for k, v in zip(_d.get('hook_ui_key', []),
482 for k, v in zip(_d.get('hook_ui_key', []),
482 _d.get('hook_ui_value_new', [])):
483 _d.get('hook_ui_value_new', [])):
483 model.create_or_update_hook(k, v)
484 model.create_or_update_hook(k, v)
484 update = True
485 update = True
485
486
486 if update and not new_hook:
487 if update and not new_hook:
487 h.flash(_('Updated hooks'), category='success')
488 h.flash(_('Updated hooks'), category='success')
488 Session().commit()
489 Session().commit()
489 except Exception:
490 except Exception:
490 log.exception("Exception during hook creation")
491 log.exception("Exception during hook creation")
491 h.flash(_('Error occurred during hook creation'),
492 h.flash(_('Error occurred during hook creation'),
492 category='error')
493 category='error')
493
494
494 return redirect(url('admin_settings_hooks'))
495 return redirect(url('admin_settings_hooks'))
495
496
496 @HasPermissionAllDecorator('hg.admin')
497 @HasPermissionAllDecorator('hg.admin')
497 def settings_hooks(self):
498 def settings_hooks(self):
498 """GET /admin/settings/hooks: All items in the collection"""
499 """GET /admin/settings/hooks: All items in the collection"""
499 # url('admin_settings_hooks')
500 # url('admin_settings_hooks')
500 c.active = 'hooks'
501 c.active = 'hooks'
501
502
502 model = SettingsModel()
503 model = SettingsModel()
503 c.hooks = model.get_builtin_hooks()
504 c.hooks = model.get_builtin_hooks()
504 c.custom_hooks = model.get_custom_hooks()
505 c.custom_hooks = model.get_custom_hooks()
505
506
506 return htmlfill.render(
507 return htmlfill.render(
507 render('admin/settings/settings.html'),
508 render('admin/settings/settings.html'),
508 defaults=self._form_defaults(),
509 defaults=self._form_defaults(),
509 encoding="UTF-8",
510 encoding="UTF-8",
510 force_defaults=False)
511 force_defaults=False)
511
512
512 @HasPermissionAllDecorator('hg.admin')
513 @HasPermissionAllDecorator('hg.admin')
513 def settings_search(self):
514 def settings_search(self):
514 """GET /admin/settings/search: All items in the collection"""
515 """GET /admin/settings/search: All items in the collection"""
515 # url('admin_settings_search')
516 # url('admin_settings_search')
516 c.active = 'search'
517 c.active = 'search'
517
518
518 from rhodecode.lib.index import searcher_from_config
519 from rhodecode.lib.index import searcher_from_config
519 searcher = searcher_from_config(config)
520 searcher = searcher_from_config(config)
520 c.statistics = searcher.statistics()
521 c.statistics = searcher.statistics()
521
522
522 return render('admin/settings/settings.html')
523 return render('admin/settings/settings.html')
523
524
524 @HasPermissionAllDecorator('hg.admin')
525 @HasPermissionAllDecorator('hg.admin')
525 def settings_system(self):
526 def settings_system(self):
526 """GET /admin/settings/system: All items in the collection"""
527 """GET /admin/settings/system: All items in the collection"""
527 # url('admin_settings_system')
528 # url('admin_settings_system')
528 snapshot = str2bool(request.GET.get('snapshot'))
529 snapshot = str2bool(request.GET.get('snapshot'))
529 c.active = 'system'
530 c.active = 'system'
530
531
531 defaults = self._form_defaults()
532 defaults = self._form_defaults()
532 c.rhodecode_ini = rhodecode.CONFIG
533 c.rhodecode_ini = rhodecode.CONFIG
533 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
534 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
534 server_info = ScmModel().get_server_info(request.environ)
535 server_info = ScmModel().get_server_info(request.environ)
535 for key, val in server_info.iteritems():
536 for key, val in server_info.iteritems():
536 setattr(c, key, val)
537 setattr(c, key, val)
537
538
538 if c.disk['percent'] > 90:
539 if c.disk['percent'] > 90:
539 h.flash(h.literal(_(
540 h.flash(h.literal(_(
540 'Critical: your disk space is very low <b>%s%%</b> used' %
541 'Critical: your disk space is very low <b>%s%%</b> used' %
541 c.disk['percent'])), 'error')
542 c.disk['percent'])), 'error')
542 elif c.disk['percent'] > 70:
543 elif c.disk['percent'] > 70:
543 h.flash(h.literal(_(
544 h.flash(h.literal(_(
544 'Warning: your disk space is running low <b>%s%%</b> used' %
545 'Warning: your disk space is running low <b>%s%%</b> used' %
545 c.disk['percent'])), 'warning')
546 c.disk['percent'])), 'warning')
546
547
547 try:
548 try:
548 c.uptime_age = h._age(
549 c.uptime_age = h._age(
549 h.time_to_datetime(c.boot_time), False, show_suffix=False)
550 h.time_to_datetime(c.boot_time), False, show_suffix=False)
550 except TypeError:
551 except TypeError:
551 c.uptime_age = c.boot_time
552 c.uptime_age = c.boot_time
552
553
553 try:
554 try:
554 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
555 c.system_memory = '%s/%s, %s%% (%s%%) used%s' % (
555 h.format_byte_size_binary(c.memory['used']),
556 h.format_byte_size_binary(c.memory['used']),
556 h.format_byte_size_binary(c.memory['total']),
557 h.format_byte_size_binary(c.memory['total']),
557 c.memory['percent2'],
558 c.memory['percent2'],
558 c.memory['percent'],
559 c.memory['percent'],
559 ' %s' % c.memory['error'] if 'error' in c.memory else '')
560 ' %s' % c.memory['error'] if 'error' in c.memory else '')
560 except TypeError:
561 except TypeError:
561 c.system_memory = 'NOT AVAILABLE'
562 c.system_memory = 'NOT AVAILABLE'
562
563
563 rhodecode_ini_safe = rhodecode.CONFIG.copy()
564 rhodecode_ini_safe = rhodecode.CONFIG.copy()
564 blacklist = [
565 blacklist = [
565 'rhodecode_license_key',
566 'rhodecode_license_key',
566 'routes.map',
567 'routes.map',
567 'pylons.h',
568 'pylons.h',
568 'pylons.app_globals',
569 'pylons.app_globals',
569 'pylons.environ_config',
570 'pylons.environ_config',
570 'sqlalchemy.db1.url',
571 'sqlalchemy.db1.url',
571 ('app_conf', 'sqlalchemy.db1.url')
572 ('app_conf', 'sqlalchemy.db1.url')
572 ]
573 ]
573 for k in blacklist:
574 for k in blacklist:
574 if isinstance(k, tuple):
575 if isinstance(k, tuple):
575 section, key = k
576 section, key = k
576 if section in rhodecode_ini_safe:
577 if section in rhodecode_ini_safe:
577 rhodecode_ini_safe[section].pop(key, None)
578 rhodecode_ini_safe[section].pop(key, None)
578 else:
579 else:
579 rhodecode_ini_safe.pop(k, None)
580 rhodecode_ini_safe.pop(k, None)
580
581
581 c.rhodecode_ini_safe = rhodecode_ini_safe
582 c.rhodecode_ini_safe = rhodecode_ini_safe
582
583
583 # 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
584 c.allowed_to_snapshot = False
585 c.allowed_to_snapshot = False
585
586
586 if snapshot:
587 if snapshot:
587 if c.allowed_to_snapshot:
588 if c.allowed_to_snapshot:
588 return render('admin/settings/settings_system_snapshot.html')
589 return render('admin/settings/settings_system_snapshot.html')
589 else:
590 else:
590 h.flash('You are not allowed to do this', category='warning')
591 h.flash('You are not allowed to do this', category='warning')
591
592
592 return htmlfill.render(
593 return htmlfill.render(
593 render('admin/settings/settings.html'),
594 render('admin/settings/settings.html'),
594 defaults=defaults,
595 defaults=defaults,
595 encoding="UTF-8",
596 encoding="UTF-8",
596 force_defaults=False)
597 force_defaults=False)
597
598
598 @staticmethod
599 @staticmethod
599 def get_update_data(update_url):
600 def get_update_data(update_url):
600 """Return the JSON update data."""
601 """Return the JSON update data."""
601 ver = rhodecode.__version__
602 ver = rhodecode.__version__
602 log.debug('Checking for upgrade on `%s` server', update_url)
603 log.debug('Checking for upgrade on `%s` server', update_url)
603 opener = urllib2.build_opener()
604 opener = urllib2.build_opener()
604 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
605 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
605 response = opener.open(update_url)
606 response = opener.open(update_url)
606 response_data = response.read()
607 response_data = response.read()
607 data = json.loads(response_data)
608 data = json.loads(response_data)
608
609
609 return data
610 return data
610
611
611 @HasPermissionAllDecorator('hg.admin')
612 @HasPermissionAllDecorator('hg.admin')
612 def settings_system_update(self):
613 def settings_system_update(self):
613 """GET /admin/settings/system/updates: All items in the collection"""
614 """GET /admin/settings/system/updates: All items in the collection"""
614 # url('admin_settings_system_update')
615 # url('admin_settings_system_update')
615 defaults = self._form_defaults()
616 defaults = self._form_defaults()
616 update_url = defaults.get('rhodecode_update_url', '')
617 update_url = defaults.get('rhodecode_update_url', '')
617
618
618 _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)
619 try:
620 try:
620 data = self.get_update_data(update_url)
621 data = self.get_update_data(update_url)
621 except urllib2.URLError as e:
622 except urllib2.URLError as e:
622 log.exception("Exception contacting upgrade server")
623 log.exception("Exception contacting upgrade server")
623 return _err('Failed to contact upgrade server: %r' % e)
624 return _err('Failed to contact upgrade server: %r' % e)
624 except ValueError as e:
625 except ValueError as e:
625 log.exception("Bad data sent from update server")
626 log.exception("Bad data sent from update server")
626 return _err('Bad data sent from update server')
627 return _err('Bad data sent from update server')
627
628
628 latest = data['versions'][0]
629 latest = data['versions'][0]
629
630
630 c.update_url = update_url
631 c.update_url = update_url
631 c.latest_data = latest
632 c.latest_data = latest
632 c.latest_ver = latest['version']
633 c.latest_ver = latest['version']
633 c.cur_ver = rhodecode.__version__
634 c.cur_ver = rhodecode.__version__
634 c.should_upgrade = False
635 c.should_upgrade = False
635
636
636 if (packaging.version.Version(c.latest_ver) >
637 if (packaging.version.Version(c.latest_ver) >
637 packaging.version.Version(c.cur_ver)):
638 packaging.version.Version(c.cur_ver)):
638 c.should_upgrade = True
639 c.should_upgrade = True
639 c.important_notices = latest['general']
640 c.important_notices = latest['general']
640
641
641 return render('admin/settings/settings_system_update.html')
642 return render('admin/settings/settings_system_update.html')
642
643
643 @HasPermissionAllDecorator('hg.admin')
644 @HasPermissionAllDecorator('hg.admin')
644 def settings_supervisor(self):
645 def settings_supervisor(self):
645 c.rhodecode_ini = rhodecode.CONFIG
646 c.rhodecode_ini = rhodecode.CONFIG
646 c.active = 'supervisor'
647 c.active = 'supervisor'
647
648
648 c.supervisor_procs = OrderedDict([
649 c.supervisor_procs = OrderedDict([
649 (SUPERVISOR_MASTER, {}),
650 (SUPERVISOR_MASTER, {}),
650 ])
651 ])
651
652
652 c.log_size = 10240
653 c.log_size = 10240
653 supervisor = SupervisorModel()
654 supervisor = SupervisorModel()
654
655
655 _connection = supervisor.get_connection(
656 _connection = supervisor.get_connection(
656 c.rhodecode_ini.get('supervisor.uri'))
657 c.rhodecode_ini.get('supervisor.uri'))
657 c.connection_error = None
658 c.connection_error = None
658 try:
659 try:
659 _connection.supervisor.getAllProcessInfo()
660 _connection.supervisor.getAllProcessInfo()
660 except Exception as e:
661 except Exception as e:
661 c.connection_error = str(e)
662 c.connection_error = str(e)
662 log.exception("Exception reading supervisor data")
663 log.exception("Exception reading supervisor data")
663 return render('admin/settings/settings.html')
664 return render('admin/settings/settings.html')
664
665
665 groupid = c.rhodecode_ini.get('supervisor.group_id')
666 groupid = c.rhodecode_ini.get('supervisor.group_id')
666
667
667 # feed our group processes to the main
668 # feed our group processes to the main
668 for proc in supervisor.get_group_processes(_connection, groupid):
669 for proc in supervisor.get_group_processes(_connection, groupid):
669 c.supervisor_procs[proc['name']] = {}
670 c.supervisor_procs[proc['name']] = {}
670
671
671 for k in c.supervisor_procs.keys():
672 for k in c.supervisor_procs.keys():
672 try:
673 try:
673 # master process info
674 # master process info
674 if k == SUPERVISOR_MASTER:
675 if k == SUPERVISOR_MASTER:
675 _data = supervisor.get_master_state(_connection)
676 _data = supervisor.get_master_state(_connection)
676 _data['name'] = 'supervisor master'
677 _data['name'] = 'supervisor master'
677 _data['description'] = 'pid %s, id: %s, ver: %s' % (
678 _data['description'] = 'pid %s, id: %s, ver: %s' % (
678 _data['pid'], _data['id'], _data['ver'])
679 _data['pid'], _data['id'], _data['ver'])
679 c.supervisor_procs[k] = _data
680 c.supervisor_procs[k] = _data
680 else:
681 else:
681 procid = groupid + ":" + k
682 procid = groupid + ":" + k
682 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
683 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
683 except Exception as e:
684 except Exception as e:
684 log.exception("Exception reading supervisor data")
685 log.exception("Exception reading supervisor data")
685 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
686 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
686
687
687 return render('admin/settings/settings.html')
688 return render('admin/settings/settings.html')
688
689
689 @HasPermissionAllDecorator('hg.admin')
690 @HasPermissionAllDecorator('hg.admin')
690 def settings_supervisor_log(self, procid):
691 def settings_supervisor_log(self, procid):
691 import rhodecode
692 import rhodecode
692 c.rhodecode_ini = rhodecode.CONFIG
693 c.rhodecode_ini = rhodecode.CONFIG
693 c.active = 'supervisor_tail'
694 c.active = 'supervisor_tail'
694
695
695 supervisor = SupervisorModel()
696 supervisor = SupervisorModel()
696 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
697 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
697 groupid = c.rhodecode_ini.get('supervisor.group_id')
698 groupid = c.rhodecode_ini.get('supervisor.group_id')
698 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
699 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
699
700
700 c.log_size = 10240
701 c.log_size = 10240
701 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
702 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
703 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
703
704
704 return render('admin/settings/settings.html')
705 return render('admin/settings/settings.html')
705
706
706 @HasPermissionAllDecorator('hg.admin')
707 @HasPermissionAllDecorator('hg.admin')
707 @auth.CSRFRequired()
708 @auth.CSRFRequired()
708 def settings_labs_update(self):
709 def settings_labs_update(self):
709 """POST /admin/settings/labs: All items in the collection"""
710 """POST /admin/settings/labs: All items in the collection"""
710 # url('admin_settings/labs', method={'POST'})
711 # url('admin_settings/labs', method={'POST'})
711 c.active = 'labs'
712 c.active = 'labs'
712
713
713 application_form = LabsSettingsForm()()
714 application_form = LabsSettingsForm()()
714 try:
715 try:
715 form_result = application_form.to_python(dict(request.POST))
716 form_result = application_form.to_python(dict(request.POST))
716 except formencode.Invalid as errors:
717 except formencode.Invalid as errors:
717 h.flash(
718 h.flash(
718 _('Some form inputs contain invalid data.'),
719 _('Some form inputs contain invalid data.'),
719 category='error')
720 category='error')
720 return htmlfill.render(
721 return htmlfill.render(
721 render('admin/settings/settings.html'),
722 render('admin/settings/settings.html'),
722 defaults=errors.value,
723 defaults=errors.value,
723 errors=errors.error_dict or {},
724 errors=errors.error_dict or {},
724 prefix_error=False,
725 prefix_error=False,
725 encoding='UTF-8',
726 encoding='UTF-8',
726 force_defaults=False
727 force_defaults=False
727 )
728 )
728
729
729 try:
730 try:
730 session = Session()
731 session = Session()
731 for setting in _LAB_SETTINGS:
732 for setting in _LAB_SETTINGS:
732 setting_name = setting.key[len('rhodecode_'):]
733 setting_name = setting.key[len('rhodecode_'):]
733 sett = SettingsModel().create_or_update_setting(
734 sett = SettingsModel().create_or_update_setting(
734 setting_name, form_result[setting.key], setting.type)
735 setting_name, form_result[setting.key], setting.type)
735 session.add(sett)
736 session.add(sett)
736
737
737 except Exception:
738 except Exception:
738 log.exception('Exception while updating lab settings')
739 log.exception('Exception while updating lab settings')
739 h.flash(_('Error occurred during updating labs settings'),
740 h.flash(_('Error occurred during updating labs settings'),
740 category='error')
741 category='error')
741 else:
742 else:
742 Session().commit()
743 Session().commit()
743 SettingsModel().invalidate_settings_cache()
744 SettingsModel().invalidate_settings_cache()
744 h.flash(_('Updated Labs settings'), category='success')
745 h.flash(_('Updated Labs settings'), category='success')
745 return redirect(url('admin_settings_labs'))
746 return redirect(url('admin_settings_labs'))
746
747
747 return htmlfill.render(
748 return htmlfill.render(
748 render('admin/settings/settings.html'),
749 render('admin/settings/settings.html'),
749 defaults=self._form_defaults(),
750 defaults=self._form_defaults(),
750 encoding='UTF-8',
751 encoding='UTF-8',
751 force_defaults=False)
752 force_defaults=False)
752
753
753 @HasPermissionAllDecorator('hg.admin')
754 @HasPermissionAllDecorator('hg.admin')
754 def settings_labs(self):
755 def settings_labs(self):
755 """GET /admin/settings/labs: All items in the collection"""
756 """GET /admin/settings/labs: All items in the collection"""
756 # url('admin_settings_labs')
757 # url('admin_settings_labs')
757 if not c.labs_active:
758 if not c.labs_active:
758 redirect(url('admin_settings'))
759 redirect(url('admin_settings'))
759
760
760 c.active = 'labs'
761 c.active = 'labs'
761 c.lab_settings = _LAB_SETTINGS
762 c.lab_settings = _LAB_SETTINGS
762
763
763 return htmlfill.render(
764 return htmlfill.render(
764 render('admin/settings/settings.html'),
765 render('admin/settings/settings.html'),
765 defaults=self._form_defaults(),
766 defaults=self._form_defaults(),
766 encoding='UTF-8',
767 encoding='UTF-8',
767 force_defaults=False)
768 force_defaults=False)
768
769
769 def _form_defaults(self):
770 def _form_defaults(self):
770 defaults = SettingsModel().get_all_settings()
771 defaults = SettingsModel().get_all_settings()
771 defaults.update(self._get_hg_ui_settings())
772 defaults.update(self._get_hg_ui_settings())
772 defaults.update({
773 defaults.update({
773 'new_svn_branch': '',
774 'new_svn_branch': '',
774 'new_svn_tag': '',
775 'new_svn_tag': '',
775 })
776 })
776 return defaults
777 return defaults
777
778
778
779
779 # :param key: name of the setting including the 'rhodecode_' prefix
780 # :param key: name of the setting including the 'rhodecode_' prefix
780 # :param type: the RhodeCodeSetting type to use.
781 # :param type: the RhodeCodeSetting type to use.
781 # :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
782 # :param label: the i18ned label we should display for this setting
783 # :param label: the i18ned label we should display for this setting
783 # :param help: the i18ned help we should dispaly for this setting
784 # :param help: the i18ned help we should dispaly for this setting
784 LabSetting = collections.namedtuple(
785 LabSetting = collections.namedtuple(
785 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
786 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
786
787
787
788
788 # This list has to be kept in sync with the form
789 # This list has to be kept in sync with the form
789 # rhodecode.model.forms.LabsSettingsForm.
790 # rhodecode.model.forms.LabsSettingsForm.
790 _LAB_SETTINGS = [
791 _LAB_SETTINGS = [
791 LabSetting(
792 LabSetting(
792 key='rhodecode_hg_use_rebase_for_merging',
793 key='rhodecode_hg_use_rebase_for_merging',
793 type='bool',
794 type='bool',
794 group=lazy_ugettext('Mercurial server-side merge'),
795 group=lazy_ugettext('Mercurial server-side merge'),
795 label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'),
796 label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'),
796 help='' # Do not translate the empty string!
797 help='' # Do not translate the empty string!
797 ),
798 ),
798 LabSetting(
799 LabSetting(
799 key='rhodecode_proxy_subversion_http_requests',
800 key='rhodecode_proxy_subversion_http_requests',
800 type='bool',
801 type='bool',
801 group=lazy_ugettext('Subversion HTTP Support'),
802 group=lazy_ugettext('Subversion HTTP Support'),
802 label=lazy_ugettext('Proxy subversion HTTP requests'),
803 label=lazy_ugettext('Proxy subversion HTTP requests'),
803 help='' # Do not translate the empty string!
804 help='' # Do not translate the empty string!
804 ),
805 ),
805 LabSetting(
806 LabSetting(
806 key='rhodecode_subversion_http_server_url',
807 key='rhodecode_subversion_http_server_url',
807 type='str',
808 type='str',
808 group=lazy_ugettext('Subversion HTTP Server URL'),
809 group=lazy_ugettext('Subversion HTTP Server URL'),
809 label='', # Do not translate the empty string!
810 label='', # Do not translate the empty string!
810 help=lazy_ugettext('e.g. http://localhost:8080/')
811 help=lazy_ugettext('e.g. http://localhost:8080/')
811 ),
812 ),
812 ]
813 ]
813
814
815 NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url'])
816
817
818 class NavEntry(object):
819
820 def __init__(self, key, name, view_name, pyramid=False):
821 self.key = key
822 self.name = name
823 self.view_name = view_name
824 self.pyramid = pyramid
825
826 def generate_url(self, request):
827 if self.pyramid:
828 if hasattr(request, 'route_path'):
829 return request.route_path(self.view_name)
830 else:
831 # TODO: johbo: Remove this after migrating to pyramid.
832 # We need the pyramid request here to generate URLs to pyramid
833 # views from within pylons views.
834 from pyramid.threadlocal import get_current_request
835 pyramid_request = get_current_request()
836 return pyramid_request.route_path(self.view_name)
837 else:
838 return url(self.view_name)
839
840
841 class NavigationRegistry(object):
842
843 _base_entries = [
844 NavEntry('global', lazy_ugettext('Global'), 'admin_settings_global'),
845 NavEntry('vcs', lazy_ugettext('VCS'), 'admin_settings_vcs'),
846 NavEntry('visual', lazy_ugettext('Visual'), 'admin_settings_visual'),
847 NavEntry('mapping', lazy_ugettext('Remap and Rescan'),
848 'admin_settings_mapping'),
849 NavEntry('issuetracker', lazy_ugettext('Issue Tracker'),
850 'admin_settings_issuetracker'),
851 NavEntry('email', lazy_ugettext('Email'), 'admin_settings_email'),
852 NavEntry('hooks', lazy_ugettext('Hooks'), 'admin_settings_hooks'),
853 NavEntry('search', lazy_ugettext('Full Text Search'),
854 'admin_settings_search'),
855 NavEntry('system', lazy_ugettext('System Info'),
856 'admin_settings_system'),
857 NavEntry('open_source', lazy_ugettext('Open Source Licenses'),
858 'admin_settings_open_source', pyramid=True),
859 # TODO: marcink: we disable supervisor now until the supervisor stats
860 # page is fixed in the nix configuration
861 # NavEntry('supervisor', lazy_ugettext('Supervisor'),
862 # 'admin_settings_supervisor'),
863 ]
864
865 def __init__(self):
866 self._registered_entries = collections.OrderedDict([
867 (item.key, item) for item in self.__class__._base_entries
868 ])
869
870 # Add the labs entry when it's activated.
871 labs_active = str2bool(
872 rhodecode.CONFIG.get('labs_settings_active', 'false'))
873 if labs_active:
874 self.add_entry(
875 NavEntry('labs', lazy_ugettext('Labs'), 'admin_settings_labs'))
876
877 def add_entry(self, entry):
878 self._registered_entries[entry.key] = entry
879
880 def get_navlist(self, request):
881 navlist = [NavListEntry(i.key, i.name, i.generate_url(request))
882 for i in self._registered_entries.values()]
883 return navlist
884
885 navigation = NavigationRegistry()
General Comments 0
You need to be logged in to leave comments. Login now