Files
shopdb-flask/plugins/usb/plugin.py
cproudlock 65b0197b2b Document external-DB schema contracts for employees + USB plugins
Every site's HR directory and USB check-in/out databases may use a different
schema, so document exactly what each plugin queries and how to adapt.

- plugins/employees/README.md: required employees table columns (SSO,
  First_Name, Last_Name, Team, Role, Picture), the queries run, photo handling,
  and a CREATE VIEW recipe to map a different site schema without code changes.
- plugins/usb/README.md: cmmc_usb devices / checkinoutlog / users columns,
  read-write ops, the employee-directory dependency, and a view recipe.
- USB plugin gains get_config_schema() (cmmc_usb_db_host/name/user + password);
  cmmc_usb_connection reads host/name/user settings-first (env fallback), the
  password stays env-only - matching the employees plugin.
- Config-field help points at the READMEs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 08:19:26 -04:00

98 lines
3.6 KiB
Python

"""USB plugin main class."""
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 shopdb.api import db
from .models import USBDevice, USBDeviceType, USBCheckout
from .api import usb_bp
logger = logging.getLogger(__name__)
class USBPlugin(BasePlugin):
"""
USB plugin - manages USB device tracking and checkouts.
Standalone plugin for tracking USB flash drives, external drives,
and other portable storage devices with checkout/checkin functionality.
"""
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', 'usb'),
version=self._manifest.get('version', '1.0.0'),
description=self._manifest.get('description', 'USB device checkout management'),
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/usb'),
)
def get_blueprint(self) -> Optional[Blueprint]:
"""Return Flask Blueprint with API routes."""
return usb_bp
def get_models(self) -> List[Type]:
"""Return list of SQLAlchemy model classes."""
return [USBDeviceType, USBDevice, USBCheckout]
def get_config_schema(self) -> List[Dict]:
"""CMMC USB check-in/out database connection. Host/name/user are settings
the wizard can edit; the password stays in .env (emitted, not stored)."""
return [
{'key': 'cmmc_usb_db_host', 'label': 'USB DB host', 'type': 'text',
'secret': False, 'default': 'localhost',
'help': 'This DB must expose devices / checkinoutlog / users tables '
'(or views). See plugins/usb/README.md.'},
{'key': 'cmmc_usb_db_name', 'label': 'USB DB name', 'type': 'text',
'secret': False, 'default': 'cmmc_usb'},
{'key': 'cmmc_usb_db_user', 'label': 'USB DB user', 'type': 'text',
'secret': False},
{'key': 'cmmc_usb_db_password', 'label': 'USB DB password', 'type': 'password',
'secret': True, 'envvar': 'CMMC_USB_DB_PASSWORD',
'help': 'Stored in .env, not the database. The wizard shows the line to paste.'},
]
def init_app(self, app: Flask, db_instance) -> None:
"""Initialize plugin with Flask app."""
logger.info(f"USB plugin initialized (v{self.meta.version})")
def on_install(self, app: Flask) -> None:
"""Called when plugin is installed."""
logger.info("USB plugin installed")
def on_uninstall(self, app: Flask) -> None:
"""Called when plugin is uninstalled."""
logger.info("USB plugin uninstalled")
def get_navigation_items(self) -> List[Dict]:
"""Return navigation menu items."""
return [
{
'name': 'USB Devices',
'icon': 'usb',
'route': '/usb',
'position': 45,
},
]