*: Make setup method part of App class for all apps

- Primary purpose is to complete the App API and allow for multiple apps to be
present in a module without a single clashing setup() method. Secondary
objective is to get rid of SetupHelper instance simple use App instance instead.

- This brings us closer to not needing to implement setup() method for some of
the typical apps.

- Remove default value None for old_version parameter.

  - A valid integer value is always passed to this call.

  - The value of None is undefined.

  - Simplifies the App API slightly.

- Drop setting 'pre', 'post' values to indicate the stage of setup for the App.

  - Simplifies the setup methods significantly. Eliminates a class of
  bugs (some of them seen earlier).

  - The UI can show a simple 'installing...' or progress spinner instead of
  individual stages.

  - There are currently many inconsistencies where many operations are not
  wrapped in helper.call() calls.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2022-04-14 17:34:55 -07:00 committed by James Valleroy
parent cbef3e0163
commit 75f6abac1e
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
55 changed files with 505 additions and 553 deletions

View File

@ -9,28 +9,33 @@ Installing packages required for the app
So far, we haven't dealt with installing the packages needed for Transmission to
work. Nor did we take care of performing the initial configuration for
Transmission. FreedomBox takes care of installing all the Debian packages
required for our app to work. All we need to do is specify the list of the
Debian packages required in the ``setup()`` method that is called during
installation:
required for our app to work. All we need to do is call the base class method in
the ``setup()`` method that of the ``TrasmissionApp`` class that is called
during installation. The base class ``setup()`` method in turn calls ``setup()``
on the ``Packages`` component which performs the actual installation:
.. code-block:: python3
:caption: ``__init__.py``
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
class TransmissionApp(app_module.App):
...
new_configuration = {
'rpc-whitelist-enabled': False,
'rpc-authentication-required': False
}
helper.call('post', privileged.merge_configuration, new_configuration)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
new_configuration = {
'rpc-whitelist-enabled': False,
'rpc-authentication-required': False
}
privileged.merge_configuration(new_configuration)
self.enable()
The first time this app's view is accessed, FreedomBox shows an app installation
page and allows the user to install the app. After the app installation is
completed, the user is shown the app's configuration page.
In case of our app Transmission, first we are installing the Debian packages,
then performing the first time configuration on the app using the action script
and finally enabling the app.
In case of our app Transmission, first we are installing the Debian packages (by
calling base class ``setup()`` method), then performing the first time
configuration on the app using the action script and finally enabling the app.

View File

@ -59,14 +59,13 @@ class ApacheApp(app_module.App):
daemon = RelatedDaemon('related-daemon-apache', 'uwsgi')
self.add(daemon)
def setup(helper, old_version=None):
"""Configure the module."""
app.setup(old_version)
actions.superuser_run(
'apache',
['setup', '--old-version', str(old_version)])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('apache',
['setup', '--old-version',
str(old_version)])
self.enable()
# (U)ser (W)eb (S)ites

View File

@ -86,16 +86,14 @@ class AvahiApp(app_module.App):
post_hostname_change.connect(on_post_hostname_change)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
# Reload avahi-daemon now that first-run does not reboot. After performing
# FreedomBox Service (Plinth) package installation, new Avahi files will be
# available and require restart.
helper.call('post', actions.superuser_run, 'service',
['reload', 'avahi-daemon'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
# Reload avahi-daemon now that first-run does not reboot. After
# performing FreedomBox Service (Plinth) package installation, new
# Avahi files will be available and require restart.
actions.superuser_run('service', ['reload', 'avahi-daemon'])
self.enable()
def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs):

View File

@ -67,18 +67,17 @@ class BackupsApp(app_module.App):
interval = 180 if cfg.develop else 3600
glib.schedule(interval, backup_by_schedule)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
from . import repository
actions.superuser_run(
'backups', ['setup', '--path', repository.RootBorgRepository.PATH])
self.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
from . import repository
helper.call('post', actions.superuser_run, 'backups',
['setup', '--path', repository.RootBorgRepository.PATH])
helper.call('post', app.enable)
# First time setup or upgrading from older versions.
if old_version <= 2:
_show_schedule_setup_notification()
# First time setup or upgrading from older versions.
if old_version <= 2:
_show_schedule_setup_notification()
def _backup_handler(packet, encryption_passphrase=None):

View File

@ -96,16 +96,17 @@ class BepastyApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'bepasty',
['setup', '--domain-name', 'freedombox.local'])
helper.call('post', app.enable)
if old_version == 1 and not get_configuration().get('DEFAULT_PERMISSIONS'):
# Upgrade to a better default only if user hasn't changed the value.
set_default_permissions('read')
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('bepasty',
['setup', '--domain-name', 'freedombox.local'])
self.enable()
if old_version == 1 and not get_configuration().get(
'DEFAULT_PERMISSIONS'):
# Upgrade to a better default only if user hasn't changed the
# value.
set_default_permissions('read')
def get_configuration():

