""" 個人化服務設定 API 記錄員工啟用的個人化服務(SSO, Email, Calendar, Drive, Office) """ from typing import List, Optional from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, Query, status, Request from sqlalchemy.orm import Session from app.db.session import get_db from app.models.emp_personal_service_setting import EmpPersonalServiceSetting from app.models.personal_service import PersonalService from app.schemas.response import MessageResponse from app.services.audit_service import audit_service router = APIRouter() def get_current_tenant_id() -> int: """取得當前租戶 ID (暫時寫死為 1, 未來從 JWT token realm 取得)""" return 1 def get_current_user_id() -> str: """取得當前使用者 ID (暫時寫死, 未來從 JWT token sub 取得)""" return "system-admin" @router.get("/users/{keycloak_user_id}/services") def get_user_services( keycloak_user_id: str, db: Session = Depends(get_db), include_inactive: bool = False, ): """ 取得使用者已啟用的服務列表 Args: keycloak_user_id: Keycloak User UUID include_inactive: 是否包含已停用的服務 """ tenant_id = get_current_tenant_id() query = db.query(EmpPersonalServiceSetting).filter( EmpPersonalServiceSetting.tenant_id == tenant_id, EmpPersonalServiceSetting.tenant_keycloak_user_id == keycloak_user_id ) if not include_inactive: query = query.filter( EmpPersonalServiceSetting.is_active == True, EmpPersonalServiceSetting.disabled_at == None ) settings = query.all() result = [] for setting in settings: service = setting.service result.append({ "id": setting.id, "service_id": setting.service_id, "service_name": service.service_name if service else None, "service_code": service.service_code if service else None, "quota_gb": setting.quota_gb, "quota_mb": setting.quota_mb, "enabled_at": setting.enabled_at, "enabled_by": setting.enabled_by, "disabled_at": setting.disabled_at, "disabled_by": setting.disabled_by, "is_active": setting.is_active, }) return result @router.post("/users/{keycloak_user_id}/services", status_code=status.HTTP_201_CREATED) def enable_service_for_user( keycloak_user_id: str, data: dict, request: Request, db: Session = Depends(get_db), ): """ 為使用者啟用個人化服務 Body: { "service_id": 4, // 服務 ID (必填) "quota_gb": 20, // 儲存配額 (Drive 服務用) "quota_mb": 5120 // 郵件配額 (Email 服務用) } """ tenant_id = get_current_tenant_id() current_user = get_current_user_id() service_id = data.get("service_id") quota_gb = data.get("quota_gb") quota_mb = data.get("quota_mb") if not service_id: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="service_id is required" ) # 檢查服務是否存在 service = db.query(PersonalService).filter( PersonalService.id == service_id, PersonalService.is_active == True ).first() if not service: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Service with id {service_id} not found or inactive" ) # 檢查是否已經啟用 existing = db.query(EmpPersonalServiceSetting).filter( EmpPersonalServiceSetting.tenant_id == tenant_id, EmpPersonalServiceSetting.tenant_keycloak_user_id == keycloak_user_id, EmpPersonalServiceSetting.service_id == service_id, EmpPersonalServiceSetting.is_active == True ).first() if existing: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=f"Service {service.service_name} already enabled for this user" ) # 建立服務設定 setting = EmpPersonalServiceSetting( tenant_id=tenant_id, tenant_keycloak_user_id=keycloak_user_id, service_id=service_id, quota_gb=quota_gb, quota_mb=quota_mb, enabled_at=datetime.utcnow(), enabled_by=current_user, is_active=True, edit_by=current_user ) db.add(setting) db.commit() db.refresh(setting) # 審計日誌 audit_service.log_action( db=db, tenant_id=tenant_id, user_id=current_user, action="enable_service", resource_type="emp_personal_service_setting", resource_id=setting.id, details=f"Enabled {service.service_name} for user {keycloak_user_id}", ip_address=request.client.host if request.client else None ) return { "id": setting.id, "service_id": setting.service_id, "service_name": service.service_name, "enabled_at": setting.enabled_at, "quota_gb": setting.quota_gb, "quota_mb": setting.quota_mb, } @router.delete("/users/{keycloak_user_id}/services/{service_id}") def disable_service_for_user( keycloak_user_id: str, service_id: int, request: Request, db: Session = Depends(get_db), ): """ 停用使用者的個人化服務(軟刪除) """ tenant_id = get_current_tenant_id() current_user = get_current_user_id() # 查詢啟用中的服務設定 setting = db.query(EmpPersonalServiceSetting).filter( EmpPersonalServiceSetting.tenant_id == tenant_id, EmpPersonalServiceSetting.tenant_keycloak_user_id == keycloak_user_id, EmpPersonalServiceSetting.service_id == service_id, EmpPersonalServiceSetting.is_active == True ).first() if not setting: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Service setting not found or already disabled" ) # 軟刪除 setting.is_active = False setting.disabled_at = datetime.utcnow() setting.disabled_by = current_user setting.edit_by = current_user db.commit() # 審計日誌 service = setting.service audit_service.log_action( db=db, tenant_id=tenant_id, user_id=current_user, action="disable_service", resource_type="emp_personal_service_setting", resource_id=setting.id, details=f"Disabled {service.service_name if service else service_id} for user {keycloak_user_id}", ip_address=request.client.host if request.client else None ) return MessageResponse(message="Service disabled successfully") @router.post("/users/{keycloak_user_id}/services/batch-enable", status_code=status.HTTP_201_CREATED) def batch_enable_services( keycloak_user_id: str, data: dict, request: Request, db: Session = Depends(get_db), ): """ 批次啟用所有個人化服務(員工到職時使用) Body: { "storage_quota_gb": 20, "email_quota_mb": 5120 } """ tenant_id = get_current_tenant_id() current_user = get_current_user_id() storage_quota_gb = data.get("storage_quota_gb", 20) email_quota_mb = data.get("email_quota_mb", 5120) # 取得所有啟用的服務 all_services = db.query(PersonalService).filter( PersonalService.is_active == True ).all() enabled_services = [] for service in all_services: # 檢查是否已啟用 existing = db.query(EmpPersonalServiceSetting).filter( EmpPersonalServiceSetting.tenant_id == tenant_id, EmpPersonalServiceSetting.tenant_keycloak_user_id == keycloak_user_id, EmpPersonalServiceSetting.service_id == service.id, EmpPersonalServiceSetting.is_active == True ).first() if existing: continue # 已啟用,跳過 # 根據服務類型設定配額 quota_gb = storage_quota_gb if service.service_code == "Drive" else None quota_mb = email_quota_mb if service.service_code == "Email" else None setting = EmpPersonalServiceSetting( tenant_id=tenant_id, tenant_keycloak_user_id=keycloak_user_id, service_id=service.id, quota_gb=quota_gb, quota_mb=quota_mb, enabled_at=datetime.utcnow(), enabled_by=current_user, is_active=True, edit_by=current_user ) db.add(setting) enabled_services.append(service.service_name) db.commit() # 審計日誌 audit_service.log_action( db=db, tenant_id=tenant_id, user_id=current_user, action="batch_enable_services", resource_type="emp_personal_service_setting", resource_id=None, details=f"Batch enabled {len(enabled_services)} services for user {keycloak_user_id}: {', '.join(enabled_services)}", ip_address=request.client.host if request.client else None ) return { "enabled_count": len(enabled_services), "services": enabled_services } @router.get("/services") def get_all_services( db: Session = Depends(get_db), include_inactive: bool = False, ): """ 取得所有可用的個人化服務列表 """ query = db.query(PersonalService) if not include_inactive: query = query.filter(PersonalService.is_active == True) services = query.all() return [ { "id": s.id, "service_name": s.service_name, "service_code": s.service_code, "is_active": s.is_active, } for s in services ]