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§
- Exercise
Services 🔒Client Routes ApiDoc - Supported
Client - Extractor guarding every client route: reads
X-Client-Versionand 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.
Nonedisables the check; a"major.minor.patch"string rejects older clients with426 Upgrade Required.
Functions§
- _add_
routes - check_
client_ 🔒version - Rejects clients older than
minimumwith426 Upgrade Required; aNoneminimum 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.patchversion string into a comparable tuple. Missing minor/patch components default to0; a malformed string returnsNone. - 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
fileanswer names files previously storedthrough this exercise’sfilesendpoint, in the order they are to be graded; those files are theanswer. An answer that names no files is a JSON answer, carried indata_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.