Files
Aislo/B01_Dashboard/B01_Dashboard_Router_Trash.py
T
eomsangdonandClaude Opus 5.5 ac481a0764 feat(B01): 프로젝트 휴지통 — 지움 = 휴지통 · 7 일 뒤 영구 삭제 · 되살리기 (PLAN 592-1 · 요구 454 · 455)
- 대시보드 지움 = 늘 휴지통(deleted_at) · PROJECT_DELETE_HARD_ENABLED 스위치 걷음 → TRASH_RETENTION_DAYS(7)
- 영구 삭제(hard_delete_project) = 휴지통 것만 · FOR UPDATE · 이미 지운 것 False 로 건너뜀 · 감사 기록 동작 이름 받음
- 정리 루프에 purge_expired_trash — GET_LOCK 이름 잠금(두 PC 서버 중 하나만) · 기한 지난 것 PROJECT_PURGE
- API /api/dashboard/trash/projects — 보기 · 되살리기 = 시스템 관리자(전부) · 회사 관리자(자기 회사) · 영구 삭제 = 시스템 관리자만
- 화면 휴지통 — 시스템 관리 › 휴지통 · 회사 관리 › 휴지통(회사 관리자 · 되살리기만) · 지운 사람 = 감사 기록
- 시험 test_592_1_trash 새로 · test_546 메뉴 기대값에 휴지통 · test_573 복제본 지움을 휴지통 거쳐 영구 삭제로(영구 삭제 = 휴지통 것만)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 08:31:11 +09:00

52 lines
2.0 KiB
Python

"""B01_Dashboard 프로젝트 휴지통 API(592) — 본체 라우터가 include 함.
보기 · 되살리기 = 시스템 관리자(전부) · 회사 관리자(자기 회사) · 영구 삭제 = 시스템 관리자만.
"""
from typing import Any
from fastapi import APIRouter, Depends, HTTPException, Request
from common_util.common_util_auth import require_system_admin
from common_util.common_util_project_delete import hard_delete_project
from .B01_Dashboard_Repository_Trash import get_trash_project, list_trash_projects, restore_project
from .B01_Dashboard_Scope import _require_company_id, _same_company, require_company_admin
router = APIRouter()
_GONE = "휴지통에 없는 프로젝트입니다."
@router.get("/trash/projects")
async def trash_projects(session: dict[str, Any] = Depends(require_company_admin)):
company_id = None if session["role"] == "SYSTEM_ADMIN" else _require_company_id(session)
return {"status": "success", "projects": await list_trash_projects(company_id)}
@router.post("/trash/projects/{project_id}/restore")
async def trash_restore(
project_id: str,
request: Request,
session: dict[str, Any] = Depends(require_company_admin),
):
project = await get_trash_project(project_id)
if not project:
raise HTTPException(status_code=404, detail=_GONE)
if session["role"] != "SYSTEM_ADMIN" and not _same_company(session, project.get("company_id")):
raise HTTPException(status_code=403, detail="다른 회사의 프로젝트는 되살릴 수 없습니다.")
if not await restore_project(project_id, int(session["user_id"]), request):
raise HTTPException(status_code=404, detail=_GONE)
return {"status": "success"}
@router.delete("/trash/projects/{project_id}")
async def trash_purge(
project_id: str,
request: Request,
session: dict[str, Any] = Depends(require_system_admin),
):
if not await hard_delete_project(project_id, int(session["user_id"]), request):
raise HTTPException(status_code=404, detail=_GONE)
return {"status": "success"}