Files
shopdb-flask/shopdb/plugins/templates/api/routes.py.tmpl
cproudlock f663cc5bbe Enforce plugin contract purity: single import surface via shopdb.api
Plugins were reaching into internal core paths (shopdb.core.models.*,
shopdb.extensions, shopdb.utils.*), coupling them to core's file layout and
violating the ADR-001 contract. Consolidate onto one versioned surface.

- shopdb.api: expand from 2 helpers to the full plugin import surface -
  db, cache; BaseModel, AuditMixin; core models (Asset, AssetType,
  AssetStatus, Vendor, Model, Communication, CommunicationType, Location,
  Setting, AuditLog, Application, AppVersion, OperatingSystem); response +
  pagination helpers; employee_connection. Documented in PLUGIN-HOOKS.md.
- Migrate all 22 plugin source files to import only from shopdb.api (plus
  shopdb.plugins.base for the ABC).
- Drop the printers plugin's legacy MachineType dependency: remove
  _ensure_legacy_machine_types and the seed_supplies machinetypeid lookup
  (Model.machinetypeid is nullable; printers carry type via PrinterType).
- Guard test test_plugins_only_import_contract_surface scans plugin source
  and fails on any core import outside shopdb.api / shopdb.plugins.base.
- Scaffold templates updated so generated plugins are contract-pure.
- Bump __contract_version__ 0.2.0 -> 0.3.0 (additive surface expansion;
  manifests pin <1.0.0 so they still satisfy).

145 tests pass, naming/style green, app factory boots all 6 plugins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:45:06 -04:00

46 lines
1.1 KiB
Cheetah

"""$Name plugin API routes."""
from flask import Blueprint, request
from flask_jwt_extended import jwt_required
from shopdb.api import (
success_response,
error_response,
paginated_response,
ErrorCodes,
get_pagination_params,
paginate_query,
)
from ..models import $Name
${name}_bp = Blueprint('$name', __name__)
@${name}_bp.route('', methods=['GET'])
@jwt_required(optional=True)
def list_${name}():
"""List $name assets, paginated."""
page, per_page = get_pagination_params(request)
query = ${Name}.query
items, total = paginate_query(query, page, per_page)
data = [item.to_dict() for item in items]
return paginated_response(data, page, per_page, total)
@${name}_bp.route('/<int:assetid>', methods=['GET'])
@jwt_required(optional=True)
def get_${name}(assetid: int):
"""Get a single $name by assetid."""
item = ${Name}.query.get(assetid)
if not item:
return error_response(
ErrorCodes.NOT_FOUND,
f'$Name with assetid {assetid} not found',
http_code=404,
)
return success_response(item.to_dict())