First steps for auth

This commit is contained in:
Xoconoch
2025-08-03 20:16:07 -06:00
parent dc878b26ac
commit 6ab603d90a
37 changed files with 2315 additions and 160 deletions

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter, HTTPException, Request
from fastapi import APIRouter, HTTPException, Request, Depends
from fastapi.responses import JSONResponse
import json
import logging
@@ -18,6 +18,9 @@ from routes.utils.watch.manager import (
CONFIG_FILE_PATH as WATCH_CONFIG_FILE_PATH,
)
# Import authentication dependencies
from routes.auth.middleware import require_admin_from_state, User
logger = logging.getLogger(__name__)
router = APIRouter()
@@ -206,7 +209,7 @@ def save_watch_config_http(watch_config_data): # Renamed
@router.get("/config")
async def handle_config():
async def handle_config(current_user: User = Depends(require_admin_from_state)):
"""Handles GET requests for the main configuration."""
try:
config = get_config()
@@ -221,7 +224,7 @@ async def handle_config():
@router.post("/config")
@router.put("/config")
async def update_config(request: Request):
async def update_config(request: Request, current_user: User = Depends(require_admin_from_state)):
"""Handles POST/PUT requests to update the main configuration."""
try:
new_config = await request.json()
@@ -271,7 +274,7 @@ async def update_config(request: Request):
@router.get("/config/check")
async def check_config_changes():
async def check_config_changes(current_user: User = Depends(require_admin_from_state)):
# This endpoint seems more related to dynamically checking if config changed
# on disk, which might not be necessary if settings are applied on restart
# or by a dedicated manager. For now, just return current config.
@@ -287,7 +290,7 @@ async def check_config_changes():
@router.post("/config/validate")
async def validate_config_endpoint(request: Request):
async def validate_config_endpoint(request: Request, current_user: User = Depends(require_admin_from_state)):
"""Validate configuration without saving it."""
try:
config_data = await request.json()
@@ -313,7 +316,7 @@ async def validate_config_endpoint(request: Request):
@router.post("/config/watch/validate")
async def validate_watch_config_endpoint(request: Request):
async def validate_watch_config_endpoint(request: Request, current_user: User = Depends(require_admin_from_state)):
"""Validate watch configuration without saving it."""
try:
watch_data = await request.json()
@@ -339,7 +342,7 @@ async def validate_watch_config_endpoint(request: Request):
@router.get("/config/watch")
async def handle_watch_config():
async def handle_watch_config(current_user: User = Depends(require_admin_from_state)):
"""Handles GET requests for the watch configuration."""
try:
watch_config = get_watch_config_http()
@@ -354,7 +357,7 @@ async def handle_watch_config():
@router.post("/config/watch")
@router.put("/config/watch")
async def update_watch_config(request: Request):
async def update_watch_config(request: Request, current_user: User = Depends(require_admin_from_state)):
"""Handles POST/PUT requests to update the watch configuration."""
try:
new_watch_config = await request.json()

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter, HTTPException, Request
from fastapi import APIRouter, HTTPException, Request, Depends
from fastapi.responses import JSONResponse, StreamingResponse
import logging
import time
@@ -15,6 +15,9 @@ from routes.utils.celery_tasks import (
ProgressState,
)
# Import authentication dependencies
from routes.auth.middleware import require_auth_from_state, get_current_user_from_state, User
# Configure logging
logger = logging.getLogger(__name__)
@@ -575,7 +578,7 @@ async def get_paginated_tasks(page=1, limit=20, active_only=False, request: Requ
# Otherwise "updates" gets matched as a {task_id} parameter!
@router.get("/list")
async def list_tasks(request: Request):
async def list_tasks(request: Request, current_user: User = Depends(require_auth_from_state)):
"""
Retrieve a paginated list of all tasks in the system.
Returns a detailed list of task objects including status and metadata.
@@ -704,7 +707,7 @@ async def list_tasks(request: Request):
@router.get("/updates")
async def get_task_updates(request: Request):
async def get_task_updates(request: Request, current_user: User = Depends(require_auth_from_state)):
"""
Retrieve only tasks that have been updated since the specified timestamp.
This endpoint is optimized for polling to reduce unnecessary data transfer.
@@ -791,7 +794,7 @@ async def get_task_updates(request: Request):
# Sort by priority (active first, then by creation time)
all_returned_tasks.sort(key=lambda x: (
0 if x.get("task_id") in [t["task_id"] for t in active_tasks] else 1,
-x.get("created_at", 0)
-(x.get("created_at") or 0)
))
response = {
@@ -823,7 +826,7 @@ async def get_task_updates(request: Request):
@router.post("/cancel/all")
async def cancel_all_tasks():
async def cancel_all_tasks(current_user: User = Depends(require_auth_from_state)):
"""
Cancel all active (running or queued) tasks.
"""
@@ -856,7 +859,7 @@ async def cancel_all_tasks():
@router.post("/cancel/{task_id}")
async def cancel_task_endpoint(task_id: str):
async def cancel_task_endpoint(task_id: str, current_user: User = Depends(require_auth_from_state)):
"""
Cancel a running or queued task.
@@ -888,7 +891,7 @@ async def cancel_task_endpoint(task_id: str):
@router.delete("/delete/{task_id}")
async def delete_task(task_id: str):
async def delete_task(task_id: str, current_user: User = Depends(require_auth_from_state)):
"""
Delete a task's information and history.
@@ -907,10 +910,11 @@ async def delete_task(task_id: str):
@router.get("/stream")
async def stream_task_updates(request: Request):
async def stream_task_updates(request: Request, current_user: User = Depends(get_current_user_from_state)):
"""
Stream real-time task updates via Server-Sent Events (SSE).
Now uses event-driven architecture for true real-time updates.
Uses optional authentication to avoid breaking SSE connections.
Query parameters:
active_only (bool): If true, only stream active tasks (downloading, processing, etc.)
@@ -1101,7 +1105,7 @@ async def generate_task_update_event(since_timestamp: float, active_only: bool,
# Sort by priority (active first, then by creation time)
all_returned_tasks.sort(key=lambda x: (
0 if x.get("task_id") in [t["task_id"] for t in active_tasks] else 1,
-x.get("created_at", 0)
-(x.get("created_at") or 0)
))
initial_data = {
@@ -1127,7 +1131,7 @@ async def generate_task_update_event(since_timestamp: float, active_only: bool,
# IMPORTANT: This parameterized route MUST come AFTER all specific routes
# Otherwise FastAPI will match specific routes like "/updates" as task_id parameters
@router.get("/{task_id}")
async def get_task_details(task_id: str, request: Request):
async def get_task_details(task_id: str, request: Request, current_user: User = Depends(require_auth_from_state)):
"""
Return a JSON object with the resource type, its name (title),
the last progress update, and, if available, the original request parameters.