View File

@ -99,14 +99,13 @@ class BindApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call(
'post', actions.superuser_run, 'bind',
['setup', '--old-version', str(old_version)])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('bind',
['setup', '--old-version',
str(old_version)])
self.enable()
def force_upgrade(helper, _packages):

View File

@ -101,11 +101,10 @@ class CalibreApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()
def validate_library_name(library_name):

View File

@ -89,10 +89,9 @@ class CockpitApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', privileged.setup)
if not old_version:
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
privileged.setup()
if not old_version:
self.enable()

View File

@ -84,6 +84,25 @@ class ConfigApp(app_module.App):
domain_type='domain-type-static',
name=domainname, services='__all__')
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
_migrate_home_page_config()
if old_version <= 3:
privileged.set_logging_mode('volatile')
# systemd-journald is socket activated, it may not be running and it
# does not support reload.
actions.superuser_run('service', ['try-restart', 'systemd-journald'])
# rsyslog when enabled, is activated by syslog.socket (shipped by
# systemd). See:
# https://www.freedesktop.org/wiki/Software/systemd/syslog/ .
actions.superuser_run('service', ['disable', 'rsyslog'])
# Ensure that rsyslog is not started by something else as it is
# installed by default on Debian systems.
actions.superuser_run('service', ['mask', 'rsyslog'])
def get_domainname():
"""Return the domainname"""
@ -192,25 +211,6 @@ def set_advanced_mode(advanced_mode):
kvstore.set(ADVANCED_MODE_KEY, advanced_mode)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
_migrate_home_page_config()
if old_version <= 3:
privileged.set_logging_mode('volatile')
# systemd-journald is socket activated, it may not be running and it does
# not support reload.
actions.superuser_run('service', ['try-restart', 'systemd-journald'])
# rsyslog when enabled, is activated by syslog.socket (shipped by systemd).
# See: https://www.freedesktop.org/wiki/Software/systemd/syslog/ .
actions.superuser_run('service', ['disable', 'rsyslog'])
# Ensure that rsyslog is not started by something else as it is installed
# by default on Debian systems.
actions.superuser_run('service', ['mask', 'rsyslog'])
def _migrate_home_page_config():
"""Move the home page configuration to an external file."""

View File

@ -108,16 +108,15 @@ class CoturnApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('coturn', ['setup'])
if old_version == 0:
self.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'coturn', ['setup'])
if old_version == 0:
helper.call('post', app.enable)
app.get_component('letsencrypt-coturn').setup_certificates()
notify_configuration_change()
self.get_component('letsencrypt-coturn').setup_certificates()
notify_configuration_change()
def get_available_domains():

View File

@ -97,10 +97,10 @@ class DateTimeApp(app_module.App):
"""Return that app has diagnostics only when time is managed."""
return self._is_time_managed()
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()
def _diagnose_time_synchronized():

View File

