90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from fastapi import HTTPException, Request
|
|
from pydantic import ValidationError
|
|
|
|
from .config import ACCOUNTS_PATH, CLASSNOTES_PATH, TEACHERS_PATH
|
|
from .data import Account, Payment, Teacher, read_accounts, read_classnotes, read_teachers
|
|
from .schemas import AccountPayload, RegisterLinesPayload, TeacherPayload
|
|
|
|
|
|
async def read_register_payload(request: Request) -> RegisterLinesPayload:
|
|
body = await request.body()
|
|
if not body.strip():
|
|
return RegisterLinesPayload()
|
|
|
|
content_type = request.headers.get("content-type", "").lower()
|
|
if "application/json" in content_type:
|
|
try:
|
|
data = json.loads(body)
|
|
if isinstance(data, str):
|
|
return RegisterLinesPayload(line=data)
|
|
if isinstance(data, list):
|
|
return RegisterLinesPayload(lines=data)
|
|
if isinstance(data, dict):
|
|
return RegisterLinesPayload(**data)
|
|
except (json.JSONDecodeError, ValidationError) as exc:
|
|
raise ValueError("登记 JSON 格式错误") from exc
|
|
raise ValueError("登记 JSON 必须是字符串、字符串数组,或包含 line/lines 的对象")
|
|
|
|
try:
|
|
text = body.decode("utf-8")
|
|
except UnicodeDecodeError as exc:
|
|
raise ValueError("登记内容必须使用 UTF-8 编码") from exc
|
|
return RegisterLinesPayload(lines=text.splitlines())
|
|
|
|
|
|
def load_records():
|
|
if not CLASSNOTES_PATH.exists():
|
|
raise HTTPException(status_code=503, detail=f"课程记录文件不存在: {CLASSNOTES_PATH}")
|
|
return read_classnotes(CLASSNOTES_PATH)
|
|
|
|
|
|
def load_accounts():
|
|
if not ACCOUNTS_PATH.exists():
|
|
raise HTTPException(status_code=503, detail=f"课时账户文件不存在: {ACCOUNTS_PATH}")
|
|
return read_accounts(ACCOUNTS_PATH)
|
|
|
|
|
|
def load_teachers():
|
|
if not TEACHERS_PATH.exists():
|
|
return []
|
|
return read_teachers(TEACHERS_PATH)
|
|
|
|
|
|
def file_meta(path: Path) -> dict:
|
|
if not path.exists():
|
|
return {"exists": False, "path": str(path)}
|
|
stat = path.stat()
|
|
return {
|
|
"exists": True,
|
|
"path": str(path),
|
|
"size": stat.st_size,
|
|
"mtime": stat.st_mtime,
|
|
}
|
|
|
|
|
|
def payload_to_account(payload: AccountPayload, student_id: str | None = None) -> Account:
|
|
return Account(
|
|
student_id=student_id if student_id is not None else payload.student_id,
|
|
student=payload.student,
|
|
payments=[Payment(date=item.date, hours=item.hours) for item in payload.payments],
|
|
remaining=payload.remaining,
|
|
account_status=payload.account_status,
|
|
note=payload.note,
|
|
)
|
|
|
|
|
|
def payload_to_teacher(payload: TeacherPayload, teacher_id: str | None = None) -> Teacher:
|
|
return Teacher(
|
|
teacher_id=teacher_id if teacher_id is not None else payload.teacher_id,
|
|
name=payload.name,
|
|
alias=payload.alias,
|
|
subjects=payload.subjects,
|
|
status=payload.status,
|
|
note=payload.note,
|
|
)
|