*: Drop module level app property

module.app property usage is greatly reduced because setup() and force_upgrade()
method are now part of App class instead of at the module level. Remove the
remaining minor cases of usage and drop the property altogether.

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-07-27 11:25:44 -07:00 committed by James Valleroy
parent 0a9514228f
commit 900c0d30b9
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
89 changed files with 151 additions and 200 deletions

View File

@ -552,7 +552,7 @@ def _initialize_module(module_name, module):
cls for _, cls in module_classes if issubclass(cls, App)
]
for app_class in app_classes:
module.app = app_class()
app_class()
except Exception as exception:
logger.exception('Exception while running init for %s: %s', module,
exception)

View File

@ -15,8 +15,6 @@ from plinth.modules.letsencrypt.components import LetsEncrypt
from plinth.package import Packages
from plinth.utils import format_lazy, is_valid_user_name
app = None
class ApacheApp(app_module.App):
"""FreedomBox app for Apache web server."""

View File

@ -32,8 +32,6 @@ _description = [
'hostile local network.'), box_name=_(cfg.box_name))
]
app = None
class AvahiApp(app_module.App):
"""FreedomBox app for Avahi."""

View File

@ -31,8 +31,6 @@ MANIFESTS_FOLDER = '/var/lib/plinth/backups-manifests/'
# session variable name that stores when a backup file should be deleted
SESSION_PATH_VARIABLE = 'fbx-backups-upload-path'
app = None
class BackupsApp(app_module.App):
"""FreedomBox app for backup and restore."""

View File

@ -20,6 +20,7 @@ from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy
from django.views.generic import FormView, TemplateView, View
from plinth import app as app_module
from plinth.errors import PlinthError
from plinth.modules import backups, storage
@ -40,7 +41,7 @@ class IndexView(TemplateView):
def get_context_data(self, **kwargs):
"""Return additional context for rendering the template."""
context = super().get_context_data(**kwargs)
context['app_info'] = backups.app.info
context['app_info'] = app_module.App.get('backups').info
context['repositories'] = [
repository.get_view_content() for repository in get_repositories()
]

View File

