Sunil Mohan Adapa 89bce7a344
app: Add tags to menu and frontpage components
- Add typing information for init methods Info, Shortcut, and Menu to easily
  identify problems.

- Update docstrings for these components.

- Updates test cases to deal with tags instead of short description.

- Update custom shortcuts code to read tags and ignore short description.

- Update API to send tags instead of custom shortcuts.

- OpenVPN special treatment of info.description in Shortcut

Tests:

- All unit tests pass and type checking succeeds.

- All apps show icons with tags in apps and system section.

- In help section cards don't show tags.

- In front page, enabled apps show shortcuts with tags.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Joseph Nuthalapati <njoseph@riseup.net>
2025-01-09 21:08:10 +05:30

123 lines
4.7 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""FreedomBox app for calibre e-book library."""
import re
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
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.users.components import UsersAndGroups
from plinth.package import Packages
from plinth.utils import format_lazy
from . import manifest, privileged
_description = [
format_lazy(
_('calibre server provides online access to your e-book collection. '
'You can store your e-books on your {box_name}, read them online or '
'from any of your devices.'), box_name=_(cfg.box_name)),
_('You can organize your e-books, extract and edit their metadata, and '
'perform advanced search. calibre can import, export, or convert across '
'a wide range of formats to make e-books ready for reading on any '
'device. It also provides an online web reader. It remembers your '
'last read location, bookmarks, and highlighted text. Content '
'distribution using OPDS is currently not supported.'),
_('Only users belonging to <em>calibre</em> group will be able to access '
'the app. All users with access can use all the libraries.')
]
LIBRARY_NAME_PATTERN = r'[a-zA-Z0-9 _-]+'
class CalibreApp(app_module.App):
"""FreedomBox app for calibre."""
app_id = 'calibre'
_version = 3
DAEMON = 'calibre-server-freedombox'
def __init__(self) -> None:
"""Create components for the app."""
super().__init__()
groups = {'calibre': _('Use calibre e-book libraries')}
info = app_module.Info(app_id=self.app_id, version=self._version,
name=_('calibre'), icon_filename='calibre',
description=_description, manual_page='Calibre',
clients=manifest.clients, tags=manifest.tags,
donation_url='https://calibre-ebook.com/donate')
self.add(info)
menu_item = menu.Menu('menu-calibre', info.name, info.icon_filename,
info.tags, 'calibre:index',
parent_url_name='apps')
self.add(menu_item)
shortcut = frontpage.Shortcut('shortcut-calibre', info.name,
icon=info.icon_filename, url='/calibre',
clients=info.clients, tags=info.tags,
login_required=True,
allowed_groups=list(groups))
self.add(shortcut)
packages = Packages('packages-calibre', ['calibre'])
self.add(packages)
dropin_configs = DropinConfigs('dropin-configs-calibre', [
'/etc/apache2/conf-available/calibre-freedombox.conf',
])
self.add(dropin_configs)
firewall = Firewall('firewall-calibre', info.name,
ports=['http', 'https'], is_external=True)
self.add(firewall)
firewall_local_protection = FirewallLocalProtection(
'firewall-local-protection-calibre', ['8844'])
self.add(firewall_local_protection)
webserver = Webserver('webserver-calibre', 'calibre-freedombox',
urls=['https://{host}/calibre'])
self.add(webserver)
daemon = Daemon('daemon-calibre', self.DAEMON,
listen_ports=[(8844, 'tcp4')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-calibre',
reserved_usernames=['calibre'],
groups=groups)
self.add(users_and_groups)
backup_restore = BackupRestore('backup-restore-calibre',
**manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
self.enable()
def uninstall(self):
"""De-configure and uninstall the app."""
super().uninstall()
privileged.uninstall()
def validate_library_name(library_name):
"""Raise exception if library name does not fit the accepted pattern."""
if not re.fullmatch(r'[A-Za-z0-9_.-]+', library_name):
raise Exception('Invalid library name')