"""Printers plugin main class.""" import json import logging from pathlib import Path from typing import List, Dict, Optional, Type from flask import Flask, Blueprint import click from shopdb.plugins.base import BasePlugin, PluginMeta from shopdb.extensions import db from shopdb.core.models.machine import MachineType from .models import PrinterData from .api import printers_bp from .services import ZabbixService logger = logging.getLogger(__name__) class PrintersPlugin(BasePlugin): """ Printers plugin - extends machines with printer-specific functionality. Printers use the unified Machine model with machinetype.category = 'Printer'. This plugin adds: - PrinterData table for printer-specific fields (windowsname, sharename, etc.) - Zabbix integration for real-time supply level lookups """ def __init__(self): self._manifest = self._load_manifest() self._zabbixservice = None def _load_manifest(self) -> Dict: """Load plugin manifest from JSON file.""" manifestpath = Path(__file__).parent / 'manifest.json' if manifestpath.exists(): with open(manifestpath, 'r') as f: return json.load(f) return {} @property def meta(self) -> PluginMeta: """Return plugin metadata.""" return PluginMeta( name=self._manifest.get('name', 'printers'), version=self._manifest.get('version', '1.0.0'), description=self._manifest.get( 'description', 'Printer management with Zabbix integration' ), author=self._manifest.get('author', 'ShopDB Team'), dependencies=self._manifest.get('dependencies', []), core_version=self._manifest.get('core_version', '>=1.0.0'), api_prefix=self._manifest.get('api_prefix', '/api/printers'), ) def get_blueprint(self) -> Optional[Blueprint]: """Return Flask Blueprint with API routes.""" return printers_bp def get_models(self) -> List[Type]: """Return list of SQLAlchemy model classes.""" return [PrinterData] def get_services(self) -> Dict[str, Type]: """Return plugin services.""" return { 'zabbix': ZabbixService, } @property def zabbixservice(self) -> ZabbixService: """Get Zabbix service instance.""" if self._zabbixservice is None: self._zabbixservice = ZabbixService() return self._zabbixservice def init_app(self, app: Flask, db_instance) -> None: """Initialize plugin with Flask app.""" app.config.setdefault('ZABBIX_URL', '') app.config.setdefault('ZABBIX_TOKEN', '') logger.info(f"Printers plugin initialized (v{self.meta.version})") def on_install(self, app: Flask) -> None: """Called when plugin is installed.""" with app.app_context(): self._ensureprintertypes() logger.info("Printers plugin installed") def _ensureprintertypes(self) -> None: """Ensure basic printer machine types exist.""" printertypes = [ ('Laser Printer', 'Printer', 'Standard laser printer'), ('Inkjet Printer', 'Printer', 'Inkjet printer'), ('Label Printer', 'Printer', 'Label/barcode printer'), ('Multifunction Printer', 'Printer', 'MFP with scan/copy/fax'), ('Plotter', 'Printer', 'Large format plotter'), ] for name, category, description in printertypes: existing = MachineType.query.filter_by(machinetype=name).first() if not existing: mt = MachineType( machinetype=name, category=category, description=description, icon='printer' ) db.session.add(mt) logger.debug(f"Created machine type: {name}") db.session.commit() def on_uninstall(self, app: Flask) -> None: """Called when plugin is uninstalled.""" logger.info("Printers plugin uninstalled") def get_cli_commands(self) -> List: """Return CLI commands for this plugin.""" @click.group('printers') def printerscli(): """Printers plugin commands.""" pass @printerscli.command('check-supplies') @click.argument('ip') def checksupplies(ip): """Check supply levels for a printer by IP (via Zabbix).""" from flask import current_app with current_app.app_context(): service = ZabbixService() if not service.isconfigured: click.echo('Error: Zabbix not configured. Set ZABBIX_URL and ZABBIX_TOKEN.') return supplies = service.getsuppliesbyip(ip) if not supplies: click.echo(f'No supply data found for {ip}') return click.echo(f'Supply levels for {ip}:') for supply in supplies: click.echo(f" {supply['name']}: {supply['level']}%") return [printerscli] def get_dashboard_widgets(self) -> List[Dict]: """Return dashboard widget definitions.""" return [ { 'name': 'Printer Status', 'component': 'PrinterStatusWidget', 'endpoint': '/api/printers/dashboard/summary', 'size': 'medium', 'position': 10, }, ] def get_navigation_items(self) -> List[Dict]: """Return navigation menu items.""" return [ { 'name': 'Printers', 'icon': 'printer', 'route': '/printers', 'position': 20, }, ]