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