# SPDX-License-Identifier: AGPL-3.0-or-later """FreedomBox app to configure Nextcloud.""" from django.utils.translation import gettext_lazy as _ from plinth import app as app_module from plinth import frontpage, menu from plinth.config import DropinConfigs from plinth.daemon import Daemon, SharedDaemon from plinth.modules.apache.components import Webserver, diagnose_url from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import (Firewall, FirewallLocalProtection) from plinth.package import Packages from . import manifest, privileged _description = [ _('Nextcloud is a self-hosted productivity platform which provides ' 'private and secure functions for file sharing, collaborative work, ' 'and more. Nextcloud includes the Nextcloud server, client applications ' 'for desktop computers, and mobile clients. The Nextcloud server ' 'provides a well integrated web interface.'), _('All users of FreedomBox can use Nextcloud.'), _('To perform administrative actions, use the ' f'"{privileged.GUI_ADMIN}" user.'), _('You can set a new password in the "Configuration" section below.'), _('Please note, that Nextcloud isn\'t maintained by Debian, which means ' 'security and feature updates are applied independently.') ] class NextcloudApp(app_module.App): """FreedomBox app for Nextcloud.""" app_id = 'nextcloud' _version = 1 configure_when_disabled = False def __init__(self): """Create components for the app.""" super().__init__() info = app_module.Info( app_id=self.app_id, version=self._version, name=_('Nextcloud'), icon_filename='nextcloud', short_description=_('File Storage & Collaboration'), description=_description, manual_page='Nextcloud', clients=manifest.clients) self.add(info) menu_item = menu.Menu('menu-nextcloud', info.name, info.short_description, info.icon_filename, 'nextcloud:index', parent_url_name='apps') self.add(menu_item) shortcut = frontpage.Shortcut('shortcut-nextcloud', info.name, short_description=info.short_description, icon=info.icon_filename, url='/nextcloud/', clients=info.clients, login_required=True) self.add(shortcut) packages = Packages('packages-nextcloud', [ 'podman', 'default-mysql-server', 'python3-iso3166', 'redis-server', 'php-redis' ], conflicts=['libpam-tmpdir'], conflicts_action=Packages.ConflictsAction.REMOVE) self.add(packages) dropin_configs = DropinConfigs('dropin-configs-nextcloud', [ '/etc/apache2/conf-available/nextcloud-freedombox.conf', '/etc/fail2ban/jail.d/nextcloud-freedombox.conf', '/etc/fail2ban/filter.d/nextcloud-freedombox.conf', ]) self.add(dropin_configs) firewall = Firewall('firewall-nextcloud', info.name, ports=['http', 'https'], is_external=True) self.add(firewall) firewall_local_protection = FirewallLocalProtection( 'firewall-local-protection-nextcloud', ['8181']) self.add(firewall_local_protection) webserver = Webserver('webserver-nextcloud', 'nextcloud-freedombox', urls=['https://{host}/nextcloud/login']) self.add(webserver) daemon = Daemon('daemon-nextcloud', 'nextcloud-fbx') self.add(daemon) daemon = Daemon('daemon-nextcloud-timer', 'nextcloud-cron-fbx.timer') self.add(daemon) daemon = SharedDaemon('shared-daemon-podman-auto-update', 'podman-auto-update.timer') self.add(daemon) daemon = SharedDaemon('shared-daemon-nextcloud-redis', 'redis-server', listen_ports=[(6379, 'tcp4')]) self.add(daemon) daemon = SharedDaemon('shared-daemon-nextcloud-mysql', 'mysql') self.add(daemon) backup_restore = NextcloudBackupRestore('backup-restore-nextcloud', **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 uninstall(self): """De-configure and uninstall the app.""" privileged.uninstall() super().uninstall() def diagnose(self): """Run diagnostics and return the results.""" results = super().diagnose() results.append(diagnose_url('docker.com')) return results class NextcloudBackupRestore(BackupRestore): """Component to backup/restore Nextcloud.""" def backup_pre(self, packet): """Save database contents.""" super().backup_pre(packet) privileged.dump_database() def restore_post(self, packet): """Restore database contents.""" super().restore_post(packet) privileged.restore_database()