Skip to content

Youwenqwq/ysu-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ysu-api

WARNING: This project's code is 100% generated by AI, use at your own risk.

This document is also available in 中文

A FastAPI third-party HTTP layer over Yanshan University's unified authentication (CAS) and academic systems — the network wrapper around ysu-sdk.

  • Exposes the SDK's full CAS login flow, including CAPTCHA and SMS / cpdaily MFA.
  • Exposes the SDK's full academic-system surface: grades, statistics / distribution / ranking, GPA, schedule, exams, student profile, training plan, academic completion / warnings, and course evaluation.

Design principles

  • Stateless. The server never holds user credentials. Every request carries a Base64-encoded CAS cookie JSON (the output of CASCredential.to_json()) in the X-CAS-Credential header, and an optional X-JWXT-Session header for jwxt-domain cookies.
  • Session rotation. After each request the server may return updated X-CAS-Credential / X-JWXT-Session response headers (via SessionRotationMiddleware). Clients should read and persist them to minimize CAS round-trips.
  • Error pass-through. CASError / JWXTError raised by the SDK are mapped into HTTP responses with a code field (see Error model), so clients can branch on a business code rather than parse messages.
  • Only evaluation writes. Like the SDK, the only endpoint that mutates server state is POST /jwxt/evaluation/submit.

Install

Requires Python ≥ 3.12 and uv. ysu-sdk is declared as a path dependency in pyproject.toml and resolved automatically by uv:

uv sync
# or
uv pip install -e .

Run

uv run python -m ysu_api.main

The service binds 0.0.0.0:11920 by default. Once running, open http://localhost:11920/docs for Swagger UI or http://localhost:11920/redoc for ReDoc.

For production, drive uvicorn directly:

uv run uvicorn ysu_api.main:app --host 0.0.0.0 --port 11920

Environment variables

Variable Default Notes
YSU_API_HOST 0.0.0.0 Only honored when launched via python -m ysu_api.main.
YSU_API_PORT 11920 Same as above.
YSU_API_RELOAD 0 Set to 1 to enable uvicorn autoreload (development only).
YSU_API_LOG_LEVEL INFO Standard logging level name.
YSU_API_CORS_ORIGINS unset Comma-separated allow-list. Leaving it unset disables CORSMiddleware entirely. Setting it to * turns off allow_credentials to comply with browser policy.

Authentication flows

The API exposes both of the SDK's login paths so callers can pick whichever fits — one-shot for CLIs, step-by-step for browser front-ends.

Option A — one-shot login (POST /auth/login)

Submit everything (password, CAPTCHA, MFA code) in a single request. Convenient for CLIs and scripts.

curl -sX POST http://localhost:11920/auth/login \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "<student id>",
    "password": "<password>",
    "captcha": "",
    "mfa_code": "<sms code>",
    "mfa_method": "cpdaily"
  }'
# → {"credential": "<base64-json>"}

If the server requires CAPTCHA and captcha is empty → 403 NEED_CAPTCHA. Call POST /auth/captcha to fetch a Base64 PNG, then retry.

If the server requires MFA and mfa_code is empty → 403 MFA_REQUIRED.

Option B — stepped login (web front-ends)

Use this when you cannot complete "ask for password → prompt for MFA → resubmit" inside a single request.

1. POST /auth/captcha             → fetch a CAPTCHA image if needed
2. POST /auth/login/step1         → submit username / password (/ captcha)
                                     - authenticated=true → full credential returned, done
                                     - needs_mfa=true     → temporary credential returned, go to 3
3. POST /auth/login/mfa/request   (header: X-CAS-Credential) → ask server to send SMS
4. POST /auth/login/mfa/submit    (header: X-CAS-Credential) → submit code, receive final credential

The returned credential string is the auth token for every academic endpoint, carried via X-CAS-Credential. You may also supply an X-JWXT-Session header (see Session rotation) to skip the CAS authorize cold path:

curl -s http://localhost:11920/jwxt/student/info \
  -H "X-CAS-Credential: $CREDENTIAL" \
  -H "X-JWXT-Session: $JWXT_SESSION"

Clients should persist both headers (e.g. browser localStorage) and update them from every response (see Session rotation below). When the credential expires, academic endpoints return 401 not authenticated — run the login flow again.

API overview

The full schema is served at /docs. The tables below list endpoints by category.

Auth / credentials (/auth)

