Files
shopdb-flask/plugins/slides/plugin.py

90 lines
3.1 KiB
Python

"""Slides plugin main class.
Display/service plugin: contributes a blueprint only (no model, no AssetType,
no nav). Serves TV-dashboard slideshow images. Demonstrates the minimal plugin
shape - a feature that is purely an API surface.
"""
import json
import logging
from pathlib import Path
from typing import List, Dict, Optional, Type
from flask import Flask, Blueprint
from shopdb.plugins.base import BasePlugin, PluginMeta
from .api import slides_bp
from .models import TvSlide
logger = logging.getLogger(__name__)
class SlidesPlugin(BasePlugin):
"""Slides plugin - TV dashboard slideshow images."""
def __init__(self):
self._manifest = self._load_manifest()
def _load_manifest(self) -> Dict:
"""Load plugin manifest from JSON file."""
manifest_path = Path(__file__).parent / 'manifest.json'
if manifest_path.exists():
with open(manifest_path, 'r') as f:
return json.load(f)
return {}
@property
def meta(self) -> PluginMeta:
"""Return plugin metadata."""
return PluginMeta(
name=self._manifest.get('name', 'slides'),
version=self._manifest.get('version', '1.0.0'),
description=self._manifest.get(
'description',
'TV dashboard slideshow images'
),
author=self._manifest.get('author', 'ShopDB Team'),
dependencies=self._manifest.get('dependencies', []),
core_version=self._manifest.get('core_version', '>=0.1.0,<1.0.0'),
api_prefix=self._manifest.get('api_prefix', '/api/slides'),
)
def get_blueprint(self) -> Optional[Blueprint]:
"""Return Flask Blueprint with API routes."""
return slides_bp
def get_models(self) -> List[Type]:
"""Slide playlist metadata (image files live on disk)."""
return [TvSlide]
def get_permissions(self) -> List:
"""RBAC permission for curating slides (both surfaces). Grantable to a
non-admin role so a curator can manage the lobby TV + screensaver
without full admin. Admins hold it by default."""
return [
('slides.view', 'View the slide decks', 'slides'),
('slides.manage',
'Manage lobby display and screensaver slides', 'slides'),
]
def get_navigation_items(self) -> List[Dict]:
"""Sidebar entry for the slide manager. Gated on slides.manage so only a
curator (or admin, who holds it by default) sees the link."""
return [
{
'name': 'Slides',
'icon': 'image',
'route': '/settings/slides',
'position': 7,
# The read permission: a manager holds it implicitly through
# the route's require_any_permission, and it is the one a site
# can grant to guests.
'permission': ['slides.view', 'slides.manage'],
},
]
def init_app(self, app: Flask, db_instance) -> None:
"""Initialize plugin with Flask app."""
logger.info(f"Slides plugin initialized (v{self.meta.version})")