@ -94,10 +94,9 @@ class DelugeApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
add_user_to_share_group(SYSTEM_USER)
helper.call('post', actions.superuser_run, 'deluge', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
add_user_to_share_group(SYSTEM_USER)
actions.superuser_run('deluge', ['setup'])
self.enable()

View File

@ -98,24 +98,23 @@ class DynamicDNSApp(app_module.App):
interval = 180 if cfg.develop else 300
glib.schedule(interval, update_dns)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
self.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if not old_version:
helper.call('post', app.enable)
if old_version == 1:
config = actions.superuser_run('dynamicdns', ['export-config'])
config = json.loads(config)
if config['enabled']:
self.enable()
else:
self.disable()
if old_version == 1:
config = actions.superuser_run('dynamicdns', ['export-config'])
config = json.loads(config)
if config['enabled']:
app.enable()
else:
app.disable()
del config['enabled']
set_config(config)
actions.superuser_run('dynamicdns', ['clean'])
del config['enabled']
set_config(config)
actions.superuser_run('dynamicdns', ['clean'])
def _query_external_address(domain):

View File

@ -128,6 +128,25 @@ class EjabberdApp(app_module.App):
post_hostname_change.connect(on_post_hostname_change)
domain_added.connect(on_domain_added)
def setup(self, old_version):
"""Install and configure the app."""
domainname = config.get_domainname()
logger.info('ejabberd service domainname - %s', domainname)
actions.superuser_run('ejabberd',
['pre-install', '--domainname', domainname])
# XXX: Configure all other domain names
super().setup(old_version)
self.get_component('letsencrypt-ejabberd').setup_certificates(
[domainname])
actions.superuser_run('ejabberd',
['setup', '--domainname', domainname])
self.enable()
# Configure STUN/TURN only if there's a valid TLS domain set for Coturn
configuration = self.get_component('turn-ejabberd').get_configuration()
update_turn_configuration(configuration, force=True)
class EjabberdTurnConsumer(TurnConsumer):
"""Component to manage Coturn configuration for ejabberd."""
@ -137,27 +156,6 @@ class EjabberdTurnConsumer(TurnConsumer):
update_turn_configuration(config)
def setup(helper, old_version=None):
"""Install and configure the module."""
domainname = config.get_domainname()
logger.info('ejabberd service domainname - %s', domainname)
helper.call('pre', actions.superuser_run, 'ejabberd',
['pre-install', '--domainname', domainname])
# XXX: Configure all other domain names
app.setup(old_version)
helper.call('post',
app.get_component('letsencrypt-ejabberd').setup_certificates,
[domainname])
helper.call('post', actions.superuser_run, 'ejabberd',
['setup', '--domainname', domainname])
helper.call('post', app.enable)
# Configure STUN/TURN only if there's a valid TLS domain set for Coturn
configuration = app.get_component('turn-ejabberd').get_configuration()
update_turn_configuration(configuration, force=True)
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
"""
Backup ejabberd database before hostname is changed.

View File

@ -165,6 +165,39 @@ class EmailApp(plinth.app.App):
domain_added.connect(on_domain_added)
domain_removed.connect(on_domain_removed)
def setup(self, old_version):
"""Install and configure the app."""
def _clear_conflicts():
component = self.get_component('packages-email')
packages_to_remove = component.find_conflicts()
if packages_to_remove:
logger.info('Removing conflicting packages: %s',
packages_to_remove)
remove(packages_to_remove)
# Install
_clear_conflicts()
super().setup(old_version)
# Setup
privileged.home.setup()
self.get_component('letsencrypt-email-postfix').setup_certificates()
self.get_component('letsencrypt-email-dovecot').setup_certificates()
privileged.domain.set_domains()
privileged.postfix.setup()
aliases.setup_common_aliases(_get_first_admin())
privileged.spam.setup()
# Restart daemons
actions.superuser_run('service', ['try-restart', 'postfix'])
actions.superuser_run('service', ['try-restart', 'dovecot'])
actions.superuser_run('service', ['try-restart', 'rspamd'])
# Expose to public internet
if old_version == 0:
self.enable()
def get_domains():
"""Return the list of domains configured."""
@ -179,40 +212,6 @@ def _get_first_admin():
return users[0].username if users else None
def setup(helper, old_version=None):
"""Installs and configures module"""
def _clear_conflicts():
component = app.get_component('packages-email')
packages_to_remove = component.find_conflicts()
if packages_to_remove:
logger.info('Removing conflicting packages: %s',
packages_to_remove)
remove(packages_to_remove)
# Install
helper.call('pre', _clear_conflicts)
app.setup(old_version)
# Setup
helper.call('post', privileged.home.setup)
app.get_component('letsencrypt-email-postfix').setup_certificates()
app.get_component('letsencrypt-email-dovecot').setup_certificates()
helper.call('post', privileged.domain.set_domains)
helper.call('post', privileged.postfix.setup)
helper.call('post', aliases.setup_common_aliases, _get_first_admin())
helper.call('post', privileged.spam.setup)
# Restart daemons
actions.superuser_run('service', ['try-restart', 'postfix'])
actions.superuser_run('service', ['try-restart', 'dovecot'])
actions.superuser_run('service', ['try-restart', 'rspamd'])
# Expose to public internet
if old_version == 0:
helper.call('post', app.enable)
def on_domain_added(sender, domain_type, name, description='', services=None,
**kwargs):
"""Handle addition of a new domain."""

View File

@ -78,6 +78,11 @@ class FirewallApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
_run_setup()
def _run_setup():
"""Run firewalld setup."""
@ -90,12 +95,6 @@ def _run_setup():
add_service('dhcp', 'internal')
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
_run_setup()
def force_upgrade(helper, packages):
"""Force upgrade firewalld to resolve conffile prompts."""
if 'firewalld' not in packages:

View File

@ -128,6 +128,12 @@ class GitwebApp(app_module.App):
self.set_shortcut_login_required(True)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('gitweb', ['setup'])
self.enable()
class GitwebWebserverAuth(Webserver):
"""Component to handle Gitweb authentication webserver configuration."""
@ -157,13 +163,6 @@ class GitwebBackupRestore(BackupRestore):
app.update_service_access()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'gitweb', ['setup'])
helper.call('post', app.enable)
def repo_exists(name):
"""Check whether a remote repository exists."""
try:

View File

@ -98,33 +98,32 @@ class I2PApp(app_module.App):
backup_restore = BackupRestore('backup-restore-i2p', **manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
self.disable()
# Add favorites to the configuration
for fav in FAVORITES:
args = [
'add-favorite',
'--name',
fav.get('name'),
'--url',
fav.get('url'),
]
if 'icon' in fav:
args.extend(['--icon', fav.get('icon')])
helper.call('post', app.disable)
# Add favorites to the configuration
for fav in FAVORITES:
args = [
'add-favorite',
'--name',
fav.get('name'),
'--url',
fav.get('url'),
]
if 'icon' in fav:
args.extend(['--icon', fav.get('icon')])
if 'description' in fav:
args.extend(['--description', fav.get('description')])
if 'description' in fav:
args.extend(['--description', fav.get('description')])
actions.superuser_run('i2p', args)
helper.call('post', actions.superuser_run, 'i2p', args)
# Tunnels to all interfaces
for tunnel in tunnels_to_manage:
helper.call('post', actions.superuser_run, 'i2p', [
'set-tunnel-property', '--name', tunnel, '--property', 'interface',
'--value', '0.0.0.0'
])
helper.call('post', app.enable)
# Tunnels to all interfaces
for tunnel in tunnels_to_manage:
actions.superuser_run('i2p', [
'set-tunnel-property', '--name', tunnel, '--property',
'interface', '--value', '0.0.0.0'
])
self.enable()

View File

@ -112,9 +112,8 @@ class IkiwikiApp(app_module.App):
return sites
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'ikiwiki', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('ikiwiki', ['setup'])
self.enable()

View File

@ -76,9 +76,8 @@ class InfinotedApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'infinoted', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('infinoted', ['setup'])
self.enable()

View File

@ -89,9 +89,8 @@ class JanusApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the app."""
app.setup(old_version)
actions.superuser_run('janus', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('janus', ['setup'])
self.enable()

View File

@ -80,8 +80,7 @@ class JSXCApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()

View File

@ -99,13 +99,12 @@ class LetsEncryptApp(app_module.App):
return results
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
actions.superuser_run(
'letsencrypt',
['setup', '--old-version', str(old_version)])
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('letsencrypt',
['setup', '--old-version',
str(old_version)])
def certificate_obtain(domain):

View File

@ -20,7 +20,7 @@ from plinth.modules.backups.components import BackupRestore
from plinth.modules.coturn.components import TurnConfiguration, TurnConsumer
from plinth.modules.firewall.components import Firewall
from plinth.modules.letsencrypt.components import LetsEncrypt
from plinth.package import Packages
from plinth.package import Packages, install
from plinth.utils import format_lazy, is_non_empty_file
from . import manifest
@ -118,6 +118,23 @@ class MatrixSynapseApp(app_module.App):
turn = MatrixSynapseTurnConsumer('turn-matrixsynapse')
self.add(turn)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if old_version and old_version < 6:
upgrade()
else:
actions.superuser_run('matrixsynapse', ['post-install'])
if not old_version:
self.enable()
self.get_component('letsencrypt-matrixsynapse').setup_certificates()
# Configure STUN/TURN only if there's a valid TLS domain set for Coturn
config = self.get_component('turn-matrixsynapse').get_configuration()
update_turn_configuration(config, force=True)
class MatrixSynapseTurnConsumer(TurnConsumer):
"""Component to manage Coturn configuration for Matrix Synapse."""
@ -127,31 +144,12 @@ class MatrixSynapseTurnConsumer(TurnConsumer):
update_turn_configuration(config)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if old_version and old_version < 6:
helper.call('post', upgrade, helper)
else:
helper.call('post', actions.superuser_run, 'matrixsynapse',
['post-install'])
if not old_version:
helper.call('post', app.enable)
app.get_component('letsencrypt-matrixsynapse').setup_certificates()
# Configure STUN/TURN only if there's a valid TLS domain set for Coturn
config = app.get_component('turn-matrixsynapse').get_configuration()
update_turn_configuration(config, force=True)
def upgrade(helper):
def upgrade():
"""Upgrade matrix-synapse configuration to avoid conffile prompt."""
public_registration_status = get_public_registration_status()
actions.superuser_run('matrixsynapse', ['move-old-conf'])
helper.install(['matrix-synapse'], force_configuration='new',
reinstall=True, force_missing_configuration=True)
install(['matrix-synapse'], force_configuration='new', reinstall=True,
force_missing_configuration=True)
actions.superuser_run('matrixsynapse', ['post-install'])
if public_registration_status:
actions.superuser_run('matrixsynapse',

View File

@ -95,6 +95,13 @@ class MediaWikiApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('mediawiki', ['setup'])
actions.superuser_run('mediawiki', ['update'])
self.enable()
class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut for only logged users when in private mode."""
@ -105,14 +112,6 @@ class Shortcut(frontpage.Shortcut):
self.login_required = is_private_mode_enabled()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'mediawiki', ['setup'])
helper.call('post', actions.superuser_run, 'mediawiki', ['update'])
helper.call('post', app.enable)
def is_public_registration_enabled():
"""Return whether public registration is enabled."""
output = actions.superuser_run('mediawiki',

View File

@ -97,11 +97,10 @@ class MinetestApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()
def load_augeas():

View File

@ -90,13 +90,12 @@ class MiniDLNAApp(app_module.App):
groups=groups)
self.add(users_and_groups)
def setup(helper, old_version=None):
"""Install and configure the package"""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'minidlna', ['setup'])
if not old_version:
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('minidlna', ['setup'])
if not old_version:
self.enable()
def get_media_dir():

View File

@ -93,15 +93,14 @@ class MumbleApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
privileged.setup()
if not old_version:
self.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', privileged.setup)
if not old_version:
helper.call('post', app.enable)
app.get_component('letsencrypt-mumble').setup_certificates()
app.get_component('letsencrypt-mumble').setup_certificates()
def force_upgrade(helper, packages):
@ -115,7 +114,7 @@ def force_upgrade(helper, packages):
return False
helper.install(['mumble-server'], force_configuration='new')
helper.call('post', privileged.setup)
privileged.setup()
return True

View File

@ -80,12 +80,11 @@ class NetworksApp(app_module.App):
return results
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
actions.superuser_run('networks')
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('networks')
self.enable()
def get_network_topology_type():

View File

@ -106,12 +106,11 @@ class OpenVPNApp(app_module.App):
"""
return super().is_enabled() and is_setup()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'openvpn', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('openvpn', ['setup'])
self.enable()
def is_setup():

View File

@ -101,12 +101,12 @@ class PagekiteApp(app_module.App):
utils.update_names_module(is_enabled=False)
super().disable()
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
self.enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if not old_version:
helper.call('post', app.enable)
if old_version == 1:
actions.superuser_run('service', ['try-restart', PagekiteApp.DAEMON])
if old_version == 1:
actions.superuser_run('service',
['try-restart', PagekiteApp.DAEMON])

View File

@ -74,8 +74,7 @@ class PerformanceApp(app_module.App):
listen_ports=None)
self.add(daemon_3)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()

View File

@ -94,13 +94,12 @@ class PrivoxyApp(app_module.App):
results.extend(diagnose_url_with_proxy())
return results
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', privileged.pre_install)
app.setup(old_version)
helper.call('post', privileged.setup)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
privileged.pre_install()
super().setup(old_version)
privileged.setup()
self.enable()
def diagnose_url_with_proxy():

View File

@ -100,12 +100,11 @@ class QuasselApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
app.get_component('letsencrypt-quassel').setup_certificates()
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()
self.get_component('letsencrypt-quassel').setup_certificates()
def set_domain(domain):

View File

@ -98,11 +98,10 @@ class RadicaleApp(app_module.App):
actions.superuser_run('radicale', ['fix-paths'])
super().enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()
def force_upgrade(helper, packages):

View File

@ -88,17 +88,14 @@ class RoundcubeApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', privileged.pre_install)
app.setup(old_version)
helper.call('post', privileged.setup)
if old_version == 0:
privileged.set_config(local_only=True)
helper.call('post', app.enable)
elif old_version <= 2:
privileged.set_config(privileged.get_config()['local_only'])
def setup(self, old_version):
"""Install and configure the app."""
privileged.pre_install()
super().setup(old_version)
privileged.setup()
if old_version == 0:
privileged.set_config(local_only=True)
self.enable()
def force_upgrade(helper, packages):

View File

@ -85,9 +85,8 @@ class RSSBridgeApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', privileged.setup)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
privileged.setup()
self.enable()

View File

@ -101,6 +101,12 @@ class SambaApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('samba', ['setup'])
self.enable()
class SambaBackupRestore(BackupRestore):
"""Component to backup/restore Samba."""
@ -117,13 +123,6 @@ class SambaBackupRestore(BackupRestore):
actions.superuser_run('samba', ['restore-shares'])
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'samba', ['setup'])
helper.call('post', app.enable)
def add_share(mount_point, share_type, filesystem):
"""Add a share."""
command = [

View File

@ -94,6 +94,15 @@ class SearxApp(app_module.App):
shortcut.login_required = login_required
self.add(shortcut)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('searx', ['setup'])
if not old_version or old_version < 3:
actions.superuser_run('searx', ['disable-public-access'])
self.enable()
self.set_shortcut_login_required(True)
class SearxWebserverAuth(Webserver):
"""Component to handle Searx authentication webserver configuration."""
@ -108,17 +117,6 @@ class SearxWebserverAuth(Webserver):
super().enable()
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'searx', ['setup'])
if not old_version or old_version < 3:
helper.call('post', actions.superuser_run, 'searx',
['disable-public-access'])
helper.call('post', app.enable)
app.set_shortcut_login_required(True)
def get_safe_search_setting():
"""Get the current value of the safe search setting for Searx."""
value = actions.superuser_run('searx', ['get-safe-search'])

View File

@ -57,20 +57,19 @@ class SecurityApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
enable_fail2ban()
def setup(helper, old_version=None):
"""Install the required packages"""
app.setup(old_version)
if not old_version:
enable_fail2ban()
actions.superuser_run('service', ['reload', 'fail2ban'])
actions.superuser_run('service', ['reload', 'fail2ban'])
# Migrate to new config file.
enabled = get_restricted_access_enabled()
set_restricted_access(False)
if enabled:
set_restricted_access(True)
# Migrate to new config file.
enabled = get_restricted_access_enabled()
set_restricted_access(False)
if enabled:
set_restricted_access(True)
def enable_fail2ban():

View File

@ -67,8 +67,7 @@ class ShaarliApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()

View File

@ -84,9 +84,8 @@ class ShadowsocksApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'shadowsocks', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('shadowsocks', ['setup'])
self.enable()

View File

@ -67,6 +67,15 @@ class SnapshotApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if is_supported():
actions.superuser_run('snapshot',
['setup', '--old-version',
str(old_version)])
self.enable()
class SnapshotBackupRestore(BackupRestore):
"""Component to backup/restore snapshot module."""
@ -86,16 +95,6 @@ def is_supported():
return fs_type in fs_types_supported and root_inode_number == 256
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if is_supported():
helper.call('post', actions.superuser_run, 'snapshot',
['setup', '--old-version',
str(old_version)])
helper.call('post', app.enable)
def load_augeas():
"""Initialize Augeas."""
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +

View File

@ -64,12 +64,11 @@ class SSHApp(app_module.App):
backup_restore = BackupRestore('backup-restore-ssh', **manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Configure the module."""
app.setup(old_version)
actions.superuser_run('ssh', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('ssh', ['setup'])
self.enable()
def get_host_keys():

View File

@ -33,8 +33,7 @@ class SSOApp(app_module.App):
])
self.add(packages)
def setup(helper, old_version=None):
"""Install the required packages"""
app.setup(old_version)
actions.superuser_run('auth-pubtkt', ['create-key-pair'])
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('auth-pubtkt', ['create-key-pair'])

View File

@ -76,6 +76,19 @@ class StorageApp(app_module.App):
# Schedule initialization of UDisks2 initialization
glib.schedule(3, udisks2.init, repeat=False)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('storage', ['setup'])
self.enable()
disks = get_disks()
root_device = get_root_device(disks)
if is_expandable(root_device):
try:
expand_partition(root_device)
except ActionError:
pass
def get_disks():
"""Returns list of disks and their free space.
@ -275,20 +288,6 @@ def get_error_message(error):
return message_map.get(short_error, error)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'storage', ['setup'])
helper.call('post', app.enable)
disks = get_disks()
root_device = get_root_device(disks)
if is_expandable(root_device):
try:
expand_partition(root_device)
except ActionError:
pass
def warn_about_low_disk_space(request):
"""Warn about insufficient space on root partition."""
from plinth.notification import Notification

View File

@ -105,42 +105,42 @@ class SyncthingApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('syncthing', ['setup'])
add_user_to_share_group(SYSTEM_USER, SyncthingApp.DAEMON)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'syncthing', ['setup'])
add_user_to_share_group(SYSTEM_USER, SyncthingApp.DAEMON)
if not old_version:
self.enable()
if not old_version:
helper.call('post', app.enable)
actions.superuser_run('syncthing', ['setup-config'])
helper.call('post', actions.superuser_run, 'syncthing', ['setup-config'])
if old_version == 1 and self.is_enabled():
self.get_component('firewall-syncthing-ports').enable()
if old_version == 1 and app.is_enabled():
app.get_component('firewall-syncthing-ports').enable()
if old_version and old_version <= 3:
# rename LDAP and Django group
old_groupname = 'syncthing'
new_groupname = 'syncthing-access'
if old_version and old_version <= 3:
# rename LDAP and Django group
old_groupname = 'syncthing'
new_groupname = 'syncthing-access'
actions.superuser_run(
'users',
options=['rename-group', old_groupname, new_groupname])
actions.superuser_run(
'users', options=['rename-group', old_groupname, new_groupname])
from django.contrib.auth.models import Group
Group.objects.filter(name=old_groupname).update(name=new_groupname)
from django.contrib.auth.models import Group
Group.objects.filter(name=old_groupname).update(name=new_groupname)
# update web shares to have new group name
from plinth.modules import sharing
shares = sharing.list_shares()
for share in shares:
if old_groupname in share['groups']:
new_groups = share['groups']
new_groups.remove(old_groupname)
new_groups.append(new_groupname)
# update web shares to have new group name
from plinth.modules import sharing
shares = sharing.list_shares()
for share in shares:
if old_groupname in share['groups']:
new_groups = share['groups']
new_groups.remove(old_groupname)
new_groups.append(new_groupname)
name = share['name']
sharing.remove_share(name)
sharing.add_share(name, share['path'], new_groups,
share['is_public'])
name = share['name']
sharing.remove_share(name)
sharing.add_share(name, share['path'], new_groups,
share['is_public'])