Endpoint Purpose
POST /auth/captcha Fetch a CAPTCHA image when the server requires one.
POST /auth/login One-shot login.
POST /auth/login/step1 Stepped login — submit credentials.
POST /auth/login/mfa/request Stepped login — request MFA code.
POST /auth/login/mfa/submit Stepped login — submit MFA code.
GET /auth/status Check whether a credential is still valid.

Academic system (/jwxt)

Every /jwxt/* endpoint requires the X-CAS-Credential header and optionally accepts X-JWXT-Session (see Session rotation).

Endpoint Purpose
GET /jwxt/student/info Student profile.
GET /jwxt/grades Grades query (paginated, filterable by term / course name).
GET /jwxt/gpa Credit and GPA summary.
GET /jwxt/grades/statistics Grade statistics (by teaching class or whole course).
GET /jwxt/grades/distribution Grade distribution bucketed by letter grade.
GET /jwxt/grades/ranking Student's rank within a class or course.
GET /jwxt/schedule Lecture schedule.
GET /jwxt/schedule/experimental Lab / experiment schedule.
GET /jwxt/schedule/unscheduled Courses not yet placed on the timetable.
GET /jwxt/class-periods Class period (bell) configuration.
GET /jwxt/term-calendar Term calendar.
GET /jwxt/current-week Current (or given-date) teaching week.
GET /jwxt/exams Exam arrangements.
GET /jwxt/training-plan Training plan course list.
GET /jwxt/academic-completion Academic completion progress.
GET /jwxt/academic-warnings Academic warnings.
GET /jwxt/evaluation/types Evaluation categories and pending counts.
GET /jwxt/evaluation/pending Pending evaluation tasks within a category.
GET /jwxt/evaluation/detail Evaluation questionnaire detail.
POST /jwxt/evaluation/calculate-score Pre-check answers without writing.
POST /jwxt/evaluation/submit Submit the questionnaire (only write endpoint, irreversible).

grades/statistics, grades/distribution, and grades/ranking share one dispatch rule: exactly one of class_id or course_code must be provided. Passing both or neither follows the SDK and raises JWXTBusinessError / ValueError (the former maps to HTTP 422).

Session rotation

During a request the SDK may refresh CAS-domain cookies (e.g. happyVoyage) or jwxt-domain cookies (JSESSIONID, _WEU). To keep these updates on the client side, SessionRotationMiddleware writes the latest snapshots back into every response:

Response header Content
X-CAS-Credential Base64-encoded CASCredential.to_json()
X-JWXT-Session Base64-encoded JWXTSession.to_json() (only when non-empty)

Clients must read these headers after each API call and overwrite their local copy. Supplying a stale X-JWXT-Session is safe — the server falls back to the cold path (one extra CAS authorize call), but persisting the fresh values eliminates most round-trips to cer.ysu.edu.cn.

When YSU_API_CORS_ORIGINS is configured, both headers are already listed in expose_headers so browser JS can read them.

Error model

SDK exceptions are normalized into the response shape below (see ysu_api/exc_handlers.py):

HTTP code Trigger
401 (none) NotAuthenticatedError / LoginFailedError / NotLoggedInError: missing or expired credential.
403 NEED_CAPTCHA One-shot login without a CAPTCHA when one is required.
403 MFA_REQUIRED One-shot login without an MFA code when one is required.
403 MFA_FAILED MFA code is wrong or expired.
422 <EMAP code> JWXTBusinessError: business-rule rejection (e.g. "evaluation window not open").
429 IP_BLOCKED The auth gateway has temporarily banned this IP.
500 CAS_ERROR Other uncategorized CAS exceptions.
502 CAS_PROTOCOL_ERROR Malformed CAS response.
502 JWXT_PROTOCOL_ERROR Malformed academic-system response (non-JSON, broken envelope, etc.).

Body shape:

{"detail": "human-readable message", "code": "NEED_CAPTCHA"}

code is only present for rows in the table above. Clients should branch on code and surface detail for display.

Security notes

  • Treat both headers as session cookies. Anyone holding X-CAS-Credential or X-JWXT-Session can impersonate the student. Beyond TLS in transit, clients should guard them as carefully as access tokens.
  • CORS is off by default. Without YSU_API_CORS_ORIGINS, CORSMiddleware is not mounted. Configure the allow-list explicitly when deploying behind a browser front-end.
  • The credential header is read only when necessary. /auth/login and /auth/login/step1 ignore X-CAS-Credential, so the credential never traverses pre-login paths.

About

A FastAPI third-party HTTP layer over Yanshan University's CAS and academic systems — the network wrapper around ysu-sdk.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages