""" 프로젝트 소스 등록 관리 API — 바이브 코딩 / 배포 파이프라인 연결. """ from datetime import datetime from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user from database import get_db from models import ( Project, ProjectCreate, ProjectOut, ProjectUpdate, User, UserRole, ) router = APIRouter(prefix="/api/projects", tags=["projects"]) def _require_admin_pm(u: User = Depends(get_current_user)) -> User: if u.role not in (UserRole.ADMIN, UserRole.PM): raise HTTPException(403, "프로젝트 관리 권한이 없습니다.") return u @router.get("", response_model=List[ProjectOut]) async def list_projects( db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user), ): """프로젝트 목록 조회.""" r = await db.execute(select(Project).order_by(Project.created_at.desc())) return r.scalars().all() @router.get("/{project_id}", response_model=ProjectOut) async def get_project( project_id: int, db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user), ): r = await db.execute(select(Project).where(Project.id == project_id)) p = r.scalars().first() if not p: raise HTTPException(404, "프로젝트를 찾을 수 없습니다.") return p @router.post("", response_model=ProjectOut, status_code=201) async def create_project( payload: ProjectCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(_require_admin_pm), ): """프로젝트 등록 (소스 경로, 빌드 명령, 배포 서버 등).""" # 중복 이름 검사 dup = await db.execute( select(Project).where(Project.project_name == payload.project_name) ) if dup.scalars().first(): raise HTTPException(400, f"이미 존재하는 프로젝트 이름: {payload.project_name}") p = Project( **payload.model_dump(), created_by=current_user.username, ) db.add(p) await db.commit() await db.refresh(p) return p @router.put("/{project_id}", response_model=ProjectOut) async def update_project( project_id: int, payload: ProjectUpdate, db: AsyncSession = Depends(get_db), _u: User = Depends(_require_admin_pm), ): r = await db.execute(select(Project).where(Project.id == project_id)) p = r.scalars().first() if not p: raise HTTPException(404, "프로젝트를 찾을 수 없습니다.") for field, value in payload.model_dump(exclude_none=True).items(): setattr(p, field, value) p.updated_at = datetime.now() await db.commit() await db.refresh(p) return p @router.delete("/{project_id}", status_code=204) async def delete_project( project_id: int, db: AsyncSession = Depends(get_db), _u: User = Depends(_require_admin_pm), ): r = await db.execute(select(Project).where(Project.id == project_id)) p = r.scalars().first() if not p: raise HTTPException(404, "프로젝트를 찾을 수 없습니다.") await db.delete(p) await db.commit()