163 lines
6.5 KiB
Python
163 lines
6.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from typing import Optional
|
|
import os
|
|
import string
|
|
import uuid
|
|
from pathlib import Path
|
|
from pydantic import BaseModel
|
|
|
|
from app.core.database import get_db
|
|
from app.api.deps import require_admin
|
|
from app.models.models import User
|
|
from app.schemas.schemas import SystemSettingsResponse, SystemSettingsUpdate
|
|
from app.services.settings_service import get_all_settings, update_settings_service
|
|
|
|
router = APIRouter(prefix="/settings", tags=["System Settings"])
|
|
|
|
class TestShareRequest(BaseModel):
|
|
path: str
|
|
username: str
|
|
password: str
|
|
|
|
@router.get("", response_model=SystemSettingsResponse)
|
|
async def get_settings(
|
|
db: AsyncSession = Depends(get_db),
|
|
admin_user: User = Depends(require_admin)
|
|
):
|
|
"""Retrieve global system settings."""
|
|
settings_dict = await get_all_settings(db)
|
|
return {
|
|
"storage_root": settings_dict.get("storage_root", ""),
|
|
"global_quota_gb": int(settings_dict.get("global_quota_gb", 1000)),
|
|
"default_client_quota_gb": int(settings_dict.get("default_client_quota_gb", 100)),
|
|
"default_keep_daily": int(settings_dict.get("default_keep_daily", 7)),
|
|
"default_keep_weekly": int(settings_dict.get("default_keep_weekly", 4)),
|
|
"default_keep_monthly": int(settings_dict.get("default_keep_monthly", 12)),
|
|
"auth_mode": settings_dict.get("auth_mode", "local"),
|
|
"radius_host": settings_dict.get("radius_host", ""),
|
|
"radius_port": int(settings_dict.get("radius_port", 1812)) if settings_dict.get("radius_port") else 1812,
|
|
"radius_secret": settings_dict.get("radius_secret", ""),
|
|
"storage_network_enabled": settings_dict.get("storage_network_enabled", "false").lower() == "true",
|
|
"storage_network_user": settings_dict.get("storage_network_user", ""),
|
|
"storage_network_pass": settings_dict.get("storage_network_pass", ""),
|
|
}
|
|
|
|
@router.put("", response_model=SystemSettingsResponse)
|
|
async def update_settings(
|
|
payload: SystemSettingsUpdate,
|
|
db: AsyncSession = Depends(get_db),
|
|
admin_user: User = Depends(require_admin)
|
|
):
|
|
"""Update global system settings."""
|
|
# Convert Pydantic model to a dict of values (filtering out None)
|
|
updates = {k: v for k, v in payload.model_dump().items() if v is not None}
|
|
|
|
try:
|
|
settings_dict = await update_settings_service(db, updates)
|
|
except ValueError as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=str(e)
|
|
)
|
|
|
|
return {
|
|
"storage_root": settings_dict.get("storage_root", ""),
|
|
"global_quota_gb": int(settings_dict.get("global_quota_gb", 1000)),
|
|
"default_client_quota_gb": int(settings_dict.get("default_client_quota_gb", 100)),
|
|
"default_keep_daily": int(settings_dict.get("default_keep_daily", 7)),
|
|
"default_keep_weekly": int(settings_dict.get("default_keep_weekly", 4)),
|
|
"default_keep_monthly": int(settings_dict.get("default_keep_monthly", 12)),
|
|
"auth_mode": settings_dict.get("auth_mode", "local"),
|
|
"radius_host": settings_dict.get("radius_host", ""),
|
|
"radius_port": int(settings_dict.get("radius_port", 1812)) if settings_dict.get("radius_port") else 1812,
|
|
"radius_secret": settings_dict.get("radius_secret", ""),
|
|
"storage_network_enabled": settings_dict.get("storage_network_enabled", "false").lower() == "true",
|
|
"storage_network_user": settings_dict.get("storage_network_user", ""),
|
|
"storage_network_pass": settings_dict.get("storage_network_pass", ""),
|
|
}
|
|
|
|
@router.get("/explore-dir")
|
|
async def explore_directory(
|
|
path: Optional[str] = None,
|
|
admin_user: User = Depends(require_admin)
|
|
):
|
|
"""
|
|
Explore directories on the host filesystem.
|
|
"""
|
|
import platform
|
|
|
|
if not path or path.strip() == "":
|
|
if platform.system().lower() == "windows":
|
|
drives = []
|
|
for letter in string.ascii_uppercase:
|
|
drive_path = f"{letter}:\\"
|
|
if os.path.exists(drive_path):
|
|
drives.append({"name": drive_path, "path": drive_path})
|
|
return {"current_path": "", "folders": drives}
|
|
else:
|
|
return {"current_path": "/", "folders": [{"name": "/", "path": "/"}]}
|
|
|
|
# Resolve path
|
|
target = Path(path).resolve()
|
|
if not target.exists() or not target.is_dir():
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"The path '{path}' does not exist or is not a directory."
|
|
)
|
|
|
|
try:
|
|
folders = []
|
|
for entry in os.scandir(target):
|
|
try:
|
|
if entry.is_dir():
|
|
folders.append({
|
|
"name": entry.name,
|
|
"path": str(Path(entry.path).resolve())
|
|
})
|
|
except Exception:
|
|
continue # Skip inaccessible
|
|
|
|
folders.sort(key=lambda x: x["name"].lower())
|
|
|
|
return {
|
|
"current_path": str(target),
|
|
"parent_path": str(target.parent) if target.parent != target else None,
|
|
"folders": folders
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Failed to read directory contents: {str(e)}"
|
|
)
|
|
|
|
@router.post("/test-network-share")
|
|
async def test_network_share(
|
|
payload: TestShareRequest,
|
|
admin_user: User = Depends(require_admin)
|
|
):
|
|
"""
|
|
Attempts to connect to a UNC network share and tests write access.
|
|
"""
|
|
from app.services.settings_service import connect_network_share
|
|
|
|
ok = connect_network_share(payload.path, payload.username, payload.password)
|
|
if not ok:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Failed to connect to the network share. Check the server path, username, and password."
|
|
)
|
|
|
|
try:
|
|
target_path = Path(payload.path)
|
|
os.makedirs(target_path, exist_ok=True)
|
|
test_file = target_path / f".write_test_{uuid.uuid4().hex[:6]}"
|
|
test_file.touch()
|
|
test_file.unlink()
|
|
return {"message": "Network share connected and write access verified successfully!"}
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Network share connected, but write access test failed: {str(e)}"
|
|
)
|