solorpower/api_server/app/routers/plants.py
haneulai a716dbef96
Some checks are pending
CI / Crawler (Python ${{ matrix.python-version }}) (3.10) (push) Waiting to run
CI / Crawler (Python ${{ matrix.python-version }}) (3.11) (push) Waiting to run
CI / API (Python 3.11) (push) Waiting to run
CI / Database migration (push) Waiting to run
CI / App web build (Node 20) (push) Waiting to run
feat: harden solar monitoring through stage 7
2026-08-07 14:07:22 +09:00

187 lines
5.1 KiB
Python

"""
발전소 관련 API 엔드포인트
- 발전소 목록 조회
- 발전 현황 조회
"""
from fastapi import APIRouter, HTTPException, Depends
from supabase import Client
from typing import List
from app.core.database import get_db
from app.schemas.plant import (
PlantAlertUpdateRequest,
PlantAlertUpdateResponse,
PlantDetailResponse,
PlantsListResponse,
PlantWithLatestLog,
SolarLogBase,
)
router = APIRouter(
prefix="/plants",
tags=["Plants"]
)
@router.get("/{company_id}", response_model=PlantsListResponse)
def get_plants_by_company(
company_id: int,
db: Client = Depends(get_db)
) -> PlantsListResponse:
"""
특정 업체의 모든 발전소 목록과 최신 발전 현황을 조회합니다.
Args:
company_id: 업체 ID
Returns:
발전소 목록 및 각 발전소의 최신 발전 로그
"""
try:
# 발전소와 각 발전소의 최신 로그 1건을 관계 중첩 조회로 한 번에 가져온다.
plants_response = db.table("plants") \
.select(
"*,solar_logs("
"id,plant_id,current_kw,today_kwh,status,created_at"
")"
) \
.eq("company_id", company_id) \
.order("created_at", desc=True, foreign_table="solar_logs") \
.limit(1, foreign_table="solar_logs") \
.execute()
plants = plants_response.data
if not plants:
return PlantsListResponse(
status="success",
data=[],
total_count=0
)
result: List[PlantWithLatestLog] = []
for plant_row in plants:
plant = dict(plant_row)
nested_logs = plant.pop("solar_logs", None) or []
latest_log = None
if nested_logs:
latest_log = SolarLogBase(**nested_logs[0])
plant_with_log = PlantWithLatestLog(
**plant,
latest_log=latest_log
)
result.append(plant_with_log)
return PlantsListResponse(
status="success",
data=result,
total_count=len(result)
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"데이터베이스 조회 중 오류가 발생했습니다: {str(e)}"
)
@router.get("/{company_id}/{plant_id}", response_model=PlantDetailResponse)
def get_plant_detail(
company_id: int,
plant_id: str,
db: Client = Depends(get_db)
) -> dict:
"""
특정 발전소의 상세 정보를 조회합니다.
Args:
company_id: 업체 ID
plant_id: 발전소 ID
Returns:
발전소 상세 정보 및 최근 발전 로그
"""
try:
# 발전소 조회
plant_response = db.table("plants") \
.select("*") \
.eq("id", plant_id) \
.eq("company_id", company_id) \
.limit(1) \
.execute()
if not plant_response.data:
raise HTTPException(
status_code=404,
detail="발전소를 찾을 수 없습니다."
)
plant = plant_response.data[0]
# 최근 발전 로그 10건 조회
logs_response = db.table("solar_logs") \
.select("*") \
.eq("plant_id", plant_id) \
.order("created_at", desc=True) \
.limit(10) \
.execute()
return {
"status": "success",
"data": {
"plant": plant,
"recent_logs": logs_response.data or []
}
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"데이터베이스 조회 중 오류가 발생했습니다: {str(e)}"
)
@router.patch(
"/{company_id}/{plant_id}/alerts",
response_model=PlantAlertUpdateResponse,
)
def update_plant_alerts(
company_id: int,
plant_id: str,
alert_update: PlantAlertUpdateRequest,
db: Client = Depends(get_db)
) -> PlantAlertUpdateResponse:
"""
특정 발전소의 알림 활성화 상태를 변경합니다.
"""
try:
response = db.table("plants") \
.update({"alerts_enabled": alert_update.alerts_enabled}) \
.eq("id", plant_id) \
.eq("company_id", company_id) \
.execute()
if not response.data:
raise HTTPException(
status_code=404,
detail="발전소를 찾을 수 없거나 업데이트에 실패했습니다."
)
return PlantAlertUpdateResponse(
status="success",
message="알림 설정이 변경되었습니다.",
data=response.data[0],
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"알림 설정 변경 중 오류가 발생했습니다: {str(e)}"
)