diff --git a/plinth/app.py b/plinth/app.py index bb519d7f8..c3d388c44 100644 --- a/plinth/app.py +++ b/plinth/app.py @@ -5,6 +5,8 @@ Base class for all Freedombox applications. import collections +from . import clients as clients_module + class App: """Implement common functionality for an app. @@ -373,3 +375,5 @@ class Info(FollowerComponent): self.manual_page = manual_page self.clients = clients self.donation_url = donation_url + if clients: + clients_module.validate(clients) diff --git a/plinth/modules/bepasty/manifest.py b/plinth/modules/bepasty/manifest.py index f61f96a81..1d5873a41 100644 --- a/plinth/modules/bepasty/manifest.py +++ b/plinth/modules/bepasty/manifest.py @@ -2,15 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('bepasty'), 'platforms': [{ 'type': 'web', 'url': '/bepasty' }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/calibre/manifest.py b/plinth/modules/calibre/manifest.py index dde545875..85dcee040 100644 --- a/plinth/modules/calibre/manifest.py +++ b/plinth/modules/calibre/manifest.py @@ -2,15 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('calibre'), 'platforms': [{ 'type': 'web', 'url': '/calibre/' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/cockpit/manifest.py b/plinth/modules/cockpit/manifest.py index a0d873945..db8953a66 100644 --- a/plinth/modules/cockpit/manifest.py +++ b/plinth/modules/cockpit/manifest.py @@ -5,15 +5,13 @@ Application manifest for cockpit. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Cockpit'), 'platforms': [{ 'type': 'web', 'url': '/_cockpit/' }] -}]) +}] # cockpit.conf need not be backed up because add/remove domain signals are # triggered on every Plinth domain change (and cockpit application install) and diff --git a/plinth/modules/deluge/manifest.py b/plinth/modules/deluge/manifest.py index da06256a4..8d6241785 100644 --- a/plinth/modules/deluge/manifest.py +++ b/plinth/modules/deluge/manifest.py @@ -2,16 +2,14 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Deluge'), 'description': _('Bittorrent client written in Python/PyGTK'), 'platforms': [{ 'type': 'web', 'url': '/deluge' }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/diaspora/manifest.py b/plinth/modules/diaspora/manifest.py index b44ecae9c..02b0efdc7 100644 --- a/plinth/modules/diaspora/manifest.py +++ b/plinth/modules/diaspora/manifest.py @@ -2,11 +2,11 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url from plinth.modules import diaspora from plinth.utils import format_lazy -clients = validate([{ +clients = [{ 'name': _('dandelion*'), 'description': @@ -30,4 +30,4 @@ clients = validate([{ host=diaspora.get_configured_domain_name() if diaspora.is_setup() else "") }] -}]) +}] diff --git a/plinth/modules/ejabberd/manifest.py b/plinth/modules/ejabberd/manifest.py index eff22e9b7..c1006331c 100644 --- a/plinth/modules/ejabberd/manifest.py +++ b/plinth/modules/ejabberd/manifest.py @@ -2,10 +2,10 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url from plinth.modules.jsxc import manifest as jsxc_manifest -_clients = validate([{ +_clients = [{ 'name': _('Conversations'), 'platforms': [{ @@ -99,7 +99,7 @@ _clients = validate([{ 'os': 'windows', 'url': 'https://gajim.org/downloads.php' }] -}]) +}] _clients.extend(jsxc_manifest.clients) diff --git a/plinth/modules/gitweb/manifest.py b/plinth/modules/gitweb/manifest.py index 08dc4e6d9..f37c347e9 100644 --- a/plinth/modules/gitweb/manifest.py +++ b/plinth/modules/gitweb/manifest.py @@ -2,12 +2,10 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - CONFIG_FILE = '/etc/gitweb-freedombox.conf' GIT_REPO_PATH = '/var/lib/git' -clients = validate([ +clients = [ { 'name': _('Gitweb'), 'platforms': [{ @@ -32,7 +30,7 @@ clients = validate([ 'url': 'https://git-scm.com/download/windows' }] }, -]) +] backup = { 'config': { diff --git a/plinth/modules/i2p/manifest.py b/plinth/modules/i2p/manifest.py index e631bf8af..335fbea7f 100644 --- a/plinth/modules/i2p/manifest.py +++ b/plinth/modules/i2p/manifest.py @@ -5,12 +5,10 @@ Application manifest for I2P. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - _package_id = 'net.geti2p.i2p' _download_url = 'https://geti2p.net/download' -clients = validate([{ +clients = [{ 'name': _('I2P'), 'platforms': [{ @@ -33,7 +31,7 @@ clients = validate([{ 'os': 'windows', 'url': _download_url, }] -}]) +}] backup = { 'secrets': { diff --git a/plinth/modules/ikiwiki/manifest.py b/plinth/modules/ikiwiki/manifest.py index 69773651b..e2e4b82c7 100644 --- a/plinth/modules/ikiwiki/manifest.py +++ b/plinth/modules/ikiwiki/manifest.py @@ -2,14 +2,12 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('ikiwiki'), 'platforms': [{ 'type': 'web', 'url': '/ikiwiki' }] -}]) +}] backup = {'data': {'directories': ['/var/lib/ikiwiki/', '/var/www/ikiwiki/']}} diff --git a/plinth/modules/infinoted/manifest.py b/plinth/modules/infinoted/manifest.py index daf1d4b15..a9e89364c 100644 --- a/plinth/modules/infinoted/manifest.py +++ b/plinth/modules/infinoted/manifest.py @@ -3,10 +3,9 @@ from django.utils.translation import ugettext_lazy as _ from plinth import cfg -from plinth.clients import validate from plinth.utils import format_lazy -clients = validate([{ +clients = [{ 'name': _('Gobby'), 'description': @@ -29,7 +28,7 @@ clients = validate([{ 'format': 'deb', 'name': 'gobby' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/jsxc/manifest.py b/plinth/modules/jsxc/manifest.py index 2bb8c46b6..c1b5f1e8e 100644 --- a/plinth/modules/jsxc/manifest.py +++ b/plinth/modules/jsxc/manifest.py @@ -3,14 +3,12 @@ from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('JSXC'), 'platforms': [{ 'type': 'web', 'url': reverse_lazy('jsxc:jsxc') }] -}]) +}] backup = {} diff --git a/plinth/modules/matrixsynapse/manifest.py b/plinth/modules/matrixsynapse/manifest.py index dba665640..a9eb3f56c 100644 --- a/plinth/modules/matrixsynapse/manifest.py +++ b/plinth/modules/matrixsynapse/manifest.py @@ -2,12 +2,12 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url _android_package_id = 'im.vector.app' _element_desktop_download_url = 'https://element.io/get-started' -clients = validate([{ +clients = [{ 'name': _('Element'), 'platforms': [{ @@ -41,7 +41,7 @@ clients = validate([{ 'os': 'windows', 'url': _element_desktop_download_url, }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/mediawiki/manifest.py b/plinth/modules/mediawiki/manifest.py index a457ca908..1612300d4 100644 --- a/plinth/modules/mediawiki/manifest.py +++ b/plinth/modules/mediawiki/manifest.py @@ -2,15 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('MediaWiki'), 'platforms': [{ 'type': 'web', 'url': '/mediawiki' }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/minetest/manifest.py b/plinth/modules/minetest/manifest.py index 039bc9478..f0fc23b7e 100644 --- a/plinth/modules/minetest/manifest.py +++ b/plinth/modules/minetest/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('Minetest'), 'platforms': [{ @@ -34,7 +34,7 @@ clients = validate([{ 'format': 'deb', 'name': 'minetest' }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/minidlna/manifest.py b/plinth/modules/minidlna/manifest.py index 55c233df3..1c9ae1945 100644 --- a/plinth/modules/minidlna/manifest.py +++ b/plinth/modules/minidlna/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([ +clients = [ { 'name': _('vlc'), @@ -96,7 +96,7 @@ clients = validate([ 'name': 'totem', }] }, -]) +] # TODO: get all media directories from config file # for now hard code default media folder. diff --git a/plinth/modules/mldonkey/manifest.py b/plinth/modules/mldonkey/manifest.py index 2240ae774..18280f0fc 100644 --- a/plinth/modules/mldonkey/manifest.py +++ b/plinth/modules/mldonkey/manifest.py @@ -5,9 +5,9 @@ Application manifest for mldonkey. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('MLDonkey'), 'platforms': [{ 'type': 'web', @@ -34,7 +34,7 @@ clients = validate([{ 'store_name': 'google-play', 'url': store_url('google-play', 'com.devwom.amldonkey'), }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/mumble/manifest.py b/plinth/modules/mumble/manifest.py index 79a702b7d..d99b6b53f 100644 --- a/plinth/modules/mumble/manifest.py +++ b/plinth/modules/mumble/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('Mumble'), 'platforms': [{ @@ -52,7 +52,7 @@ clients = validate([{ 'store_name': 'google-play', 'url': store_url('google-play', 'se.lublin.mumla') }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/openvpn/manifest.py b/plinth/modules/openvpn/manifest.py index 88d3c0b74..9a15acc11 100644 --- a/plinth/modules/openvpn/manifest.py +++ b/plinth/modules/openvpn/manifest.py @@ -5,14 +5,14 @@ Application manifest for OpenVPN. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url _package_id = 'de.blinkt.openvpn' _download_url = 'https://openvpn.net/community-downloads' backup = {'secrets': {'directories': ['/etc/openvpn/']}} -clients = validate([{ +clients = [{ 'name': _('OpenVPN'), 'platforms': [{ @@ -50,4 +50,4 @@ clients = validate([{ 'os': 'macos', 'url': 'https://tunnelblick.net/downloads.html' }] -}]) +}] diff --git a/plinth/modules/performance/manifest.py b/plinth/modules/performance/manifest.py index 22b616c51..3101ea0f3 100644 --- a/plinth/modules/performance/manifest.py +++ b/plinth/modules/performance/manifest.py @@ -5,12 +5,10 @@ FreedomBox app for System Monitoring (cockpit-pcp) in ‘System’. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Cockpit'), 'platforms': [{ 'type': 'web', 'url': '/_cockpit/system/graphs' }] -}]) +}] diff --git a/plinth/modules/quassel/manifest.py b/plinth/modules/quassel/manifest.py index 8cab21ab4..fe3afcfb1 100644 --- a/plinth/modules/quassel/manifest.py +++ b/plinth/modules/quassel/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('Quassel'), 'platforms': [{ @@ -42,7 +42,7 @@ clients = validate([{ 'store_name': 'google-play', 'url': store_url('google-play', 'com.iskrembilen.quasseldroid'), }] -}]) +}] backup = { 'secrets': { diff --git a/plinth/modules/radicale/manifest.py b/plinth/modules/radicale/manifest.py index a341863ab..aded1f039 100644 --- a/plinth/modules/radicale/manifest.py +++ b/plinth/modules/radicale/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('DAVx5'), 'usage': @@ -76,7 +76,7 @@ clients = validate([{ 'type': 'web', 'url': '/radicale/' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/roundcube/manifest.py b/plinth/modules/roundcube/manifest.py index 30756b043..124b5ae69 100644 --- a/plinth/modules/roundcube/manifest.py +++ b/plinth/modules/roundcube/manifest.py @@ -2,14 +2,12 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Roundcube'), 'platforms': [{ 'type': 'web', 'url': '/roundcube' }] -}]) +}] backup = {} diff --git a/plinth/modules/samba/manifest.py b/plinth/modules/samba/manifest.py index 41869533c..6defc1d29 100644 --- a/plinth/modules/samba/manifest.py +++ b/plinth/modules/samba/manifest.py @@ -5,11 +5,11 @@ Application manifest for Samba. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url SHARES_CONF_BACKUP_FILE = '/var/lib/plinth/backups-data/samba-shares-dump.conf' -clients = validate([{ +clients = [{ 'name': _('Android Samba Client'), 'platforms': [{ @@ -74,7 +74,7 @@ clients = validate([{ 'os': 'gnu-linux', 'url': 'https://kde.org/applications/system/org.kde.dolphin' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/searx/manifest.py b/plinth/modules/searx/manifest.py index 8b260ce46..09f55904c 100644 --- a/plinth/modules/searx/manifest.py +++ b/plinth/modules/searx/manifest.py @@ -2,15 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Searx'), 'platforms': [{ 'type': 'web', 'url': '/searx/' }] -}]) +}] PUBLIC_ACCESS_SETTING_FILE = '/etc/searx/allow_public_access' diff --git a/plinth/modules/shaarli/manifest.py b/plinth/modules/shaarli/manifest.py index d4258df40..93fe4d885 100644 --- a/plinth/modules/shaarli/manifest.py +++ b/plinth/modules/shaarli/manifest.py @@ -2,12 +2,10 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Shaarli'), 'platforms': [{ 'type': 'web', 'url': '/shaarli' }] -}]) +}] diff --git a/plinth/modules/syncthing/manifest.py b/plinth/modules/syncthing/manifest.py index 02b7d0293..565412612 100644 --- a/plinth/modules/syncthing/manifest.py +++ b/plinth/modules/syncthing/manifest.py @@ -2,12 +2,12 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url _package_id = 'com.nutomic.syncthingandroid' _download_url = 'https://syncthing.net/' -clients = validate([{ +clients = [{ 'name': _('Syncthing'), 'platforms': [{ @@ -44,7 +44,7 @@ clients = validate([{ 'type': 'web', 'url': '/syncthing' }] -}]) +}] backup = { 'secrets': { diff --git a/plinth/modules/tor/manifest.py b/plinth/modules/tor/manifest.py index 3a00a257d..3377bf261 100644 --- a/plinth/modules/tor/manifest.py +++ b/plinth/modules/tor/manifest.py @@ -2,13 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url _orbot_package_id = 'org.torproject.android' _tor_browser_download_url = \ 'https://www.torproject.org/download/download-easy.html' -clients = validate([{ +clients = [{ 'name': _('Tor Browser'), 'platforms': [{ @@ -38,7 +38,7 @@ clients = validate([{ 'store_name': 'f-droid', 'url': store_url('f-droid', _orbot_package_id) }] -}]) +}] backup = { 'config': { diff --git a/plinth/modules/transmission/manifest.py b/plinth/modules/transmission/manifest.py index dd6dccad5..a9adbd834 100644 --- a/plinth/modules/transmission/manifest.py +++ b/plinth/modules/transmission/manifest.py @@ -2,15 +2,13 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import validate - -clients = validate([{ +clients = [{ 'name': _('Transmission'), 'platforms': [{ 'type': 'web', 'url': '/transmission' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/ttrss/manifest.py b/plinth/modules/ttrss/manifest.py index 3c44b8e7e..7e0229277 100644 --- a/plinth/modules/ttrss/manifest.py +++ b/plinth/modules/ttrss/manifest.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url -clients = validate([{ +clients = [{ 'name': _('Tiny Tiny RSS (Fork)'), 'platforms': [{ @@ -25,7 +25,7 @@ clients = validate([{ 'type': 'web', 'url': '/tt-rss' }] -}]) +}] backup = { 'data': { diff --git a/plinth/modules/wireguard/manifest.py b/plinth/modules/wireguard/manifest.py index 61b2207c9..8ac7a8cee 100644 --- a/plinth/modules/wireguard/manifest.py +++ b/plinth/modules/wireguard/manifest.py @@ -5,11 +5,11 @@ Application manifest for WireGuard. from django.utils.translation import ugettext_lazy as _ -from plinth.clients import store_url, validate +from plinth.clients import store_url _wireguard_package_id = 'com.wireguard.android' -clients = validate([{ +clients = [{ 'name': _('WireGuard'), 'platforms': [{ @@ -40,4 +40,4 @@ clients = validate([{ 'store_name': 'app-store', 'url': 'https://apps.apple.com/us/app/wireguard/id1441195209' }] -}]) +}] diff --git a/plinth/tests/test_app.py b/plinth/tests/test_app.py index 7b91d9f04..c2a05539d 100644 --- a/plinth/tests/test_app.py +++ b/plinth/tests/test_app.py @@ -10,6 +10,8 @@ import pytest from plinth.app import App, Component, FollowerComponent, Info, LeaderComponent +# pylint: disable=protected-access + class AppTest(App): """Sample App for testing.""" @@ -302,10 +304,17 @@ def test_info_initialization_without_args(): def test_info_initialization_with_args(): """Test initializing the Info component with arguments.""" + clients = [{ + 'name': 'test', + 'platforms': [{ + 'type': 'web', + 'url': 'test-url' + }] + }] info = Info('test-app', 3, is_essential=True, depends=['test-app-2'], name='Test App', icon='fa-test', icon_filename='test-icon', short_description='For Test', description='Test description', - manual_page='Test', clients=['test']) + manual_page='Test', clients=clients) assert info.is_essential assert info.depends == ['test-app-2'] assert info.name == 'Test App' @@ -314,4 +323,19 @@ def test_info_initialization_with_args(): assert info.short_description == 'For Test' assert info.description == 'Test description' assert info.manual_page == 'Test' - assert info.clients == ['test'] + assert info.clients == clients + + +def test_info_clients_validation(): + """Test clients parameter validation during initialization.""" + with pytest.raises(AssertionError): + Info('test-app', 3, clients='invalid') + + clients = [{ + 'name': 'test', + 'platforms': [{ + 'type': 'web', + 'url': 'test-url' + }] + }] + Info('test-app', 3, clients=clients)