175 lines
5.8 KiB
Python
175 lines
5.8 KiB
Python
"""
|
||
项目Git仓库管理 API
|
||
"""
|
||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from sqlalchemy import select, update, func
|
||
from typing import List
|
||
|
||
from app.core.database import get_db
|
||
from app.core.deps import get_current_user
|
||
from app.models.user import User
|
||
from app.models.project import Project, ProjectMember
|
||
from app.models.git_repo import ProjectGitRepo
|
||
from app.schemas.git_repo import GitRepoCreate, GitRepoUpdate, GitRepoResponse
|
||
from app.schemas.response import success_response
|
||
from app.services.log_service import log_service
|
||
from app.core.enums import OperationType
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
async def check_project_permission(db: AsyncSession, project_id: int, user_id: int, required_roles: list = None):
|
||
"""检查项目权限"""
|
||
# 查询项目
|
||
result = await db.execute(select(Project).where(Project.id == project_id))
|
||
project = result.scalar_one_or_none()
|
||
|
||
if not project:
|
||
raise HTTPException(status_code=404, detail="项目不存在")
|
||
|
||
# 如果是所有者,直接通过
|
||
if project.owner_id == user_id:
|
||
return project
|
||
|
||
# 如果指定了角色要求
|
||
if required_roles:
|
||
member_result = await db.execute(
|
||
select(ProjectMember).where(
|
||
ProjectMember.project_id == project_id,
|
||
ProjectMember.user_id == user_id,
|
||
ProjectMember.role.in_(required_roles)
|
||
)
|
||
)
|
||
if not member_result.scalar_one_or_none():
|
||
raise HTTPException(status_code=403, detail="无权执行此操作")
|
||
|
||
return project
|
||
|
||
|
||
@router.get("/projects/{project_id}/git-repos", response_model=dict)
|
||
async def get_project_git_repos(
|
||
project_id: int,
|
||
current_user: User = Depends(get_current_user),
|
||
db: AsyncSession = Depends(get_db)
|
||
):
|
||
"""获取项目的Git仓库列表"""
|
||
# 检查权限(查看权限即可)
|
||
# 这里稍微放宽一点,只要能访问项目就能看Git配置?
|
||
# 为了安全,还是限制为成员
|
||
await check_project_permission(db, project_id, current_user.id, ['admin', 'editor', 'viewer'])
|
||
|
||
result = await db.execute(
|
||
select(ProjectGitRepo).where(ProjectGitRepo.project_id == project_id).order_by(ProjectGitRepo.created_at)
|
||
)
|
||
repos = result.scalars().all()
|
||
|
||
# 隐藏 token
|
||
data = []
|
||
for repo in repos:
|
||
repo_dict = GitRepoResponse.from_orm(repo).dict()
|
||
# repo_dict['token'] = '******' if repo.token else None # 前端可能需要回显或者判断是否有token
|
||
data.append(repo_dict)
|
||
|
||
return success_response(data=data)
|
||
|
||
|
||
@router.post("/projects/{project_id}/git-repos", response_model=dict)
|
||
async def create_git_repo(
|
||
project_id: int,
|
||
repo_in: GitRepoCreate,
|
||
request: Request,
|
||
current_user: User = Depends(get_current_user),
|
||
db: AsyncSession = Depends(get_db)
|
||
):
|
||
"""添加Git仓库"""
|
||
await check_project_permission(db, project_id, current_user.id, ['admin', 'editor'])
|
||
|
||
# 如果是设为默认,先取消其他默认
|
||
if repo_in.is_default:
|
||
await db.execute(
|
||
update(ProjectGitRepo)
|
||
.where(ProjectGitRepo.project_id == project_id)
|
||
.values(is_default=0)
|
||
)
|
||
|
||
# 检查是否是第一个仓库,如果是,强制设为默认
|
||
result = await db.execute(select(func.count()).select_from(ProjectGitRepo).where(ProjectGitRepo.project_id == project_id))
|
||
count = result.scalar()
|
||
is_default = repo_in.is_default
|
||
if count == 0:
|
||
is_default = 1
|
||
|
||
db_repo = ProjectGitRepo(
|
||
project_id=project_id,
|
||
name=repo_in.name,
|
||
repo_url=repo_in.repo_url,
|
||
branch=repo_in.branch,
|
||
username=repo_in.username,
|
||
token=repo_in.token,
|
||
is_default=is_default
|
||
)
|
||
db.add(db_repo)
|
||
await db.commit()
|
||
await db.refresh(db_repo)
|
||
|
||
return success_response(data=GitRepoResponse.from_orm(db_repo).dict(), message="Git仓库添加成功")
|
||
|
||
|
||
@router.put("/projects/{project_id}/git-repos/{repo_id}", response_model=dict)
|
||
async def update_git_repo(
|
||
project_id: int,
|
||
repo_id: int,
|
||
repo_in: GitRepoUpdate,
|
||
request: Request,
|
||
current_user: User = Depends(get_current_user),
|
||
db: AsyncSession = Depends(get_db)
|
||
):
|
||
"""更新Git仓库"""
|
||
await check_project_permission(db, project_id, current_user.id, ['admin', 'editor'])
|
||
|
||
result = await db.execute(select(ProjectGitRepo).where(ProjectGitRepo.id == repo_id, ProjectGitRepo.project_id == project_id))
|
||
repo = result.scalar_one_or_none()
|
||
|
||
if not repo:
|
||
raise HTTPException(status_code=404, detail="仓库不存在")
|
||
|
||
# 如果设为默认,取消其他默认
|
||
if repo_in.is_default == 1:
|
||
await db.execute(
|
||
update(ProjectGitRepo)
|
||
.where(ProjectGitRepo.project_id == project_id)
|
||
.values(is_default=0)
|
||
)
|
||
|
||
update_data = repo_in.dict(exclude_unset=True)
|
||
for field, value in update_data.items():
|
||
setattr(repo, field, value)
|
||
|
||
await db.commit()
|
||
await db.refresh(repo)
|
||
|
||
return success_response(data=GitRepoResponse.from_orm(repo).dict(), message="更新成功")
|
||
|
||
|
||
@router.delete("/projects/{project_id}/git-repos/{repo_id}", response_model=dict)
|
||
async def delete_git_repo(
|
||
project_id: int,
|
||
repo_id: int,
|
||
current_user: User = Depends(get_current_user),
|
||
db: AsyncSession = Depends(get_db)
|
||
):
|
||
"""删除Git仓库"""
|
||
await check_project_permission(db, project_id, current_user.id, ['admin', 'editor'])
|
||
|
||
result = await db.execute(select(ProjectGitRepo).where(ProjectGitRepo.id == repo_id, ProjectGitRepo.project_id == project_id))
|
||
repo = result.scalar_one_or_none()
|
||
|
||
if not repo:
|
||
raise HTTPException(status_code=404, detail="仓库不存在")
|
||
|
||
await db.delete(repo)
|
||
await db.commit()
|
||
|
||
return success_response(message="删除成功")
|