first commit

This commit is contained in:
2026-02-08 14:42:58 +08:00
commit 20e1deae21
8197 changed files with 2264639 additions and 0 deletions

325
backend/app/routes/gitea.py Normal file
View File

@@ -0,0 +1,325 @@
"""Gitea相关的路由"""
from fastapi import APIRouter, Depends, HTTPException, status, Body, File, Form, UploadFile
import os
import logging
from typing import Optional, Dict, Any, List
from app.gitea.service import gitea_service
from app.dependencies import get_current_active_user
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/gitea", tags=["gitea"])
@router.get("/config")
async def get_gitea_config(
current_user: dict = Depends(get_current_active_user)
):
"""
获取Gitea配置
"""
config = gitea_service.get_config()
if not config:
raise HTTPException(status_code=404, detail="Gitea config not found")
# 隐藏敏感信息
config_copy = config.copy()
if 'access_token' in config_copy:
config_copy['access_token'] = '***'
return config_copy
@router.post("/config")
async def set_gitea_config(
config: Dict[str, Any],
current_user: dict = Depends(get_current_active_user)
):
"""
设置Gitea配置
"""
# 验证配置
required_fields = ['server_url', 'access_token', 'default_owner']
for field in required_fields:
if field not in config or not config[field]:
raise HTTPException(status_code=400, detail=f"Missing required field: {field}")
# 保存配置
success = gitea_service.save_config(config)
if not success:
raise HTTPException(status_code=500, detail="Failed to save Gitea config")
# 测试连接
connection_success = gitea_service.test_connection()
return {
"success": True,
"message": "Gitea config saved successfully",
"connection_test": "success" if connection_success else "failed"
}
@router.get("/test-connection")
async def test_gitea_connection(
current_user: dict = Depends(get_current_active_user)
):
"""
测试Gitea连接
"""
success = gitea_service.test_connection()
if not success:
raise HTTPException(status_code=500, detail="Failed to connect to Gitea server")
return {
"success": True,
"message": "Connected to Gitea server successfully"
}
@router.get("/repos")
async def list_gitea_repositories(
owner: Optional[str] = None,
current_user: dict = Depends(get_current_active_user)
):
"""
列出Gitea仓库
"""
repos = gitea_service.list_repositories(owner)
if repos is None:
raise HTTPException(status_code=500, detail="Failed to list repositories")
return {
"success": True,
"repositories": repos
}
@router.post("/repos/create")
async def create_gitea_repository(
algorithm_id: str = Body(..., description="算法ID"),
algorithm_name: str = Body(..., description="算法名称"),
description: str = Body("", description="仓库描述"),
current_user: dict = Depends(get_current_active_user)
):
"""
创建Gitea仓库
"""
repo = gitea_service.create_repository(algorithm_id, algorithm_name, description)
if not repo:
raise HTTPException(status_code=500, detail="Failed to create repository")
return {
"success": True,
"repository": repo
}
@router.post("/repos/clone")
async def clone_gitea_repository(
repo_url: str = Body(..., description="仓库URL"),
algorithm_id: str = Body(..., description="算法ID"),
branch: str = Body("main", description="分支名称"),
current_user: dict = Depends(get_current_active_user)
):
"""
克隆Gitea仓库
"""
success = gitea_service.clone_repository(repo_url, algorithm_id, branch)
if not success:
# 即使克隆失败,也尝试继续执行,因为我们可能已经初始化了仓库
logger.info("Clone failed, but continuing with existing repository setup")
return {
"success": True,
"message": "Repository cloned or initialized successfully"
}
@router.post("/repos/push")
async def push_to_gitea_repository(
algorithm_id: str = Body(..., description="算法ID"),
message: str = Body("Update code", description="提交消息"),
current_user: dict = Depends(get_current_active_user)
):
"""
推送代码到Gitea仓库
"""
success = gitea_service.push_to_repository(algorithm_id, message)
if not success:
raise HTTPException(status_code=500, detail="Failed to push code")
# 验证推送是否成功
verify_success = gitea_service.verify_push(algorithm_id)
if not verify_success:
logger.warning(f"Push completed but verification failed for algorithm: {algorithm_id}")
return {
"success": True,
"message": "Code pushed but verification failed",
"verified": False
}
return {
"success": True,
"message": "Code pushed successfully",
"verified": True
}
@router.post("/repos/upload", dependencies=[Depends(get_current_active_user)])
async def upload_files_to_repository(
files: list[UploadFile] = File(..., description="上传的文件列表"),
algorithm_id: str = Form(..., description="算法ID")
):
"""
上传文件到仓库(支持大量文件)
"""
try:
logger.info("=== 开始上传文件 ===")
logger.info(f"Received {len(files)} files for algorithm: {algorithm_id}")
# 验证文件数量
MAX_FILES = 50000
if len(files) > MAX_FILES:
logger.error(f"Too many files: {len(files)} (max: {MAX_FILES})")
raise HTTPException(
status_code=400,
detail=f"Too many files. Maximum number of files is {MAX_FILES}."
)
# 创建仓库目录
repo_dir = f"/tmp/algorithms/{algorithm_id}"
logger.info(f"Repository directory: {repo_dir}")
os.makedirs(repo_dir, exist_ok=True)
logger.info(f"Created repository directory: {repo_dir}")
# 保存上传的文件
logger.info("=== 保存上传的文件 ===")
saved_files = []
# 分批处理文件,避免内存问题
batch_size = 100 # 每批处理100个文件
for batch_start in range(0, len(files), batch_size):
batch_end = min(batch_start + batch_size, len(files))
batch = files[batch_start:batch_end]
logger.info(f"Processing batch {batch_start//batch_size + 1}: files {batch_start+1} to {batch_end}")
for i, file in enumerate(batch):
# 为了获取文件内容,我们需要读取它
file_content = await file.read()
# 获取文件路径使用file.filename它应该包含相对路径
file_path = os.path.join(repo_dir, file.filename)
logger.info(f"Processing file {batch_start + i + 1}/{len(files)}: {file.filename}")
logger.info(f" Target path: {file_path}")
# 确保文件所在目录存在
os.makedirs(os.path.dirname(file_path), exist_ok=True)
logger.info(f" Created directory: {os.path.dirname(file_path)}")
# 保存文件
try:
with open(file_path, "wb") as f:
f.write(file_content)
file_stats = os.stat(file_path)
logger.info(f" File size: {file_stats.st_size} bytes")
logger.info(f" ✅ File saved successfully: {file_path}")
saved_files.append(file_path)
except Exception as file_error:
logger.error(f" ❌ Failed to save file {file.filename}: {str(file_error)}")
raise
logger.info(f"=== 文件上传完成 ===")
logger.info(f"Successfully saved {len(saved_files)} files to repository")
return {
"success": True,
"message": "Files uploaded successfully",
"saved_files": saved_files,
"total_files": len(files)
}
except Exception as e:
logger.error(f"=== 上传文件失败 ===")
logger.error(f"Error: {str(e)}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
raise HTTPException(status_code=500, detail=f"Failed to upload files: {str(e)}")
@router.post("/repos/pull")
async def pull_from_gitea_repository(
algorithm_id: str = Body(..., description="算法ID"),
current_user: dict = Depends(get_current_active_user)
):
"""
从Gitea仓库拉取代码
"""
success = gitea_service.pull_from_repository(algorithm_id)
if not success:
raise HTTPException(status_code=500, detail="Failed to pull code")
return {
"success": True,
"message": "Code pulled successfully"
}
@router.patch("/repos/update")
async def update_gitea_repository(
algorithm_id: str = Body(..., description="算法ID"),
name: Optional[str] = Body(None, description="新的仓库名称"),
description: Optional[str] = Body(None, description="新的仓库描述"),
private: Optional[bool] = Body(None, description="是否私有"),
current_user: dict = Depends(get_current_active_user)
):
"""
更新Gitea仓库信息
"""
updated_repo = gitea_service.update_repository_info(algorithm_id, name, description, private)
if not updated_repo:
raise HTTPException(status_code=500, detail="Failed to update repository info")
return {
"success": True,
"message": "Repository info updated successfully",
"repository": updated_repo
}
@router.post("/repos/register")
async def register_algorithm_from_repository(
repo_owner: str = Body(..., description="仓库所有者"),
repo_name: str = Body(..., description="仓库名称"),
algorithm_id: str = Body(..., description="算法ID"),
current_user: dict = Depends(get_current_active_user)
):
"""
从仓库注册算法服务
"""
success = gitea_service.register_algorithm_from_repo(repo_owner, repo_name, algorithm_id)
if not success:
raise HTTPException(status_code=500, detail="Failed to register algorithm from repository")
return {
"success": True,
"message": "Algorithm registered from repository successfully"
}
@router.get("/repos/{repo_owner}/{repo_name}")
async def get_gitea_repository_info(
repo_owner: str,
repo_name: str,
current_user: dict = Depends(get_current_active_user)
):
"""
获取仓库信息
"""
repo = gitea_service.get_repository_info(repo_owner, repo_name)
if not repo:
raise HTTPException(status_code=404, detail="Repository not found")
return repo