mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-04 08:13:38 +00:00
- Remove the first setup wizard step to run security upgrades. At the time of its introduction, it was felt that this is very important. Some things have changed since then: - We have mechanism for queuing package operations. Users can now trigger software updates and start installing apps before that is completed. Or vice versa. Earlier if the software updates were running, app install used to fail with an error. - There were no notifications. Since then we have added 'first setup' notification for important topics such as Privacy. This step can be replaced with a notification. - Automatic diagnostics and a diagnostic to notify of updated packages also helps bring attention to software updates if they are missed during first setup. - A proposed change will re-introduce an advice to run updates in the 'Next steps' wizard step along with a button trigger it right there. - The new notification for software updates will bring more attention to running updates as part of first setup. - It would be nice not be stuck in the first setup wizard for a long period and make it look simple. It improves the fun factor of setting up FreedomBox. - It would present an opportunity to utilize the parallel installation of apps/updates to the full extent. Although this can also be done by skipping the progress step after updates are run. - First wizard steps tend to get less testing. Tests: - Run the first setup wizard by removing /var/lib/plinth/plinth.sqlite3 and running the service. Notice that the software update step is not shown and wizard completes successfully. - On stable container, backports step is shown as expected (if not already enabled). Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Veiko Aasa <veiko17@disroot.org>
179 lines
6.3 KiB
Python
179 lines
6.3 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""FreedomBox app for upgrades."""
|
|
|
|
import subprocess
|
|
|
|
from apt.cache import Cache
|
|
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 gettext as _
|
|
from django.views.generic.edit import FormView
|
|
|
|
from plinth import __version__
|
|
from plinth.modules import first_boot, upgrades
|
|
from plinth.privileged import packages as packages_privileged
|
|
from plinth.views import AppView, messages_error
|
|
|
|
from . import privileged
|
|
from .forms import BackportsFirstbootForm, ConfigureForm
|
|
|
|
|
|
class UpgradesConfigurationView(AppView):
|
|
"""Serve configuration page."""
|
|
|
|
form_class = ConfigureForm
|
|
success_url = reverse_lazy('upgrades:index')
|
|
template_name = "upgrades_configure.html"
|
|
app_id = 'upgrades'
|
|
|
|
def get_initial(self):
|
|
"""Return the initial values for the form."""
|
|
return {
|
|
'auto_upgrades_enabled': privileged.check_auto(),
|
|
'dist_upgrade_enabled': upgrades.is_dist_upgrade_enabled()
|
|
}
|
|
|
|
def get_context_data(self, *args, **kwargs):
|
|
"""Add additional context data for template."""
|
|
context = super().get_context_data(*args, **kwargs)
|
|
context['can_activate_backports'] = upgrades.can_activate_backports()
|
|
context['is_backports_requested'] = upgrades.is_backports_requested()
|
|
context['is_busy'] = (_is_updating()
|
|
or packages_privileged.is_package_manager_busy())
|
|
context['log'] = privileged.get_log()
|
|
context['refresh_page_sec'] = 3 if context['is_busy'] else None
|
|
context['version'] = __version__
|
|
context['new_version'] = is_newer_version_available()
|
|
context['os_release'] = get_os_release()
|
|
context['can_test_dist_upgrade'] = upgrades.can_test_dist_upgrade()
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
"""Apply the form changes."""
|
|
old_status = form.initial
|
|
new_status = form.cleaned_data
|
|
|
|
is_changed = False
|
|
|
|
if old_status['auto_upgrades_enabled'] \
|
|
!= new_status['auto_upgrades_enabled']:
|
|
|
|
try:
|
|
if new_status['auto_upgrades_enabled']:
|
|
privileged.enable_auto()
|
|
else:
|
|
privileged.disable_auto()
|
|
|
|
is_changed = True
|
|
except Exception as exception:
|
|
messages_error(self.request,
|
|
_('Error when configuring unattended-upgrades'),
|
|
exception)
|
|
|
|
if old_status['dist_upgrade_enabled'] \
|
|
!= new_status['dist_upgrade_enabled']:
|
|
upgrades.set_dist_upgrade_enabled(
|
|
new_status['dist_upgrade_enabled'])
|
|
is_changed = True
|
|
|
|
if is_changed:
|
|
messages.success(self.request, _('Configuration updated.'))
|
|
|
|
return super().form_valid(form)
|
|
|
|
|
|
def is_newer_version_available():
|
|
"""Return whether a newer Freedombox version is available."""
|
|
cache = Cache()
|
|
freedombox = cache['freedombox']
|
|
return not freedombox.candidate.is_installed
|
|
|
|
|
|
def get_os_release():
|
|
"""Return the Debian release number and name."""
|
|
output = 'Error: Cannot read PRETTY_NAME in /etc/os-release.'
|
|
with open('/etc/os-release', 'r', encoding='utf-8') as release_file:
|
|
for line in release_file:
|
|
if 'PRETTY_NAME=' in line:
|
|
line = line.replace('"', '').strip()
|
|
line = line.split('=')
|
|
output = line[1]
|
|
return output
|
|
|
|
|
|
def _is_updating():
|
|
"""Check if manually triggered update is running."""
|
|
command = ['systemctl', 'is-active', 'freedombox-manual-upgrade']
|
|
result = subprocess.run(command, capture_output=True, text=True,
|
|
check=False)
|
|
return str(result.stdout).startswith('activ') # 'active' or 'activating'
|
|
|
|
|
|
def upgrade(request):
|
|
"""Serve the upgrade page."""
|
|
if request.method == 'POST':
|
|
try:
|
|
privileged.run()
|
|
messages.success(request, _('Upgrade process started.'))
|
|
except Exception:
|
|
messages.error(request, _('Starting upgrade failed.'))
|
|
|
|
return redirect(reverse_lazy('upgrades:index'))
|
|
|
|
|
|
def activate_backports(request):
|
|
"""Activate backports."""
|
|
if request.method == 'POST':
|
|
upgrades.set_backports_requested(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.
|
|
upgrades.set_backports_requested(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.
|
|
upgrades.set_backports_requested(False)
|
|
first_boot.mark_step_done('backports_wizard')
|
|
return HttpResponseRedirect(reverse_lazy(first_boot.next_step()))
|
|
|
|
return super().dispatch(request, *args, *kwargs)
|
|
|
|
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']
|
|
upgrades.set_backports_requested(enabled)
|
|
upgrades.setup_repositories(None)
|
|
first_boot.mark_step_done('backports_wizard')
|
|
return super().form_valid(form)
|
|
|
|
|
|
def test_dist_upgrade(request):
|
|
"""Test dist-upgrade from stable to testing."""
|
|
if request.method == 'POST':
|
|
upgrades.test_dist_upgrade()
|
|
messages.success(request, _('Starting distribution upgrade test.'))
|
|
|
|
return redirect(reverse_lazy('upgrades:index'))
|