# # This file is part of Plinth. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # """ Plinth module for configuring PageKite service """ from django import forms from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core import validators from django.core.urlresolvers import reverse_lazy from django.template.response import TemplateResponse from gettext import gettext as _ import logging from plinth import actions from plinth import cfg from plinth import package LOGGER = logging.getLogger(__name__) subsubmenu = [{'url': reverse_lazy('pagekite:index'), 'text': _('About PageKite')}, {'url': reverse_lazy('pagekite:configure'), 'text': _('Configure PageKite')}] def init(): """Intialize the PageKite module""" menu = cfg.main_menu.get('apps:index') menu.add_urlname(_('Public Visibility (PageKite)'), 'glyphicon-flag', 'pagekite:index', 50) @login_required def index(request): """Serve introduction page""" return TemplateResponse(request, 'pagekite_introduction.html', {'title': _('Public Visibility (PageKite)'), 'subsubmenu': subsubmenu}) 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 ConfigureForm(forms.Form): # pylint: disable-msg=W0232 """Form to configure PageKite""" enabled = forms.BooleanField(label=_('Enable PageKite'), required=False) server = forms.CharField( label=_('Server'), required=False, help_text=_('Currently only pagekite.net server is supported'), widget=forms.TextInput(attrs={'placeholder': 'pagekite.net', 'disabled': 'disabled'})) kite_name = TrimmedCharField( label=_('Kite name'), help_text=_('Example: mybox1-myacc.pagekite.me'), validators=[ validators.RegexValidator(r'^[\w-]{1,63}(\.[\w-]{1,63})*$', _('Invalid kite name'))]) kite_secret = TrimmedCharField( label=_('Kite secret'), help_text=_('A secret associated with the kite or the default secret \ for your account if no secret is set on the kite')) http_enabled = forms.BooleanField( label=_('Web Server (HTTP)'), required=False, help_text=_('Site will be available at \ http://mybox1-myacc.pagekite.me \ ')) ssh_enabled = forms.BooleanField( label=_('Secure Shell (SSH)'), required=False, help_text=_('See SSH client setup instructions')) @login_required @package.required('pagekite') def configure(request): """Serve the configuration form""" status = get_status() form = None if request.method == 'POST': form = ConfigureForm(request.POST, prefix='pagekite') # pylint: disable-msg=E1101 if form.is_valid(): _apply_changes(request, status, form.cleaned_data) status = get_status() form = ConfigureForm(initial=status, prefix='pagekite') else: form = ConfigureForm(initial=status, prefix='pagekite') return TemplateResponse(request, 'pagekite_configure.html', {'title': _('Configure PageKite'), 'status': status, 'form': form, 'subsubmenu': subsubmenu}) def get_status(): """ Return the current status of PageKite configuration by executing various actions. """ status = {} # PageKite service enabled/disabled output = _run(['get-status']) status['enabled'] = (output.split()[0] == 'enabled') # PageKite kite details output = _run(['get-kite']) kite_details = output.split() status['kite_name'] = kite_details[0] status['kite_secret'] = kite_details[1] # Service status status['service'] = {} for service in ('http', 'ssh'): output = _run(['get-service-status', service]) status[service + '_enabled'] = (output.split()[0] == 'enabled') return status def _apply_changes(request, old_status, new_status): """Apply the changes to PageKite configuration""" LOGGER.info('New status is - %s', new_status) if old_status != new_status: _run(['stop']) if old_status['enabled'] != new_status['enabled']: if new_status['enabled']: _run(['set-status', 'enable']) messages.success(request, _('PageKite enabled')) else: _run(['set-status', 'disable']) messages.success(request, _('PageKite disabled')) if old_status['kite_name'] != new_status['kite_name'] or \ old_status['kite_secret'] != new_status['kite_secret']: _run(['set-kite', '--kite-name', new_status['kite_name'], '--kite-secret', new_status['kite_secret']]) messages.success(request, _('Kite details set')) for service in ['http', 'ssh']: if old_status[service + '_enabled'] != \ new_status[service + '_enabled']: if new_status[service + '_enabled']: _run(['set-service-status', service, 'enable']) messages.success(request, _('Service enabled: {service}') .format(service=service)) else: _run(['set-service-status', service, 'disable']) messages.success(request, _('Service disabled: {service}') .format(service=service)) if old_status != new_status: _run(['start']) def _run(arguments, superuser=True): """Run a given command and raise exception if there was an error""" command = 'pagekite-configure' if superuser: return actions.superuser_run(command, arguments) else: return actions.run(command, arguments)