freeleaps-ops/apps/gitea-webhook-ambassador-python/app/handlers/projects.py
Nicolas f6c515157c feat: 添加 Python 版本的 Gitea Webhook Ambassador
- 新增完整的 Python 实现,替代 Go 版本
- 添加 Web 登录界面和仪表板
- 实现 JWT 认证和 API 密钥管理
- 添加数据库存储功能
- 保持与 Go 版本一致的目录结构和启动脚本
- 包含完整的文档和测试脚本
2025-07-20 21:17:10 +08:00

161 lines
4.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from pydantic import BaseModel
from typing import List, Optional
from ..models.database import get_db, ProjectMapping, BranchJob, BranchPattern
from ..auth.middleware import auth_middleware
router = APIRouter(prefix="/api/projects", tags=["projects"])
# 请求/响应模型
class ProjectCreate(BaseModel):
name: str
jenkinsJob: str
giteaRepo: str
class ProjectResponse(BaseModel):
id: int
name: str
jenkinsJob: str
giteaRepo: str
created_at: str
class Config:
from_attributes = True
class ProjectList(BaseModel):
projects: List[ProjectResponse]
@router.post("/", response_model=ProjectResponse)
async def create_project(
request: ProjectCreate,
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""创建新项目映射"""
# 检查项目是否已存在
existing_project = db.query(ProjectMapping).filter(
ProjectMapping.repository_name == request.giteaRepo
).first()
if existing_project:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Project with this repository already exists"
)
# 创建新项目
project = ProjectMapping(
repository_name=request.giteaRepo,
default_job=request.jenkinsJob
)
db.add(project)
db.commit()
db.refresh(project)
return ProjectResponse(
id=project.id,
name=request.name,
jenkinsJob=project.default_job,
giteaRepo=project.repository_name,
created_at=project.created_at.isoformat()
)
@router.get("/", response_model=ProjectList)
async def list_projects(
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""获取所有项目"""
projects = db.query(ProjectMapping).order_by(ProjectMapping.created_at.desc()).all()
return ProjectList(
projects=[
ProjectResponse(
id=project.id,
name=project.repository_name.split('/')[-1], # 使用仓库名作为项目名
jenkinsJob=project.default_job,
giteaRepo=project.repository_name,
created_at=project.created_at.isoformat()
)
for project in projects
]
)
@router.get("/{project_id}", response_model=ProjectResponse)
async def get_project(
project_id: int,
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""获取特定项目"""
project = db.query(ProjectMapping).filter(ProjectMapping.id == project_id).first()
if not project:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Project not found"
)
return ProjectResponse(
id=project.id,
name=project.repository_name.split('/')[-1],
jenkinsJob=project.default_job,
giteaRepo=project.repository_name,
created_at=project.created_at.isoformat()
)
@router.delete("/{project_id}")
async def delete_project(
project_id: int,
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""删除项目"""
project = db.query(ProjectMapping).filter(ProjectMapping.id == project_id).first()
if not project:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Project not found"
)
db.delete(project)
db.commit()
return {"message": "Project deleted successfully"}
@router.get("/mapping/{repository_name}")
async def get_project_mapping(
repository_name: str,
db: Session = Depends(get_db)
):
"""根据仓库名获取项目映射(用于 webhook 处理)"""
project = db.query(ProjectMapping).filter(
ProjectMapping.repository_name == repository_name
).first()
if not project:
return None
return {
"id": project.id,
"repository_name": project.repository_name,
"default_job": project.default_job,
"branch_jobs": [
{
"branch_name": job.branch_name,
"job_name": job.job_name
}
for job in project.branch_jobs
],
"branch_patterns": [
{
"pattern": pattern.pattern,
"job_name": pattern.job_name
}
for pattern in project.branch_patterns
]
}