feat: complete web application — FastAPI backend + Vue 3 SPA frontend
- Full FastAPI backend with JWT auth, file management, processing pipeline, memory CRUD, barcode mappings, config management, cloud sync - Vue 3 + Element Plus frontend with dashboard, task history, HTTP logs, memory editor, barcode editor, config editor, sync page - HTTP request logging middleware with SQLite persistence - Task history tracking with progress and retry support - File metadata recording for upload/download operations - WebAuth section in config.ini for bcrypt password storage - Bug fix: logs.py count query returns tuple not dict Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""Cloud sync endpoints (Gitea-based)."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends, Request
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..auth.dependencies import get_current_user
|
||||
from ..services.task_manager import TaskManager
|
||||
|
||||
router = APIRouter(prefix="/api/sync", tags=["sync"])
|
||||
|
||||
_project_root = Path(__file__).resolve().parent.parent.parent.parent
|
||||
|
||||
|
||||
class SyncResponse(BaseModel):
|
||||
task_id: str
|
||||
status: str
|
||||
message: str
|
||||
|
||||
|
||||
def _get_sync():
|
||||
from app.core.utils.cloud_sync import GiteaSync
|
||||
from app.config.settings import ConfigManager
|
||||
cfg = ConfigManager()
|
||||
return GiteaSync(cfg)
|
||||
|
||||
|
||||
@router.post("/push", response_model=SyncResponse)
|
||||
async def sync_push(
|
||||
request: Request,
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
tm = request.state.task_manager
|
||||
task = tm.create_task("推送到云端")
|
||||
|
||||
async def _run():
|
||||
try:
|
||||
tm.update_progress(task.id, 10, "正在初始化同步...")
|
||||
sync = _get_sync()
|
||||
tm.update_progress(task.id, 30, "正在推送文件...")
|
||||
tm.add_log(task.id, "[Push] 开始推送")
|
||||
result = sync.push()
|
||||
tm.add_log(task.id, f"[Push] 完成: {result}")
|
||||
tm.set_completed(task.id, message="推送完成")
|
||||
except Exception as e:
|
||||
tm.set_failed(task.id, str(e))
|
||||
|
||||
import asyncio
|
||||
asyncio.create_task(_run())
|
||||
return SyncResponse(task_id=task.id, status="accepted", message="推送任务已创建")
|
||||
|
||||
|
||||
@router.post("/pull", response_model=SyncResponse)
|
||||
async def sync_pull(
|
||||
request: Request,
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
tm = request.state.task_manager
|
||||
task = tm.create_task("从云端拉取")
|
||||
|
||||
async def _run():
|
||||
try:
|
||||
tm.update_progress(task.id, 10, "正在初始化同步...")
|
||||
sync = _get_sync()
|
||||
tm.update_progress(task.id, 30, "正在拉取文件...")
|
||||
tm.add_log(task.id, "[Pull] 开始拉取")
|
||||
result = sync.pull()
|
||||
tm.add_log(task.id, f"[Pull] 完成: {result}")
|
||||
tm.set_completed(task.id, message="拉取完成")
|
||||
except Exception as e:
|
||||
tm.set_failed(task.id, str(e))
|
||||
|
||||
import asyncio
|
||||
asyncio.create_task(_run())
|
||||
return SyncResponse(task_id=task.id, status="accepted", message="拉取任务已创建")
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def sync_status(
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
try:
|
||||
from app.config.settings import ConfigManager
|
||||
cfg = ConfigManager()
|
||||
base_url = cfg.get("Gitea", "base_url", fallback="")
|
||||
owner = cfg.get("Gitea", "owner", fallback="")
|
||||
repo = cfg.get("Gitea", "repo", fallback="")
|
||||
enabled = bool(base_url and owner and repo)
|
||||
repo_url = f"{base_url}/{owner}/{repo}" if enabled else ""
|
||||
return {"enabled": enabled, "repo_url": repo_url}
|
||||
except Exception:
|
||||
return {"enabled": False, "repo_url": ""}
|
||||
Reference in New Issue
Block a user