From 85b6e00001c1b848c93e559927d38425098d9a42 Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Thu, 5 Dec 2024 12:32:32 +0200 Subject: [PATCH] deluge: Fix app installation on Debian testing Closes: #2322. On Debian stable, mark deluge app as not available because deluge-web is not working in this distribution. - Default deluged configuration directory location changed. I didn't do migration from the old location because deluge app hasn't been working on Debian stable. - Make deluge-web systemd service start after deluged service to prevent Connection Manager popup in deluge-web after system reboot. Tests performed: - On Debian stable: - Deluge app is not installable from the app page. - All functional tests are skipped. - On Debian testing: - All tests pass. - After reboot, deluge-web service started after deluge service and there is no Connection Manager popup in deluge web UI. - Changing torrent download directory works. Signed-off-by: Veiko Aasa [sunil: Add type signature to an overridden method] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/deluge/__init__.py | 19 +++- plinth/modules/deluge/manifest.py | 2 +- plinth/modules/deluge/privileged.py | 7 +- .../modules/deluge/tests/test_functional.py | 88 ++++++------------- 4 files changed, 48 insertions(+), 68 deletions(-) diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py index 9772fcf19..004b30bf6 100644 --- a/plinth/modules/deluge/__init__.py +++ b/plinth/modules/deluge/__init__.py @@ -11,6 +11,7 @@ from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import (Firewall, FirewallLocalProtection) +from plinth.modules.upgrades import get_current_release from plinth.modules.users import add_user_to_share_group from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages @@ -26,12 +27,26 @@ _description = [ SYSTEM_USER = 'debian-deluged' +class DelugePackages(Packages): + """Mark deluge app as not available in Debian Bookworm. + + deluge-web is broken in Debian Bookworm. Related bug report: + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1031593 + """ + + def has_unavailable_packages(self) -> bool | None: + if get_current_release()[1] == 'bookworm': + return True + + return super().has_unavailable_packages() + + class DelugeApp(app_module.App): """FreedomBox app for Deluge.""" app_id = 'deluge' - _version = 8 + _version = 9 def __init__(self) -> None: """Create components for the app.""" @@ -64,7 +79,7 @@ class DelugeApp(app_module.App): allowed_groups=list(groups)) self.add(shortcut) - packages = Packages('packages-deluge', ['deluged', 'deluge-web']) + packages = DelugePackages('packages-deluge', ['deluged', 'deluge-web']) self.add(packages) dropin_configs = DropinConfigs( diff --git a/plinth/modules/deluge/manifest.py b/plinth/modules/deluge/manifest.py index c3d4b0bbf..2f1bd54a6 100644 --- a/plinth/modules/deluge/manifest.py +++ b/plinth/modules/deluge/manifest.py @@ -13,7 +13,7 @@ clients = [{ backup = { 'config': { - 'directories': ['/var/lib/deluged/.config'] + 'directories': ['/var/lib/deluged/config'] }, 'services': ['deluged', 'deluge-web'] } diff --git a/plinth/modules/deluge/privileged.py b/plinth/modules/deluge/privileged.py index 59a6fe891..48dd72ffe 100644 --- a/plinth/modules/deluge/privileged.py +++ b/plinth/modules/deluge/privileged.py @@ -13,10 +13,10 @@ from plinth.actions import privileged from plinth.modules.deluge.utils import Config DELUGED_DEFAULT_FILE = '/etc/default/deluged' -DELUGE_CONF_DIR = pathlib.Path('/var/lib/deluged/.config/deluge/') +DELUGE_CONF_DIR = pathlib.Path('/var/lib/deluged/config/') DELUGE_WEB_SYSTEMD_SERVICE_PATH = '/etc/systemd/system/deluge-web.service' -DELUGE_WEB_SYSTEMD_SERVICE = ''' +DELUGE_WEB_SYSTEMD_SERVICE = f''' # # This file is managed and overwritten by Plinth. If you wish to edit # it, disable Deluge in Plinth, remove this file and manage it manually. @@ -25,9 +25,10 @@ DELUGE_WEB_SYSTEMD_SERVICE = ''' Description=Deluge Web Interface Documentation=man:deluge-web(1) After=network.target +After=deluged.service [Service] -ExecStart=bash -c "/usr/bin/deluge-web --base=deluge $(/usr/bin/deluge-web --version | grep deluge-web | cut -f2 -d' ' | grep -q '^1.' && echo '' || echo '--do-not-daemonize')" +ExecStart=/usr/bin/deluge-web --config {DELUGE_CONF_DIR} --base=deluge --do-not-daemonize Restart=on-failure User=debian-deluged Group=debian-deluged diff --git a/plinth/modules/deluge/tests/test_functional.py b/plinth/modules/deluge/tests/test_functional.py index 5261170fd..d6918fa0a 100644 --- a/plinth/modules/deluge/tests/test_functional.py +++ b/plinth/modules/deluge/tests/test_functional.py @@ -35,14 +35,12 @@ class TestDelugeApp(functional.BaseAppTests): 'nogroupuser') assert not functional.is_available(session_browser, 'deluge') - functional.login(session_browser) - def test_upload_torrent(self, session_browser): """Test uploading a torrent.""" functional.app_enable(session_browser, 'deluge') _remove_all_torrents(session_browser) _upload_sample_torrent(session_browser) - assert _get_number_of_torrents(session_browser) == 1 + assert len(_get_torrents(session_browser)) == 1 @pytest.mark.backups def test_backup_restore(self, session_browser): @@ -55,7 +53,7 @@ class TestDelugeApp(functional.BaseAppTests): _remove_all_torrents(session_browser) functional.backup_restore(session_browser, 'deluge', 'test_deluge') assert functional.service_is_running(session_browser, 'deluge') - assert _get_number_of_torrents(session_browser) == 1 + assert len(_get_torrents(session_browser)) == 1 def _get_active_window_title(browser): @@ -81,49 +79,30 @@ def _ensure_logged_in(browser): # After a backup restore, service may not be available immediately functional.eventually(service_is_available) - time.sleep(1) # Wait for Ext.js application in initialize + functional.eventually(browser.is_element_present_by_id, ['add']) - if _get_active_window_title(browser) != 'Login': - return + def logged_in(): + active_window_title = _get_active_window_title(browser) - browser.find_by_id('_password').first.fill('deluge') - _click_active_window_button(browser, 'Login') + # Change Default Password window appears once. + if active_window_title == 'Change Default Password': + _click_active_window_button(browser, 'No') - assert functional.eventually( - lambda: _get_active_window_title(browser) != 'Login') - functional.eventually(browser.is_element_not_present_by_css, - args=['#add.x-item-disabled'], timeout=0.3) + if active_window_title == 'Login': + browser.find_by_id('_password').first.fill('deluge') + _click_active_window_button(browser, 'Login') + return browser.is_element_not_present_by_css('#add .x-item-disabled') -def _open_connection_manager(browser): - """Open the connection manager dialog if not already open.""" - title = 'Connection Manager' - if _get_active_window_title(browser) == title: - return - - browser.find_by_css('button.x-deluge-connection-manager').first.click() - functional.eventually(lambda: _get_active_window_title(browser) == title) - - -def _ensure_connected(browser): - """Type the connection password if required and start Deluge daemon.""" - _ensure_logged_in(browser) - - # Change Default Password window appears once. - if _get_active_window_title(browser) == 'Change Default Password': - _click_active_window_button(browser, 'No') - - assert functional.eventually(browser.is_element_not_present_by_css, - args=['#add.x-item-disabled']) + functional.eventually(logged_in) def _remove_all_torrents(browser): """Remove all torrents from deluge.""" - _ensure_connected(browser) - - while browser.find_by_css('#torrentGrid .torrent-name'): - browser.find_by_css('#torrentGrid .torrent-name').first.click() + _ensure_logged_in(browser) + for torrent in _get_torrents(browser): + torrent.click() # Click remove toolbar button browser.find_by_id('remove').first.click() @@ -155,9 +134,9 @@ def _click_active_window_button(browser, button_text): def _upload_sample_torrent(browser): """Upload a sample torrent into deluge.""" - _ensure_connected(browser) + _ensure_logged_in(browser) - number_of_torrents = _get_number_of_torrents(browser) + number_of_torrents = len(_get_torrents(browser)) # Click add toolbar button browser.find_by_id('add').first.click() @@ -168,35 +147,20 @@ def _upload_sample_torrent(browser): file_path = os.path.join(os.path.dirname(__file__), 'data', 'sample.torrent') - - if browser.find_by_id('fileUploadForm'): # deluge-web 2.x - browser.attach_file('file', file_path) - else: # deluge-web 1.x - browser.find_by_css('button.x-deluge-add-file').first.click() - - # Add from file window appears - functional.eventually( - lambda: _get_active_window_title(browser) == 'Add from File') - - # Attach file - browser.attach_file('file', file_path) - - # Click Add - _click_active_window_button(browser, 'Add') - - functional.eventually( - lambda: _get_active_window_title(browser) == 'Add Torrents') + browser.attach_file('file', file_path) # Click Add time.sleep(1) _click_active_window_button(browser, 'Add') functional.eventually( - lambda: _get_number_of_torrents(browser) > number_of_torrents) + lambda: len(_get_torrents(browser)) > number_of_torrents) -def _get_number_of_torrents(browser): - """Return the number torrents currently in deluge.""" - _ensure_connected(browser) +def _get_torrents(browser): + """Return list of torrents currently in deluge.""" + _ensure_logged_in(browser) + # wait until torrent list is loaded + functional.eventually(browser.is_element_present_by_css, ['.x-deluge-all']) - return len(browser.find_by_css('#torrentGrid .torrent-name')) + return browser.find_by_css('#torrentGrid .torrent-name')