courses
Courses, rosters, enrollment, groups, grades, and their assignments and problems.
Get a course's activity feed
Returns a paginated activity feed for one course: course/assignment/problem/ submission activity plus member logins. Course-content activity by admins (even if not enrolled) and enrolled staff (Faculty/TA) shows any time (so an admin creating or editing a problem before the term is included), while other members' content and all member logins are clipped to the course's start/end dates. Admin logins are never shown (only their course edits). Staff-only to read (see access gate below).
Archive or unarchive a course
Toggles a course's archived state. **Both archiving and un-archiving are admin-only**: freezing a course (or reopening a frozen one to edits) is a privileged action. Archiving also runs a safety check (canArchiveCourse) using the course's stored dates rather than any client value, to avoid timezone drift deciding whether a course has really ended.
List an assignment's assignees
Lists an assignment's audience (its AssignmentAssignee rows). Empty when the assignment is assigned to everyone. Course staff (faculty or TAs) or a system admin.
Replace an assignment's audience
Replaces an assignment's audience. Course staff (faculty or TAs) or a system admin. `assignedToEveryone` true clears the explicit list; false assigns only the given targets (students for an individual assignment, groups for a group assignment). Overrides for anyone no longer assigned are dropped in the same transaction.
Duplicate an assignment
Duplicate an assignment within the same course. The title/description come from the request; the type (groupSetId), audience (AssignmentAssignee), schedule, and date exceptions (AssignmentOverride) are copied verbatim from the source and are editable afterward. The copy is always created unpublished. Submissions and grades are never copied. Problems are handled by `problemMode`: - none : the copy has no problems. - link : the copy shares the source's Problem records (editing one edits both). - duplicate : each problem is copied to a new Problem (with its own solution file).
Update an assignment due-date override
Updates a per-student due-date override. Course staff (faculty or TAs) or a system admin. Omitted fields keep their current value; null inherits the base.
Delete an assignment due-date override
Deletes a per-student due-date override (the student falls back to the base dates). Course staff (faculty or TAs) or a system admin.
List an assignment's due-date overrides
Lists the per-student due-date overrides for an assignment. Course staff (faculty or TAs) or a system admin.
Create an assignment due-date override
Creates a per-student due-date override. Course staff (faculty or TAs) or a system admin. The target must be a student enrolled in the course. Dates are interpreted in the course's timezone; the effective window (override values falling back to the base) must stay ordered.
Get a student's problem grades for an assignment
Returns a student's per-problem grades and feedback for one assignment, keyed by problem id. A student may read their own; staff may read anyone's. Responds 204 when nothing has been graded yet.
Batch set/clear a student's problem grades for an assignment
Batch-saves this student's problem grades for the assignment in a single request; the write counterpart to the GET above (co-located as the same resource). The body maps problemId β grade (a number within [0, maxPoints], or null to clear). Course staff (faculty or TAs) or a system admin. Only problems whose grade actually changed are written: a null for a graded problem deletes it, a number upserts it (existing feedback is left untouched), and unchanged problems are skipped. Every applied change is audited with its previous value, mirroring the single-problem grade route.
Get an assignment's grading-completion summary
Per-student completion summary for one assignment: maps each student to whether every problem in the assignment has been graded (used to flag fully-graded students in the grading UI). Course staff (faculty or TAs) or a system admin.
Get a single problem grade
Reads one student's grade and feedback for a specific problem within an assignment. The student themselves, course staff, or a system admin. Returns nulls (not 404) when the problem exists but hasn't been graded.
Set or clear a problem grade
Sets or clears a student's grade (and optional feedback) for one problem. Course staff (faculty or TAs) or a system admin. A numeric grade must be within [0, maxPoints]; sending a null grade deletes the record. Every change is audited with the previous value.
Revoke an extra-submission grant
Revokes an extra-submission grant. Submissions already made stay untouched; the target's cap simply returns to the shared value. Course staff (faculty or TAs) or a system admin.
List a problem's extra-submission grants
Lists the extra-submission grants for one assignment problem. Course staff (faculty or TAs) or a system admin.
Grant extra submissions to a student or group
Grants extra submissions to one student or group on this problem, on top of the problem's shared cap. Repeat grants to the same target accumulate onto one row. Course staff (faculty or TAs) or a system admin.
Update an assignment problem's settings
Updates the per-assignment settings for one problem: its point value, submission cap, and whether the autograder runs. Course staff (faculty or TAs) or a system admin. The problem must already be linked to the assignment, and the assignment must belong to the course in the path.
Add problems to an assignment
Attaches problems to an assignment with per-problem settings (points, submission cap, autograder). Course staff (faculty or TAs) or a system admin. Adds only problems not already linked; existing links, especially those with submissions, are preserved and reported back. Only problems belonging to this course are accepted.
Remove a problem from an assignment
Detaches a problem from an assignment, leaving the problem itself intact in the course. Course staff (faculty or TAs) or a system admin. Both the assignment and the problem must belong to the course in the path. The problem id travels in the request body.
Get a student's review data for an assignment
Assembles the grading/review view for one student on one assignment: their submissions (grouped by problem, with evaluation output), the comments about them, and their per-problem grades. Falls back gracefully if the optional `evaluationRaw` column is absent. Access: the student themselves, course staff, or a system admin (`studentId` must be the caller's id unless they are course staff or a system admin). Course membership is also required, except for global admins.
Get a course assignment
Returns the assignment with its problems. Staff/admins also get the course roster in the full view; non-staff members see published assignments only (unpublished are masked as 404) and no roster.
Update a course assignment (full)
Full update of an assignment. Course staff (faculty or TAs) or a system admin. Guards protect data integrity: an assignment can't be unpublished once it has submissions or grades, and its group mode can't change after any submission exists. Late-submission rules are validated the same way as on create.
Update a course assignment (partial)
Partial update of an assignment: only the fields present in the body are changed. Course staff (faculty or TAs) or a system admin, with the same unpublish guard and late-window validation as the full update.
Delete a course assignment
Deletes an assignment, but only when it's safe: no submissions and no comments. Its problem links are cleared first, then the assignment is removed. Course staff (faculty or TAs) or a system admin.
Get an assignment's analytics
Aggregate analytics for one assignment: score histogram, per-problem box plots, and submission-status breakdown, measured in students (individual) or groups (group assignment). Course staff (faculty or TAs) or a system admin only. These are aggregate student-performance figures, a FERPA-relevant read, so the access is audited (throttled).
Get my context for an assignment
Everything the caller needs to see their own work on an assignment, grouped by problem: their submissions, the comments addressed to them, and their per-problem and overall grades. Requires enrollment in the course; students can't see it until the assignment is published. Scoped entirely to the caller's own data.
Get a student's group membership for an assignment
Whether a student submits this assignment individually or as a group, the group's name + groupmates (for a group), and the student's EFFECTIVE schedule (their own or their group's date override resolved against the base). Drives the per-student due/late line and the Individual / Group indicator on the staff Submissions view. Course staff or a system admin.
Get a student's submissions for an assignment
Returns a student's submissions for an assignment, grouped by problem and each annotated with that problem's metadata (falls back gracefully if the optional `evaluationRaw` column is absent). The `[sid]` segment is the student id. Access: the student themselves, course staff, or a system admin (`sid` must be the caller's id unless they are course staff or a system admin). Course membership is also required, except for global admins.
Change an assignment's individual/group type
Changes an assignment's individual/group type. Course staff (faculty or TAs) or a system admin. `groupSetId: null` makes it individual; a set id makes it a group assignment tied to that set. Because assignees and date overrides reference the old type's targets, switching resets the audience to everyone and clears all assignees + overrides in one transaction (staff rebuild them on the Assign To tab).
Import an assignment from another course
Imports an assignment from ANOTHER course the caller can manage into this course. Unlike duplicate, audience, group set, and date exceptions are not carried across (they reference records scoped to the source course); the import always lands as an unpublished, individual, assigned-to-everyone assignment. The schedule (due date, available-from, late settings) is copied from the source as a starting point and is editable afterward. Problems are handled by `problemMode`: - none : the imported assignment has no problems. - copy : each problem is copied into THIS course (a new Problem with its own solution file); there is no 'link' mode because problems are course-scoped. Permission is tiered: the wrapper gates the destination course (manage), and the caller must also be able to manage the source course.
List a course's assignments
Lists a course's assignments with each one's total and max grade (summed across its problems). Published only by default; pass `includeUnpublished=1` to also return drafts (used by the staff assignment switcher). Course staff or a system admin.
Create a course assignment
Creates an assignment in the course. Course staff (faculty or TAs) or a system admin. The due date is interpreted as end-of-day in the **course's** timezone. The late cutoff is optional when late submissions are on (blank means no deadline), must be omitted when late is off, and must fall on or after the due date when set.
Duplicate a course
Creates a new course modeled on an existing one, in a single transaction. The copy's faculty comes from the copied faculty roster and/or an explicit `instructorIds` list; at least one faculty member is required (the caller is NOT added automatically). TAs are copied only when asked. `copyMode` (or the legacy copyAssignments/copyProblems booleans) selects what carries over: assignments only, problems only, or assignments with their problems. The copy always starts unpublished with a fresh registration code. System administrators only. Dates are interpreted in the actor's timezone.
Export course grades as an LMS CSV
Builds an import-ready LMS gradebook CSV server-side and returns it as a download. The export is audited here (atomically with generation) rather than via a separate, skippable client call. Course staff (faculty or TAs) or a system admin.
Get the course grade matrix
Returns the full gradebook matrix for a course: students x assignments with each cell holding the student's summed assignment grade (problem grades collapsed into one total). Course staff (faculty or TAs) or a system admin. Reading the whole gradebook is a FERPA-relevant access, so it's recorded (throttled) in the audit log.
Duplicate a group set
Duplicates a group set into a new, independent set in the same course. Copies groups (and, optionally, current active-student memberships). Inactive students and non-student roster members are never copied. Nothing else is copied (no submissions, grades, feedback, assignment links, or activity). Renaming and duplication stay allowed even when a set is locked. Course staff or admin.
Rename a group in a set
Renames a group within its set (unique per set, case-insensitive). Course staff or admin.
Delete a group in a set
Deletes a group (its memberships cascade away). Blocked when the set is locked. Course staff or admin.
Create a group in a set
Creates a group inside a set. Blocked when the set is locked. Group names are unique within their set (case-insensitive); different sets may reuse names. Course staff or admin.
Bulk change group-set memberships
Atomically assigns, moves, and removes students within a group set. Each operation sets one student's group (or removes them when groupId is null). A move is a single upsert on the (set, student) unique key, so a student is never transiently in two groups. Assign/move targets must be active STUDENTs; removals are allowed even for inactive members. When expectedBasis is provided and no longer matches the set's current memberships, the change is rejected with 409 so a stale client cannot silently overwrite another staff member's edit. Blocked when the set is locked. Course staff or admin.
Preview a random group assignment
Computes a balanced random-assignment PREVIEW without writing anything. The client shows the preview, then applies it by POSTing the returned operations to the memberships endpoint together with `basis` as expectedBasis (so a change by another staff member since the preview is caught). Never creates groups: a set with no groups returns 400. Blocked when the set is locked. Course staff or admin.
Get a group set's detail
Full detail for one group set: its groups, each group's members (with an inactive flag), and the eligible active-student roster. Course staff or admin.
Rename a group set
Renames a group set (allowed even when locked). Names are unique per course (case-insensitive). Course staff or admin.
Delete a group set
Deletes a group set and its groups + memberships (cascade). Deletion is blocked when the set has dependencies (none exist yet; the assignment-integration phase adds submission/grade checks). Dependencies are re-checked inside the delete transaction. Course staff or admin.
List course group sets
Lists a course's group sets with summary counts. Course staff (faculty or TAs) or a system admin.
Create a course group set
Creates a group set, optionally seeding a number of empty default-named groups. Course staff (faculty or TAs) or a system admin. Set names are unique per course (case-insensitive).
Look up users by email
Resolves a list of emails to user records, splitting them into `found` and `notFound`, used by the roster importer to preview who exists before enrolling. Matching is case-insensitive regardless of DB collation. Restricted to course staff (faculty or TAs) or a system admin: only someone who can manage the course in the path may resolve emails to accounts.
Duplicate a course problem
Duplicate a problem within the same course. The title/description come from the request; the type, state cap, determinism flag, and the solution file (answer key) are copied from the source and stay editable afterward. The solution file is copied to a fresh name on disk so the two problems never share a file.
Update a course problem
Updates a problem within a course (multipart/form-data). Course staff (faculty or TAs) or a system admin. The problem must belong to the course in the path. Sending a new file replaces the stored solution; it's structure-validated and size-checked first, and the previous file is removed. Omitting the file keeps the current one.
Delete a course problem
Deletes a problem within a course and its solution file. Course staff (faculty or TAs) or a system admin. The problem must belong to the course in the path. Refused while the problem is still attached to any assignment (problems are shared across assignments many-to-many); otherwise its submissions are removed first, then the record and file.
Import a problem from another course
Imports a problem from ANOTHER course the caller can manage into this course. The title/description come from the request; the type, state cap, determinism flag, and the solution file (answer key) are copied from the source. The solution file is copied to a fresh name on disk so the two problems never share a file. Permission is tiered: the wrapper gates the destination course (manage), and the caller must also be able to manage the source course.
List a course's problems
Lists a course's problem bank (id, title, description, type), for pickers such as the 'import a problem from another course' wizard. Course staff (faculty or TAs) or a system admin; this route is manage-gated, so no student reaches it.
Create a problem in a course
Creates a problem in a course from an uploaded solution file (multipart/form-data). Course staff (faculty or TAs) or a system admin. The file's XML structure is validated against the problem type before it's written to disk, and it's size-checked against the system upload limit. `maxStates` applies to FA/PDA and `isDeterministic` to FA. The course comes from the path.
Publish or unpublish a course
Toggles a course's published state. Course staff (faculty or TA) or a system admin. Unpublishing runs a safety check (canUnpublishCourse) that refuses if students would lose access to work already in progress.
Reset a student's password (course staff)
Course-staff password reset for a student on the roster. This is a stop-gap for small deployments so course staff can help a student who is locked out, without a system administrator. Permission is tiered: the wrapper admits course FACULTY and TAs (and global admins); this handler additionally requires the target to be a STUDENT enrolled in THIS course. It refuses to reset a staff member, a global administrator, or anyone not on this roster, so it can never be used to seize a privileged account. System-wide resets stay on the admin User Accounts page. Not blocked on an archived course: a student may still need to sign in to review past work, and the reset touches the user account, not course content.
Remove a user from a course
Removes a user from a course roster. Permission is tiered: the shared wrapper admits global admins and course faculty only (TAs and students are rejected up front); the remaining rule (a faculty member may not remove another faculty member) is enforced here (a global admin may). Two safety rules block the removal outright: the user must have no submissions in the course, and a course can't lose its last faculty member.
Get a roster entry
Returns one roster entry (with the user's profile) plus the viewer's own course role and an `viewerIsAdmin` flag, so the UI can decide which actions to offer. Access is tiered: the caller must be a member of the course (the wrapper enforces this), and a non-staff member may only read their OWN entry; course staff (faculty/TA) and admins may read anyone's. `userId` may be the literal 'me' to target the caller.
Change a user's course role
Changes a user's course role. Only a global admin or a course faculty member may do this. The last faculty member can't be demoted, keeping every course with someone in charge.
Drop or re-enroll a student
Drop or re-enroll a student in a course. A DROPPED student keeps their roster row and all their work (submissions, grades, group membership, audience/override rows) but loses access: `canAccessCourse` denies them, so they can't see or interact with the course, and it disappears from their own lists. Staff review surfaces still show them, marked 'Dropped'. Re-enrolling flips them back to ENROLLED and restores everything. This is distinct from removal (`DELETE .../roster/[userId]`): removal is a hard delete for a student with no work; drop is the reversible action for a student who has work. Only a global admin or a course FACULTY member may do it (TAs may not, matching the other roster mutations), and it applies only to STUDENT rows.
Bulk-enroll students
Bulk-adds users as STUDENT to a course roster (the roster's bulk-add flow). Course staff (faculty or TAs) or a system admin. Purely additive: users not yet on the roster are inserted as STUDENT and anyone already enrolled is left untouched, so it's idempotent and safe to re-run. Changing an existing member's role is the dedicated faculty-gated role-change endpoint's job.
Enroll a user in a course
Adds a single user to a course roster. Course staff (faculty or TAs) or a system admin. A brand-new member is added as STUDENT; callers don't pick the role. Purely additive: an already-enrolled member keeps their current role (changing a role, including demoting staff, is the dedicated faculty-gated role-change endpoint's job).
Get a course
Fetches one course with derived metadata, shaped by the `view` query param to keep payloads lean (full/summary/roster/assignments/problems). Assignments come back with derived point totals and submission/comment counts; problems are tagged with whether an assignment uses them; the roster is flattened into a single `enrolled` array, and the caller's own course role is included. Access is restricted: any enrolled member of the course (any role) or a system admin.
Update a course
Updates a course's details and, when `instructorIds` is supplied, reconciles its faculty roster (adds, promotes, or removes to match the desired set). Runs the same archive/unpublish safety checks as the dedicated toggles, requires a registration window, and records a beforeβafter diff of changed fields. Course staff (faculty or TAs) or a system admin.
Delete a course
Deletes a course (system admin only). An **empty** course (no assignments, no problems, no student enrollments, and no submissions) is removed permanently (its staff-only roster cascades away; audit logs keep a nulled course pointer). Any course that holds real work or students is **soft-deleted** instead: the row and all its data are retained but `deletedAt` is stamped so the access gates and list queries treat it as gone (recoverable later). The response says which happened via `{ deleted: 'hard' | 'soft' }`.
Get my grades for a course
Returns the signed-in student's own grade breakdown for a course: published assignments, their problems, and per-problem grade, latest submission status, and attempt count. Available to enrolled members (viewing their own data) and to staff.
List a course's students
Returns the STUDENT members of a course (user profiles, each tagged with its `enrollmentStatus`). Course staff (faculty or TAs) or a system admin. By default only ACTIVE (ENROLLED) students are returned, since the main caller is the assignment-audience picker, where a dropped student must not be offered as a new target. Pass `?includeDropped=1` to also return dropped students (for staff review surfaces like the submissions view, which show them labeled).
Rerun all submissions in a course
Re-queues every submission in a course, resetting each to PENDING (with a fresh attempt budget) and clearing its feedback/result: the bulk counterpart to the single-submission rerun. Course staff (faculty or TAs) or a system admin. Logs one batch-summary event and returns the count re-queued.
Join a course by registration code
Enrolls the signed-in user in a course via its registration code, as a STUDENT. Users never learn that an unpublished/archived course exists (masked as 404). Global admins can't self-enroll, and the registration window must be open.
List all courses
Returns every course with its roster and assignment metadata. System administrators only; the payload spans all courses and includes every member's identity and each course's registration code.
Create a course
Creates a course (with a generated registration code) and seeds its faculty roster, all in one transaction. System administrators only. A new course is always created unpublished (publishing is a separate action) and requires at least one faculty member. Datetime-local strings are interpreted in the course's timezone before being stored as UTC.
List my started courses
Returns the signed-in user's own started, non-archived courses (id + name), used by pickers that only make sense for courses already underway. Note: the `email` path segment is ignored; results are always scoped to the caller's id, so one user can't enumerate another's courses.