From 743b7bd163c8ee9f00d9397113ac9dff0a379d45 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 8 Nov 2025 07:09:09 -0800 Subject: [PATCH] ttrss: Remove app not available in Trixie Tests: - Running 'make build install' remove the module loading include file for ttrss. - TT-RSS is no longer available in apps page. - Installing Tor works. Onion header is set correctly. Re-running app setup works. - RSS Bridge's description is updated as expected. Links work. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- Makefile | 3 +- debian/copyright | 9 - plinth/modules/rssbridge/__init__.py | 5 +- plinth/modules/tor/privileged.py | 2 +- plinth/modules/ttrss/__init__.py | 153 ----------------- .../system/tt-rss.service.d/freedombox.conf | 35 ---- .../apache2/conf-available/tt-rss-plinth.conf | 39 ----- .../share/freedombox/modules-enabled/ttrss | 1 - plinth/modules/ttrss/manifest.py | 55 ------ plinth/modules/ttrss/privileged.py | 160 ------------------ plinth/modules/ttrss/static/icons/ttrss.png | Bin 5361 -> 0 bytes plinth/modules/ttrss/static/icons/ttrss.svg | 88 ---------- plinth/modules/ttrss/tests/__init__.py | 0 plinth/modules/ttrss/tests/test_functional.py | 103 ----------- plinth/modules/ttrss/urls.py | 10 -- plinth/modules/ttrss/views.py | 33 ---- .../upgrades/tests/test_distupgrade.py | 4 +- plinth/tests/functional/__init__.py | 1 - 18 files changed, 8 insertions(+), 693 deletions(-) delete mode 100644 plinth/modules/ttrss/__init__.py delete mode 100644 plinth/modules/ttrss/data/usr/lib/systemd/system/tt-rss.service.d/freedombox.conf delete mode 100644 plinth/modules/ttrss/data/usr/share/freedombox/etc/apache2/conf-available/tt-rss-plinth.conf delete mode 100644 plinth/modules/ttrss/data/usr/share/freedombox/modules-enabled/ttrss delete mode 100644 plinth/modules/ttrss/manifest.py delete mode 100644 plinth/modules/ttrss/privileged.py delete mode 100644 plinth/modules/ttrss/static/icons/ttrss.png delete mode 100644 plinth/modules/ttrss/static/icons/ttrss.svg delete mode 100644 plinth/modules/ttrss/tests/__init__.py delete mode 100644 plinth/modules/ttrss/tests/test_functional.py delete mode 100644 plinth/modules/ttrss/urls.py delete mode 100644 plinth/modules/ttrss/views.py diff --git a/Makefile b/Makefile index 7f2ac4a2d..f870aa9be 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ DISABLED_APPS_TO_REMOVE := \ repro \ tahoe \ mldonkey \ - i2p + i2p \ + ttrss APP_FILES_TO_REMOVE := $(foreach app,$(DISABLED_APPS_TO_REMOVE),$(ENABLED_APPS_PATH)/$(app)) diff --git a/debian/copyright b/debian/copyright index 3928b60a2..40ab87c2d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -318,15 +318,6 @@ Copyright: Transmission Authors Comment: https://github.com/transmission/transmission/blob/master/gtk/icons/hicolor_apps_scalable_transmission.svg License: GPL-3 -Files: plinth/modules/ttrss/static/icons/ttrss.png -Copyright: Mark James -License: CC-BY-3.0 - -Files: plinth/modules/ttrss/static/icons/ttrss.svg -Copyright: 2005 Andrew Dolgov -Comment: https://git.tt-rss.org/fox/tt-rss/src/master/images/favicon-72px.png -License: GPL-3+ - Files: plinth/modules/upgrades/data/usr/share/augeas/lenses/aptsources.aug plinth/modules/upgrades/data/usr/share/augeas/lenses/tests/test_aptsources.aug Copyright: 2007-2025 David Lutterkort diff --git a/plinth/modules/rssbridge/__init__.py b/plinth/modules/rssbridge/__init__.py index e29833db2..aefb95c95 100644 --- a/plinth/modules/rssbridge/__init__.py +++ b/plinth/modules/rssbridge/__init__.py @@ -26,11 +26,12 @@ _description = [ users_url=reverse_lazy('users:index')), format_lazy( _('You can use RSS-Bridge with Miniflux ' - 'or Tiny Tiny RSS to follow various ' + 'or Nextcloud News to follow various ' 'websites. When adding a feed, enable authentication and use your ' '{box_name} credentials.'), miniflux_url=reverse_lazy('miniflux:index'), - ttrss_url=reverse_lazy('ttrss:index'), box_name=_(cfg.box_name)), + nextcloud_url=reverse_lazy('nextcloud:index'), + box_name=_(cfg.box_name)), ] diff --git a/plinth/modules/tor/privileged.py b/plinth/modules/tor/privileged.py index 17ca0bebe..1aec47b85 100644 --- a/plinth/modules/tor/privileged.py +++ b/plinth/modules/tor/privileged.py @@ -471,7 +471,7 @@ def _set_onion_header(hidden_service): # https://community.torproject.org/onion-services/advanced/onion-location/ hostname = hidden_service['hostname'] config_contents = f'''# This file is managed by FreedomBox - + Header set Onion-Location "http://{hostname}%{{REQUEST_URI}}s" ''' diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py deleted file mode 100644 index ad5a9b13e..000000000 --- a/plinth/modules/ttrss/__init__.py +++ /dev/null @@ -1,153 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -"""FreedomBox app to configure Tiny Tiny RSS.""" - -from django.urls import reverse_lazy -from django.utils.translation import gettext_lazy as _ - -from plinth import app as app_module -from plinth import cfg, frontpage, menu -from plinth.config import DropinConfigs -from plinth.daemon import Daemon, SharedDaemon -from plinth.modules.apache.components import Webserver -from plinth.modules.backups.components import BackupRestore -from plinth.modules.firewall.components import Firewall -from plinth.modules.users.components import UsersAndGroups -from plinth.package import Packages, install -from plinth.utils import Version, format_lazy - -from . import manifest, privileged - -_description = [ - _('Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, ' - 'designed to allow reading news from any location, while feeling as ' - 'close to a real desktop application as possible.'), - format_lazy( - _('When enabled, Tiny Tiny RSS can be accessed by ' - 'any user belonging to the ' - 'feed-reader group.'), box_name=_(cfg.box_name), - users_url=reverse_lazy('users:index')), - format_lazy( - _('When using a mobile or desktop application for Tiny Tiny RSS, use ' - 'the URL /tt-rss or ' - '/tt-rss-app for connecting.')) -] - - -class TTRSSApp(app_module.App): - """FreedomBox app for TT-RSS.""" - - app_id = 'ttrss' - - _version = 7 - - def __init__(self) -> None: - """Create components for the app.""" - super().__init__() - - groups = {'feed-reader': _('Read and subscribe to news feeds')} - - info = app_module.Info(app_id=self.app_id, version=self._version, - name=_('Tiny Tiny RSS'), icon_filename='ttrss', - description=_description, - manual_page='TinyTinyRSS', - clients=manifest.clients, tags=manifest.tags, - donation_url='https://www.patreon.com/cthulhoo') - self.add(info) - - menu_item = menu.Menu('menu-ttrss', info.name, info.icon_filename, - info.tags, 'ttrss:index', parent_url_name='apps') - self.add(menu_item) - - shortcut = frontpage.Shortcut('shortcut-ttrss', info.name, - icon=info.icon_filename, url='/tt-rss', - clients=info.clients, tags=info.tags, - login_required=True, - allowed_groups=list(groups)) - self.add(shortcut) - - packages = Packages('packages-ttrss', [ - 'tt-rss', 'postgresql', 'dbconfig-pgsql', 'php-pgsql', - 'python3-psycopg2' - ]) - self.add(packages) - - dropin_configs = DropinConfigs('dropin-configs-ttrss', [ - '/etc/apache2/conf-available/tt-rss-plinth.conf', - ]) - self.add(dropin_configs) - - firewall = Firewall('firewall-ttrss', info.name, - ports=['http', 'https'], is_external=True) - self.add(firewall) - - webserver = Webserver('webserver-ttrss', 'tt-rss-plinth', - urls=['https://{host}/tt-rss'], - last_updated_version=5) - self.add(webserver) - - daemon1 = SharedDaemon('shared-daemon-ttrss-postgresql', 'postgresql') - self.add(daemon1) - - daemon2 = Daemon('daemon-ttrss', 'tt-rss') - self.add(daemon2) - - users_and_groups = UsersAndGroups('users-and-groups-ttrss', - groups=groups) - self.add(users_and_groups) - - backup_restore = TTRSSBackupRestore('backup-restore-ttrss', - **manifest.backup) - self.add(backup_restore) - - def enable(self): - """Enable components and API access.""" - super().enable() - privileged.enable_api_access() - - # Try to set the domain to one of the available TLS domains - domain = privileged.get_domain() - if not domain or domain == 'localhost': - from plinth.modules import names - domain = next(names.get_available_tls_domains(), None) - privileged.set_domain(domain) - - def setup(self, old_version): - """Install and configure the app.""" - privileged.pre_setup() - 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 force_upgrade(self, packages): - """Force update package to resolve conffile prompts.""" - if 'tt-rss' not in packages: - return False - - # Allow tt-rss any lower version to upgrade to 21.* - package = packages['tt-rss'] - if Version(package['new_version']) > Version('22~'): - return False - - install(['tt-rss'], force_configuration='new') - privileged.setup() - return True - - -class TTRSSBackupRestore(BackupRestore): - """Component to backup/restore TT-RSS.""" - - 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() diff --git a/plinth/modules/ttrss/data/usr/lib/systemd/system/tt-rss.service.d/freedombox.conf b/plinth/modules/ttrss/data/usr/lib/systemd/system/tt-rss.service.d/freedombox.conf deleted file mode 100644 index e5c1a5d7a..000000000 --- a/plinth/modules/ttrss/data/usr/lib/systemd/system/tt-rss.service.d/freedombox.conf +++ /dev/null @@ -1,35 +0,0 @@ -# Restart the service every 120 seconds always. When tt-rss can't connect to a -# database temporarily, it will exist with exit code 101. 120 seconds is the -# default daemon sleep interval for tt-rss. -[Service] -CacheDirectory=tt-rss -CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER CAP_NET_ADMIN CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE CAP_KILL CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_LINUX_IMMUTABLE CAP_IPC_LOCK CAP_SYS_CHROOT CAP_BLOCK_SUSPEND CAP_LEASE CAP_SYS_PACCT CAP_SYS_TTY_CONFIG CAP_SYS_BOOT CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_SYS_NICE CAP_SYS_RESOURCE -DevicePolicy=closed -LockPersonality=yes -NoNewPrivileges=yes -PrivateDevices=yes -PrivateMounts=yes -PrivateTmp=yes -PrivateUsers=yes -ProtectControlGroups=yes -ProtectClock=yes -ProtectHome=yes -ProtectHostname=yes -ProtectKernelLogs=yes -ProtectKernelModules=yes -ProtectKernelTunables=yes -ProtectProc=invisible -ProtectSystem=strict -RemoveIPC=yes -Restart=always -RestartSec=120s -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 -RestrictNamespaces=yes -RestrictSUIDSGID=yes -RestrictRealtime=yes -StateDirectory=tt-rss -SystemCallArchitectures=native -SystemCallFilter=@system-service -SystemCallFilter=~@resources -SystemCallFilter=~@privileged -SystemCallErrorNumber=EPERM diff --git a/plinth/modules/ttrss/data/usr/share/freedombox/etc/apache2/conf-available/tt-rss-plinth.conf b/plinth/modules/ttrss/data/usr/share/freedombox/etc/apache2/conf-available/tt-rss-plinth.conf deleted file mode 100644 index e5577eef5..000000000 --- a/plinth/modules/ttrss/data/usr/share/freedombox/etc/apache2/conf-available/tt-rss-plinth.conf +++ /dev/null @@ -1,39 +0,0 @@ -## -## On all sites, provide Tiny Tiny RSS on a default path: /tt-rss -## Allow all valid LDAP users. -## -Alias /tt-rss /usr/share/tt-rss/www -Alias /tt-rss-app /usr/share/tt-rss/www - - - # If a client sends 'Authorization' HTTP Header, perform Basic authorization - # using LDAP, otherwise redirect to FreedomBox single sign-on. It is not - # mandatory for the server to return HTTP 401 with 'WWW-Authenticate'. See - # https://datatracker.ietf.org/doc/html/rfc2616#section-14.8 - - Include includes/freedombox-auth-ldap.conf - Require ldap-group cn=admin,ou=groups,dc=thisbox - Require ldap-group cn=feed-reader,ou=groups,dc=thisbox - - - Include includes/freedombox-single-sign-on.conf - - TKTAuthToken "feed-reader" "admin" - - - - -# URLs without further authentication. The URLs contain a unique key generated -# and managed by tt-rss. This includes articles marked public or even other -# categories. - - Require all granted - - -# Legacy configuration for apps that expect a HTTP 401 response -# 'WWW-Authenticate' header. - - Include includes/freedombox-auth-ldap.conf - Require ldap-group cn=admin,ou=groups,dc=thisbox - Require ldap-group cn=feed-reader,ou=groups,dc=thisbox - diff --git a/plinth/modules/ttrss/data/usr/share/freedombox/modules-enabled/ttrss b/plinth/modules/ttrss/data/usr/share/freedombox/modules-enabled/ttrss deleted file mode 100644 index 0c9a11e5e..000000000 --- a/plinth/modules/ttrss/data/usr/share/freedombox/modules-enabled/ttrss +++ /dev/null @@ -1 +0,0 @@ -plinth.modules.ttrss diff --git a/plinth/modules/ttrss/manifest.py b/plinth/modules/ttrss/manifest.py deleted file mode 100644 index 523b85870..000000000 --- a/plinth/modules/ttrss/manifest.py +++ /dev/null @@ -1,55 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later - -from django.utils.translation import gettext_lazy as _ - -from plinth.clients import store_url - -clients = [ - { - 'name': - _('TTRSS-Reader'), - 'platforms': [{ - 'type': 'store', - 'os': 'android', - 'store_name': 'google-play', - 'url': store_url('google-play', 'org.ttrssreader') - }, { - 'type': 'store', - 'os': 'android', - 'store_name': 'f-droid', - 'url': store_url('f-droid', 'org.ttrssreader') - }] - }, - { - 'name': - _('Geekttrss'), - 'platforms': [{ - 'type': 'store', - 'os': 'android', - 'store_name': 'google-play', - 'url': store_url('google-play', 'com.geekorum.ttrss') - }] - }, - { - 'name': _('Tiny Tiny RSS'), - 'platforms': [{ - 'type': 'web', - 'url': '/tt-rss' - }] - }, -] - -backup = { - 'data': { - 'files': ['/var/lib/plinth/backups-data/ttrss-database.sql'] - }, - 'secrets': { - 'files': [ - '/etc/tt-rss/database.php', - '/etc/dbconfig-common/tt-rss.conf', - ] - }, - 'services': ['tt-rss'] -} - -tags = [_('Feed reader'), _('News aggregation'), _('RSS'), _('ATOM')] diff --git a/plinth/modules/ttrss/privileged.py b/plinth/modules/ttrss/privileged.py deleted file mode 100644 index 4c5d60c12..000000000 --- a/plinth/modules/ttrss/privileged.py +++ /dev/null @@ -1,160 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -"""Configure Tiny Tiny RSS.""" - -import augeas - -from plinth import action_utils -from plinth.actions import privileged -from plinth.db import postgres - -CONFIG_FILE = '/etc/tt-rss/config.php' -DEFAULT_FILE = '/etc/default/tt-rss' -DATABASE_FILE = '/etc/tt-rss/database.php' -DB_BACKUP_FILE = '/var/lib/plinth/backups-data/ttrss-database.sql' - - -@privileged -def pre_setup(): - """Preseed debconf values before packages are installed.""" - action_utils.debconf_set_selections([ - 'tt-rss tt-rss/database-type string pgsql', - 'tt-rss tt-rss/purge boolean true', - 'tt-rss tt-rss/dbconfig-remove boolean true', - 'tt-rss tt-rss/dbconfig-reinstall boolean true' - ]) - - -@privileged -def get_domain() -> str | None: - """Get the domain set for Tiny Tiny RSS.""" - aug = load_augeas() - - from urllib.parse import urlparse - for match in aug.match('/files' + CONFIG_FILE + '/define'): - if aug.get(match) == 'SELF_URL_PATH': - url = aug.get(match + '/value').strip("'") - return urlparse(url).netloc - - return None - - -@privileged -def set_domain(domain_name: str | None): - """Set the domain to be used by Tiny Tiny RSS.""" - if not domain_name: - return - - url = f"'https://{domain_name}/tt-rss/'" - aug = load_augeas() - - for match in aug.match('/files' + CONFIG_FILE + '/define'): - if aug.get(match) == 'SELF_URL_PATH': - aug.set(match + '/value', url) - - aug.save() - - -@privileged -def setup(): - """Setup Tiny Tiny RSS configuration.""" - aug = load_augeas() - - aug.set('/files' + DEFAULT_FILE + '/DISABLED', '0') - - skip_self_url_path_exists = False - - for match in aug.match('/files' + CONFIG_FILE + '/define'): - if aug.get(match) == 'PLUGINS': - aug.set(match + '/value', "'auth_remote, note'") - elif aug.get(match) == '_SKIP_SELF_URL_PATH_CHECKS': - skip_self_url_path_exists = True - aug.set(match + '/value', 'true') - - if not skip_self_url_path_exists: - aug.set('/files' + CONFIG_FILE + '/define[last() + 1]', - '_SKIP_SELF_URL_PATH_CHECKS') - aug.set('/files' + CONFIG_FILE + '/define[last()]/value', 'true') - - aug.save() - - config = _get_database_config() - # dbconfig may not always setup the database and user account correctly. - # Following, operation to create database/user is an idempotent operation. - postgres.create_database(config['database'], config['user'], - config['password']) - - if action_utils.service_is_enabled('tt-rss'): - action_utils.service_restart('tt-rss') - - -def _get_database_config(): - """Return the database configuration.""" - aug = load_augeas() - - def _get_value(variable_name): - """Return the value of a variable from database configuration file.""" - return aug.get('/files' + DATABASE_FILE + '/$' + variable_name) \ - .strip("'\"") - - return { - 'user': _get_value('dbuser'), - 'password': _get_value('dbpass'), - 'database': _get_value('dbname'), - 'host': _get_value('dbserver') - } - - -@privileged -def enable_api_access(): - """Enable API access so that tt-rss can be accessed through mobile app.""" - import psycopg2 # Only available post installation - - config = _get_database_config() - - connection = psycopg2.connect(database=config['database'], - user=config['user'], - password=config['password'], - host=config['host']) - cursor = connection.cursor() - - cursor.execute("UPDATE ttrss_prefs SET def_value=true " - "WHERE pref_name='ENABLE_API_ACCESS';") - - connection.commit() - connection.close() - - -@privileged -def dump_database(): - """Dump database to file.""" - config = _get_database_config() - postgres.dump_database(DB_BACKUP_FILE, config['database']) - - -@privileged -def restore_database(): - """Restore database from file.""" - config = _get_database_config() - postgres.restore_database(DB_BACKUP_FILE, config['database'], - config['user'], config['password']) - - -def load_augeas(): - """Initialize Augeas.""" - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') - aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE) - aug.set('/augeas/load/Phpvars/lens', 'Phpvars.lns') - aug.set('/augeas/load/Phpvars/incl[last() + 1]', CONFIG_FILE) - aug.set('/augeas/load/Phpvars/incl[last() + 1]', DATABASE_FILE) - aug.load() - return aug - - -@privileged -def uninstall(): - """Ensure that the database is removed.""" - # This setting set before deb package installation is not retrained, - # somehow. - action_utils.debconf_set_selections(['tt-rss tt-rss/purge boolean true']) diff --git a/plinth/modules/ttrss/static/icons/ttrss.png b/plinth/modules/ttrss/static/icons/ttrss.png deleted file mode 100644 index 961d8e5d2182b13e5151807ee4179657fb140bd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5361 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 - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/plinth/modules/ttrss/tests/__init__.py b/plinth/modules/ttrss/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/plinth/modules/ttrss/tests/test_functional.py b/plinth/modules/ttrss/tests/test_functional.py deleted file mode 100644 index 77349e3db..000000000 --- a/plinth/modules/ttrss/tests/test_functional.py +++ /dev/null @@ -1,103 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Functional, browser based tests for ttrss app. -""" - -import pytest - -from plinth.tests import functional - -APP_ID = 'ttrss' - -pytestmark = [pytest.mark.apps, pytest.mark.ttrss, pytest.mark.sso] - - -class TestTTRSSApp(functional.BaseAppTests): - """Class to customize basic app tests for TTRSS.""" - - app_name = 'ttrss' - has_service = True - has_web = True - - @pytest.mark.backups - def test_backup_restore(self, session_browser): - """Test backup and restore of app data.""" - functional.app_enable(session_browser, APP_ID) - _subscribe(session_browser) - functional.backup_create(session_browser, APP_ID, 'test_ttrss') - - functional.uninstall(session_browser, self.app_name) - functional.backup_restore(session_browser, APP_ID, 'test_ttrss') - - assert functional.service_is_running(session_browser, APP_ID) - assert _is_subscribed(session_browser) - - -def _ttrss_load_main_interface(browser): - """Load the TT-RSS interface.""" - functional.visit(browser, '/tt-rss/') - overlay = browser.find_by_id('overlay') - functional.eventually(lambda: not overlay.visible) - - -def _expand_nodes(browser): - """If interface has category nodes collapsed, expand them.""" - nodes = browser.find_by_css('span.dijitTreeExpandoClosed') - for node in nodes: - node.click() - - -def _is_feed_shown(browser, invert=False): - """Return whether the test feed is present.""" - _expand_nodes(browser) - return browser.is_text_present('Planet Debian') != invert - - -def _click_main_menu_item(browser, text): - """Select an item from the main actions menu.""" - browser.find_by_css('.action-chooser').click() - browser.find_by_text(text).click() - - -def _subscribe(browser): - """Subscribe to a feed in TT-RSS.""" - - def _already_subscribed_message(): - return browser.is_text_present( - 'You are already subscribed to this feed.') - - _ttrss_load_main_interface(browser) - - _click_main_menu_item(browser, 'Subscribe to feed...') - browser.find_by_id('feedDlg_feedUrl').fill( - 'https://planet.debian.org/atom.xml') - browser.find_by_text('Subscribe').click() - add_dialog = browser.find_by_css('#feedAddDlg') - functional.eventually( - lambda: not add_dialog.visible or _already_subscribed_message()) - if _already_subscribed_message(): - browser.find_by_text('Cancel').click() - functional.eventually(lambda: not add_dialog.visible) - - -def _unsubscribe(browser): - """Unsubscribe from a feed in TT-RSS.""" - _ttrss_load_main_interface(browser) - _expand_nodes(browser) - - browser.find_by_text('Planet Debian').click() - _click_main_menu_item(browser, 'Unsubscribe') - - prompt = browser.get_alert() - prompt.accept() - - # Reload as sometimes the feed does not disappear immediately - _ttrss_load_main_interface(browser) - - assert functional.eventually(_is_feed_shown, [browser, True]) - - -def _is_subscribed(browser): - """Return whether subscribed to a feed in TT-RSS.""" - _ttrss_load_main_interface(browser) - return _is_feed_shown(browser) diff --git a/plinth/modules/ttrss/urls.py b/plinth/modules/ttrss/urls.py deleted file mode 100644 index 737e9dea1..000000000 --- a/plinth/modules/ttrss/urls.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -URLs for the Tiny Tiny RSS module. -""" - -from django.urls import re_path - -from .views import TTRSSAppView - -urlpatterns = [re_path(r'^apps/ttrss/$', TTRSSAppView.as_view(), name='index')] diff --git a/plinth/modules/ttrss/views.py b/plinth/modules/ttrss/views.py deleted file mode 100644 index 244aa462e..000000000 --- a/plinth/modules/ttrss/views.py +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -"""Django views for Tiny Tiny RSS app.""" - -from django.contrib import messages -from django.utils.translation import gettext_lazy as _ - -from plinth.forms import TLSDomainForm -from plinth.views import AppView - -from . import privileged - - -class TTRSSAppView(AppView): - """Show TTRSS app main view.""" - - app_id = 'ttrss' - form_class = TLSDomainForm - - def get_initial(self): - """Return the values to fill in the form.""" - initial = super().get_initial() - initial['domain'] = privileged.get_domain() - return initial - - def form_valid(self, form): - """Change the domain of TT-RSS app.""" - data = form.cleaned_data - old_data = form.initial - if old_data['domain'] != data['domain']: - privileged.set_domain(data['domain']) - messages.success(self.request, _('Configuration updated')) - - return super().form_valid(form) diff --git a/plinth/modules/upgrades/tests/test_distupgrade.py b/plinth/modules/upgrades/tests/test_distupgrade.py index 84efd6a8c..7fa8dc739 100644 --- a/plinth/modules/upgrades/tests/test_distupgrade.py +++ b/plinth/modules/upgrades/tests/test_distupgrade.py @@ -335,9 +335,9 @@ def test_packages_remove_obsolete(apt_run): apt_run.assert_not_called() # No obsolete package to remove currently. with patch('plinth.modules.upgrades.distupgrade.OBSOLETE_PACKAGES', - ['tt-rss', 'searx']): + ['searx']): distupgrade._packages_remove_obsolete() - apt_run.assert_called_with(['remove', 'tt-rss', 'searx']) + apt_run.assert_called_with(['remove', 'searx']) @patch('plinth.modules.upgrades.distupgrade._apt_run') diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 55737c85e..4bbd4005d 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -52,7 +52,6 @@ _site_url = { 'cockpit': '/_cockpit/', 'syncthing': '/syncthing/', 'rssbridge': '/rss-bridge/', - 'ttrss': '/tt-rss/', 'sogo': '/SOGo/', }