View File

@ -155,19 +155,18 @@ class TorApp(app_module.App):
return results
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('tor',
['setup', '--old-version',
str(old_version)])
if not old_version:
actions.superuser_run(
'tor', ['configure', '--apt-transport-tor', 'enable'])
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call(
'post', actions.superuser_run, 'tor',
['setup', '--old-version', str(old_version)])
if not old_version:
helper.call('post', actions.superuser_run, 'tor',
['configure', '--apt-transport-tor', 'enable'])
helper.call('post', update_hidden_service_domain)
helper.call('post', app.enable)
update_hidden_service_domain()
self.enable()
def update_hidden_service_domain(status=None):

View File

@ -115,18 +115,17 @@ class TransmissionApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if old_version and old_version <= 3 and self.is_enabled():
self.get_component('firewall-transmission').enable()
if old_version and old_version <= 3 and app.is_enabled():
app.get_component('firewall-transmission').enable()
new_configuration = {
'rpc-whitelist-enabled': False,
'rpc-authentication-required': False
}
helper.call('post', privileged.merge_configuration, new_configuration)
add_user_to_share_group(SYSTEM_USER, TransmissionApp.DAEMON)
helper.call('post', app.enable)
new_configuration = {
'rpc-whitelist-enabled': False,
'rpc-authentication-required': False
}
privileged.merge_configuration(new_configuration)
add_user_to_share_group(SYSTEM_USER, TransmissionApp.DAEMON)
self.enable()

