diff --git a/plinth/modules/first_boot/__init__.py b/plinth/modules/first_boot/__init__.py
index 508feb26b..77e6948df 100644
--- a/plinth/modules/first_boot/__init__.py
+++ b/plinth/modules/first_boot/__init__.py
@@ -22,12 +22,16 @@ Plinth module for first boot wizard
version = 1
is_essential = True
-first_boot_steps = [{'id': 'firstboot_state0',
- 'url': 'first_boot:state0',
- 'order': 0
- },
- {'id': 'firstboot_state10',
- 'url': 'first_boot:state10',
- 'order': 10
- }
- ]
+
+first_boot_steps = [
+ {
+ 'id': 'firstboot_state0',
+ 'url': 'first_boot:state0',
+ 'order': 0
+ },
+ {
+ 'id': 'firstboot_state10',
+ 'url': 'first_boot:state10',
+ 'order': 10
+ }
+]
diff --git a/plinth/modules/first_boot/forms.py b/plinth/modules/first_boot/forms.py
deleted file mode 100644
index 457f866a9..000000000
--- a/plinth/modules/first_boot/forms.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#
-# 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 .
-#
-
-"""
-Forms for first boot module.
-"""
-
-import json
-import logging
-import requests
-
-from django import forms
-from django.contrib import auth
-from django.contrib import messages
-from django.core.exceptions import ValidationError
-from django.utils.translation import ugettext as _, ugettext_lazy
-
-from plinth import actions
-from plinth import cfg
-from plinth.errors import ActionError, DomainRegistrationError
-from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
-from plinth.modules.security import set_restricted_access
-from plinth.modules.users.forms import GROUP_CHOICES, ValidNewUsernameCheckMixin
-from plinth.utils import format_lazy
-
-logger = logging.getLogger(__name__)
-
-
-class State1Form(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm):
- """Firstboot state 1: create a new user."""
-
- def __init__(self, *args, **kwargs):
- self.request = kwargs.pop('request')
- super().__init__(*args, **kwargs)
-
- def save(self, commit=True):
- """Create and log the user in."""
- user = super().save(commit=commit)
- if commit:
- try:
- actions.superuser_run(
- 'ldap',
- ['create-user', user.get_username()],
- input=self.cleaned_data['password1'].encode())
- except ActionError:
- messages.error(self.request,
- _('Creating LDAP user failed.'))
-
- try:
- actions.superuser_run(
- 'ldap',
- ['add-user-to-group', user.get_username(), 'admin'])
- except ActionError:
- messages.error(self.request,
- _('Failed to add new user to admin group.'))
-
- # Create initial Django groups
- for group_choice in GROUP_CHOICES:
- auth.models.Group.objects.get_or_create(name=group_choice[0])
-
- admin_group = auth.models.Group.objects.get(name='admin')
- admin_group.user_set.add(user)
-
- self.login_user(self.cleaned_data['username'],
- self.cleaned_data['password1'])
-
- # Restrict console login to users in admin or sudo group
- try:
- set_restricted_access(True)
- message = _('Console login access restricted to users in '
- '"admin" group. This can be configured in '
- 'security settings.')
- messages.success(self.request, message)
- except Exception:
- messages.error(self.request,
- _('Failed to restrict console access.'))
-
- return user
-
- def login_user(self, username, password):
- """Try to login the user with the credentials provided"""
- try:
- user = auth.authenticate(username=username, password=password)
- auth.login(self.request, user)
- except Exception:
- pass
- else:
- message = _('User account created, you are now logged in')
- messages.success(self.request, message)
-
-
-class State5Form(forms.Form):
- """Set up freedombox.me pagekite subdomain"""
- DOMAIN_APPENDIX = '.freedombox.me'
- # Webservice url for domain validation and registration
- service_url = 'http://freedombox.me/cgi-bin/freedomkite.pl'
-
- code_help_text = format_lazy(
- ugettext_lazy('The voucher you received with your {box_name} Danube '
- 'Edition'), box_name=ugettext_lazy(cfg.box_name))
-
- code = forms.CharField(help_text=code_help_text)
-
- domain = forms.SlugField(label=_('Subdomain'),
- widget=SubdomainWidget(domain=DOMAIN_APPENDIX),
- help_text=_('The subdomain you want to register'))
-
- def clean_domain(self):
- """Append the domain to the users' subdomain"""
- return self.cleaned_data['domain'] + self.DOMAIN_APPENDIX
-
- def clean(self):
- """Validate user input (subdomain and code)"""
- cleaned_data = super().clean()
-
- # If the subdomain is wrong, don't look if the domain is
- # available
- if self.errors:
- return cleaned_data
-
- self.domain_already_registered = False
- code = cleaned_data.get('code')
- domain = cleaned_data.get('domain')
-
- response = requests.get(self.service_url, params={'code': code}).json()
-
- # 1. Code is invalid: {}
- if 'domain' not in response:
- raise ValidationError(_('This code is not valid'), code='invalid')
- # 2. Code is valid, domain registered: {'domain': 'xx.freedombox.me'}
- elif response['domain']:
- if response['domain'] == domain:
- self.domain_already_registered = True
- else:
- message = _('This code is bound to the domain {domain}.') \
- .format(domain=response['domain'])
- raise ValidationError(message, code='invalid')
- # 3. Code is valid, no domain registered: {'domain': None}
- elif response['domain'] is None:
- # Make sure that the desired domain is available
- data = {'domain': domain}
- domain_response = requests.get(self.service_url, params=data)
- registered_domain = domain_response.json()['domain']
- if registered_domain is not None:
- message = _('The requested domain is already registered.')
- raise ValidationError(message, code='invalid')
-
- return cleaned_data
-
- def register_domain(self):
- """Register a domain (only if it's not already registered)"""
- if self.domain_already_registered:
- return
-
- data = {'domain': self.cleaned_data['domain'],
- 'code': self.cleaned_data['code']}
- response = requests.post(self.service_url, data)
- if not response.ok:
- message = _('Domain registration failed: {response}.').format(
- response=response.text)
- logger.error(message)
- raise DomainRegistrationError(message)
-
- def setup_pagekite(self):
- """Configure and enable PageKite service."""
- # Set kite name and secret
- run(['set-kite', '--kite-name', self.cleaned_data['domain']],
- input=self.cleaned_data['code'].encode())
-
- # Set frontend
- run(['set-frontend', '%s:80' % self.cleaned_data['domain']])
-
- # Enable PageKite HTTP + HTTPS service
- for service_name in ['http', 'https']:
- service = PREDEFINED_SERVICES[service_name]['params']
- try:
- run(['add-service', '--service', json.dumps(service)])
- except ActionError as err:
- if 'already exists' not in str(err):
- raise
-
- run(['start-and-enable'])
diff --git a/plinth/modules/first_boot/middleware.py b/plinth/modules/first_boot/middleware.py
index 99b25d9dd..d56a9579a 100644
--- a/plinth/modules/first_boot/middleware.py
+++ b/plinth/modules/first_boot/middleware.py
@@ -43,8 +43,10 @@ class FirstBootMiddleware(object):
if state == 0 and old_state == 10:
state = 1
kvstore.set('setup_state', 1)
+
user_requests_firstboot = is_firstboot(request.path)
- user_requests_login = request.path.startswith(reverse(settings.LOGIN_URL))
+ user_requests_login = request.path.startswith(
+ reverse(settings.LOGIN_URL))
help_index_url = reverse('help:index')
user_requests_help = request.path.startswith(help_index_url)
if not user_requests_login and not user_requests_help:
@@ -65,6 +67,7 @@ def is_firstboot(path):
for step in steps:
if reverse(step.get('url')) == path:
return True
+
return False
@@ -76,6 +79,7 @@ def get_firstboot_steps():
if getattr(module_object, 'first_boot_steps', None):
for step in module_object.first_boot_steps:
steps.append(step)
+
steps = sorted(steps, key=itemgetter('order'))
return steps
@@ -85,6 +89,7 @@ def next_step():
global firstboot_steps
if len(firstboot_steps) == 0:
firstboot_steps = get_firstboot_steps()
+
for step in firstboot_steps:
done = kvstore.get_default(step.get('id'), 0)
if done == 0:
@@ -100,11 +105,13 @@ def mark_step_done(id):
global firstboot_steps
if len(firstboot_steps) == 0:
firstboot_steps = get_firstboot_steps()
+
setup_done = True
for step in firstboot_steps:
done = kvstore.get_default(step.get('id'), 0)
if done == 0:
setup_done = False
break
+
if setup_done:
kvstore.set('setup_state', 1)
diff --git a/plinth/modules/first_boot/views.py b/plinth/modules/first_boot/views.py
index 0d9299350..37546127a 100644
--- a/plinth/modules/first_boot/views.py
+++ b/plinth/modules/first_boot/views.py
@@ -18,7 +18,7 @@
from django.contrib.auth.models import User
from django.shortcuts import render
from django.utils.translation import ugettext as _
-from django.views.generic import CreateView, FormView, TemplateView
+from django.views.generic import TemplateView
from plinth import network
from .middleware import mark_step_done, next_step
@@ -29,7 +29,7 @@ class State0View(TemplateView):
template_name = 'firstboot_state0.html'
def get_context_data(self, **kwargs):
- """Returns the context data"""
+ """Returns the context data for the template."""
context = super(State0View, self).get_context_data(**kwargs)
mark_step_done('firstboot_state0')
context['next_url'] = next_step()
diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py
index 048b0e5d8..719c00c5e 100644
--- a/plinth/modules/pagekite/__init__.py
+++ b/plinth/modules/pagekite/__init__.py
@@ -31,11 +31,13 @@ depends = ['system', 'names']
managed_packages = ['pagekite']
-first_boot_steps = [{'id': 'pagekite_firstboot',
- 'url': 'pagekite:firstboot',
- 'order': 5,
- },
- ]
+first_boot_steps = [
+ {
+ 'id': 'pagekite_firstboot',
+ 'url': 'pagekite:firstboot',
+ 'order': 5,
+ },
+]
title = _('Public Visibility (PageKite)')
diff --git a/plinth/modules/pagekite/forms.py b/plinth/modules/pagekite/forms.py
index 81ef9ae47..b41266bac 100644
--- a/plinth/modules/pagekite/forms.py
+++ b/plinth/modules/pagekite/forms.py
@@ -25,13 +25,12 @@ from django.utils.translation import ugettext as _, ugettext_lazy
import json
import logging
+from . import utils
from plinth import cfg
from plinth.errors import ActionError, DomainRegistrationError
from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
from plinth.utils import format_lazy
-from . import utils
-
LOGGER = logging.getLogger(__name__)
@@ -71,9 +70,9 @@ class ConfigurationForm(forms.Form):
server_domain = forms.CharField(
label=ugettext_lazy('Server domain'), required=False,
- help_text= \
- ugettext_lazy('Select your pagekite server. Set "pagekite.net" to use '
- 'the default pagekite.net server.'),
+ help_text=ugettext_lazy(
+ 'Select your pagekite server. Set "pagekite.net" to use '
+ 'the default pagekite.net server.'),
widget=forms.TextInput())
server_port = forms.IntegerField(
label=ugettext_lazy('Server port'), required=False,
@@ -87,9 +86,9 @@ class ConfigurationForm(forms.Form):
kite_secret = TrimmedCharField(
label=ugettext_lazy('Kite secret'),
- help_text= \
- ugettext_lazy('A secret associated with the kite or the default secret '
- 'for your account if no secret is set on the kite.'))
+ help_text=ugettext_lazy(
+ 'A secret associated with the kite or the default secret '
+ 'for your account if no secret is set on the kite.'))
def save(self, request):
"""Save the form on submission after validation."""
@@ -101,14 +100,14 @@ class ConfigurationForm(forms.Form):
config_changed = False
if old['kite_name'] != new['kite_name'] or \
- old['kite_secret'] != new['kite_secret']:
+ old['kite_secret'] != new['kite_secret']:
utils.run(['set-kite', '--kite-name', new['kite_name']],
input=new['kite_secret'].encode())
messages.success(request, _('Kite details set'))
config_changed = True
if old['server_domain'] != new['server_domain'] or \
- old['server_port'] != new['server_port']:
+ old['server_port'] != new['server_port']:
server = "%s:%s" % (new['server_domain'], new['server_port'])
utils.run(['set-frontend', server])
messages.success(request, _('Pagekite server set'))
@@ -208,6 +207,8 @@ class BaseCustomServiceForm(forms.Form):
class DeleteCustomServiceForm(BaseCustomServiceForm):
+ """Form to remove custom service."""
+
def delete(self, request):
service = self.convert_formdata_to_service(self.cleaned_data)
utils.run(['remove-service', '--service', json.dumps(service)])
diff --git a/plinth/modules/pagekite/views.py b/plinth/modules/pagekite/views.py
index 3746ead85..41621af26 100644
--- a/plinth/modules/pagekite/views.py
+++ b/plinth/modules/pagekite/views.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
+
from django.contrib import messages
from django.http.response import HttpResponseRedirect
from django.template.response import TemplateResponse
@@ -21,11 +22,11 @@ from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.views.generic import View, TemplateView
from django.views.generic.edit import FormView
-from plinth.errors import DomainRegistrationError
from . import utils
from .forms import ConfigurationForm, StandardServiceForm, \
AddCustomServiceForm, DeleteCustomServiceForm, State5Form
+from plinth.errors import DomainRegistrationError
from plinth.modules import pagekite
from plinth.modules.first_boot.middleware import mark_step_done
diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py
index cad4201b5..bec3acd39 100644
--- a/plinth/modules/users/__init__.py
+++ b/plinth/modules/users/__init__.py
@@ -34,11 +34,15 @@ depends = ['system']
managed_packages = ['ldapscripts', 'ldap-utils', 'libnss-ldapd',
'libpam-ldapd', 'nslcd', 'slapd']
-first_boot_steps = [{'id': 'users_firstboot',
- 'url': 'users:firstboot',
- 'order': 1
- },
- ]
+
+first_boot_steps = [
+ {
+ 'id': 'users_firstboot',
+ 'url': 'users:firstboot',
+ 'order': 1
+ },
+]
+
title = _('Users and Groups')
@@ -80,4 +84,4 @@ def _diagnose_ldap_entry(search_item):
pass
return [_('Check LDAP entry "{search_item}"')
- .format(search_item=search_item), result]
+ .format(search_item=search_item), result]
diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py
index 1ff3e72dd..b6b62bcf9 100644
--- a/plinth/modules/users/forms.py
+++ b/plinth/modules/users/forms.py
@@ -27,11 +27,9 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from plinth import actions
from plinth.errors import ActionError
-
from plinth.modules.security import set_restricted_access
# Usernames used by optional services (that might not be installed yet).
-
RESERVED_USERNAMES = [
'debian-deluged',
'Debian-minetest',
@@ -95,14 +93,14 @@ class CreateUserForm(ValidNewUsernameCheckMixin, UserCreationForm):
label=ugettext_lazy('Groups'),
required=False,
widget=forms.CheckboxSelectMultiple,
- help_text= \
- ugettext_lazy('Select which services should be available to the new '
- 'user. The user will be able to log in to services that '
- 'support single sign-on through LDAP, if they are in the '
- 'appropriate group.
Users in the admin group '
- 'will be able to log in to all services. They can also '
- 'log in to the system through SSH and have '
- 'administrative privileges (sudo).'))
+ help_text=ugettext_lazy(
+ 'Select which services should be available to the new '
+ 'user. The user will be able to log in to services that '
+ 'support single sign-on through LDAP, if they are in the '
+ 'appropriate group.
Users in the admin group '
+ 'will be able to log in to all services. They can also '
+ 'log in to the system through SSH and have '
+ 'administrative privileges (sudo).'))
def __init__(self, request, *args, **kwargs):
"""Initialize the form with extra request argument."""
@@ -132,7 +130,7 @@ class CreateUserForm(ValidNewUsernameCheckMixin, UserCreationForm):
messages.error(
self.request,
_('Failed to add new user to {group} group.')
- .format(group=group))
+ .format(group=group))
group_object, created = Group.objects.get_or_create(name=group)
group_object.user_set.add(user)
@@ -146,12 +144,12 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, forms.ModelForm):
label=ugettext_lazy('SSH Keys'),
required=False,
widget=forms.Textarea,
- help_text= \
- ugettext_lazy('Setting an SSH public key will allow this user to '
- 'securely log in to the system without using a '
- 'password. You may enter multiple keys, one on each '
- 'line. Blank lines and lines starting with # will be '
- 'ignored.'))
+ help_text=ugettext_lazy(
+ 'Setting an SSH public key will allow this user to '
+ 'securely log in to the system without using a '
+ 'password. You may enter multiple keys, one on each '
+ 'line. Blank lines and lines starting with # will be '
+ 'ignored.'))
class Meta:
"""Metadata to control automatic form building."""
diff --git a/plinth/modules/users/views.py b/plinth/modules/users/views.py
index 5f89824a0..613c4c100 100644
--- a/plinth/modules/users/views.py
+++ b/plinth/modules/users/views.py
@@ -22,13 +22,13 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse, reverse_lazy
from django.views.generic.edit import (CreateView, DeleteView, UpdateView,
FormView)
-from django.views.generic import ListView, CreateView as CV
+import django.views.generic
from django.utils.translation import ugettext as _, ugettext_lazy
-from plinth import cfg
-
-from .forms import CreateUserForm, UserChangePasswordForm, UserUpdateForm, State1Form
+from .forms import CreateUserForm, UserChangePasswordForm, UserUpdateForm, \
+ State1Form
from plinth import actions
+from plinth import cfg
from plinth.errors import ActionError
from plinth.modules.first_boot.middleware import mark_step_done, next_step
@@ -65,7 +65,7 @@ class UserCreate(ContextMixin, SuccessMessageMixin, CreateView):
return kwargs
-class UserList(ContextMixin, ListView):
+class UserList(ContextMixin, django.views.generic.ListView):
"""View to list users."""
model = User
template_name = 'users_list.html'
@@ -168,7 +168,7 @@ class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView):
return super(UserChangePassword, self).form_valid(form)
-class State1View(CV):
+class State1View(django.views.generic.CreateView):
"""Create user account and log the user in."""
template_name = 'firstboot_state1.html'
form_class = State1Form
@@ -178,6 +178,7 @@ class State1View(CV):
"""Initialize the view object."""
if not cfg.danube_edition:
mark_step_done('pagekite_firstboot')
+
mark_step_done('users_firstboot')
self.success_url = next_step()
return super(State1View, self).__init__(*args, **kwargs)