"""쉘 스크립트 라이브러리 CRUD 엔드포인트.""" from datetime import datetime from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import select, or_ from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user from database import get_db from models import ( ShellScript, ShellScriptCreate, ShellScriptOut, ShellScriptUpdate, User, UserRole, ) router = APIRouter(prefix="/api/shell-scripts", tags=["shell-scripts"]) @router.get("", response_model=List[ShellScriptOut]) async def list_scripts( category: Optional[str] = Query(None), target_layer: Optional[str] = Query(None), os_type: Optional[str] = Query(None), keyword: Optional[str] = Query(None), inst_id: Optional[int] = Query(None), include_public: bool = Query(True), skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user), ): q = select(ShellScript).where(ShellScript.is_active == True) # inst_id 필터: 해당 기관 전용 + 공용(NULL) 포함 가능 if inst_id is not None: if include_public: q = q.where(or_(ShellScript.inst_id == inst_id, ShellScript.inst_id == None)) else: q = q.where(ShellScript.inst_id == inst_id) if category: q = q.where(ShellScript.category == category) if target_layer: q = q.where(or_(ShellScript.target_layer == target_layer, ShellScript.target_layer == "ALL")) if os_type: q = q.where(or_(ShellScript.os_type == os_type, ShellScript.os_type == "ALL")) if keyword: q = q.where( or_( ShellScript.script_name.contains(keyword), ShellScript.description.contains(keyword), ShellScript.tags.contains(keyword), ) ) q = q.order_by(ShellScript.category, ShellScript.script_name).offset(skip).limit(limit) result = await db.execute(q) return result.scalars().all() @router.get("/{script_id}", response_model=ShellScriptOut) async def get_script( script_id: int, db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user), ): r = await db.execute(select(ShellScript).where(ShellScript.id == script_id)) script = r.scalars().first() if not script: raise HTTPException(404, "스크립트를 찾을 수 없습니다.") return script @router.post("", response_model=ShellScriptOut, status_code=201) async def create_script( payload: ShellScriptCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): if current_user.role not in (UserRole.ADMIN, UserRole.PM, UserRole.ENGINEER): raise HTTPException(403, "권한이 없습니다.") data = payload.model_dump() data["author"] = data.get("author") or current_user.username script = ShellScript(**data) db.add(script) await db.commit() await db.refresh(script) return script @router.patch("/{script_id}", response_model=ShellScriptOut) async def update_script( script_id: int, payload: ShellScriptUpdate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): if current_user.role not in (UserRole.ADMIN, UserRole.PM, UserRole.ENGINEER): raise HTTPException(403, "권한이 없습니다.") r = await db.execute(select(ShellScript).where(ShellScript.id == script_id)) script = r.scalars().first() if not script: raise HTTPException(404, "스크립트를 찾을 수 없습니다.") for k, v in payload.model_dump(exclude_unset=True).items(): setattr(script, k, v) script.updated_at = datetime.now() await db.commit() await db.refresh(script) return script @router.delete("/{script_id}", status_code=204) async def delete_script( script_id: int, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): if current_user.role not in (UserRole.ADMIN, UserRole.PM): raise HTTPException(403, "ADMIN 또는 PM 권한이 필요합니다.") r = await db.execute(select(ShellScript).where(ShellScript.id == script_id)) script = r.scalars().first() if not script: raise HTTPException(404, "스크립트를 찾을 수 없습니다.") script.is_active = False script.updated_at = datetime.now() await db.commit() @router.post("/{script_id}/increment-use", status_code=204) async def increment_use_count( script_id: int, db: AsyncSession = Depends(get_db), _u: User = Depends(get_current_user), ): """스크립트 사용 횟수 증가 (타임테이블 연계 시 호출).""" r = await db.execute(select(ShellScript).where(ShellScript.id == script_id)) script = r.scalars().first() if script: script.use_count = (script.use_count or 0) + 1 await db.commit()