from __future__ import annotations from fastapi import APIRouter, Depends from sqlmodel import Session from ..connectors.radarr import RadarrConnector from ..db.session import get_session from ..services.approval_service import create_approval from ..services.audit_logger import log_event from ..services.job_runner import complete_job, create_job, set_job_progress, start_job from ..services.policy_engine import evaluate_policy from .connector_runtime import load_connector_runtime router = APIRouter(prefix='/api/apps/radarr', dependencies=[Depends(load_connector_runtime)]) _ADD_MOVIE_STEPS = [ 'Validate payload', 'Evaluate policy', 'Resolve root folder / quality profile defaults', 'Add movie in Radarr', 'Optional search movie', 'Verify movie exists', 'Complete audit/job', ] @router.get('/health') def health(): return RadarrConnector().health() @router.get('/queue') def queue(): return RadarrConnector().queue_status() @router.get('/wanted') def wanted(): return RadarrConnector().wanted_missing() @router.get('/search') def search(q: str = ''): query = q.strip() if not query: return {'success': False, 'status': 'error', 'message': 'query_required', 'items': []} return RadarrConnector().search_movie(query) @router.post('/movie') def add_movie(payload: dict, session: Session = Depends(get_session)): action = 'radarr.add_movie' target = 'radarr' source = str(payload.get('source', 'manual')).strip() or 'manual' policy = evaluate_policy(session=session, action=action, target=target, source=source) risk = str(policy.get('risk', 'low')) if policy['decision'] == 'blocked': audit = log_event( session, source='action', identity=source, action_id=action, target=target, risk=risk, policy_decision='blocked', reason=policy['reason'], result='blocked', execution_plan={'plan': _ADD_MOVIE_STEPS, 'policyReason': policy['reason']}, ) return { 'success': False, 'decision': 'blocked', 'status': 'failed', 'policy_decision': 'blocked', 'result': 'blocked', 'message': policy['reason'], 'auditId': audit.id, } if policy['decision'] == 'approval_required': approval = create_approval( session, action=action, target=target, source=source, risk=risk, reason=policy['reason'], requester=source, ) audit = log_event( session, source='action', identity=source, action_id=action, target=target, risk=risk, policy_decision='approval_required', reason=policy['reason'], result='approval_requested', execution_plan={'plan': _ADD_MOVIE_STEPS, 'approvalId': approval.id}, redacted_metadata={'approval_id': approval.id}, ) return { 'success': False, 'decision': 'approval_required', 'status': 'failed', 'policy_decision': 'approval_required', 'result': 'approval_required', 'message': 'Action requires approval before execution.', 'approvalId': approval.id, 'auditId': audit.id, } job = create_job( session, action_id=action, target=target, source=source, risk=risk, policy_decision='allowed', steps=_ADD_MOVIE_STEPS, ) start_job(session, job) set_job_progress(session, job, 35, 'Payload validated and policy allowed.') connector_result = RadarrConnector().add_movie(payload) success = bool(connector_result.get('success')) result_status = 'succeeded' if success else 'failed' message = str(connector_result.get('message', 'movie_added' if success else 'radarr_failed')) completed = complete_job( session, job, status=result_status, result_summary=message, ) audit = log_event( session, source='action', identity=source, action_id=action, target=target, risk=risk, policy_decision='allowed', reason=policy['reason'], result='success' if success else 'failed', execution_plan={'plan': _ADD_MOVIE_STEPS, 'jobId': completed.id}, after_state={'status': connector_result.get('status'), 'message': message}, redacted_metadata={'connector': 'radarr'}, ) if not success: return { 'success': False, 'decision': 'failed', 'status': 'failed', 'policy_decision': 'allowed', 'result': 'failed', 'message': message, 'jobId': completed.id, 'auditId': audit.id, 'data': connector_result.get('data'), } return { 'success': True, 'decision': 'allowed', 'status': 'success', 'policy_decision': 'allowed', 'result': 'success', 'message': message, 'jobId': completed.id, 'auditId': audit.id, 'data': connector_result.get('data', {}), }