"""Settings API endpoints.""" import json from pathlib import Path from quart import Blueprint, request, jsonify, current_app from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.models.setting import Setting, DEFAULT_SETTINGS, EXTENSION_API_KEY_SETTING, generate_api_key from app.config import get_settings bp = Blueprint("settings", __name__) async def get_or_create_extension_api_key(session: AsyncSession) -> str: """Get the extension API key, creating one if it doesn't exist.""" result = await session.execute( select(Setting).where(Setting.key == EXTENSION_API_KEY_SETTING) ) setting = result.scalar() if setting: return setting.value # Generate new key new_key = generate_api_key() setting = Setting(key=EXTENSION_API_KEY_SETTING, value=new_key) session.add(setting) await session.commit() return new_key @bp.route("", methods=["GET"]) async def get_all_settings(): """Get all application settings.""" async with current_app.db_engine.connect() as conn: session = AsyncSession(bind=conn) result = await session.execute(select(Setting)) settings = result.scalars().all() # Build settings dict with defaults settings_dict = dict(DEFAULT_SETTINGS) for s in settings: settings_dict[s.key] = s.value # Ensure extension API key exists api_key = await get_or_create_extension_api_key(session) settings_dict[EXTENSION_API_KEY_SETTING] = api_key return jsonify({"settings": settings_dict}) @bp.route("", methods=["PATCH"]) async def update_settings(): """Update application settings.""" data = await request.get_json() if not data: return jsonify({"error": "No settings provided"}), 400 async with current_app.db_engine.connect() as conn: session = AsyncSession(bind=conn) for key, value in data.items(): # Check if setting exists result = await session.execute(select(Setting).where(Setting.key == key)) setting = result.scalar() if setting: setting.value = value else: setting = Setting(key=key, value=value) session.add(setting) await session.commit() # Return updated settings result = await session.execute(select(Setting)) settings = result.scalars().all() settings_dict = dict(DEFAULT_SETTINGS) for s in settings: settings_dict[s.key] = s.value current_app.logger.info(f"Updated settings: {list(data.keys())}") return jsonify({"settings": settings_dict}) @bp.route("/api-key", methods=["GET"]) async def get_extension_api_key(): """Get the extension API key.""" async with current_app.db_engine.connect() as conn: session = AsyncSession(bind=conn) api_key = await get_or_create_extension_api_key(session) return jsonify({"api_key": api_key}) @bp.route("/api-key/regenerate", methods=["POST"]) async def regenerate_extension_api_key(): """Regenerate the extension API key.""" async with current_app.db_engine.connect() as conn: session = AsyncSession(bind=conn) # Find existing key result = await session.execute( select(Setting).where(Setting.key == EXTENSION_API_KEY_SETTING) ) setting = result.scalar() # Generate new key new_key = generate_api_key() if setting: setting.value = new_key else: setting = Setting(key=EXTENSION_API_KEY_SETTING, value=new_key) session.add(setting) await session.commit() current_app.logger.info("Extension API key regenerated") return jsonify({"api_key": new_key, "message": "API key regenerated"}) @bp.route("/gallery-dl", methods=["GET"]) async def get_gallery_dl_config(): """Get gallery-dl configuration.""" config = get_settings() config_path = Path(config.config_path) / "gallery-dl.conf" if not config_path.exists(): return jsonify({"config": {}, "message": "No configuration file found"}) try: with open(config_path) as f: gallery_dl_config = json.load(f) return jsonify({"config": gallery_dl_config}) except json.JSONDecodeError as e: return jsonify({"error": f"Invalid JSON in config file: {e}"}), 500 @bp.route("/gallery-dl", methods=["PUT"]) async def update_gallery_dl_config(): """Update gallery-dl configuration.""" data = await request.get_json() if not data.get("config"): return jsonify({"error": "Config object is required"}), 400 config = get_settings() config_path = Path(config.config_path) / "gallery-dl.conf" # Ensure config directory exists config_path.parent.mkdir(parents=True, exist_ok=True) try: with open(config_path, "w") as f: json.dump(data["config"], f, indent=4) current_app.logger.info("Updated gallery-dl configuration") return jsonify({"message": "Configuration updated", "config": data["config"]}) except Exception as e: current_app.logger.error(f"Failed to write gallery-dl config: {e}") return jsonify({"error": f"Failed to write config: {e}"}), 500