mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-26 17:41:58 -06:00
174 lines
5.2 KiB
Python
174 lines
5.2 KiB
Python
"""Administrative HTTP endpoints for the Borealis Engine."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from flask import Blueprint, Flask, current_app, jsonify, request, session
|
|
|
|
from Data.Engine.services.container import EngineServiceContainer
|
|
|
|
|
|
blueprint = Blueprint("engine_admin", __name__, url_prefix="/api/admin")
|
|
|
|
|
|
def register(app: Flask, _services: EngineServiceContainer) -> None:
|
|
"""Attach administrative routes to *app*."""
|
|
|
|
if "engine_admin" not in app.blueprints:
|
|
app.register_blueprint(blueprint)
|
|
|
|
|
|
def _services() -> EngineServiceContainer:
|
|
services = current_app.extensions.get("engine_services")
|
|
if services is None: # pragma: no cover - defensive
|
|
raise RuntimeError("engine services not initialized")
|
|
return services
|
|
|
|
|
|
def _admin_service():
|
|
return _services().enrollment_admin_service
|
|
|
|
|
|
def _require_admin():
|
|
username = session.get("username")
|
|
role = (session.get("role") or "").strip().lower()
|
|
if not isinstance(username, str) or not username:
|
|
return jsonify({"error": "not_authenticated"}), 401
|
|
if role != "admin":
|
|
return jsonify({"error": "forbidden"}), 403
|
|
return None
|
|
|
|
|
|
@blueprint.route("/enrollment-codes", methods=["GET"])
|
|
def list_enrollment_codes() -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
status = request.args.get("status")
|
|
records = _admin_service().list_install_codes(status=status)
|
|
return jsonify({"codes": [record.to_dict() for record in records]})
|
|
|
|
|
|
@blueprint.route("/enrollment-codes", methods=["POST"])
|
|
def create_enrollment_code() -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
payload = request.get_json(silent=True) or {}
|
|
|
|
ttl_value = payload.get("ttl_hours")
|
|
if ttl_value is None:
|
|
ttl_value = payload.get("ttl") or 1
|
|
try:
|
|
ttl_hours = int(ttl_value)
|
|
except (TypeError, ValueError):
|
|
ttl_hours = 1
|
|
|
|
max_uses_value = payload.get("max_uses")
|
|
if max_uses_value is None:
|
|
max_uses_value = payload.get("allowed_uses", 2)
|
|
try:
|
|
max_uses = int(max_uses_value)
|
|
except (TypeError, ValueError):
|
|
max_uses = 2
|
|
|
|
creator = session.get("username") if isinstance(session.get("username"), str) else None
|
|
|
|
try:
|
|
record = _admin_service().create_install_code(
|
|
ttl_hours=ttl_hours,
|
|
max_uses=max_uses,
|
|
created_by=creator,
|
|
)
|
|
except ValueError as exc:
|
|
if str(exc) == "invalid_ttl":
|
|
return jsonify({"error": "invalid_ttl"}), 400
|
|
raise
|
|
|
|
response = jsonify(record.to_dict())
|
|
response.status_code = 201
|
|
return response
|
|
|
|
|
|
@blueprint.route("/enrollment-codes/<code_id>", methods=["DELETE"])
|
|
def delete_enrollment_code(code_id: str) -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
if not _admin_service().delete_install_code(code_id):
|
|
return jsonify({"error": "not_found"}), 404
|
|
return jsonify({"status": "deleted"})
|
|
|
|
|
|
@blueprint.route("/device-approvals", methods=["GET"])
|
|
def list_device_approvals() -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
status = request.args.get("status")
|
|
records = _admin_service().list_device_approvals(status=status)
|
|
return jsonify({"approvals": [record.to_dict() for record in records]})
|
|
|
|
|
|
@blueprint.route("/device-approvals/<approval_id>/approve", methods=["POST"])
|
|
def approve_device_approval(approval_id: str) -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
payload = request.get_json(silent=True) or {}
|
|
guid = payload.get("guid")
|
|
resolution_raw = payload.get("conflict_resolution") or payload.get("resolution")
|
|
resolution = resolution_raw.strip().lower() if isinstance(resolution_raw, str) else None
|
|
|
|
actor = session.get("username") if isinstance(session.get("username"), str) else None
|
|
|
|
try:
|
|
result = _admin_service().approve_device_approval(
|
|
approval_id,
|
|
actor=actor,
|
|
guid=guid,
|
|
conflict_resolution=resolution,
|
|
)
|
|
except LookupError:
|
|
return jsonify({"error": "not_found"}), 404
|
|
except ValueError as exc:
|
|
code = str(exc)
|
|
if code == "approval_not_pending":
|
|
return jsonify({"error": "approval_not_pending"}), 409
|
|
if code == "conflict_resolution_required":
|
|
return jsonify({"error": "conflict_resolution_required"}), 409
|
|
if code == "invalid_guid":
|
|
return jsonify({"error": "invalid_guid"}), 400
|
|
raise
|
|
|
|
response = jsonify(result.to_dict())
|
|
response.status_code = 200
|
|
return response
|
|
|
|
|
|
@blueprint.route("/device-approvals/<approval_id>/deny", methods=["POST"])
|
|
def deny_device_approval(approval_id: str) -> object:
|
|
guard = _require_admin()
|
|
if guard:
|
|
return guard
|
|
|
|
actor = session.get("username") if isinstance(session.get("username"), str) else None
|
|
|
|
try:
|
|
result = _admin_service().deny_device_approval(approval_id, actor=actor)
|
|
except LookupError:
|
|
return jsonify({"error": "not_found"}), 404
|
|
except ValueError as exc:
|
|
if str(exc) == "approval_not_pending":
|
|
return jsonify({"error": "approval_not_pending"}), 409
|
|
raise
|
|
|
|
return jsonify(result.to_dict())
|
|
|
|
|
|
__all__ = ["register", "blueprint"]
|