diff --git a/plinth/modules/first_boot/forms.py b/plinth/modules/first_boot/forms.py
index 0cead0456..457f866a9 100644
--- a/plinth/modules/first_boot/forms.py
+++ b/plinth/modules/first_boot/forms.py
@@ -22,7 +22,6 @@ Forms for first boot module.
import json
import logging
import requests
-import subprocess
from django import forms
from django.contrib import auth
@@ -43,6 +42,7 @@ 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)
@@ -103,22 +103,6 @@ class State1Form(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm):
messages.success(self.request, message)
-class SubdomainWidget(forms.widgets.TextInput):
- """Append the domain to the subdomain bootstrap input field"""
- def __init__(self, domain, *args, **kwargs):
- """Intialize the widget by storing the domain value."""
- super().__init__(*args, **kwargs)
- self.domain = domain
-
- def render(self, *args, **kwargs):
- """Return the HTML for the widget."""
- inputfield = super().render(*args, **kwargs)
- return """
- {0}
- {1}
-
""".format(inputfield, self.domain)
-
-
class State5Form(forms.Form):
"""Set up freedombox.me pagekite subdomain"""
DOMAIN_APPENDIX = '.freedombox.me'
diff --git a/plinth/modules/first_boot/middleware.py b/plinth/modules/first_boot/middleware.py
index d2cc7db84..99b25d9dd 100644
--- a/plinth/modules/first_boot/middleware.py
+++ b/plinth/modules/first_boot/middleware.py
@@ -26,10 +26,11 @@ from django.conf import settings
import logging
from operator import itemgetter
from plinth import kvstore, module_loader
-from django.shortcuts import render
LOGGER = logging.getLogger(__name__)
+firstboot_steps = []
+
class FirstBootMiddleware(object):
"""Forward to firstboot page if firstboot isn't finished yet."""
@@ -37,7 +38,11 @@ class FirstBootMiddleware(object):
@staticmethod
def process_request(request):
"""Handle a request as Django middleware request handler."""
- state = kvstore.get_default('firstboot_state', 0)
+ old_state = kvstore.get_default('firstboot_state', 0)
+ state = kvstore.get_default('setup_state', 0)
+ 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))
help_index_url = reverse('help:index')
@@ -77,8 +82,10 @@ def get_firstboot_steps():
def next_step():
""" Returns the next first boot step required to run """
- steps = get_firstboot_steps()
- for step in steps:
+ 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:
return step.get('url')
@@ -90,3 +97,14 @@ def mark_step_done(id):
:param id: id of the firstboot step
"""
kvstore.set(id, 1)
+ 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 305597a05..0d9299350 100644
--- a/plinth/modules/first_boot/views.py
+++ b/plinth/modules/first_boot/views.py
@@ -15,19 +15,11 @@
# along with this program. If not, see .
#
-from django.contrib import messages
from django.contrib.auth.models import User
-from django.http.response import HttpResponseRedirect
from django.shortcuts import render
-from django.urls import reverse_lazy
from django.utils.translation import ugettext as _
from django.views.generic import CreateView, FormView, TemplateView
-
-from plinth import cfg
-from plinth import kvstore
from plinth import network
-from plinth.errors import DomainRegistrationError
-from .forms import State1Form, State5Form
from .middleware import mark_step_done, next_step
@@ -51,7 +43,7 @@ def state10(request):
"""
# Make sure that a user exists before finishing firstboot
if User.objects.all():
- mark_step_done('firstboot_state')
+ mark_step_done('firstboot_state10')
connections = network.get_connection_list()
diff --git a/plinth/modules/pagekite/forms.py b/plinth/modules/pagekite/forms.py
index c2230ed5a..81ef9ae47 100644
--- a/plinth/modules/pagekite/forms.py
+++ b/plinth/modules/pagekite/forms.py
@@ -27,7 +27,6 @@ import logging
from plinth import cfg
from plinth.errors import ActionError, DomainRegistrationError
-from plinth.modules.first_boot.forms import SubdomainWidget
from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
from plinth.utils import format_lazy
@@ -38,6 +37,7 @@ LOGGER = logging.getLogger(__name__)
class TrimmedCharField(forms.CharField):
"""Trim the contents of a CharField"""
+
def clean(self, value):
"""Clean and validate the field value"""
if value:
@@ -46,6 +46,23 @@ class TrimmedCharField(forms.CharField):
return super(TrimmedCharField, self).clean(value)
+class SubdomainWidget(forms.widgets.TextInput):
+ """Append the domain to the subdomain bootstrap input field"""
+
+ def __init__(self, domain, *args, **kwargs):
+ """Intialize the widget by storing the domain value."""
+ super().__init__(*args, **kwargs)
+ self.domain = domain
+
+ def render(self, *args, **kwargs):
+ """Return the HTML for the widget."""
+ inputfield = super().render(*args, **kwargs)
+ return """
+ {0}
+ {1}
+
""".format(inputfield, self.domain)
+
+
class ConfigurationForm(forms.Form):
"""Configure PageKite credentials and frontend"""
@@ -54,9 +71,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,
@@ -70,9 +87,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."""
@@ -84,14 +101,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'))
@@ -191,7 +208,6 @@ class BaseCustomServiceForm(forms.Form):
class DeleteCustomServiceForm(BaseCustomServiceForm):
-
def delete(self, request):
service = self.convert_formdata_to_service(self.cleaned_data)
utils.run(['remove-service', '--service', json.dumps(service)])
@@ -244,6 +260,8 @@ class AddCustomServiceForm(BaseCustomServiceForm):
messages.error(request, _('This service already exists'))
else:
raise
+
+
class State5Form(forms.Form):
"""Set up freedombox.me pagekite subdomain"""
DOMAIN_APPENDIX = '.freedombox.me'
diff --git a/plinth/modules/pagekite/views.py b/plinth/modules/pagekite/views.py
index c81f69c61..3746ead85 100644
--- a/plinth/modules/pagekite/views.py
+++ b/plinth/modules/pagekite/views.py
@@ -21,7 +21,6 @@ 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 import kvstore
from plinth.errors import DomainRegistrationError
from . import utils
diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py
index f4b429c2c..1ff3e72dd 100644
--- a/plinth/modules/users/forms.py
+++ b/plinth/modules/users/forms.py
@@ -28,9 +28,10 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from plinth import actions
from plinth.errors import ActionError
-# Usernames used by optional services (that might not be installed yet).
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',
@@ -55,11 +56,12 @@ GROUP_CHOICES = (
class ValidNewUsernameCheckMixin(object):
"""Mixin to check if a username is valid for created new user."""
+
def clean_username(self):
"""Check for username collisions with system users."""
username = self.cleaned_data['username']
if self.instance.username != username and \
- not self.is_valid_new_username():
+ not self.is_valid_new_username():
raise ValidationError(_('Username is taken or is reserved.'),
code='invalid')
@@ -93,14 +95,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."""
@@ -130,7 +132,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)
@@ -144,12 +146,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."""
@@ -244,8 +246,10 @@ class UserChangePasswordForm(SetPasswordForm):
return user
+
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)
diff --git a/plinth/modules/users/views.py b/plinth/modules/users/views.py
index 283078af8..5f89824a0 100644
--- a/plinth/modules/users/views.py
+++ b/plinth/modules/users/views.py
@@ -22,10 +22,9 @@ 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
+from django.views.generic import ListView, CreateView as CV
from django.utils.translation import ugettext as _, ugettext_lazy
from plinth import cfg
-from plinth import kvstore
from .forms import CreateUserForm, UserChangePasswordForm, UserUpdateForm, State1Form
@@ -169,7 +168,7 @@ class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView):
return super(UserChangePassword, self).form_valid(form)
-class State1View(CreateView):
+class State1View(CV):
"""Create user account and log the user in."""
template_name = 'firstboot_state1.html'
form_class = State1Form