166 lines
5.2 KiB
Python
166 lines
5.2 KiB
Python
"""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
|