"""B01_Dashboard 프로젝트 휴지통(592) — 목록 · 되살리기 · 영구 삭제는 common_util_project_delete.""" from typing import Any import aiomysql from common_util.common_util_audit import record_audit from common_util.common_util_project_delete import DELETED_BY_SQL from config.config_db import get_db_pool from config.config_system import TRASH_RETENTION_DAYS def days_left(seconds_left: int | None) -> int: """영구 삭제까지 남은 날 — 하루 덜 찼어도 하루로(올림) · 지났으면 0.""" if seconds_left is None or seconds_left <= 0: return 0 return -(-int(seconds_left) // 86400) async def list_trash_projects(company_id: int | None = None) -> list[dict[str, Any]]: """휴지통 — 최근 지운 것부터 · company_id 면 그 회사 것만.""" where = " AND p.company_id = %s" if company_id is not None else "" pool = get_db_pool() async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor: await cursor.execute( f"""SELECT t.*, du.name AS deleted_by_name, du.email AS deleted_by_email FROM (SELECT p.id, p.name, p.project_kind, p.company_id, c.name AS company_name, p.deleted_at, {DELETED_BY_SQL} AS deleted_by, TIMESTAMPDIFF(SECOND, CURRENT_TIMESTAMP, p.deleted_at + INTERVAL %s DAY) AS seconds_left FROM projects p LEFT JOIN companies c ON c.id = p.company_id WHERE p.deleted_at IS NOT NULL{where}) t LEFT JOIN users du ON du.id = t.deleted_by ORDER BY t.deleted_at DESC""", (TRASH_RETENTION_DAYS, company_id) if company_id is not None else (TRASH_RETENTION_DAYS,), ) rows = list(await cursor.fetchall()) for row in rows: row["days_left"] = days_left(row.pop("seconds_left")) return rows async def get_trash_project(project_id: str) -> dict[str, Any] | None: pool = get_db_pool() async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor: await cursor.execute( "SELECT id, company_id, name FROM projects WHERE id = %s AND deleted_at IS NOT NULL", (project_id,), ) return await cursor.fetchone() async def restore_project(project_id: str, actor_id: int, request: Any | None = None) -> bool: pool = get_db_pool() async with pool.acquire() as connection, connection.cursor() as cursor: await connection.begin() await cursor.execute( "UPDATE projects SET deleted_at = NULL WHERE id = %s AND deleted_at IS NOT NULL", (project_id,), ) changed = cursor.rowcount > 0 if changed: await record_audit( cursor, actor_id=actor_id, action="PROJECT_RESTORE", resource_type="project", resource_ref=project_id, request=request, ) await connection.commit() return changed