- 新增完整的 Python 实现,替代 Go 版本 - 添加 Web 登录界面和仪表板 - 实现 JWT 认证和 API 密钥管理 - 添加数据库存储功能 - 保持与 Go 版本一致的目录结构和启动脚本 - 包含完整的文档和测试脚本
161 lines
4.5 KiB
Python
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
|
|
]
|
|
} |