From 6ebfe23c4bf3867651985549e8201933fcc2d14e Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 11 May 2014 16:26:52 +0530 Subject: [PATCH] Convert config page to Django form --- modules/installed/system/config.py | 207 ++++++++---------- .../installed/system/templates/config.html | 28 +++ 2 files changed, 122 insertions(+), 113 deletions(-) create mode 100644 modules/installed/system/templates/config.html diff --git a/modules/installed/system/config.py b/modules/installed/system/config.py index 588a705ce..1985a7afd 100644 --- a/modules/installed/system/config.py +++ b/modules/installed/system/config.py @@ -20,6 +20,8 @@ Plinth module for configuring timezone, hostname etc. """ import cherrypy +from django import forms +from django.core import validators from gettext import gettext as _ try: import simplejson as json @@ -30,61 +32,119 @@ import socket import actions import cfg -from forms import Form from modules.auth import require -from plugin_mount import PagePlugin, FormPlugin +from plugin_mount import PagePlugin import util -class Config(PagePlugin): +class TrimmedCharField(forms.CharField): + """Trim the contents of a CharField""" + def clean(self, value): + """Clean and validate the field value""" + if value: + value = value.strip() + + return super(TrimmedCharField, self).clean(value) + + +class ConfigurationForm(forms.Form): + """Main system configuration form""" + time_zone = forms.ChoiceField( + label=_('Time Zone'), + help_text=_('Set your timezone to get accurate timestamps. \ +This information will be used to set your systemwide timezone')) + + # We're more conservative than RFC 952 and RFC 1123 + hostname = TrimmedCharField( + label=_('Hostname'), + help_text=_('Your hostname is the local name by which other machines \ +on your LAN can reach you. It must be alphanumeric, start with an alphabet \ +and must not be greater than 63 characters in length.'), + validators=[ + validators.RegexValidator(r'^[a-zA-Z][a-zA-Z0-9]{,62}$', + _('Invalid hostname'))]) + + def __init__(self, *args, **kwargs): + # pylint: disable-msg=E1101, W0233 + forms.Form.__init__(self, *args, **kwargs) + + self.fields['time_zone'].choices = [(zone, zone) + for zone in self.get_time_zones()] + + @staticmethod + def get_time_zones(): + """Return list of available time zones""" + # XXX: Get rid of a custom file and read the values from /usr + module_file = __file__ + if module_file.endswith(".pyc"): + module_file = module_file[:-1] + + module_dir = os.path.dirname(os.path.realpath(module_file)) + time_zones_file = os.path.join(module_dir, 'time_zones') + return json.loads(util.slurp(time_zones_file)) + + +class Configuration(PagePlugin): """System configuration page""" def __init__(self, *args, **kwargs): del args # Unused del kwargs # Unused - self.register_page("sys.config") + self.register_page('sys.config') self.menu = cfg.html_root.sys.menu.add_item(_('Configure'), 'icon-cog', '/sys/config', 10) @cherrypy.expose @require() - def index(self): - """Serve configuration page""" - parts = self.forms('/sys/config') - parts['title'] = _("Configure this {box_name}") \ - .format(box_name=cfg.box_name) + def index(self, **kwargs): + """Serve the configuration form""" + status = self.get_status() - return util.render_template(**parts) # pylint: disable-msg=W0142 + form = None + messages = [] + if kwargs and cfg.users.expert(): + form = ConfigurationForm(kwargs, prefix='configuration') + # pylint: disable-msg=E1101 + if form.is_valid(): + self._apply_changes(status, form.cleaned_data, messages) + status = self.get_status() + form = ConfigurationForm(initial=status, + prefix='configuration') + else: + form = ConfigurationForm(initial=status, prefix='configuration') -def valid_hostname(name): - """ - Return '' if name is a valid hostname by our standards (not just - by RFC 952 and RFC 1123. We're more conservative than the - standard. If hostname isn't valid, return message explaining why. - """ - message = '' - if len(name) > 63: - message += "
Hostname too long (max is 63 characters)" + return util.render_template(template='config', + title=_('General Configuration'), + form=form, messages=messages) - if not util.is_alphanumeric(name): - message += "
Hostname must be alphanumeric" + @staticmethod + def get_status(): + """Return the current status""" + return {'hostname': socket.gethostname(), + 'time_zone': util.slurp('/etc/timezone').rstrip()} - if not name[0] in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ": - message += "
Hostname must start with a letter" + @staticmethod + def _apply_changes(old_status, new_status, messages): + """Apply the form changes""" + if old_status['hostname'] != new_status['hostname']: + set_hostname(new_status['hostname']) + messages.append(('success', _('Hostname set'))) + else: + messages.append(('info', _('Hostname is unchanged'))) - return message - - -def get_hostname(): - """Return the current hostname of the system""" - return socket.gethostname() - - -def get_time_zone(): - """Return currently set system's timezone""" - return util.slurp('/etc/timezone').rstrip() + if old_status['time_zone'] != new_status['time_zone']: + output, error = actions.superuser_run('timezone-change', + [new_status['time_zone']]) + del output # Unused + if error: + messages.append(('error', + _('Error setting time zone - %s') % error)) + else: + messages.append(('success', _('Time zone set'))) + else: + messages.append(('info', _('Time zone is unchanged'))) def set_hostname(hostname): @@ -104,82 +164,3 @@ def set_hostname(hostname): except OSError as exception: raise cherrypy.HTTPError(500, 'Updating hostname failed: %s' % exception) - -class general(FormPlugin, PagePlugin): - """Form to update hostname and time zone""" - url = ["/sys/config"] - order = 30 - - @staticmethod - def help(*args, **kwargs): - """Build and return the help content area""" - del args # Unused - del kwargs # Unused - - return _(''' -

Set your timezone to get accurate timestamps. {product} will use -this information to set your {box}'s systemwide timezone.

''').format( - product=cfg.product_name, box=cfg.box_name) - - def main(self, message='', time_zone=None, **kwargs): - """Build and return the main content area which is the form""" - del kwargs # Unused - - if not cfg.users.expert(): - return _(''' -

Only members of the expert group are allowed to see and modify the system -setup.

''') - - if not time_zone: - time_zone = get_time_zone() - - # Get the list of supported timezones and the index in that - # list of the current one - module_file = __file__ - if module_file.endswith(".pyc"): - module_file = module_file[:-1] - module_dir = os.path.dirname(os.path.realpath(module_file)) - time_zones_file = os.path.join(module_dir, 'time_zones') - time_zones = json.loads(util.slurp(time_zones_file)) - try: - time_zone_id = time_zones.index(time_zone) - except ValueError: - cfg.log.critical("Unknown Time Zone: %s" % time_zone) - raise cherrypy.HTTPError(500, "Unknown Time Zone: %s" % time_zone) - - # And now, the form. - form = Form(title=_("General Config"), - action=cfg.server_dir + "/sys/config/general/index", - name="config_general_form", - message=message) - form.html(self.help()) - form.dropdown(_("Time Zone"), name="time_zone", vals=time_zones, - select=time_zone_id) - form.html(''' -

Your hostname is the local name by which other machines on your LAN -can reach you.

''') - form.text_input('Hostname', name='hostname', value=get_hostname()) - form.submit(_("Submit")) - - return form.render() - - @staticmethod - def process_form(time_zone='', hostname='', *args, **kwargs): - """Handle form submission""" - del args # Unused - del kwargs # Unused - - message = '' - if hostname != get_hostname(): - msg = valid_hostname(hostname) - if msg == '': - set_hostname(hostname) - else: - message += msg - - time_zone = time_zone.strip() - if time_zone != get_time_zone(): - cfg.log.info("Setting timezone to %s" % time_zone) - actions.superuser_run("timezone-change", [time_zone]) - - return message or "Settings updated." diff --git a/modules/installed/system/templates/config.html b/modules/installed/system/templates/config.html new file mode 100644 index 000000000..89f766784 --- /dev/null +++ b/modules/installed/system/templates/config.html @@ -0,0 +1,28 @@ +{% extends "login_nav.html" %} +{% load bootstrap %} + +{% block main_block %} + +{% if cfg.users.expert %} + + {% for severity, message in messages %} +
{{ message }}
+ {% endfor %} + +
+ {% csrf_token %} + + {{ form|bootstrap }} + + + +
+ +{% else %} + +

Only members of the expert group are allowed to see and modify + the system setup.

+ +{% endif %} + +{% endblock %}