From 65d8f82ae1f5dc7c80cda628c9713615a33b74bf Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Tue, 21 Jul 2020 19:41:35 -0400 Subject: [PATCH] upgrades: Add first boot step to configure backports Closes: #1855. Tests: - On unstable, first boot step is not shown. Backports are not enabled. - On testing, tested enabling backports at first boot step. Backports are enabled. - On testing, tested not enabling backports. Backports are not enabled and can be activated later. - On testing, confirmed that functional tests can click through the first boot step. - On stable with backports, first boot step is not shown. Backports are enabled. - On stable, tested enabling backports at first boot step. Backports are enabled. - On stable, tested not enabling backports. Backports are not enabled and can be activated later. Signed-off-by: James Valleroy [sunil: Avoid two different i18n strings with almost same content] [sunil: Use box_name instead of hardcoded FreedomBox name] [sunil: Use consistent terminology 'activate' instead of 'enable'] [sunil: Rename the wizard, form, view, url for consistency with existing code] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .../modules/security/templates/security.html | 11 ++-- plinth/modules/upgrades/__init__.py | 20 +++++-- plinth/modules/upgrades/forms.py | 7 +++ .../templates/backports-firstboot.html | 47 +++++++++++++++ .../templates/upgrades_configure.html | 11 ++-- plinth/modules/upgrades/urls.py | 2 + plinth/modules/upgrades/views.py | 59 ++++++++++++++++++- plinth/tests/functional/__init__.py | 7 ++- 8 files changed, 145 insertions(+), 19 deletions(-) create mode 100644 plinth/modules/upgrades/templates/backports-firstboot.html diff --git a/plinth/modules/security/templates/security.html b/plinth/modules/security/templates/security.html index 2d8ed7001..56bd907d1 100644 --- a/plinth/modules/security/templates/security.html +++ b/plinth/modules/security/templates/security.html @@ -22,11 +22,12 @@

{% blocktrans trimmed %} - This will allow a very limited set of software, including FreedomBox - service, to be updated to receive newer features regularly instead of - once every 2 years or so. Note that packages with frequent feature - updates do not have support from Debian Security Team. They are instead - maintained by contributors to Debian and the FreedomBox community. + Frequent feature updates allow a very limited set of software, including + {{box_name}} service, to be updated to receive newer features regularly + instead of once every 2 years or so. Note that packages with frequent + feature updates do not have support from Debian Security Team. They are + instead maintained by contributors to Debian and the {{box_name}} + community. {% endblocktrans %}

