184 lines
6.3 KiB
Python
184 lines
6.3 KiB
Python
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
|
|
|
from ..api_utils import file_meta, load_accounts, load_teachers, payload_to_account, payload_to_teacher, read_register_payload
|
|
from ..auth import verify_accounts_auth, verify_admin_auth
|
|
from ..config import (
|
|
ACCOUNTS_PATH,
|
|
ADMIN_TASKS_PATH,
|
|
CLASSNOTES_PATH,
|
|
COURSE_SUMMARIES_ROOT,
|
|
COURSE_SUMMARY_STATE_PATH,
|
|
OPERATION_LOGS_PATH,
|
|
TEACHERS_PATH,
|
|
write_lock,
|
|
)
|
|
from ..data import (
|
|
ACCOUNT_STATUSES,
|
|
TEACHER_STATUSES,
|
|
DuplicateRecordError,
|
|
account_summary,
|
|
account_to_dict,
|
|
create_account,
|
|
create_teacher,
|
|
filter_accounts,
|
|
register_class_record_lines,
|
|
register_course_summary_texts,
|
|
register_payment_lines,
|
|
teacher_to_dict,
|
|
update_account,
|
|
update_teacher,
|
|
)
|
|
from ..schemas import AccountPayload, TeacherPayload
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/api/register/class-records")
|
|
async def register_class_records(request: Request, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
payload = await read_register_payload(request)
|
|
with write_lock:
|
|
result = register_class_record_lines(
|
|
CLASSNOTES_PATH,
|
|
ACCOUNTS_PATH,
|
|
lines=payload.lines,
|
|
line=payload.line,
|
|
)
|
|
except DuplicateRecordError as exc:
|
|
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.post("/api/register/payments")
|
|
async def register_payments(request: Request, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
payload = await read_register_payload(request)
|
|
with write_lock:
|
|
result = register_payment_lines(ACCOUNTS_PATH, lines=payload.lines, line=payload.line)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.post("/api/register/course-summaries")
|
|
async def register_course_summaries(request: Request, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
payload = await read_register_payload(request)
|
|
with write_lock:
|
|
result = register_course_summary_texts(
|
|
classnotes_path=CLASSNOTES_PATH,
|
|
accounts_path=ACCOUNTS_PATH,
|
|
tasks_path=ADMIN_TASKS_PATH,
|
|
summaries_root=COURSE_SUMMARIES_ROOT,
|
|
state_path=COURSE_SUMMARY_STATE_PATH,
|
|
operation_logs_path=OPERATION_LOGS_PATH,
|
|
lines=payload.lines,
|
|
line=payload.line,
|
|
)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.get("/api/account-health")
|
|
def account_health(_user: str = Depends(verify_accounts_auth)):
|
|
accounts = load_accounts()
|
|
teachers = load_teachers()
|
|
return {
|
|
"ok": True,
|
|
"accounts": file_meta(ACCOUNTS_PATH),
|
|
"teachers": file_meta(TEACHERS_PATH),
|
|
"accounts_count": len(accounts),
|
|
"teachers_count": len(teachers),
|
|
"account_summary": account_summary(accounts),
|
|
}
|
|
|
|
|
|
@router.get("/api/accounts")
|
|
def accounts(
|
|
q: str = Query("", description="学生姓名或学生ID"),
|
|
status_filter: str = Query("", alias="status", description="账户状态"),
|
|
_user: str = Depends(verify_accounts_auth),
|
|
):
|
|
all_accounts = load_accounts()
|
|
rows = filter_accounts(all_accounts, keyword=q, status=status_filter)
|
|
return {
|
|
"summary": account_summary(all_accounts),
|
|
"count": len(rows),
|
|
"accounts": [account_to_dict(account) for account in rows],
|
|
}
|
|
|
|
|
|
@router.get("/api/accounts/{student}")
|
|
def account_detail(student: str, _user: str = Depends(verify_accounts_auth)):
|
|
for account in load_accounts():
|
|
if account.student == student or account.student_id == student:
|
|
return account_to_dict(account)
|
|
raise HTTPException(status_code=404, detail=f"未找到学生账户: {student}")
|
|
|
|
|
|
@router.get("/api/admin/statuses")
|
|
def admin_statuses(_user: str = Depends(verify_admin_auth)):
|
|
return {"account_statuses": sorted(ACCOUNT_STATUSES)}
|
|
|
|
|
|
@router.get("/api/admin/teacher-statuses")
|
|
def admin_teacher_statuses(_user: str = Depends(verify_admin_auth)):
|
|
return {"teacher_statuses": sorted(TEACHER_STATUSES)}
|
|
|
|
|
|
@router.get("/api/admin/teachers")
|
|
def admin_teachers(_user: str = Depends(verify_admin_auth)):
|
|
return {
|
|
"teachers": [teacher_to_dict(teacher) for teacher in load_teachers()],
|
|
}
|
|
|
|
|
|
@router.post("/api/admin/teachers")
|
|
def admin_create_teacher(payload: TeacherPayload, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
with write_lock:
|
|
result = create_teacher(TEACHERS_PATH, payload_to_teacher(payload))
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.put("/api/admin/teachers/{teacher_id}")
|
|
def admin_update_teacher(teacher_id: str, payload: TeacherPayload, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
with write_lock:
|
|
result = update_teacher(
|
|
TEACHERS_PATH,
|
|
teacher_id,
|
|
payload_to_teacher(payload, teacher_id=payload.teacher_id.strip() or teacher_id),
|
|
)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.post("/api/admin/accounts")
|
|
def admin_create_account(payload: AccountPayload, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
with write_lock:
|
|
result = create_account(ACCOUNTS_PATH, payload_to_account(payload))
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|
|
|
|
|
|
@router.put("/api/admin/accounts/{student_id}")
|
|
def admin_update_account(student_id: str, payload: AccountPayload, _user: str = Depends(verify_admin_auth)):
|
|
try:
|
|
with write_lock:
|
|
result = update_account(ACCOUNTS_PATH, student_id, payload_to_account(payload))
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
return {"ok": True, **result}
|