View File

@ -107,6 +107,13 @@ class TTRSSApp(app_module.App):
domain = next(names.get_available_tls_domains(), None)
set_domain(domain)
def setup(self, old_version):
"""Install and configure the app."""
actions.superuser_run('ttrss', ['pre-setup'])
super().setup(old_version)
actions.superuser_run('ttrss', ['setup'])
self.enable()
class TTRSSBackupRestore(BackupRestore):
"""Component to backup/restore TT-RSS"""
@ -122,14 +129,6 @@ class TTRSSBackupRestore(BackupRestore):
actions.superuser_run('ttrss', ['restore-database'])
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', actions.superuser_run, 'ttrss', ['pre-setup'])
app.setup(old_version)
helper.call('post', actions.superuser_run, 'ttrss', ['setup'])
helper.call('post', app.enable)
def force_upgrade(helper, packages):
"""Force update package to resolve conffile prompts."""
if 'tt-rss' not in packages:

View File

@ -136,32 +136,31 @@ class UpgradesApp(app_module.App):
group='admin')
note.dismiss(should_dismiss=dismiss)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
# Enable automatic upgrades but only on first install
if not old_version and not cfg.develop:
actions.superuser_run('upgrades', ['enable-auto'])
# Enable automatic upgrades but only on first install
if not old_version and not cfg.develop:
helper.call('post', actions.superuser_run, 'upgrades', ['enable-auto'])
# Update apt preferences whenever on first install and on version
# increment.
actions.superuser_run('upgrades', ['setup'])
# Update apt preferences whenever on first install and on version
# increment.
helper.call('post', actions.superuser_run, 'upgrades', ['setup'])
# When upgrading from a version without first boot wizard for
# backports, assume backports have been requested.
if old_version and old_version < 7:
set_backports_requested(can_activate_backports())
# When upgrading from a version without first boot wizard for backports,
# assume backports have been requested.
if old_version and old_version < 7:
set_backports_requested(can_activate_backports())
# Enable dist upgrade for new installs, and once when upgrading
# from version without flag.
if not old_version or old_version < 8:
set_dist_upgrade_enabled(can_enable_dist_upgrade())
# Enable dist upgrade for new installs, and once when upgrading
# from version without flag.
if not old_version or old_version < 8:
set_dist_upgrade_enabled(can_enable_dist_upgrade())
# Try to setup apt repositories, if needed, if possible, on first install
# and on version increment.
helper.call('post', setup_repositories, None)
# Try to setup apt repositories, if needed, if possible, on first
# install and on version increment.
setup_repositories(None)
def is_enabled():

