""" 網路硬碟管理 API """ from typing import List from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.db.session import get_db from app.models.employee import Employee from app.models.network_drive import NetworkDrive from app.schemas.network_drive import ( NetworkDriveCreate, NetworkDriveUpdate, NetworkDriveResponse, NetworkDriveListItem, NetworkDriveQuotaUpdate, ) from app.schemas.response import MessageResponse router = APIRouter() @router.get("/", response_model=List[NetworkDriveListItem]) def get_network_drives( db: Session = Depends(get_db), is_active: bool = True, ): """ 獲取網路硬碟列表 """ query = db.query(NetworkDrive) if is_active is not None: query = query.filter(NetworkDrive.is_active == is_active) network_drives = query.order_by(NetworkDrive.drive_name).all() return [NetworkDriveListItem.model_validate(nd) for nd in network_drives] @router.get("/{network_drive_id}", response_model=NetworkDriveResponse) def get_network_drive( network_drive_id: int, db: Session = Depends(get_db), ): """ 獲取網路硬碟詳情 """ network_drive = db.query(NetworkDrive).filter( NetworkDrive.id == network_drive_id ).first() if not network_drive: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Network drive with id {network_drive_id} not found" ) response = NetworkDriveResponse.model_validate(network_drive) response.employee_name = network_drive.employee.legal_name response.employee_username = network_drive.employee.username_base return response @router.post("/", response_model=NetworkDriveResponse, status_code=status.HTTP_201_CREATED) def create_network_drive( network_drive_data: NetworkDriveCreate, db: Session = Depends(get_db), ): """ 創建網路硬碟 檢查: - 員工是否存在 - 員工是否已有 NAS 帳號 - drive_name 唯一性 """ # 檢查員工是否存在 employee = db.query(Employee).filter( Employee.id == network_drive_data.employee_id ).first() if not employee: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Employee with id {network_drive_data.employee_id} not found" ) # 檢查員工是否已有 NAS 帳號 existing = db.query(NetworkDrive).filter( NetworkDrive.employee_id == network_drive_data.employee_id ).first() if existing: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Employee already has a network drive" ) # 檢查 drive_name 是否已存在 existing_name = db.query(NetworkDrive).filter( NetworkDrive.drive_name == network_drive_data.drive_name ).first() if existing_name: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Drive name '{network_drive_data.drive_name}' already exists" ) # 創建網路硬碟 network_drive = NetworkDrive(**network_drive_data.model_dump()) db.add(network_drive) db.commit() db.refresh(network_drive) # TODO: 創建審計日誌 # TODO: 在 NAS 上創建實際帳號 response = NetworkDriveResponse.model_validate(network_drive) response.employee_name = employee.legal_name response.employee_username = employee.username_base return response @router.put("/{network_drive_id}", response_model=NetworkDriveResponse) def update_network_drive( network_drive_id: int, network_drive_data: NetworkDriveUpdate, db: Session = Depends(get_db), ): """ 更新網路硬碟 可更新: quota_gb, webdav_url, smb_url, is_active """ network_drive = db.query(NetworkDrive).filter( NetworkDrive.id == network_drive_id ).first() if not network_drive: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Network drive with id {network_drive_id} not found" ) # 更新欄位 update_data = network_drive_data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(network_drive, field, value) db.commit() db.refresh(network_drive) # TODO: 創建審計日誌 # TODO: 更新 NAS 配額 response = NetworkDriveResponse.model_validate(network_drive) response.employee_name = network_drive.employee.legal_name response.employee_username = network_drive.employee.username_base return response @router.patch("/{network_drive_id}/quota", response_model=NetworkDriveResponse) def update_network_drive_quota( network_drive_id: int, quota_data: NetworkDriveQuotaUpdate, db: Session = Depends(get_db), ): """ 更新網路硬碟配額 專用端點,僅更新配額 """ network_drive = db.query(NetworkDrive).filter( NetworkDrive.id == network_drive_id ).first() if not network_drive: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Network drive with id {network_drive_id} not found" ) network_drive.quota_gb = quota_data.quota_gb db.commit() db.refresh(network_drive) # TODO: 創建審計日誌 # TODO: 更新 NAS 配額 response = NetworkDriveResponse.model_validate(network_drive) response.employee_name = network_drive.employee.legal_name response.employee_username = network_drive.employee.username_base return response @router.delete("/{network_drive_id}", response_model=MessageResponse) def delete_network_drive( network_drive_id: int, db: Session = Depends(get_db), ): """ 停用網路硬碟 注意: 這是軟刪除,只將 is_active 設為 False """ network_drive = db.query(NetworkDrive).filter( NetworkDrive.id == network_drive_id ).first() if not network_drive: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Network drive with id {network_drive_id} not found" ) network_drive.is_active = False db.commit() # TODO: 創建審計日誌 # TODO: 停用 NAS 帳號 (但保留資料) return MessageResponse( message=f"Network drive '{network_drive.drive_name}' has been deactivated" ) @router.get("/by-employee/{employee_id}", response_model=NetworkDriveResponse) def get_network_drive_by_employee( employee_id: int, db: Session = Depends(get_db), ): """ 根據員工 ID 獲取網路硬碟 """ employee = db.query(Employee).filter(Employee.id == employee_id).first() if not employee: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Employee with id {employee_id} not found" ) if not employee.network_drive: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Employee does not have a network drive" ) response = NetworkDriveResponse.model_validate(employee.network_drive) response.employee_name = employee.legal_name response.employee_username = employee.username_base return response