{% endif %} diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py index c93fe2fec..d144f2cd0 100644 --- a/plinth/modules/upgrades/__init__.py +++ b/plinth/modules/upgrades/__init__.py @@ -23,6 +23,14 @@ is_essential = True managed_packages = ['unattended-upgrades', 'needrestart'] +first_boot_steps = [ + { + 'id': 'backports_wizard', + 'url': 'upgrades:backports-firstboot', + 'order': 5, + }, +] + _description = [ _('Check for and apply the latest software and security updates.'), _('Updates are run at 06:00 everyday according to local time zone. Set ' @@ -34,6 +42,8 @@ _description = [ app = None +BACKPORTS_ENABLED_KEY = 'upgrades_backports_enabled' + SOURCES_LIST = '/etc/apt/sources.list.d/freedombox2.list' @@ -129,11 +139,13 @@ def disable(): def setup_repositories(data): """Setup apt backport repositories.""" - command = ['setup-repositories'] - if cfg.develop: - command += ['--develop'] + from plinth import kvstore + if kvstore.get_default(BACKPORTS_ENABLED_KEY, False): + command = ['setup-repositories'] + if cfg.develop: + command += ['--develop'] - actions.superuser_run('upgrades', command) + actions.superuser_run('upgrades', command) def is_backports_enabled(): diff --git a/plinth/modules/upgrades/forms.py b/plinth/modules/upgrades/forms.py index 26a5e0db3..5a92aa70c 100644 --- a/plinth/modules/upgrades/forms.py +++ b/plinth/modules/upgrades/forms.py @@ -12,3 +12,10 @@ class ConfigureForm(forms.Form): auto_upgrades_enabled = forms.BooleanField( label=_('Enable auto-update'), required=False, help_text=_( 'When enabled, FreedomBox automatically updates once a day.')) + + +class BackportsFirstbootForm(forms.Form): + """Form to configure backports during first boot wizard.""" + backports_enabled = forms.BooleanField( + label=_('Activate frequent feature updates (recommended)'), + required=False) diff --git a/plinth/modules/upgrades/templates/backports-firstboot.html b/plinth/modules/upgrades/templates/backports-firstboot.html new file mode 100644 index 000000000..0a5892899 --- /dev/null +++ b/plinth/modules/upgrades/templates/backports-firstboot.html @@ -0,0 +1,47 @@ +{% extends "base_firstboot.html" %} +{% comment %} +# SPDX-License-Identifier: AGPL-3.0-or-later +{% endcomment %} + +{% load bootstrap %} +{% load i18n %} +{% load static %} + +{% block content %} +

{% trans "Frequent Feature Updates" %}

+ +

+ {% blocktrans trimmed %} + Frequent feature updates allow a very limited set of software, including + {{box_name}} service, to be updated to receive newer features regularly + instead of once every 2 years or so. Note that packages with frequent + feature updates do not have support from Debian Security Team. They are + instead maintained by contributors to Debian and the {{box_name}} + community. + {% endblocktrans %} +

+ +

+ {% blocktrans trimmed %} + It is strongly recommended to activate frequent feature updates. If not + activated now, they can be activated later. + {% endblocktrans %} +

+ + + +
+ {% csrf_token %} + + {{ form|bootstrap }} + + +
+ +{% endblock %} diff --git a/plinth/modules/upgrades/templates/upgrades_configure.html b/plinth/modules/upgrades/templates/upgrades_configure.html index 0765216f9..94262751c 100644 --- a/plinth/modules/upgrades/templates/upgrades_configure.html +++ b/plinth/modules/upgrades/templates/upgrades_configure.html @@ -29,11 +29,12 @@

{% if can_activate_backports or is_backports_enabled %} {% blocktrans trimmed %} - This will allow a very limited set of software, including FreedomBox - service, to be updated to receive newer features regularly instead of - once every 2 years or so. Note that packages with frequent feature - updates do not have support from Debian Security Team. They are instead - maintained by contributors to Debian and the FreedomBox community. + Frequent feature updates allow a very limited set of software, including + {{box_name}} service, to be updated to receive newer features regularly + instead of once every 2 years or so. Note that packages with frequent + feature updates do not have support from Debian Security Team. They are + instead maintained by contributors to Debian and the {{box_name}} + community. {% endblocktrans %} {% endif %}

diff --git a/plinth/modules/upgrades/urls.py b/plinth/modules/upgrades/urls.py index 093bac122..f6acd3d87 100644 --- a/plinth/modules/upgrades/urls.py +++ b/plinth/modules/upgrades/urls.py @@ -12,5 +12,7 @@ urlpatterns = [ name='index'), url(r'^sys/upgrades/activate-backports/$', views.activate_backports, name='activate-backports'), + url(r'^sys/upgrades/firstboot/backports/$', + views.BackportsFirstbootView.as_view(), name='backports-firstboot'), url(r'^sys/upgrades/upgrade/$', views.upgrade, name='upgrade'), ] diff --git a/plinth/modules/upgrades/views.py b/plinth/modules/upgrades/views.py index 426ad6444..43648bf28 100644 --- a/plinth/modules/upgrades/views.py +++ b/plinth/modules/upgrades/views.py @@ -3,17 +3,23 @@ FreedomBox app for upgrades. """ +import logging + from django.contrib import messages +from django.http import HttpResponseRedirect from django.shortcuts import redirect from django.urls import reverse_lazy from django.utils.translation import ugettext as _ +from django.views.generic.edit import FormView -from plinth import actions, package +from plinth import actions, kvstore, package from plinth.errors import ActionError -from plinth.modules import upgrades +from plinth.modules import first_boot, upgrades from plinth.views import AppView -from .forms import ConfigureForm +from .forms import BackportsFirstbootForm, ConfigureForm + +logger = logging.getLogger(__name__) class UpgradesConfigurationView(AppView): @@ -84,7 +90,54 @@ def upgrade(request): def activate_backports(request): """Activate backports.""" if request.method == 'POST': + kvstore.set(upgrades.BACKPORTS_ENABLED_KEY, True) upgrades.setup_repositories(None) messages.success(request, _('Frequent feature updates activated.')) return redirect(reverse_lazy('upgrades:index')) + + +class BackportsFirstbootView(FormView): + """View to configure backports during first boot wizard.""" + template_name = 'backports-firstboot.html' + form_class = BackportsFirstbootForm + + def dispatch(self, request, *args, **kwargs): + """Show backports configuration form only if it can be activated.""" + if upgrades.is_backports_enabled(): + # Backports is already enabled. Record this preference and + # skip first boot step. + kvstore.set(upgrades.BACKPORTS_ENABLED_KEY, True) + first_boot.mark_step_done('backports_wizard') + return HttpResponseRedirect(reverse_lazy(first_boot.next_step())) + + if not upgrades.can_activate_backports(): + # Skip first boot step. + first_boot.mark_step_done('backports_wizard') + return HttpResponseRedirect(reverse_lazy(first_boot.next_step())) + + return super().dispatch(request, *args, *kwargs) + + def get_initial(self): + """Get initial form data.""" + return { + 'backports_enabled': + kvstore.get_default(upgrades.BACKPORTS_ENABLED_KEY, True) + } + + def get_success_url(self): + """Return next firstboot step.""" + return reverse_lazy(first_boot.next_step()) + + def form_valid(self, form): + """Mark the first wizard step as done, save value and redirect.""" + enabled = form.cleaned_data['backports_enabled'] + kvstore.set(upgrades.BACKPORTS_ENABLED_KEY, enabled) + if enabled: + upgrades.setup_repositories(None) + logger.info('Backports enabled.') + else: + logger.info('Backports not enabled.') + + first_boot.mark_step_done('backports_wizard') + return super().form_valid(form) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 61e208dbf..9987eed8d 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -13,8 +13,8 @@ from contextlib import contextmanager import pytest import requests -from selenium.common.exceptions import (WebDriverException, - StaleElementReferenceException) +from selenium.common.exceptions import (StaleElementReferenceException, + WebDriverException) from selenium.webdriver.support.ui import WebDriverWait config = configparser.ConfigParser() @@ -261,6 +261,9 @@ def login(browser, url, username, password): if '/internet-connection-type' in browser.url: submit(browser, element=browser.find_by_name('skip')[0]) + if '/firstboot/backports' in browser.url: + submit(browser, element=browser.find_by_name('next')[0]) + ################# # App utilities #