147 lines
4.7 KiB
Python
147 lines
4.7 KiB
Python
"""
|
|
app/api/templates.py
|
|
--------------------
|
|
Mobile API endpoints for inspection templates.
|
|
|
|
GET /api/v1/templates
|
|
Returns a lightweight list of all active inspection templates.
|
|
Used by the iPad app to populate the template picker when starting an
|
|
inspection.
|
|
|
|
GET /api/v1/templates/<template_id>
|
|
Returns the full template including its form_schema JSON.
|
|
The app caches this locally in SwiftData so inspections can be
|
|
executed without a network connection.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from flask import Blueprint, g
|
|
from app import db
|
|
from app.models.inspection import InspectionTemplate
|
|
from app.api.errors import api_ok, api_error
|
|
from app.api.decorators import jwt_required
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
bp = Blueprint('api_templates', __name__)
|
|
|
|
# Customer role cannot access template data — inspectors and above only
|
|
_ALLOWED_ROLES = {'admin', 'director', 'inspector', 'project_manager'}
|
|
|
|
|
|
def _template_summary_payload(template: InspectionTemplate) -> dict:
|
|
"""Serialize a template to the lightweight summary dict (no form_schema)."""
|
|
return {
|
|
'id': template.id,
|
|
'name': template.name,
|
|
'description': template.description or '',
|
|
'frequency': template.frequency or '',
|
|
}
|
|
|
|
|
|
def _template_full_payload(template: InspectionTemplate) -> dict:
|
|
"""Serialize a template including its full form_schema."""
|
|
return {
|
|
'id': template.id,
|
|
'name': template.name,
|
|
'description': template.description or '',
|
|
'frequency': template.frequency or '',
|
|
'form_schema': template.get_form_schema(), # always returns a list
|
|
}
|
|
|
|
|
|
# ── Template List ─────────────────────────────────────────────────────────────
|
|
|
|
@bp.route('/templates', methods=['GET'])
|
|
@jwt_required
|
|
def list_templates():
|
|
"""
|
|
Return a lightweight list of all inspection templates.
|
|
|
|
Only internal staff roles (admin, director, inspector, project_manager)
|
|
may access templates. Customer accounts are excluded.
|
|
|
|
Response 200
|
|
------------
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"templates": [
|
|
{
|
|
"id": 3,
|
|
"name": "Weekly Restroom Inspection",
|
|
"description": "Standard weekly restroom checklist",
|
|
"frequency": "weekly"
|
|
}
|
|
],
|
|
"count": 1
|
|
}
|
|
}
|
|
"""
|
|
user = g.api_user
|
|
|
|
if user.role not in _ALLOWED_ROLES:
|
|
logger.warning('API TEMPLATES | access denied | user=%s | role=%s',
|
|
user.username, user.role)
|
|
return api_error('Access denied', 403)
|
|
|
|
templates = (
|
|
InspectionTemplate.query
|
|
.order_by(InspectionTemplate.name)
|
|
.all()
|
|
)
|
|
|
|
payload = [_template_summary_payload(t) for t in templates]
|
|
|
|
logger.info('API TEMPLATES | list | user=%s | count=%d',
|
|
user.username, len(payload))
|
|
|
|
return api_ok({'templates': payload, 'count': len(payload)})
|
|
|
|
|
|
# ── Full Template (with form_schema) ─────────────────────────────────────────
|
|
|
|
@bp.route('/templates/<int:template_id>', methods=['GET'])
|
|
@jwt_required
|
|
def get_template(template_id):
|
|
"""
|
|
Return a single template including its complete form_schema.
|
|
|
|
The iPad app calls this endpoint once per template and caches the
|
|
result in SwiftData. Subsequent inspection executions use the cached
|
|
schema without any network calls.
|
|
|
|
Response 200
|
|
------------
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"template": {
|
|
"id": 3,
|
|
"name": "Weekly Restroom Inspection",
|
|
"description": "...",
|
|
"frequency": "weekly",
|
|
"form_schema": [
|
|
{ "id": "f1", "type": "section", "label": "General Cleanliness" },
|
|
{ "id": "f2", "type": "rating", "label": "Floor condition", "required": true }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
user = g.api_user
|
|
|
|
if user.role not in _ALLOWED_ROLES:
|
|
logger.warning('API TEMPLATES | access denied | user=%s | role=%s',
|
|
user.username, user.role)
|
|
return api_error('Access denied', 403)
|
|
|
|
template = db.session.get(InspectionTemplate, template_id)
|
|
if template is None:
|
|
return api_error('Template not found', 404)
|
|
|
|
logger.info('API TEMPLATES | detail | user=%s | template_id=%d | name=%s',
|
|
user.username, template_id, template.name)
|
|
|
|
return api_ok({'template': _template_full_payload(template)}) |