View File

@ -89,14 +89,14 @@ class UsersApp(app_module.App):
return results
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
actions.superuser_run('users', ['first-setup'])
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
if not old_version:
helper.call('post', actions.superuser_run, 'users', ['first-setup'])
helper.call('post', actions.superuser_run, 'users', ['setup'])
create_group('freedombox-share')
actions.superuser_run('users', ['setup'])
create_group('freedombox-share')
def _diagnose_ldap_entry(search_item):

View File

@ -94,8 +94,7 @@ class WireguardApp(app_module.App):
enabled = super().is_enabled()
return enabled and kvstore.get_default('wireguard-enabled', False)
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
self.enable()

View File

@ -105,6 +105,13 @@ class WordPressApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
actions.superuser_run('wordpress', ['setup'])
if not old_version:
self.enable()
class WordPressBackupRestore(BackupRestore):
"""Component to backup/restore WordPress."""
@ -118,11 +125,3 @@ class WordPressBackupRestore(BackupRestore):
"""Restore database contents."""
super().restore_post(packet)
actions.superuser_run('wordpress', ['restore-database'])
def setup(helper, old_version=None):
"""Install and configure the module."""
app.setup(old_version)
helper.call('post', actions.superuser_run, 'wordpress', ['setup'])
if not old_version:
helper.call('post', app.enable)

View File

@ -88,13 +88,12 @@ class ZophApp(app_module.App):
**manifest.backup)
self.add(backup_restore)
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', actions.superuser_run, 'zoph', ['pre-install'])
app.setup(old_version)
helper.call('post', actions.superuser_run, 'zoph', ['setup'])
helper.call('post', app.enable)
def setup(self, old_version):
"""Install and configure the app."""
actions.superuser_run('zoph', ['pre-install'])
super().setup(old_version)
actions.superuser_run('zoph', ['setup'])
self.enable()
def set_configuration(admin_user=None, enable_osm=None):