Skip to main content

Module client

Expand description

Handlers for /api/v0/exercise-services/client.

A generic native-client API for exercise services: over plain HTTP it plays the role an exercise service’s in-browser IFrame plays on the web (download a stub, edit locally, submit, poll grading, review old submissions). Specs and answers stay opaque plugin-owned blobs the host only forwards.

Which services this API serves is not hardcoded: an exercise service is served exactly when it declares supports_native_client in its service info. The course/exercise queries filter on that capability, and submit rejects a task whose service lacks it.

Structs§

ExerciseServicesClientRoutesApiDoc 🔒
SupportedClient
Extractor guarding every client route: reads X-Client-Version and rejects obsolete clients before the handler runs. Yields no data; its presence applies the check.

Constants§

CLIENT_UPLOAD_PATH_PREFIX 🔒
Object-store namespace for files uploaded through this API. Not a service slug: at upload time no task is chosen yet, and the prefix carries no authorization meaning.
CLIENT_VERSION_HEADER 🔒
Header a client sends to advertise its version, e.g. 0.39.4.
MINIMUM_CLIENT_VERSION 🔒
Minimum client version the backend accepts. None disables the check; a "major.minor.patch" string rejects older clients with 426 Upgrade Required.

Functions§

_add_routes
check_client_version 🔒
Rejects clients older than minimum with 426 Upgrade Required; a None minimum passes everything. When a minimum is set, a missing or unparseable client version counts as obsolete.
client_tasks_from_slide 🔒
Filters a slide’s tasks down to the ones whose exercise service can serve this client and converts them to the client shape. Shared by the list and single-exercise views so their visibility rules cannot drift apart. Model solutions are stripped unless reveal_model_solution; the list view never reveals them.
derive_exercise_progress 🔒
Derives the client-facing per-exercise progress from an exercise’s maximum score and the user’s exercise state (absent when the user has never touched the exercise).
download_submission 🔒
GET /api/v0/exercise-services/client/submissions/:id/downloadResolves an exercise-slide submission (by the id returned from the submissions list, or bya submit’s slide_submission_id) to the files it was made from, so the client can restorean old submission.
get_course 🔒
GET /api/v0/exercise-services/client/courses/:idReturns the course with the given id.
get_course_exercises 🔒
GET /api/v0/exercise-services/client/courses/:id/exercisesReturns the user’s exercise slides for the given course.Does not return anything for chapters which are not open yet.Selects slides for exercises with no slide selected yet.Only returns slides which have tasks whose exercise service can serve this client.
get_course_progress 🔒
GET /api/v0/exercise-services/client/courses/:id/progressReturns the current user’s progress on every exercise of the course that lives in anopen chapter (the same visibility as courses/:id/exercises): its awarded and maximumpoints and completed/attempted signals. One round-trip; course totals are derivable bysumming the returned entries.
get_courses 🔒
GET /api/v0/exercise-services/client/coursesReturns the courses that the user is currently enrolled on that contain exercises thisclient can be served.
get_exercise 🔒
GET /api/v0/exercise-services/client/exercises/:idReturns an exercise slide for the user for the given exercise.
get_exercise_submissions 🔒
GET /api/v0/exercise-services/client/exercises/:id/submissionsReturns the current user’s past submissions to the given exercise, newestfirst, each annotated with its grading score and progress if graded.
get_submission_grading 🔒
GET /api/v0/exercise-services/client/submissions/:id/gradingReturns the grading status of the given submission.
map_grading_progress 🔒
Maps the internal grading-progress enum to the exercise-services-api one.
model_answer_kind 🔒
The client API’s answer kind as the model’s. Two enums rather than one because the client crate stays free of server-internal dependencies.
model_solution_should_be_revealed 🔒
Mirrors the project-wide “solved” reveal rule (controllers/course_material/exercises.rs, domain/exercises.rs): full points, or the per-slide attempt limit exhausted.
native_client_capable_slugs 🔒
Slugs of the exercise services this API can serve: exactly those declaring supports_native_client.
open_chapter_ids 🔒
Ids of the course’s currently open chapters. Shared by the exercise list and progress views so their visibility rules cannot drift apart.
parse_version 🔒
Parses a major.minor.patch version string into a comparable tuple. Missing minor/patch components default to 0; a malformed string returns None.
share_submission 🔒
POST /api/v0/exercise-services/client/submissions/:id/shareMints a shareable link to an existing submission of the current user and returnsits URL.
store_client_uploads 🔒
Stores the multipart parts and binds them to the exercise and user, so that a failure to record the binding cannot leave uploads the reaper is unable to find.
submission_files_response 🔒
Turns the host’s own file records into the download response. Every tracked file is reachable, not just the first, so a multi-file submission is fully restorable.
submit_exercise 🔒
POST /api/v0/exercise-services/client/exercises/:id/submitAccepts an exercise submission from the user. A file answer names files previously storedthrough this exercise’s files endpoint, in the order they are to be graded; those files are theanswer. An answer that names no files is a JSON answer, carried in data_json.
upload_exercise_files 🔒
POST /api/v0/exercise-services/client/exercises/:id/filesStores files for a later submission to this exercise. Every multipart field name must be aUUID the client picks; the host assigns the ids a submit request then names. Uploads arebound to this exercise and user, and unreferenced ones are reaped, so a client should uploadimmediately before submitting.Gated on the caller being able to answer the exercise at all, so stored objects cannot beaccumulated past a deadline or a closed exam. The per-slide try limit is only checked across thewhole exercise here, because this route is bound to an exercise rather than a slide.
verify_enrolled 🔒
Rejects a user who is not enrolled on the exercise’s course.
verify_slide_and_task_belong 🔒
The URL path authorizes exercise_id; the slide/task ids come from the request body, so without this check a caller could submit into an unrelated exercise’s slide/task.
verify_submission_owner 🔒
Rejects access to a submission owned by a different user.
verify_task_is_client_capable 🔒
Rejects a submission to a task whose exercise service cannot serve a native client.