"""B01_Dashboard 회사 공유 도면 자산(로고·서명) API — 본체 라우터가 include 함.""" import mimetypes import os from typing import Any from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, Response, UploadFile from common_util.common_util_auth import verify_session from common_util.common_util_storage import read_stored_asset from .B01_Dashboard_Repository_Assets import ( ASSET_EXTENSIONS, ASSET_KINDS, ASSET_MAX_BYTES, create_company_asset, delete_company_asset, get_company_asset, list_company_assets, update_company_asset, write_company_asset_file, ) from .B01_Dashboard_Repository_Members import list_company_members, set_company_logo from .B01_Dashboard_Schema import UpdateCompanyAssetRequest, UpdateCompanyLogoRequest from .B01_Dashboard_Scope import _scope_company, require_company_admin router = APIRouter() async def _company_asset(session: dict[str, Any], asset_id: int) -> dict[str, Any]: asset = await get_company_asset(asset_id) if not asset: raise HTTPException(status_code=404, detail="자산을 찾을 수 없습니다.") _scope_company(session, int(asset["company_id"])) return asset # ---- 회사 공유 도면 자산(로고·서명) — 회사 구성원 누구나 작성·수정, 시스템관리자는 전체 ---- @router.get("/company/assets") async def company_assets( company_id: int | None = Query(None, gt=0), session: dict[str, Any] = Depends(verify_session), ): return { "status": "success", "assets": await list_company_assets(_scope_company(session, company_id)), } @router.post("/company/assets") async def company_add_asset( kind: str = Form(...), label: str = Form(...), user_id: int | None = Form(None, gt=0), company_id: int | None = Form(None, gt=0), file: UploadFile = File(...), session: dict[str, Any] = Depends(verify_session), ): kind = kind.upper() if kind not in ASSET_KINDS: raise HTTPException(status_code=400, detail="자산 종류는 LOGO 또는 SIGNATURE 입니다.") label = label.strip()[:100] if not label: raise HTTPException(status_code=400, detail="이름을 넣어 주세요.") suffix = os.path.splitext(file.filename or "")[1].lower() if suffix not in ASSET_EXTENSIONS: raise HTTPException(status_code=400, detail="png·jpg·webp·svg 그림만 올릴 수 있습니다.") blob = await file.read() if not blob or len(blob) > ASSET_MAX_BYTES: raise HTTPException(status_code=400, detail="그림은 2MB 이하여야 합니다.") scoped = _scope_company(session, company_id) if user_id and user_id not in {m["id"] for m in await list_company_members(scoped)}: raise HTTPException(status_code=400, detail="주인은 같은 회사 구성원이어야 합니다.") path = write_company_asset_file(scoped, kind, suffix, blob) asset_id = await create_company_asset( scoped, kind, label, path, user_id, int(session["user_id"]) ) return {"status": "success", "asset_id": asset_id} @router.put("/company/assets/{asset_id}") async def company_update_asset( asset_id: int, payload: UpdateCompanyAssetRequest, session: dict[str, Any] = Depends(verify_session), ): await _company_asset(session, asset_id) await update_company_asset(asset_id, payload.label.strip(), payload.user_id) return {"status": "success"} @router.delete("/company/assets/{asset_id}") async def company_delete_asset(asset_id: int, session: dict[str, Any] = Depends(verify_session)): await _company_asset(session, asset_id) await delete_company_asset(asset_id) return {"status": "success"} @router.put("/company/logo") async def company_set_logo( payload: UpdateCompanyLogoRequest, company_id: int | None = Query(None, gt=0), session: dict[str, Any] = Depends(require_company_admin), ): """회사 대표 로고를 지정·변경한다 (2026-09-02 사용자 확정). 프로젝트가 따로 고르지 않으면 도면은 이 로고를 쓴다. """ scoped = _scope_company(session, company_id) if payload.logo_asset_id is not None: asset = await get_company_asset(payload.logo_asset_id) if not asset or asset["company_id"] != scoped or asset["kind"] != "LOGO": raise HTTPException(status_code=400, detail="같은 회사의 로고 자산이어야 합니다.") if not await set_company_logo(scoped, payload.logo_asset_id): raise HTTPException(status_code=404, detail="회사를 찾을 수 없습니다.") return {"status": "success"} @router.get("/company/assets/{asset_id}/file") async def company_asset_file(asset_id: int, session: dict[str, Any] = Depends(verify_session)): """목록 미리보기용 그림. 도면에는 B07 이 같은 파일을 data URL 로 심는다.""" asset = await _company_asset(session, asset_id) blob = read_stored_asset(asset["file_path"]) if blob is None: raise HTTPException(status_code=404, detail="그림 파일이 없습니다.") media_type = mimetypes.guess_type(asset["file_path"])[0] or "application/octet-stream" return Response(content=blob, media_type=media_type)