""" 项目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="删除成功")