@ -32,8 +32,6 @@ _description = [
'their password from the list.'),
]
app = None
PERMISSIONS = {
'read': _('Read a file, if a web link to the file is available'),
'create': _('Create or upload files'),

View File

@ -58,8 +58,6 @@ listen-on-v6 { any; };
};
'''
app = None
class BindApp(app_module.App):
"""FreedomBox app for Bind."""

View File

@ -36,8 +36,6 @@ _description = [
'the app. All users with access can use all the libraries.')
]
app = None
LIBRARY_NAME_PATTERN = r'[a-zA-Z0-9 _-]+'

View File

@ -100,7 +100,7 @@ def test_create_library_invalid_name(rf):
assert response.status_code == 200
@patch('plinth.modules.calibre.app')
@patch('plinth.app.App.get')
def test_delete_library_confirmation_view(_app, rf):
"""Test that deleting library confirmation shows correct name."""
response, _ = make_request(rf.get(''), views.delete_library,
@ -110,7 +110,7 @@ def test_delete_library_confirmation_view(_app, rf):
@patch('plinth.modules.calibre.delete_library')
@patch('plinth.modules.calibre.app')
@patch('plinth.app.App.get')
def test_delete_library(_app, delete_library, rf):
"""Test that deleting a library works."""
response, messages = make_request(rf.post(''), views.delete_library,

View File

@ -12,7 +12,9 @@ from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic.edit import FormView
from plinth import actions, views
from plinth import actions
from plinth import app as app_module
from plinth import views
from plinth.modules import calibre
from . import forms
@ -70,6 +72,6 @@ def delete_library(request, name):
return redirect(reverse_lazy('calibre:index'))
return TemplateResponse(request, 'calibre-delete-library.html', {
'title': calibre.app.info.name,
'title': app_module.App.get('calibre').info.name,
'name': name
})

View File

@ -35,8 +35,6 @@ _description = [
box_name=_(cfg.box_name), users_url=reverse_lazy('users:index')),
]
app = None
class CockpitApp(app_module.App):
"""FreedomBox app for Cockpit."""

View File

@ -34,8 +34,6 @@ FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR,
'freedombox.conf')
ADVANCED_MODE_KEY = 'advanced_mode'
app = None
class ConfigApp(app_module.App):
"""FreedomBox app for basic system configuration."""

View File

@ -38,8 +38,6 @@ _description = [
e_url=reverse_lazy('ejabberd:index')),
]
app = None
logger = logging.getLogger(__name__)

View File

@ -7,6 +7,7 @@ from django.contrib import messages
from django.utils.translation import gettext_lazy as _
import plinth.modules.coturn as coturn
from plinth import app as app_module
from plinth import views
from . import forms
@ -35,7 +36,8 @@ class CoturnAppView(views.AppView):
data = form.cleaned_data
if coturn.get_domain() != data['domain']:
coturn.set_domain(data['domain'])
coturn.app.get_component('letsencrypt-coturn').setup_certificates()
app = app_module.App.get('coturn')
app.get_component('letsencrypt-coturn').setup_certificates()
messages.success(self.request, _('Configuration updated'))
return super().form_valid(form)

View File

@ -20,8 +20,6 @@ _description = [
'in synchronization with servers on the Internet.')
]
app = None
class DateTimeApp(app_module.App):
"""FreedomBox app for date and time if time syncronization is unmanaged."""

View File

@ -24,8 +24,6 @@ _description = [
'change it immediately after enabling this service.')
]
app = None
SYSTEM_USER = 'debian-deluged'

View File

@ -25,8 +25,6 @@ _description = [
'expected.')
]
app = None
logger = logging.Logger(__name__)
running_task = None

View File

@ -27,7 +27,7 @@ def index(request):
return TemplateResponse(
request, 'diagnostics.html', {
'app_info': diagnostics.app.info,
'app_info': App.get('diagnostics').info,
'is_running': is_running,
'results': results,
'refresh_page_sec': 3 if is_running else None

View File

@ -45,8 +45,6 @@ _description = [
'target=\'_blank\'>freedns.afraid.org</a>.'),
]
app = None
class DynamicDNSApp(app_module.App):
"""FreedomBox app for Dynamic DNS."""
@ -221,6 +219,7 @@ def _update_dns_for_domain(domain):
def update_dns(_data):
"""For all configured domains, check and up to date DNS records."""
config = get_config()
app = app_module.App.get('dynamicdns')
if not app.is_enabled():
return

View File

@ -46,8 +46,6 @@ _description = [
logger = logging.getLogger(__name__)
app = None
class EjabberdApp(app_module.App):
"""FreedomBox app for ejabberd."""
@ -162,6 +160,7 @@ def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
"""
del sender # Unused
del kwargs # Unused
app = app_module.App.get('ejabberd')
if app.needs_setup():
return
@ -175,6 +174,7 @@ def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs):
"""Update ejabberd config after hostname change."""
del sender # Unused
del kwargs # Unused
app = app_module.App.get('ejabberd')
if app.needs_setup():
return
@ -187,6 +187,7 @@ def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs):
def get_domains():
"""Return the list of domains configured for ejabberd.
"""
app = app_module.App.get('ejabberd')
if app.needs_setup():
return []
@ -197,6 +198,7 @@ def get_domains():
def on_domain_added(sender, domain_type, name='', description='',
services=None, **kwargs):
"""Update ejabberd config after domain name change."""
app = app_module.App.get('ejabberd')
if not name or app.needs_setup():
return
@ -208,6 +210,7 @@ def on_domain_added(sender, domain_type, name='', description='',
def set_domains(domains):
"""Configure ejabberd to have this list of domains."""
app = app_module.App.get('ejabberd')
if not domains or app.needs_setup():
return
@ -220,6 +223,7 @@ def set_domains(domains):
def update_turn_configuration(config: TurnConfiguration, managed=True,
force=False):
"""Update ejabberd's STUN/TURN server configuration."""
app = app_module.App.get('ejabberd')
if not force and app.needs_setup():
return

View File

@ -5,7 +5,7 @@ Test module for ejabberd STUN/TURN configuration.
import pathlib
import shutil
from unittest.mock import patch
from unittest.mock import Mock, patch
import pytest
@ -59,7 +59,9 @@ def fixture_test_configuration(call_action, conf_file):
The module state is patched to be 'up-to-date'.
"""
with patch('plinth.actions.superuser_run',
call_action), patch('plinth.modules.ejabberd.app') as app:
call_action), patch('plinth.app.App.get') as app_get:
app = Mock()
app_get.return_value = app
app.needs_setup.return_value = False
yield

View File

@ -44,7 +44,6 @@ _description = [
'uninstalled.')
]
app = None
logger = logging.getLogger(__name__)
@ -215,6 +214,7 @@ def _get_first_admin():
def on_domain_added(sender, domain_type, name, description='', services=None,
**kwargs):
"""Handle addition of a new domain."""
app = plinth.app.App.get('email')
if app.needs_setup():
return
@ -223,6 +223,7 @@ def on_domain_added(sender, domain_type, name, description='', services=None,
def on_domain_removed(sender, domain_type, name='', **kwargs):
"""Handle removal of a domain."""
app = plinth.app.App.get('email')
if app.needs_setup():
return

View File

@ -31,8 +31,6 @@ _description = [
_port_details = {}
app = None
logger = logging.getLogger(__name__)
_DBUS_NAME = 'org.fedoraproject.FirewallD1'

View File

@ -34,8 +34,6 @@ _description = [
'<a href="https://git-scm.com/docs/gittutorial">Git tutorial</a>.')
]
app = None
class GitwebApp(app_module.App):
"""FreedomBox app for Gitweb."""
@ -160,7 +158,7 @@ class GitwebBackupRestore(BackupRestore):
def restore_post(self, packet):
"""Update access after restoration of backups."""
super().restore_post(packet)
app.update_service_access()
self.app.update_service_access()
def repo_exists(name):

View File

@ -4,7 +4,7 @@ Tests for gitweb views.
"""
import json
from unittest.mock import patch
from unittest.mock import Mock, patch
import pytest
from django import urls
@ -70,7 +70,7 @@ def action_run(*args, **kwargs):
def gitweb_patch():
"""Patch gitweb."""
with patch('plinth.modules.gitweb.get_repo_list') as get_repo_list, \
patch('plinth.modules.gitweb.app') as gitweb_app, \
patch('plinth.app.App.get') as app_get, \
patch('plinth.actions.superuser_run', side_effect=action_run), \
patch('plinth.actions.run', side_effect=action_run):
get_repo_list.return_value = [{
@ -78,7 +78,9 @@ def gitweb_patch():
}, {
'name': EXISTING_REPOS[1]['name']
}]
gitweb_app.update_service_access.return_value = None
app = Mock()
app_get.return_value = app
app.update_service_access.return_value = None
yield

View File

@ -12,7 +12,9 @@ from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic import FormView
from plinth import actions, views
from plinth import actions
from plinth import app as app_module
from plinth import views
from plinth.errors import ActionError
from plinth.modules import gitweb
@ -69,7 +71,7 @@ class CreateRepoView(SuccessMessageMixin, FormView):
_('An error occurred while creating the repository.'),
error_text))
else:
gitweb.app.update_service_access()
app_module.App.get('gitweb').update_service_access()
return super().form_valid(form)
@ -115,7 +117,7 @@ class EditRepoView(SuccessMessageMixin, FormView):
except ActionError:
messages.error(self.request,
_('An error occurred during configuration.'))
gitweb.app.update_service_access()
app_module.App.get('gitweb').update_service_access()
return super().form_valid(form)
@ -132,6 +134,7 @@ def delete(request, name):
else:
raise Http404
app = app_module.App.get('gitweb')
if request.method == 'POST':
try:
gitweb.delete_repo(name)
@ -142,11 +145,11 @@ def delete(request, name):
_('Could not delete {name}: {error}').format(
name=name, error=error),
)
gitweb.app.update_service_access()
app.update_service_access()
return redirect(reverse_lazy('gitweb:index'))
return TemplateResponse(request, 'gitweb_delete.html', {
'title': gitweb.app.info.name,
'title': app.info.name,
'name': name
})

View File

@ -14,8 +14,6 @@ from plinth import cfg, menu, web_server
logger = logging.getLogger(__name__)
app = None
class HelpApp(app_module.App):
"""FreedomBox app for showing help."""

View File

@ -35,8 +35,6 @@ tunnels_to_manage = {
'Irc2P': 'i2p-irc-freedombox'
}
app = None
class I2PApp(app_module.App):
"""FreedomBox app for I2P."""

View File

@ -31,8 +31,6 @@ _description = [
users_url=reverse_lazy('users:index'))
]
app = None
class IkiwikiApp(app_module.App):
"""FreedomBox app for Ikiwiki."""

View File

@ -9,20 +9,23 @@ from django.template.response import TemplateResponse
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from plinth import actions, views
from plinth.modules import ikiwiki
from plinth import actions
from plinth import app as app_module
from plinth import views
from .forms import IkiwikiCreateForm
class IkiwikiAppView(views.AppView):
"""Serve configuration page."""
app_id = 'ikiwiki'
template_name = 'ikiwiki_configure.html'
def get_context_data(self, **kwargs):
"""Return the context data for rendering the template view."""
sites = ikiwiki.app.refresh_sites()
app = app_module.App.get('ikiwiki')
sites = app.refresh_sites()
sites = [name for name in sites if name != '']
context = super().get_context_data(**kwargs)
@ -34,6 +37,7 @@ def create(request):
"""Form to create a wiki or blog."""
form = None
app = app_module.App.get('ikiwiki')
if request.method == 'POST':
form = IkiwikiCreateForm(request.POST, prefix='ikiwiki')
if form.is_valid():
@ -46,16 +50,16 @@ def create(request):
form.cleaned_data['admin_name'],
form.cleaned_data['admin_password'])
ikiwiki.app.refresh_sites()
if ikiwiki.app.is_enabled():
ikiwiki.app.set_enabled(True)
app.refresh_sites()
if app.is_enabled():
app.set_enabled(True)
return redirect(reverse_lazy('ikiwiki:index'))
else:
form = IkiwikiCreateForm(prefix='ikiwiki')
return TemplateResponse(request, 'ikiwiki_create.html', {
'title': ikiwiki.app.info.name,
'title': app.info.name,
'form': form
})
@ -92,11 +96,12 @@ def delete(request, name):
On GET, display a confirmation page.
On POST, delete the wiki/blog.
"""
title = ikiwiki.app.components['shortcut-ikiwiki-' + name].name
app = app_module.App.get('ikiwiki')
title = app.components['shortcut-ikiwiki-' + name].name
if request.method == 'POST':
try:
actions.superuser_run('ikiwiki', ['delete', '--name', name])
ikiwiki.app.remove_shortcut(name)
app.remove_shortcut(name)
messages.success(request,
_('{title} deleted.').format(title=title))
except actions.ActionError as error:
@ -108,6 +113,6 @@ def delete(request, name):
return redirect(reverse_lazy('ikiwiki:index'))
return TemplateResponse(request, 'ikiwiki_delete.html', {
'title': ikiwiki.app.info.name,
'title': app.info.name,
'name': title
})

View File

@ -26,8 +26,6 @@ _description = [
box_name=_(cfg.box_name)),
]
app = None
class InfinotedApp(app_module.App):
"""FreedomBox app for infinoted."""

View File

@ -27,8 +27,6 @@ _description = [
'use Janus.'), coturn_url=reverse_lazy('coturn:index')),
]
app = None
class JanusApp(app_module.App):
"""FreedomBox app for janus."""

View File

@ -5,7 +5,7 @@ Views for the Janus app.
from django.views.generic import TemplateView
from plinth.modules import janus
from plinth import app as app_module
class JanusRoomView(TemplateView):
@ -14,7 +14,8 @@ class JanusRoomView(TemplateView):
def get_context_data(self, *args, **kwargs):
"""Add user's TURN server information to view context."""
config = janus.app.get_component('turn-janus').get_configuration()
app = app_module.App.get('janus')
config = app.get_component('turn-janus').get_configuration()
context = super().get_context_data(*args, **kwargs)
context['user_turn_config'] = config.to_json()
return context

View File

@ -24,8 +24,6 @@ _description = [
logger = logging.getLogger(__name__)
app = None
class JSXCApp(app_module.App):
"""FreedomBox app for JSXC."""

View File

@ -42,8 +42,6 @@ LIVE_DIRECTORY = '/etc/letsencrypt/live/'
CERTIFICATE_CHECK_DELAY = 120
logger = logging.getLogger(__name__)
app = None
class LetsEncryptApp(app_module.App):
"""FreedomBox app for Let's Encrypt."""

View File

@ -12,6 +12,7 @@ from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.decorators.http import require_POST
from plinth import app as app_module
from plinth.errors import ActionError
from plinth.modules import letsencrypt
@ -21,13 +22,14 @@ logger = logging.getLogger(__name__)
def index(request):
"""Serve configuration page."""
status = letsencrypt.get_status()
app = app_module.App.get('letsencrypt')
return TemplateResponse(
request, 'letsencrypt.html', {
'app_id': 'letsencrypt',
'app_info': letsencrypt.app.info,
'app_info': app.info,
'status': status,
'has_diagnostics': True,
'is_enabled': letsencrypt.app.is_enabled(),
'is_enabled': app.is_enabled(),
})

View File

@ -51,8 +51,6 @@ REGISTRATION_CONF_PATH = CONF_DIR + 'freedombox-registration.yaml'
TURN_CONF_PATH = CONF_DIR + 'freedombox-turn.yaml'
OVERRIDDEN_TURN_CONF_PATH = CONF_DIR + 'turn.yaml'
app = None
class MatrixSynapseApp(app_module.App):
"""FreedomBox app for Matrix Synapse."""
@ -158,6 +156,7 @@ def upgrade():
def setup_domain(domain_name):
"""Configure a domain name for matrixsynapse."""
app = app_module.App.get('matrixsynapse')
app.get_component('letsencrypt-matrixsynapse').setup_certificates(
[domain_name])
actions.superuser_run('matrixsynapse',
@ -212,6 +211,7 @@ def get_public_registration_status() -> bool:
def get_certificate_status():
"""Return the status of certificate for the configured domain."""
app = app_module.App.get('matrixsynapse')
status = app.get_component('letsencrypt-matrixsynapse').get_status()
if not status:
return 'no-domains'
@ -222,6 +222,7 @@ def get_certificate_status():
def update_turn_configuration(config: TurnConfiguration, managed=True,
force=False):
"""Update the STUN/TURN server configuration."""
app = app_module.App.get('matrixsynapse')
if not force and app.needs_setup():
return

View File

@ -3,7 +3,7 @@
Test module for Matrix Synapse STUN/TURN configuration.
"""
from unittest.mock import patch
from unittest.mock import patch, Mock
import pytest
@ -51,7 +51,9 @@ def fixture_test_configuration(call_action, managed_turn_conf_file,
overridden_turn_conf_file),
patch('plinth.modules.matrixsynapse.is_setup', return_value=True),
patch('plinth.actions.superuser_run', call_action),
patch('plinth.modules.matrixsynapse.app') as app):
patch('plinth.app.App.get') as app_get):
app = Mock()
app_get.return_value = app
app.needs_setup.return_value = False
yield

View File

@ -10,6 +10,7 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import FormView
from plinth import actions
from plinth import app as app_module
from plinth.forms import DomainSelectionForm
from plinth.modules import matrixsynapse, names
from plinth.modules.coturn.components import TurnConfiguration
@ -33,9 +34,10 @@ class SetupView(FormView):
def get_context_data(self, *args, **kwargs):
"""Provide context data to the template."""
context = super().get_context_data(**kwargs)
app = app_module.App.get('matrixsynapse')
context['title'] = matrixsynapse.app.info.name
context['app_info'] = matrixsynapse.app.info
context['title'] = app.info.name
context['app_info'] = app.info
context['domain_names'] = names.components.DomainName.list_names(
'matrix-synapse-plinth')

View File

@ -34,8 +34,6 @@ _description = [
'logged in can make changes to the content.')
]
app = None
STATIC_CONFIG_FILE = '/etc/mediawiki/FreedomBoxStaticSettings.php'
USER_CONFIG_FILE = '/etc/mediawiki/FreedomBoxSettings.php'

View File

@ -8,7 +8,9 @@ import logging
from django.contrib import messages
from django.utils.translation import gettext as _
from plinth import actions, views
from plinth import actions
from plinth import app as app_module
from plinth import views
from plinth.errors import ActionError
from plinth.modules import mediawiki
@ -87,7 +89,8 @@ class MediaWikiAppView(views.AppView):
actions.superuser_run('mediawiki', ['private-mode', 'disable'])
messages.success(self.request, _('Private mode disabled'))
shortcut = mediawiki.app.get_component('shortcut-mediawiki')
app = app_module.App.get('mediawiki')
shortcut = app.get_component('shortcut-mediawiki')
shortcut.login_required = new_config['enable_private_mode']
if is_changed('default_skin'):

View File

@ -42,8 +42,6 @@ _description = [
CONFIG_FILE = '/etc/minetest/minetest.conf'
AUG_PATH = '/files' + CONFIG_FILE + '/.anon'
app = None
class MinetestApp(app_module.App):
"""FreedomBox app for Minetest."""

View File

@ -4,8 +4,9 @@ FreedomBox app to configure minidlna.
"""
from django.utils.translation import gettext_lazy as _
import plinth.app as app_module
from plinth import actions, frontpage, menu
from plinth import actions
from plinth import app as app_module
from plinth import frontpage, menu
from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.backups.components import BackupRestore
@ -27,8 +28,6 @@ _description = [
'such as PS3 and Xbox 360) or applications such as totem and Kodi.')
]
app = None
class MiniDLNAApp(app_module.App):
"""Freedombox app managing miniDlna"""

View File

@ -29,8 +29,6 @@ _description = [
'from your desktop and mobile devices are available.')
]
app = None
class MumbleApp(app_module.App):
"""FreedomBox app for Mumble."""
@ -100,7 +98,7 @@ class MumbleApp(app_module.App):
if not old_version:
self.enable()
app.get_component('letsencrypt-mumble').setup_certificates()
self.get_component('letsencrypt-mumble').setup_certificates()
def force_upgrade(self, packages):
"""Force upgrade mumble-server to resolve conffile prompts."""

View File

@ -6,6 +6,7 @@ Views for mumble app.
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
from plinth import app as app_module
from plinth.modules import mumble
from plinth.modules.mumble.forms import MumbleForm
from plinth.views import AppView
@ -31,7 +32,8 @@ class MumbleAppView(AppView):
if mumble.get_domain() != new_config['domain']:
privileged.set_domain(new_config['domain'])
mumble.app.get_component('letsencrypt-mumble').setup_certificates()
app = app_module.App.get('mumble')
app.get_component('letsencrypt-mumble').setup_certificates()
messages.success(self.request, _('Configuration updated'))
password = new_config.get('super_user_password')

View File

@ -26,8 +26,6 @@ _description = [
'connections through the given name.'), box_name=(cfg.box_name))
]
app = None
class NamesApp(app_module.App):
"""FreedomBox app for names."""

View File

@ -5,7 +5,7 @@ FreedomBox app for name services.
from django.template.response import TemplateResponse
from plinth.modules import names
from plinth import app as app_module
from . import components
@ -15,7 +15,7 @@ def index(request):
status = get_status()
return TemplateResponse(request, 'names.html', {
'app_info': names.app.info,
'app_info': app_module.App.get('names').info,
'status': status
})

View File

@ -40,8 +40,6 @@ _description = [
logger = Logger(__name__)
app = None
class NetworksApp(app_module.App):
"""FreedomBox app for Networks."""

View File

@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy
from django.views.decorators.http import require_POST
from django.views.generic.edit import FormView
from plinth import app as app_module
from plinth import network
from plinth.modules import first_boot, networks
@ -123,7 +124,7 @@ def index(request):
return TemplateResponse(
request, 'networks_configuration.html', {
'app_id': 'networks',
'app_info': networks.app.info,
'app_info': app_module.App.get('networks').info,
'title': _('Network Connections'),
'has_diagnostics': True,
'is_enabled': True,

View File

@ -31,8 +31,6 @@ _description = [
'for added security and anonymity.'), box_name=_(cfg.box_name))
]
app = None
SERVER_CONFIGURATION_FILE = '/etc/openvpn/server/freedombox.conf'

View File

@ -10,6 +10,7 @@ from django.shortcuts import redirect
from django.views.decorators.http import require_POST
from plinth import actions
from plinth import app as app_module
from plinth.modules import config, openvpn
from plinth.views import AppView
@ -37,7 +38,7 @@ def setup(_):
if not openvpn.is_setup():
actions.superuser_run('openvpn', ['setup'], run_in_background=True)
openvpn.app.enable()
app_module.App.get('openvpn').enable()
return redirect('openvpn:index')

View File

@ -42,8 +42,6 @@ _description = [
box_name=_(cfg.box_name))
]
app = None
class PagekiteApp(app_module.App):
"""FreedomBox app for Pagekite."""

View File

@ -7,6 +7,7 @@ import os
from django.utils.translation import gettext_lazy as _
from plinth import actions
from plinth import app as app_module
from plinth.signals import domain_added, domain_removed
LOGGER = logging.getLogger(__name__)
@ -172,8 +173,7 @@ def update_names_module(is_enabled=None):
if is_enabled is False:
return
from plinth.modules.pagekite import app
if is_enabled is None and not app.is_enabled():
if is_enabled is None and not app_module.App.get('pagekite').is_enabled():
return
config = get_config()

View File

@ -24,8 +24,6 @@ _description = [
'viewed using the Cockpit app.'),
]
app = None
class PerformanceApp(app_module.App):
"""FreedomBox app for Performance."""

View File

@ -13,8 +13,6 @@ from . import manifest
_description = [_('Restart or shut down the system.')]
app = None
class PowerApp(app_module.App):
"""FreedomBox app for power controls."""

View File

@ -8,16 +8,18 @@ from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.urls import reverse
from plinth import actions, package
from plinth.modules import power
from plinth import actions
from plinth import app as app_module
from plinth import package
def index(request):
"""Serve power controls page."""
app = app_module.App.get('power')
return TemplateResponse(
request, 'power.html', {
'title': power.app.info.name,
'app_info': power.app.info,
'title': app.info.name,
'app_info': app.info,
'pkg_manager_is_busy': package.is_package_manager_busy()
})
@ -30,12 +32,13 @@ def restart(request):
actions.superuser_run('power', ['restart'], run_in_background=True)
return redirect(reverse('apps'))
app = app_module.App.get('power')
form = Form(prefix='power')
return TemplateResponse(
request, 'power_restart.html', {
'title': power.app.info.name,
'title': app.info.name,
'form': form,
'manual_page': power.app.info.manual_page,
'manual_page': app.info.manual_page,
'pkg_manager_is_busy': package.is_package_manager_busy()
})
@ -48,11 +51,12 @@ def shutdown(request):
actions.superuser_run('power', ['shutdown'], run_in_background=True)
return redirect(reverse('apps'))
app = app_module.App.get('power')
form = Form(prefix='power')
return TemplateResponse(
request, 'power_shutdown.html', {
'title': power.app.info.name,
'title': app.info.name,
'form': form,
'manual_page': power.app.info.manual_page,
'manual_page': app.info.manual_page,
'pkg_manager_is_busy': package.is_package_manager_busy()
})

View File

@ -35,8 +35,6 @@ _description = [
box_name=_(cfg.box_name)),
]
app = None
class PrivoxyApp(app_module.App):
"""FreedomBox app for Privoxy."""

View File

@ -38,8 +38,6 @@ _description = [
'are available.'),
]
app = None
class QuasselApp(app_module.App):
"""FreedomBox app for Quassel."""

View File

@ -3,6 +3,7 @@
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
from plinth import app as app_module
from plinth.forms import TLSDomainForm
from plinth.modules import quassel
from plinth.views import AppView
@ -23,8 +24,8 @@ class QuasselAppView(AppView):
data = form.cleaned_data
if quassel.get_domain() != data['domain']:
quassel.set_domain(data['domain'])
quassel.app.get_component(
'letsencrypt-quassel').setup_certificates()
app = app_module.App.get('quassel')
app.get_component('letsencrypt-quassel').setup_certificates()
messages.success(self.request, _('Configuration updated'))
return super().form_valid(form)

View File

@ -37,8 +37,6 @@ logger = logging.getLogger(__name__)
CONFIG_FILE = '/etc/radicale/config'
app = None
class RadicaleApp(app_module.App):
"""FreedomBox app for Radicale."""

View File

@ -33,8 +33,6 @@ _description = [
'>https://www.google.com/settings/security/lesssecureapps</a>).'),
]
app = None
class RoundcubeApp(app_module.App):
"""FreedomBox app for Roundcube."""

View File

@ -30,8 +30,6 @@ _description = [
ttrss_url=reverse_lazy('ttrss:index'), box_name=cfg.box_name),
]
app = None
class RSSBridgeApp(app_module.App):
"""FreedomBox app for RSS-Bridge."""

View File

@ -39,8 +39,6 @@ _description = [
'own private space.'),
]
app = None
class SambaApp(app_module.App):
"""FreedomBox app for Samba file sharing."""

View File

@ -25,8 +25,6 @@ _description = [
'It stores no cookies by default.')
]
app = None
class SearxApp(app_module.App):
"""FreedomBox app for Searx."""
@ -131,6 +129,7 @@ def is_public_access_enabled():
def enable_public_access():
"""Allow Searx app to be accessed by anyone with access."""
actions.superuser_run('searx', ['enable-public-access'])
app = app_module.App.get('searx')
app.get_component('webserver-searx-auth').disable()
app.set_shortcut_login_required(False)
@ -138,5 +137,6 @@ def enable_public_access():
def disable_public_access():
"""Allow Searx app to be accessed by logged-in users only."""
actions.superuser_run('searx', ['disable-public-access'])
app = app_module.App.get('searx')
app.get_component('webserver-searx-auth').enable()
app.set_shortcut_login_required(True)

View File

@ -6,7 +6,9 @@ Django views for Searx.
from django.contrib import messages
from django.utils.translation import gettext as _
from plinth import actions, views
from plinth import actions
from plinth import app as app_module
from plinth import views
from plinth.errors import ActionError
from plinth.modules import searx
@ -23,7 +25,7 @@ class SearxAppView(views.AppView):
initial = super().get_initial()
initial['safe_search'] = searx.get_safe_search_setting()
initial['public_access'] = searx.is_public_access_enabled() and \
searx.app.is_enabled()
app_module.App.get('searx').is_enabled()
return initial
def form_valid(self, form):

View File

@ -24,8 +24,6 @@ ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx plinth (admin) (sudo):ALL'
OLD_ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx (admin) (sudo):ALL'
ACCESS_CONF_SNIPPETS = [OLD_ACCESS_CONF_SNIPPET, ACCESS_CONF_SNIPPET]
app = None
class SecurityApp(app_module.App):
"""FreedomBox app for security."""

View File

@ -8,6 +8,7 @@ from django.template.response import TemplateResponse
from django.utils.translation import gettext as _
from plinth import action_utils, actions
from plinth import app as app_module
from plinth.modules import security
from plinth.modules.upgrades import is_backports_requested
@ -31,7 +32,7 @@ def index(request):
return TemplateResponse(
request, 'security.html', {
'app_info': security.app.info,
'app_info': app_module.App.get('security').info,
'form': form,
'is_backports_requested': is_backports_requested(),
})

View File

@ -20,8 +20,6 @@ _description = [
'need to setup on the initial visit.'),
]
app = None
class ShaarliApp(app_module.App):
"""FreedomBox app for Shaarli."""

View File

@ -31,8 +31,6 @@ _description = [
'device, browser or application to http://freedombox_address:1080/')
]
app = None
class ShadowsocksApp(app_module.App):
"""FreedomBox app for Shadowsocks."""

View File

@ -22,8 +22,6 @@ _description = [
box_name=_(cfg.box_name))
]
app = None
class SharingApp(app_module.App):
"""FreedomBox app for sharing files."""

View File

@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_POST
from django.views.generic import FormView, TemplateView
from plinth import app as app_module
from plinth.modules import sharing
from .forms import AddShareForm
@ -24,8 +25,9 @@ class IndexView(TemplateView):
def get_context_data(self, **kwargs):
"""Return additional context for rendering the template."""
context = super().get_context_data(**kwargs)
context['title'] = sharing.app.info.name
context['app_info'] = sharing.app.info
app = app_module.App.get('sharing')
context['title'] = app.info.name
context['app_info'] = app.info
context['shares'] = sharing.list_shares()
return context

View File

@ -36,8 +36,6 @@ DEFAULT_FILE = '/etc/default/snapper'
fs_types_supported = ['btrfs']
app = None
class SnapshotApp(app_module.App):
"""FreedomBox app for snapshots."""

View File

@ -15,6 +15,7 @@ from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy
from plinth import actions
from plinth import app as app_module
from plinth.errors import ActionError
from plinth.modules import snapshot as snapshot_module
from plinth.modules import storage
@ -43,9 +44,10 @@ subsubmenu = [
def not_supported_view(request):
"""Show that snapshots are not supported on the system."""
app = app_module.App.get('snapshot')
template_data = {
'app_info': snapshot_module.app.info,
'title': snapshot_module.app.info.name,
'app_info': app.info,
'title': app.info.name,
'fs_type': storage.get_filesystem_type(),
'fs_types_supported': snapshot_module.fs_types_supported,
}
@ -68,10 +70,11 @@ def index(request):
else:
form = SnapshotForm(initial=status)
app = app_module.App.get('snapshot')
return TemplateResponse(
request, 'snapshot.html', {
'app_info': snapshot_module.app.info,
'title': snapshot_module.app.info.name,
'app_info': app.info,
'title': app.info.name,
'subsubmenu': subsubmenu,
'form': form
})
@ -103,10 +106,11 @@ def manage(request):
if not snapshot['is_default'] and not snapshot['is_active']
])
app = app_module.App.get('snapshot')
return TemplateResponse(
request, 'snapshot_manage.html', {
'title': snapshot_module.app.info.name,
'app_info': snapshot_module.app.info,
'title': app.info.name,
'app_info': app.info,
'snapshots': snapshots,
'has_deletable_snapshots': has_deletable_snapshots,
'subsubmenu': subsubmenu,

View File

@ -26,8 +26,6 @@ _description = [
'using such connections.')
]
app = None
class SSHApp(app_module.App):
"""FreedomBox app for SSH."""

View File

@ -9,8 +9,6 @@ from plinth import actions
from plinth import app as app_module
from plinth.package import Packages
app = None
class SSOApp(app_module.App):
"""FreedomBox app for single sign on."""

View File

@ -31,8 +31,6 @@ _description = [
logger = logging.getLogger(__name__)
app = None
class StorageApp(app_module.App):
"""FreedomBox app for storage."""

View File

@ -37,8 +37,6 @@ _description = [
SYSTEM_USER = 'syncthing'
app = None
class SyncthingApp(app_module.App):
"""FreedomBox app for Syncthing."""

View File

@ -35,8 +35,6 @@ _description = [
'networks on TCP port 9050.'), box_name=_(cfg.box_name))
]
app = None
class TorApp(app_module.App):
"""FreedomBox app for Tor."""
@ -97,7 +95,7 @@ class TorApp(app_module.App):
def post_init(self):
"""Perform post initialization operations."""
# Register hidden service name with Name Services module.
if (not app.needs_setup() and self.is_enabled()
if (not self.needs_setup() and self.is_enabled()
and app_is_running(self)):
status = utils.get_status(initialized=False)
hostname = status['hs_hostname']

View File

@ -13,6 +13,7 @@ from plinth.modules.tor import forms, utils
class TestTor:
"""Test cases for testing the Tor module."""
@staticmethod
@pytest.mark.usefixtures('needs_root')
def test_is_apt_transport_tor_enabled():
@ -22,9 +23,9 @@ class TestTor:
utils.is_apt_transport_tor_enabled()
@staticmethod
@patch('plinth.modules.tor.app')
@patch('plinth.app.App.get')
@pytest.mark.usefixtures('needs_root', 'load_cfg')
def test_get_status(_app):
def test_get_status(_app_get):
"""Test that get_status does not raise any unhandled exceptions.
This should work regardless of whether tor is installed, or
@ -35,6 +36,7 @@ class TestTor:
class TestTorForm:
"""Test whether Tor configration form works."""
@staticmethod
def test_bridge_validator():
"""Test upstream bridges' form field validator."""

View File

@ -10,8 +10,8 @@ import json
import augeas
from plinth import actions
from plinth import app as app_module
from plinth.daemon import app_is_running
from plinth.modules import tor
from plinth.modules.names.components import DomainName
APT_SOURCES_URI_PATHS = ('/files/etc/apt/sources.list/*/uri',
@ -42,9 +42,10 @@ def get_status(initialized=True):
or status['bridge_relay_enabled']
}
app = app_module.App.get('tor')
return {
'enabled': tor.app.is_enabled() if initialized else False,
'is_running': app_is_running(tor.app) if initialized else False,
'enabled': app.is_enabled() if initialized else False,
'is_running': app_is_running(app) if initialized else False,
'use_upstream_bridges': status['use_upstream_bridges'],
'upstream_bridges': status['upstream_bridges'],
'relay_enabled': status['relay_enabled'],

View File

@ -7,6 +7,7 @@ from django.template.response import TemplateResponse
from django.utils.translation import gettext as _
from plinth import actions
from plinth import app as app_module
from plinth.errors import ActionError
from plinth.modules import tor
from plinth.modules.firewall.components import (Firewall,
@ -36,18 +37,19 @@ def index(request):
else:
form = TorForm(initial=status, prefix='tor')
app = app_module.App.get('tor')
return TemplateResponse(
request, 'tor.html', {
'app_id': 'tor',
'app_info': tor.app.info,
'app_info': app.info,
'status': status,
'config_running': bool(config_process),
'form': form,
'firewall': tor.app.get_components_of_type(Firewall),
'firewall': app.get_components_of_type(Firewall),
'has_diagnostics': True,
'is_enabled': status['enabled'],
'is_running': status['is_running'],
'port_forwarding_info': get_port_forwarding_info(tor.app),
'port_forwarding_info': get_port_forwarding_info(app),
'refresh_page_sec': 3 if bool(config_process) else None,
})
@ -116,10 +118,11 @@ def __apply_changes(request, old_status, new_status):
arg_value = 'enable' if new_status['enabled'] else 'disable'
arguments.extend(['--service', arg_value])
# XXX: Perform app enable/disable within the background process
app = app_module.App.get('tor')
if new_status['enabled']:
tor.app.enable()
app.enable()
else:
tor.app.disable()
app.disable()
config_process = actions.superuser_run('tor',
['configure'] + arguments,

View File

@ -42,8 +42,6 @@ _description = [
sharing_url=reverse_lazy('sharing:index'))
]
app = None
SYSTEM_USER = 'debian-transmission'

View File

@ -33,8 +33,6 @@ _description = [
'the URL <a href="/tt-rss-app/">/tt-rss-app</a> for connecting.'))
]
app = None
class TTRSSApp(app_module.App):
"""FreedomBox app for TT-RSS."""

View File

@ -44,8 +44,6 @@ _description = [
'unavailable briefly.')
]
app = None
BACKPORTS_REQUESTED_KEY = 'upgrades_backports_requested'
DIST_UPGRADE_ENABLED_KEY = 'upgrades_dist_upgrade_enabled'

View File

@ -37,8 +37,6 @@ _description = [
box_name=_(cfg.box_name))
]
app = None
class UsersApp(app_module.App):
"""FreedomBox app for users and groups management."""

View File

@ -29,8 +29,6 @@ _description = [
box_name=_(cfg.box_name))
]
app = None
SERVER_INTERFACE = 'wg0'

View File

@ -40,8 +40,6 @@ _description = [
'be installed and upgraded at your own risk.'),
]
app = None
class WordPressApp(app_module.App):
"""FreedomBox app for WordPress."""

View File

@ -40,8 +40,6 @@ _description = [
box_name=_(cfg.box_name))
]
app = None
class ZophApp(app_module.App):
"""FreedomBox app for Zoph."""

View File

@ -12,6 +12,7 @@ from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic import TemplateView
from plinth import app as app_module
from plinth import views
from plinth.errors import ActionError
from plinth.modules import zoph
@ -29,8 +30,9 @@ class SetupView(TemplateView):
def get_context_data(self, *args, **kwargs):
"""Provide context data to the template."""
context = super().get_context_data(**kwargs)
context['title'] = zoph.app.info.name
context['app_info'] = zoph.app.info
app = app_module.App.get('zoph')
context['title'] = app.info.name
context['app_info'] = app.info
return context
def post(self, _request, *args, **kwargs):