Initial curated Unraid-AppOps-Gateway source from 3bd6f6fee310125bfbb4d4650389a817f498724d
This commit is contained in:
commit
1dfbca08a1
528 files changed
+131054
No files matched your search
@@ -0,0 +1,177 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlmodel import Session
|
||||
|
||||
from ..connectors.sonarr import SonarrConnector
|
||||
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/sonarr', dependencies=[Depends(load_connector_runtime)])
|
||||
|
||||
|
||||
_ADD_SERIES_STEPS = [
|
||||
'Validate payload',
|
||||
'Evaluate policy',
|
||||
'Resolve root folder / quality profile defaults',
|
||||
'Add series in Sonarr',
|
||||
'Optional search missing episodes',
|
||||
'Verify series exists',
|
||||
'Complete audit/job',
|
||||
]
|
||||
|
||||
|
||||
@router.get('/health')
|
||||
def health():
|
||||
return SonarrConnector().health()
|
||||
|
||||
|
||||
@router.get('/queue')
|
||||
def queue():
|
||||
return SonarrConnector().queue_status()
|
||||
|
||||
|
||||
@router.get('/wanted')
|
||||
def wanted():
|
||||
return SonarrConnector().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 SonarrConnector().search_series(query)
|
||||
|
||||
|
||||
@router.post('/series')
|
||||
def add_series(payload: dict, session: Session = Depends(get_session)):
|
||||
action = 'sonarr.add_series'
|
||||
target = 'sonarr'
|
||||
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_SERIES_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_SERIES_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_SERIES_STEPS,
|
||||
)
|
||||
start_job(session, job)
|
||||
set_job_progress(session, job, 35, 'Payload validated and policy allowed.')
|
||||
|
||||
connector_result = SonarrConnector().add_series(payload)
|
||||
success = bool(connector_result.get('success'))
|
||||
result_status = 'succeeded' if success else 'failed'
|
||||
message = str(connector_result.get('message', 'series_added' if success else 'sonarr_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_SERIES_STEPS, 'jobId': completed.id},
|
||||
after_state={'status': connector_result.get('status'), 'message': message},
|
||||
redacted_metadata={'connector': 'sonarr'},
|
||||
)
|
||||
|
||||
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', {}),
|
||||
}
|
||||
Reference in new issue
Block a user