{ "openapi": "3.1.0", "info": { "title": "Main Frontend API", "description": "", "contact": { "name": "University of Helsinki", "email": "mooc@cs.helsinki.fi" }, "license": { "name": "Apache-2.0", "identifier": "Apache-2.0" }, "version": "0.1.0" }, "paths": { "/api/v0/files/{exercise_service_slug}": { "post": { "tags": ["files"], "summary": "\nPOST `/api/v0/files/:exercise_service_slug`\nUsed to upload data from exercise service iframes.\n\n# Returns\nAn ordered list of host-assigned file ids and stored URLs.", "operationId": "uploadFilesFromExerciseService", "parameters": [ { "name": "exercise_service_slug", "in": "path", "description": "Exercise service slug", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "additionalProperties": { "type": "string", "format": "binary" }, "propertyNames": { "type": "string" } } } }, "required": true }, "responses": { "200": { "description": "Uploaded files", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseServiceUploadResultEntry" } } } } } } } }, "/api/v0/main-frontend/certificates": { "post": { "tags": ["certificates"], "summary": "\nPOST `/api/v0/main-frontend/certificates/`\n\nUpdates the certificate configuration for a given module.", "operationId": "updateCertificateConfiguration", "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["metadata", "file"], "properties": { "file": { "type": "array", "items": { "type": "string", "format": "binary" }, "contentMediaType": "application/octet-stream" }, "metadata": { "$ref": "#/components/schemas/CertificateConfigurationUpdate" } } }, "encoding": { "metadata": { "contentType": "application/json" } } } }, "required": true }, "responses": { "200": { "description": "Certificate configuration updated", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/certificates/configuration/{certificate_configuration_id}": { "delete": { "tags": ["certificates"], "summary": "\nDELETE `/api/v0/main-frontend/certificates/configuration/{configuration_id}`\n\nDeletes the given configuration.", "operationId": "deleteCertificateConfiguration", "parameters": [ { "name": "certificate_configuration_id", "in": "path", "description": "Certificate configuration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Certificate configuration deleted", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/certificates/generate": { "post": { "tags": ["certificates"], "summary": "\nPOST `/api/v0/main-frontend/certificates/generate`\n\nGenerates a certificate for a given certificate configuration id.", "operationId": "generateCertificate", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CertificateGenerationRequest" } } }, "required": true }, "responses": { "200": { "description": "Certificate generated", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/certificates/generated/{certificate_id}": { "put": { "tags": ["certificates"], "operationId": "updateGeneratedCertificate", "parameters": [ { "name": "certificate_id", "in": "path", "description": "Generated certificate id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CertificateUpdateRequest" } } }, "required": true }, "responses": { "200": { "description": "Generated certificate updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GeneratedCertificate" } } } } } } }, "/api/v0/main-frontend/certificates/get-by-configuration-id/{certificate_configuration_id}": { "get": { "tags": ["certificates"], "summary": "\nGET `/api/v0/main-frontend/certificates/get-by-configuration-id/{certificate_configuration_id}`\n\nFetches the user's certificate for the given course module and course instance.", "operationId": "getCertificateByConfigurationId", "parameters": [ { "name": "certificate_configuration_id", "in": "path", "description": "Certificate configuration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Generated certificate", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/GeneratedCertificate" } ] } } } } } } }, "/api/v0/main-frontend/certificates/{certificate_verification_id}": { "get": { "tags": ["certificates"], "summary": "\nGET `/api/v0/main-frontend/certificates/{certificate_verification_id}`\n\nFetches the user's certificate using the verification id.\n\nResponse: the certificate as a png.", "operationId": "getCertificateByVerificationId", "parameters": [ { "name": "certificate_verification_id", "in": "path", "description": "Certificate verification id", "required": true, "schema": { "type": "string" } }, { "name": "debug", "in": "query", "description": "Whether to render a debug certificate", "required": true, "schema": { "type": "boolean" } }, { "name": "test_certificate_configuration_id", "in": "query", "description": "Certificate configuration id to use for preview rendering", "required": false, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Certificate image", "content": { "image/png": { "schema": {} } } } } } }, "/api/v0/main-frontend/chapters": { "post": { "tags": ["chapters"], "summary": "\nPOST `/api/v0/main-frontend/chapters` - Create a new course part.\n# Example\n\nRequest:\n```http\nPOST /api/v0/main-frontend/chapters HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"The Basics\",\n \"course_id\": \"d86cf910-4d26-40e9-8c9c-1cc35294fdbb\",\n \"chapter_number\": 1,\n \"front_page_id\": null\n}\n```", "operationId": "createChapter", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewChapter" } } }, "required": true }, "responses": { "200": { "description": "Created chapter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" } } } } } } }, "/api/v0/main-frontend/chapters/{chapter_id}": { "put": { "tags": ["chapters"], "summary": "\nPUT `/api/v0/main-frontend/chapters/:chapter_id` - Update chapter.\n# Example\n\nRequest:\n```http\nPUT /api/v0/main-frontend/chapters/d332f3d9-39a5-4a18-80f4-251727693c37 HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"The Basics\",\n \"chapter_image_url\": null,\n \"chapter_number\": 2,\n \"front_page_id\": \"0ebba931-b027-4154-8274-2afb00d79306\"\n}\n\n```", "operationId": "updateChapter", "parameters": [ { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChapterUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated chapter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" } } } } } }, "delete": { "tags": ["chapters"], "summary": "\nDELETE `/api/v0/main-frontend/chapters/:chapter_id` - Delete a chapter.", "operationId": "deleteChapter", "parameters": [ { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted chapter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" } } } } } } }, "/api/v0/main-frontend/chapters/{chapter_id}/image": { "put": { "tags": ["chapters"], "summary": "\nPUT `/api/v0/main-frontend/chapters/:chapter_id/image` - Sets or updates the chapter image.\n\n# Example\n\nRequest:\n```http\nPUT /api/v0/main-frontend/chapters/d332f3d9-39a5-4a18-80f4-251727693c37/image HTTP/1.1\nContent-Type: multipart/form-data\n\nBINARY_DATA\n```", "operationId": "updateChapterImage", "parameters": [ { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 }, "contentMediaType": "application/octet-stream" } } } } }, "required": true }, "responses": { "200": { "description": "Updated chapter image", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" } } } } } }, "delete": { "tags": ["chapters"], "summary": "\nDELETE `/api/v0/main-frontend/chapters/:chapter_id/image` - Removes the chapter image.\n\n# Example\n\nRequest:\n```http\nDELETE /api/v0/main-frontend/chapters/d332f3d9-39a5-4a18-80f4-251727693c37/image HTTP/1.1\n```", "operationId": "deleteChapterImage", "parameters": [ { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted chapter image" } } } }, "/api/v0/main-frontend/chapters/{course_id}/all-chapters-for-course": { "get": { "tags": ["chapters"], "summary": "\nGET `/api/v0/main-frontend/chapters/{course_id}/all-chapters-for-course - Gets all chapters with a course_id", "operationId": "getCourseChapters", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course chapters", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DatabaseChapter" } } } } } } } }, "/api/v0/main-frontend/chatbot-models/": { "get": { "tags": ["chatbot-models"], "summary": "GET `/api/v0/main-frontend/chatbot-models?course_id={course_id}`", "operationId": "getChatbotModels", "parameters": [ { "name": "course_id", "in": "query", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Chatbot models", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChatbotConfigurationModel" } } } } } } } }, "/api/v0/main-frontend/chatbot-models/{chatbot_model_id}": { "get": { "tags": ["chatbot-models"], "summary": "GET `/api/v0/main-frontend/chatbot-models/{chatbot_configuration_id}`", "operationId": "getChatbotModel", "parameters": [ { "name": "chatbot_model_id", "in": "path", "description": "Chatbot model id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "string", "format": "uuid" } } }, "required": true }, "responses": { "200": { "description": "Chatbot model", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfigurationModel" } } } } } } }, "/api/v0/main-frontend/chatbots/": { "get": { "tags": ["chatbots"], "summary": "GET `/api/v0/main-frontend/chatbots`", "operationId": "getAllChatbots", "responses": { "200": { "description": "All chatbots", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } } } }, "/api/v0/main-frontend/chatbots/{chatbot_configuration_id}": { "get": { "tags": ["chatbots"], "summary": "GET `/api/v0/main-frontend/chatbots/{chatbot_configuration_id}`", "operationId": "getChatbotConfiguration", "parameters": [ { "name": "chatbot_configuration_id", "in": "path", "description": "Chatbot configuration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Chatbot configuration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } }, "post": { "tags": ["chatbots"], "summary": "POST `/api/v0/main-frontend/chatbots/{chatbot_configuration_id}`", "operationId": "configureChatbot", "parameters": [ { "name": "chatbot_configuration_id", "in": "path", "description": "Chatbot configuration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewChatbotConf" } } }, "required": true }, "responses": { "200": { "description": "Updated chatbot configuration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } }, "delete": { "tags": ["chatbots"], "summary": "DELETE `/api/v0/main-frontend/chatbots/{chatbot_configuration_id}`", "operationId": "deleteChatbotConfiguration", "parameters": [ { "name": "chatbot_configuration_id", "in": "path", "description": "Chatbot configuration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted chatbot configuration" } } } }, "/api/v0/main-frontend/code-giveaways": { "post": { "tags": ["code_giveaways"], "summary": "\n * POST `/api/v0/main-frontend/code-giveaways - Creates a new code giveaway.", "operationId": "createCodeGiveaway", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewCodeGiveaway" } } }, "required": true }, "responses": { "200": { "description": "Created code giveaway", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodeGiveaway" } } } } } } }, "/api/v0/main-frontend/code-giveaways/by-course/{course_id}": { "get": { "tags": ["code_giveaways"], "summary": "\nGET `/api/v0/main-frontend/code-giveaways/by-course/:course_id` - Returns code giveaways for a course.", "operationId": "getCodeGiveawaysByCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Code giveaways for course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CodeGiveaway" } } } } } } } }, "/api/v0/main-frontend/code-giveaways/{id}": { "get": { "tags": ["code_giveaways"], "summary": "\n * GET `/api/v0/main-frontend/code-giveaways/:id - Gets a code giveaway by ID.", "operationId": "getCodeGiveawayById", "parameters": [ { "name": "id", "in": "path", "description": "Code giveaway id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Code giveaway", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodeGiveaway" } } } } } } }, "/api/v0/main-frontend/code-giveaways/{id}/codes": { "get": { "tags": ["code_giveaways"], "summary": "\n * GET `/api/v0/main-frontend/code-giveaways/:id/codes - Gets codes for a code giveaway by ID.", "operationId": "getCodeGiveawayCodes", "parameters": [ { "name": "id", "in": "path", "description": "Code giveaway id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Giveaway codes", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CodeGiveawayCode" } } } } } } }, "post": { "tags": ["code_giveaways"], "summary": "\n * POST `/api/v0/main-frontend/code-giveaways/:id/codes - Adds new codes to a code giveaway.", "operationId": "addCodeGiveawayCodes", "parameters": [ { "name": "id", "in": "path", "description": "Code giveaway id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "array", "items": { "type": "string" } } } }, "required": true }, "responses": { "200": { "description": "Added giveaway codes", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CodeGiveawayCode" } } } } } } } }, "/api/v0/main-frontend/code-giveaways/{id}/codes/csv": { "get": { "tags": ["code_giveaways"], "summary": "\n * GET `/api/v0/main-frontend/code-giveaways/:id/codes/csv - Gets codes for a code giveaway by ID as CSV.", "operationId": "downloadCodeGiveawayCodesCsv", "parameters": [ { "name": "id", "in": "path", "description": "Code giveaway id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Giveaway codes CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/code-giveaways/{id}/codes/{code_id}": { "delete": { "tags": ["code_giveaways"], "summary": "\n * DELETE `/api/v0/main-frontend/code-giveaways/:id/codes/:code_id - Deletes a code giveaway code.", "operationId": "deleteCodeGiveawayCode", "parameters": [ { "name": "id", "in": "path", "description": "Code giveaway id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "code_id", "in": "path", "description": "Giveaway code id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted giveaway code" } } } }, "/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/by-user-ids": { "post": { "tags": ["course-credit-registrations"], "summary": "\nPOST `/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/by-user-ids` - The\nregistrations of the named students, for the students tab's current page.", "operationId": "getCourseCreditRegistrationsForUsers", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCreditRegistrationUserIdsPayload" } } }, "required": true }, "responses": { "200": { "description": "The named students' registrations", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCreditRegistration" } } } } } } } }, "/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/list": { "get": { "tags": ["course-credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/list` - A page of the\ncourse's registrations, filtered by state and searched by student name, email or student number.", "operationId": "getCourseCreditRegistrations", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number, from 1", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Rows per page", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "search", "in": "query", "description": "Student name, email or student number", "required": false, "schema": { "type": "string" } }, { "name": "state", "in": "query", "description": "Ledger state filter", "required": false, "schema": { "$ref": "#/components/schemas/CreditRegistrationState" } }, { "name": "course_instance_id", "in": "query", "description": "Course instance filter", "required": false, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "A page of the course's registrations", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCreditRegistrationsPage" } } } } } } }, "/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/module-configs": { "get": { "tags": ["course-credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/module-configs` - The\ncourse's per-module credit registration configuration.", "operationId": "getCourseCreditRegistrationModuleConfigs", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The course's per-module configuration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCreditRegistrationModuleConfigs" } } } } } } }, "/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/resend-linking-email": { "post": { "tags": ["course-credit-registrations"], "summary": "\nPOST\n`/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/resend-linking-email` - Sets off\nanother account-linking mail for one person on this course.\n\nThe target has to be on this course's roster in the study registry and hold no link with us. The caps\nof the ordinary claim path apply and nothing here relaxes them.", "operationId": "resendCourseCreditRegistrationLinkingEmail", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResendLinkingEmailPayload" } } }, "required": true }, "responses": { "200": { "description": "What the attempt did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResendLinkingEmailResult" } } } }, "400": { "description": "Nothing named, or this teacher has set off too many mails this hour" } } } }, "/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/summary": { "get": { "tags": ["course-credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/course-credit-registrations/courses/{course_id}/summary` - Per-module\ncounts plus the two reasons a student of this course will not get credits.", "operationId": "getCourseCreditRegistrationSummary", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The course's credit registration summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCreditRegistrationSummary" } } } } } } }, "/api/v0/main-frontend/course-credit-registrations/registrations/{credit_registration_id}": { "get": { "tags": ["course-credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/course-credit-registrations/registrations/{credit_registration_id}` - One\nregistration with its timeline and the other attempts for the same completion.\n\nAuthorized on the row's own course: a course id from the caller would let a teacher of one course pair\nit with a foreign registration id.", "operationId": "getCreditRegistrationDetails", "parameters": [ { "name": "credit_registration_id", "in": "path", "description": "Credit registration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The registration with its timeline", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditRegistrationDetails" } } } }, "404": { "description": "No such registration" } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}": { "get": { "tags": ["course-instances"], "summary": "\nGET /course-instances/:id", "operationId": "getCourseInstance", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseInstance" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/completions": { "get": { "tags": ["course-instances"], "summary": "\nGET `/api/v0/main-frontend/course-instances/{course_instance_id}/completions`", "operationId": "getCourseInstanceCompletions", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance completion summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseInstanceCompletionSummary" } } } } } }, "post": { "tags": ["course-instances"], "summary": "\nPOST `/api/v0/main-frontend/course-instances/{course_instance_id}/completions`", "operationId": "createCourseInstanceCompletions", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeacherManualCompletionRequest" } } }, "required": true }, "responses": { "200": { "description": "Manual completions added" } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/completions/preview": { "post": { "tags": ["course-instances"], "operationId": "previewCourseInstanceCompletions", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeacherManualCompletionRequest" } } }, "required": true }, "responses": { "200": { "description": "Manual completion preview", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ManualCompletionPreview" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/course-module-completions/{user_id}": { "get": { "tags": ["course-instances"], "summary": "\nGET /course-instances/:id/course-module-completions/:user_id - Returns a list of all course module completions for a given user for this course instance.", "operationId": "getCourseInstanceCourseModuleCompletionsForUser", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course module completions for user", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/default-certificate-configurations": { "get": { "tags": ["course-instances"], "summary": "\nGET /course-instances/:id/default-certificate-configurations - gets default certificate configurations of the given course instance. A default certificate configuration requires only one course module to be completed.", "operationId": "getCourseInstanceDefaultCertificateConfigurations", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Default certificate configurations", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CertificateConfigurationAndRequirements" } } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/delete": { "post": { "tags": ["course-instances"], "summary": "\nPOST /course-instances/:id/delete", "operationId": "deleteCourseInstance", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance deleted" } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/edit": { "post": { "tags": ["course-instances"], "summary": "\nPOST /course-instances/:id/edit", "operationId": "editCourseInstance", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseInstanceForm" } } }, "required": true }, "responses": { "200": { "description": "Course instance updated" } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/email-templates": { "get": { "tags": ["course-instances"], "operationId": "getCourseInstanceEmailTemplates", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance email templates", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/EmailTemplate" } } } } } } }, "post": { "tags": ["course-instances"], "operationId": "createCourseInstanceEmailTemplate", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailTemplateNew" } } }, "required": true }, "responses": { "200": { "description": "Created email template", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailTemplate" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/export-completions": { "get": { "tags": ["course-instances"], "summary": "\nGET /course-instances/:id/export-completions - gets CSV of course completion based on course_instance ID.", "operationId": "exportCourseInstanceCompletionsCsv", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance completions CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/export-points": { "get": { "tags": ["course-instances"], "summary": "\nGET `/api/v0/main-frontend/course-instances/${courseInstanceId}/export-points` - gets CSV of course instance points based on course_instance ID.", "operationId": "exportCourseInstancePointsCsv", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instance points CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/points": { "get": { "tags": ["course-instances"], "operationId": "getCourseInstancePoints", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Course instance points", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Points" } } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/progress/{user_id}": { "get": { "tags": ["course-instances"], "summary": "\n GET /api/v0/main-frontend/course-instance/:course_instance_id/progress/:user_id - returns user progress information.", "operationId": "getCourseInstanceUserProgress", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User progress for course instance", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/course-instances/{course_instance_id}/status-for-all-exercises/{user_id}": { "get": { "tags": ["course-instances"], "summary": "\nGET /course-instances/:id/status-for-all-exercises/:user_id - Returns a status for all exercises in a course instance for a given user.", "operationId": "getCourseInstanceExerciseStatusesForUser", "parameters": [ { "name": "course_instance_id", "in": "path", "description": "Course instance id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise statuses for user", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}": { "get": { "tags": ["course_modules"], "summary": "\nGET `/api/v0/main-frontend/course-modules/{course_module_id}`\n\nReturns information about the course module.", "operationId": "getCourseModule", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course module", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseModule" } } } } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}/completion-registration-link": { "get": { "tags": ["course_modules"], "summary": "\nGET `/api/v0/main-frontend/course-modules/{course_slug}/completion-registration-link`", "operationId": "getCourseModuleCompletionRegistrationLink", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Completion registration link", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompletionRegistrationLink" } } } } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}/course-module-completion": { "get": { "tags": ["course_modules"], "summary": "\nGET `/api/v0/main-frontend/course-modules/{course_module_id}/course-module-completion`\n\nGets users's best completion for the course.", "operationId": "getCourseModuleCompletion", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Best course module completion for the current user", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CourseModuleCompletion" } ] } } } } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}/set-certificate-generation/{enabled}": { "post": { "tags": ["course_modules"], "operationId": "setCourseModuleCertificateGeneration", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "enabled", "in": "path", "description": "Whether certificate generation should be enabled", "required": true, "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "Certificate generation updated", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}/threshold": { "post": { "tags": ["course_modules"], "summary": "\n POST /api/v0/main-frontend/course-modules/${course_module_id}/threshold - post threshold for a specific course module.", "operationId": "createCourseModuleThreshold", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ThresholdData" } } }, "required": true }, "responses": { "200": { "description": "Threshold created" } } }, "delete": { "tags": ["course_modules"], "summary": "\n DELETE /api/v0/main-frontend/course-modules/${course_module_id}/threshold - delete threshold for a specific course module.", "operationId": "deleteCourseModuleThreshold", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Threshold deleted" } } } }, "/api/v0/main-frontend/course-modules/{course_module_id}/user-completion": { "get": { "tags": ["course_modules"], "summary": "\nGET `/api/v0/main-frontend/course-modules/{course_module_id}/user-completion`\n\nGets active users's completion for the course, if it exists.", "operationId": "getCourseModuleUserCompletion", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User completion information", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserCompletionInformation" } } } } } } }, "/api/v0/main-frontend/course-plans": { "get": { "tags": ["course-plans"], "operationId": "getCourseDesignerPlans", "responses": { "200": { "description": "Plans", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerPlanSummary" } } } } } } }, "post": { "tags": ["course-plans"], "operationId": "createCourseDesignerPlan", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCourseDesignerPlanRequest" } } }, "required": true }, "responses": { "200": { "description": "Created plan", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlan" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}": { "get": { "tags": ["course-plans"], "operationId": "getCourseDesignerPlan", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Plan details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/members": { "get": { "tags": ["course-plans"], "operationId": "getCoursePlanMembers", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Plan members", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PlanMemberWithDetails" } } } } } } }, "post": { "tags": ["course-plans"], "operationId": "addCoursePlanMember", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddPlanMemberRequest" } } }, "required": true }, "responses": { "200": { "description": "Added member", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlanMemberWithDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/members/{user_id}": { "delete": { "tags": ["course-plans"], "operationId": "removeCoursePlanMember", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id to remove", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Member removed" } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/schedule": { "put": { "tags": ["course-plans"], "operationId": "saveCourseDesignerSchedule", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SaveCourseDesignerScheduleRequest" } } }, "required": true }, "responses": { "200": { "description": "Updated plan details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/schedule/finalize": { "post": { "tags": ["course-plans"], "operationId": "finalizeCourseDesignerSchedule", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Finalized plan", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlan" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/schedule/suggestions": { "post": { "tags": ["course-plans"], "operationId": "createCourseDesignerScheduleSuggestion", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerScheduleSuggestionRequest" } } }, "required": true }, "responses": { "200": { "description": "Suggested schedule", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerScheduleSuggestionResponse" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/stages/advance": { "post": { "tags": ["course-plans"], "operationId": "advanceCourseDesignerStage", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Updated plan details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/stages/{stage_id}/tasks": { "post": { "tags": ["course-plans"], "operationId": "createCourseDesignerStageTask", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "stage_id", "in": "path", "description": "Stage id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCourseDesignerStageTaskRequest" } } }, "required": true }, "responses": { "200": { "description": "Created task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanStageTask" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/stages/{stage}/extend": { "post": { "tags": ["course-plans"], "operationId": "extendCourseDesignerStage", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "stage", "in": "path", "description": "Stage name", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtendStageRequest" } } }, "required": true }, "responses": { "200": { "description": "Updated plan details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/stages/{stage}/workspace": { "patch": { "tags": ["course-plans"], "operationId": "updateCourseDesignerStageWorkspace", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "stage", "in": "path", "description": "Stage name", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerStageWorkspace" } } }, "required": true }, "responses": { "200": { "description": "Updated plan details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanDetails" } } } } } } }, "/api/v0/main-frontend/course-plans/{plan_id}/tasks/{task_id}": { "delete": { "tags": ["course-plans"], "operationId": "deleteCourseDesignerStageTask", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "task_id", "in": "path", "description": "Task id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Task deleted" } } }, "patch": { "tags": ["course-plans"], "operationId": "updateCourseDesignerStageTask", "parameters": [ { "name": "plan_id", "in": "path", "description": "Plan id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "task_id", "in": "path", "description": "Task id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCourseDesignerStageTaskRequest" } } }, "required": true }, "responses": { "200": { "description": "Updated task", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseDesignerPlanStageTask" } } } } } } }, "/api/v0/main-frontend/courses": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses` - Create a new course.\n# Example\n\nRequest:\n```http\nPOST /api/v0/main-frontend/courses HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"Introduction to introduction\",\n \"slug\": \"introduction-to-introduction\",\n \"organization_id\": \"1b89e57e-8b57-42f2-9fed-c7a6736e3eec\"\n}\n```", "operationId": "createCourse", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewCourse" } } }, "required": true }, "responses": { "200": { "description": "Created course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Course" } } } } } } }, "/api/v0/main-frontend/courses/": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses` - Get all courses\n\nReturns all courses.", "operationId": "getAllCourses", "responses": { "200": { "description": "All courses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } } } } } } } }, "/api/v0/main-frontend/courses/join/{join_code}": { "get": { "tags": ["courses"], "summary": "\nGET /courses/join/:join_code - Gets the course related to join code", "operationId": "getCourseByJoinCode", "parameters": [ { "name": "join_code", "in": "path", "description": "Course join code", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Course for join code", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Course" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id` - Get course.", "operationId": "getCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Course" } } } } } }, "put": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:course_id` - Update course.\n# Example\n\nRequest:\n```http\nPUT /api/v0/main-frontend/courses/ab4541d8-6db4-4561-bdb2-45f35b2544a1 HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"Introduction to Introduction\"\n}\n\n```", "operationId": "updateCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Course" } } } } } }, "delete": { "tags": ["courses"], "summary": "\nDELETE `/api/v0/main-frontend/courses/:course_id` - Delete a course.", "operationId": "deleteCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted course", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/courses/{course_id}/breadcrumb-info": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/breadcrumb-info` - Get information to display breadcrumbs on the manage course pages.", "operationId": "getCourseBreadcrumbInfo", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course breadcrumb information", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseBreadcrumbInfo" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/chatbots": { "get": { "tags": ["courses"], "summary": "GET `/api/v0/main-frontend/courses/{course_id}/chatbots`", "operationId": "getCourseChatbots", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Course chatbots", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } } }, "post": { "tags": ["courses"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/chatbots`", "operationId": "createCourseChatbot", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "description": "JSON string literal chatbot name, e.g. \"Chatbot 1\".", "content": { "application/json": { "schema": { "type": "string" } } }, "required": true }, "responses": { "200": { "description": "Created course chatbot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/chatbots/{chatbot_configuration_id}/set-as-default": { "post": { "tags": ["courses"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/chatbots/{chatbot_configuration_id}/set-as-default`", "operationId": "setCourseChatbotAsDefault", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string" } }, { "name": "chatbot_configuration_id", "in": "path", "description": "Chatbot configuration id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Updated course chatbot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/chatbots/{chatbot_configuration_id}/set-as-non-default": { "post": { "tags": ["courses"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/chatbots/{chatbot_configuration_id}/set-as-non-default`", "operationId": "setCourseChatbotAsNonDefault", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string" } }, { "name": "chatbot_configuration_id", "in": "path", "description": "Chatbot configuration id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Updated course chatbot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatbotConfiguration" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/course-instances": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/course-instances` - Returns all course instances for given course id.", "operationId": "getCourseInstances", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instances", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseInstance" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/course-module-completions/{user_id}": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/course-module-completions/:user_id` - Returns all course module completions for a given user for this course.", "operationId": "getCourseModuleCompletionsForUser", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course module completions for course user", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleCompletion" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/course-modules": { "post": { "tags": ["courses"], "operationId": "updateCourseModules", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModuleUpdates" } } }, "required": true }, "responses": { "200": { "description": "Course modules updated" } } } }, "/api/v0/main-frontend/courses/{course_id}/course-users-counts-by-exercise": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/course-users-counts-by-exercise` - Returns the amount of users for each exercise.", "operationId": "getCourseUsersCountsByExercise", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course users counts by exercise", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseUserCounts" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/create-copy": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:id/create-copy` - Create a copy of a course with specified mode.\n\nDifferent copy modes:\n- `duplicate`: Creates a completely separate copy with new language group\n- `same_language_group`: Creates a new language version within the same language group\n- `existing_language_group`: Creates a new language version in the specified language group\n- `new_language_group`: Creates a new language version in a new language group\n\n# Example\n\nRequest:\n```http\nPOST /api/v0/main-frontend/courses/fd484707-25b6-4c51-a4ff-32d8259e3e47/create-copy HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"Johdatus kaikkeen\",\n \"slug\": \"johdatus-kaikkeen\",\n \"organization_id\": \"1b89e57e-8b57-42f2-9fed-c7a6736e3eec\",\n \"language_code\": \"fi-FI\",\n \"mode\": \"duplicate\"\n}\n```\n\nOr with an existing language group:\n```http\nPOST /api/v0/main-frontend/courses/fd484707-25b6-4c51-a4ff-32d8259e3e47/create-copy HTTP/1.1\nContent-Type: application/json\n\n{\n \"name\": \"Johdatus kaikkeen\",\n \"slug\": \"johdatus-kaikkeen\",\n \"organization_id\": \"1b89e57e-8b57-42f2-9fed-c7a6736e3eec\",\n \"language_code\": \"fi-FI\",\n \"mode\": {\n \"existing_language_group\": {\n \"target_course_id\": \"1b89e57e-8b57-42f2-9fed-c7a6736e3eec\"\n }\n }\n}\n```", "operationId": "createCourseCopy", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CopyCourseRequest" } } }, "required": true }, "responses": { "200": { "description": "Created course copy", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Course" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/daily-submission-counts": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/daily-submission-counts` - Returns submission counts grouped by day.", "operationId": "getCourseDailySubmissionCounts", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course daily submission counts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionCount" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/daily-users-who-have-submitted-something": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/daily-users-who-have-submitted-something` - Returns a count of users who have submitted something grouped by day.", "operationId": "getCourseDailyUsersWhoSubmittedSomething", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course daily user submission counts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionCount" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/default-peer-review": { "get": { "tags": ["courses"], "operationId": "getCourseDefaultPeerReview", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Default peer review configuration", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/courses/{course_id}/exercises": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/exercises` - Returns all exercises for the course.", "operationId": "getCourseExercises", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercises for course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Exercise" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/exercises-and-count-of-answers-requiring-attention": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/exercises-and-count-of-answers-requiring-attention` - Returns all exercises for the course and count of answers requiring attention in them.", "operationId": "getCourseExercisesAndAnswersRequiringAttentionCounts", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercises and answer attention counts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseAnswersInCourseRequiringAttentionCount" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-course-instances": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/export-course-instances`\n\ngets SCV course instances for course", "operationId": "exportCourseInstancesCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course instances CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-course-user-consents": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/export-course-user-consents`\n\ngets SCV course specific research form questions and user answers for course", "operationId": "exportCourseUserConsentsCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course user consents CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-exercise-tasks": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/export-exercise-tasks`\n\ngets SCV all exercise-tasks' private specs in course", "operationId": "exportCourseExerciseTasksCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course exercise tasks CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-submissions": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${courseId}/export-submissions`\n\ngets SCV of course exercise submissions", "operationId": "exportCourseSubmissionsCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course submissions CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-user-details": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/export-user-details`\n\ngets SCV of user details for all users having submitted an exercise in the course", "operationId": "exportCourseUserDetailsCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course user details CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/export-user-exercise-states": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/export-user-exercise-states`\n\ngets CSV for course specific user exercise states", "operationId": "exportCourseUserExerciseStatesCsv", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course user exercise states CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/feedback": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/feedback?read=true` - Returns feedback for the given course.", "operationId": "getCourseFeedback", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string" } }, { "name": "read", "in": "query", "description": "Whether to fetch read feedback", "required": true, "schema": { "type": "boolean" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Feedback for the course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Feedback" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/feedback-count": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/feedback-count` - Returns the amount of feedback for the given course.", "operationId": "getCourseFeedbackCount", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Feedback counts for the course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FeedbackCount" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/get-course-audiences": { "get": { "tags": ["courses"], "summary": "\nget `/api/v0/main-frontend/courses/:course_id/get-course-audiences` - Get course audiences.", "operationId": "getCourseAudiences", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course audiences", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseAudience" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/get-course-metadata": { "get": { "tags": ["courses"], "summary": "\nget `/api/v0/main-frontend/courses/:course_id/get-course-metadata` - Get course metadata.", "operationId": "getCourseMetadata", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CompleteCourseMetadata" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/get-course-prerequisites": { "get": { "tags": ["courses"], "summary": "\nget `/api/v0/main-frontend/courses/:course_id/get-course-prerequisites` - Get course prerequisites.", "operationId": "getCoursePrerequisites", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course prerequisites", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CoursePrerequisite" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/glossary": { "get": { "tags": ["glossary"], "operationId": "getCourseGlossary", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Glossary terms for the course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Term" } } } } }, "401": { "description": "Authentication required" }, "403": { "description": "User is not allowed to manage the course glossary" } } }, "post": { "tags": ["glossary"], "operationId": "createCourseGlossaryTerm", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TermUpdate" } } }, "required": true }, "responses": { "200": { "description": "Created glossary term id", "content": { "text/plain": { "schema": { "type": "string", "format": "uuid" } } } }, "401": { "description": "Authentication required" }, "403": { "description": "User is not allowed to manage the course glossary" } } } }, "/api/v0/main-frontend/courses/{course_id}/join-course-with-join-code": { "post": { "tags": ["courses"], "summary": "\nPOST /courses/:course_id/join-course-with-join-code - Adds the user to join_code_uses so the user gets access to the course", "operationId": "joinCourseWithJoinCode", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JoinCourseWithJoinCodePayload" } } }, "required": true }, "responses": { "200": { "description": "Joined course id", "content": { "text/plain": { "schema": { "type": "string", "format": "uuid" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/language-versions": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/language-versions` - Returns all language versions of the same course.\n\n# Example\n\nRequest:\n```http\nGET /api/v0/main-frontend/courses/fd484707-25b6-4c51-a4ff-32d8259e3e47/language-versions HTTP/1.1\nContent-Type: application/json\n```", "operationId": "getCourseLanguageVersions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course language versions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/new-chapter-ordering": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:id/new-chapter-ordering` - Reorders chapters based on modified chapter number.#\n\nCreates redirects if url_path changes.", "operationId": "updateCourseChapterOrdering", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Chapter" } } } }, "required": true }, "responses": { "200": { "description": "Course chapter ordering updated" } } } }, "/api/v0/main-frontend/courses/{course_id}/new-course-instance": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:id/new-course-instance`", "operationId": "createCourseInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseInstanceForm" } } }, "required": true }, "responses": { "200": { "description": "Created course instance id", "content": { "text/plain": { "schema": { "type": "string", "format": "uuid" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/new-page-ordering": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:id/new-page-ordering` - Reorders pages to the given order numbers and given chapters.\n\nNote that the page objects posted here might have the content omitted because it is not needed here and the content makes the request body to be very large.\n\nCreates redirects if url_path changes.", "operationId": "updateCoursePageOrdering", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Page" } } } }, "required": true }, "responses": { "200": { "description": "Course page ordering updated" } } } }, "/api/v0/main-frontend/courses/{course_id}/page-visit-datum-summary": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/page-visit-datum-summary` - Gets aggregated statistics for page visits for the course.", "operationId": "getCoursePageVisitDatumSummary", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course page visit summary", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageVisitDatumSummaryByCourse" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/page-visit-datum-summary-by-countries": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/page-visit-datum-summary-by-countries` - Gets aggregated statistics for page visits for the course.", "operationId": "getCoursePageVisitDatumSummaryByCountries", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course page visit summary by countries", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageVisitDatumSummaryByCoursesCountries" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/page-visit-datum-summary-by-device-types": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/page-visit-datum-summary-by-device-types` - Gets aggregated statistics for page visits for the course.", "operationId": "getCoursePageVisitDatumSummaryByDeviceTypes", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course page visit summary by device types", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageVisitDatumSummaryByCourseDeviceTypes" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/page-visit-datum-summary-by-pages": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/${course.id}/page-visit-datum-summary-by-pages` - Gets aggregated statistics for page visits for the course.", "operationId": "getCoursePageVisitDatumSummaryByPages", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course page visit summary by pages", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageVisitDatumSummaryByPages" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/partners-block": { "get": { "tags": ["courses"], "summary": "\nGET /courses/:course_id/partners_blocks - Gets a partners block related to a course", "operationId": "getCoursePartnersBlock", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Partners block", "content": { "application/json": { "schema": {} } } } } }, "post": { "tags": ["courses"], "summary": "\n POST /api/v0/main-frontend/courses/:course_id/partners_block - Create or updates a partners block for a course", "operationId": "upsertCoursePartnersBlock", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": {} } } }, "responses": { "200": { "description": "Partners block", "content": { "application/json": { "schema": {} } } } } }, "delete": { "tags": ["courses"], "summary": "\nDELETE `/api/v0/main-frontend/courses/:course_id` - Delete a partners block in a course.", "operationId": "deleteCoursePartnersBlock", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted partners block", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/courses/{course_id}/progress/{user_id}": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/progress/:user_id` - Returns user progress for the course.", "operationId": "getCourseProgressForUser", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User progress for course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserCourseProgress" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/references": { "get": { "tags": ["courses"], "operationId": "getCourseReferences", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course references", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MaterialReference" } } } } } } }, "post": { "tags": ["courses"], "operationId": "createCourseReferences", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/NewMaterialReference" } } } }, "required": true }, "responses": { "200": { "description": "Course references created" } } } }, "/api/v0/main-frontend/courses/{course_id}/references/{reference_id}": { "post": { "tags": ["courses"], "operationId": "updateCourseReference", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "reference_id", "in": "path", "description": "Reference id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewMaterialReference" } } }, "required": true }, "responses": { "200": { "description": "Course reference updated" } } }, "delete": { "tags": ["courses"], "operationId": "deleteCourseReference", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "reference_id", "in": "path", "description": "Reference id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course reference deleted" } } } }, "/api/v0/main-frontend/courses/{course_id}/reprocess-completions": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/{course_id}/reprocess-completions`\n\nReprocesses all module completions for the given course instance. Only available to admins.", "operationId": "reprocessCourseCompletions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course completions reprocessed", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/set-join-code": { "post": { "tags": ["courses"], "summary": "\n POST /api/v0/main-frontend/courses/:course_id/generate-join-code - Generates a code that is used as a part of URL to join course", "operationId": "setCourseJoinCode", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course join code set" } } } }, "/api/v0/main-frontend/courses/{course_id}/sisu-course-llm-descriptions": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/sisu-course-llm-descriptions` - Get Sisu descriptions summarised by LLM\n\nReturns LLM generated descriptions for a course based on information from Sisu API.", "operationId": "getSisuCourseLlmDescriptions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Sisu course LLM descriptions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SisuDescriptionResponse" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/all-language-versions/completions-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/all-language-versions/completions-history/{granularity}/{time_window}`", "description": "Returns completion statistics for all language versions with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getCourseCompletionsHistoryAllLanguageVersions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Course completions history across all language versions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/all-language-versions/total-users-started": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/all-language-versions/total-users-started`", "operationId": "getTotalUsersStartedAllLanguageVersions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users started across all language versions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/all-language-versions/users-starting-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/all-language-versions/users-starting-history/{granularity}/{time_window}`", "description": "Returns unique users starting statistics for all language versions with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getUniqueUsersStartingHistoryAllLanguageVersions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Unique users starting history across all language versions", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/avg-time-to-first-submission/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/avg-time-to-first-submission/{granularity}/{time_window}`", "description": "Returns average time to first submission statistics with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getAvgTimeToFirstSubmissionHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Average time to first submission history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AverageMetric" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/completions-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/completions-history/{granularity}/{time_window}`", "description": "Returns course completion statistics with specified time granularity and window, grouped by course instance.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getCourseCompletionsHistoryByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Course completions history by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/first-submissions-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/first-submissions-history/{granularity}/{time_window}`", "description": "Returns first exercise submission statistics with specified time granularity and window, grouped by course instance.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getFirstExerciseSubmissionsHistoryByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "First exercise submissions history by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/total-users-completed": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/total-users-completed`", "operationId": "getTotalUsersCompletedCourseByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users completed course by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/CountResult" }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/total-users-returned-exercises": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/total-users-returned-exercises`", "operationId": "getTotalUsersReturnedExercisesByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users returned exercises by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/CountResult" }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/total-users-started-course": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/total-users-started-course`", "operationId": "getTotalUsersStartedCourseByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users started course by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/CountResult" }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/users-returning-exercises-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/users-returning-exercises-history/{granularity}/{time_window}`", "description": "Returns users returning exercises statistics with specified time granularity and window, grouped by course instance.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getUsersReturningExercisesHistoryByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Users returning exercises history by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-instance/users-starting-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-instance/users-starting-history/{granularity}/{time_window}`", "description": "Returns unique users starting statistics with specified time granularity and window, grouped by course instance.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getUniqueUsersStartingHistoryByInstance", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Unique users starting history by instance", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/by-module/first-submissions/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/by-module/first-submissions/{granularity}/{time_window}`", "description": "Returns first exercise submission statistics with specified time granularity and window,\ngrouped by module.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getFirstExerciseSubmissionsByModule", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "First exercise submissions by module", "content": { "application/json": { "schema": { "type": "object", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } }, "propertyNames": { "type": "string", "format": "uuid" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/cohort-activity/{granularity}/{history_window}/{tracking_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/cohort-activity/{granularity}/{history_window}/{tracking_window}`", "operationId": "getCohortActivityHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "history_window", "in": "path", "description": "History window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "tracking_window", "in": "path", "description": "Tracking window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Cohort activity history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CohortActivity" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/completions-history/custom-time-period/{start_date}/{end_date}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/completions-history/custom-time-period/{start_date}/{end_date}`", "description": "Returns completion statistics by custom time period.\nQuery parameters:\n- start_date: YYYY-MM-DD\n- end_date: YYYY-MM-DD", "operationId": "getCourseCompletionsHistoryCustomTimePeriod", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "start_date", "in": "path", "description": "Start date", "required": true, "schema": { "type": "string" } }, { "name": "end_date", "in": "path", "description": "End date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Course completions history for custom time period", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/completions-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/completions-history/{granularity}/{time_window}`", "description": "Returns completion statistics for the course with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getCourseCompletionsHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Course completions history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/first-submissions-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/first-submissions-history/{granularity}/{time_window}`", "description": "Returns first exercise submission statistics with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getFirstExerciseSubmissionsHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "First exercise submissions history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/student-completions-by-country/{granularity}/{time_window}/{country}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/student-completions-by-country/{granularity}/{time_window}/{country}`", "description": "Returns student completion statistics grouped by country with the specified time granularity.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getStudentCompletionsByCountry", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "country", "in": "path", "description": "Country", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Student completions by country", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/student-enrollments-by-country/{granularity}/{time_window}/{country}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/student-enrollments-by-country/{granularity}/{time_window}/{country}`", "description": "Returns student signup statistics grouped by country with the specified time granularity.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getStudentEnrollmentsByCountry", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "country", "in": "path", "description": "Country", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Student enrollments by country", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/students-by-country-totals": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/students-by-country-totals`", "description": "Returns all enrolled students grouped by country.", "operationId": "getStudentsByCountryTotals", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Students by country totals", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/StudentsByCountryTotalsResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-completed": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-completed`", "operationId": "getTotalUsersCompletedCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users completed course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-completed/custom-time-period/{start_date}/{end_date}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-completed/custom-time-period/{start_date}/{end_date}`", "operationId": "getTotalUsersCompletedCourseCustomTimePeriod", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "start_date", "in": "path", "description": "Start date", "required": true, "schema": { "type": "string" } }, { "name": "end_date", "in": "path", "description": "End date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Total users completed course for custom time period", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-returned-exercises": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-returned-exercises`", "operationId": "getTotalUsersReturnedExercises", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users returned exercises", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-returned-exercises/custom-time-period/{start_date}/{end_date}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-returned-exercises/custom-time-period/{start_date}/{end_date}`", "operationId": "getTotalUsersReturnedExercisesCustomTimePeriod", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "start_date", "in": "path", "description": "Start date", "required": true, "schema": { "type": "string" } }, { "name": "end_date", "in": "path", "description": "End date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Total users returned exercises for custom time period", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-started-course": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-started-course`", "operationId": "getTotalUsersStartedCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Total users started course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/total-users-started-course/custom-time-period/{start_date}/{end_date}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/total-users-started-course/custom-time-period/{start_date}/{end_date}`", "operationId": "getTotalUsersStartedCourseCustomTimePeriod", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "start_date", "in": "path", "description": "Start date", "required": true, "schema": { "type": "string" } }, { "name": "end_date", "in": "path", "description": "End date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Total users started course for custom time period", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/users-returning-exercises-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/users-returning-exercises-history/{granularity}/{time_window}`", "description": "Returns users returning exercises statistics with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getUsersReturningExercisesHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Users returning exercises history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/users-starting-history/custom-time-period/{start_date}/{end_date}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/users-starting-history/custom-time-period/{start_date}/{end_date}`", "description": "Returns unique users starting statistics with specified time period.", "operationId": "getUniqueUsersStartingHistoryCustomTimePeriod", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "start_date", "in": "path", "description": "Start date", "required": true, "schema": { "type": "string" } }, { "name": "end_date", "in": "path", "description": "End date", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Unique users starting history for custom time period", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/stats/users-starting-history/{granularity}/{time_window}": { "get": { "tags": ["course-stats"], "summary": "GET `/api/v0/main-frontend/{course_id}/stats/users-starting-history/{granularity}/{time_window}`", "description": "Returns unique users starting statistics with specified time granularity and window.\n- granularity: \"year\", \"month\", or \"day\"\n- time_window: number of time units to look back", "operationId": "getUniqueUsersStartingHistory", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "granularity", "in": "path", "description": "Time granularity", "required": true, "schema": { "$ref": "#/components/schemas/TimeGranularity" } }, { "name": "time_window", "in": "path", "description": "Time window", "required": true, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Unique users starting history", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CountResult" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/status-for-all-exercises/{user_id}": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/status-for-all-exercises/:user_id` - Returns status for all exercises in the course for a given user.", "operationId": "getCourseExerciseStatusesForUser", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise statuses for course user", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseStatusSummaryForUser" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/structure": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/structure` - Returns the structure of a course.\n# Example\n```json\n{\n \"course\": {\n \"id\": \"d86cf910-4d26-40e9-8c9c-1cc35294fdbb\",\n \"slug\": \"introduction-to-everything\",\n \"created_at\": \"2021-04-28T10:40:54.503917\",\n \"updated_at\": \"2021-04-28T10:40:54.503917\",\n \"name\": \"Introduction to everything\",\n \"organization_id\": \"1b89e57e-8b57-42f2-9fed-c7a6736e3eec\",\n \"deleted_at\": null,\n \"language_code\": \"en-US\",\n \"copied_from\": null,\n \"language_version_of_course_id\": null\n },\n \"pages\": [\n {\n \"id\": \"f3b0d699-c9be-4d56-bd0a-9d40e5547e4d\",\n \"created_at\": \"2021-04-28T13:51:51.024118\",\n \"updated_at\": \"2021-04-28T14:36:18.179490\",\n \"course_id\": \"d86cf910-4d26-40e9-8c9c-1cc35294fdbb\",\n \"content\": [],\n \"url_path\": \"/\",\n \"title\": \"Welcome to Introduction to Everything\",\n \"deleted_at\": null,\n \"chapter_id\": \"d332f3d9-39a5-4a18-80f4-251727693c37\"\n }\n ],\n \"chapters\": [\n {\n \"id\": \"d332f3d9-39a5-4a18-80f4-251727693c37\",\n \"created_at\": \"2021-04-28T16:11:47.477850\",\n \"updated_at\": \"2021-04-28T16:11:47.477850\",\n \"name\": \"The Basics\",\n \"course_id\": \"d86cf910-4d26-40e9-8c9c-1cc35294fdbb\",\n \"deleted_at\": null,\n \"chapter_image_url\": \"http://project-331.local/api/v0/files/uploads/organizations/1b89e57e-8b57-42f2-9fed-c7a6736e3eec/courses/d86cf910-4d26-40e9-8c9c-1cc35294fdbb/images/mbPQh8th96TdUwX96Y0ch1fjbJLRFr.png\",\n \"chapter_number\": 1,\n \"front_page_id\": null\n }\n ]\n}\n```", "operationId": "getCourseStructure", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course structure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseStructure" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/certificates": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/certificates`", "operationId": "getCourseStudentsCertificates", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserIdsPayload" } } }, "required": true }, "responses": { "200": { "description": "Course certificates for the given users", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CertificateGridRow" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/completions": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/completions`", "operationId": "getCourseStudentsCompletions", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserIdsPayload" } } }, "required": true }, "responses": { "200": { "description": "Course completions for the given users", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CompletionGridRow" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/progress": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/progress`", "operationId": "getCourseStudentsProgress", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserIdsPayload" } } }, "required": true }, "responses": { "200": { "description": "Per-user course progress for the given users", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseStudentsProgressUsers" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/progress-structure": { "get": { "tags": ["course-students"], "summary": "GET `/api/v0/main-frontend/courses/{course_id}/students/progress-structure`", "operationId": "getCourseStudentsProgressStructure", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course-level progress structure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseStudentsProgressStructure" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/users": { "get": { "tags": ["course-students"], "summary": "GET `/api/v0/main-frontend/courses/{course_id}/students/users`", "operationId": "getCourseStudentsUsers", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number (1-based)", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Page size (1-10000)", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "search", "in": "query", "description": "Filter by name/email substring or exact user id", "required": false, "schema": { "type": "string" } }, { "name": "sort_column", "in": "query", "description": "last_name | first_name | email", "required": false, "schema": { "type": "string" } }, { "name": "sort_direction", "in": "query", "description": "asc | desc", "required": false, "schema": { "type": "string" } }, { "name": "course_instance_id", "in": "query", "description": "Filter to a single course instance", "required": false, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "A page of enrolled students", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StudentsListPage" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapter-locking-statuses": { "get": { "tags": ["course-students"], "summary": "GET `/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapter-locking-statuses`", "operationId": "getCourseStudentChapterLockingStatuses", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Target student id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Student chapter locking statuses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserChapterLockingStatus" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/lock": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/lock`", "operationId": "teacherLockStudentChapter", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Target student id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Updated chapter locking status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserChapterLockingStatus" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/status": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/status`", "operationId": "teacherSetStudentChapterStatus", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Target student id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChapterLockStatusActionPayload" } } }, "required": true }, "responses": { "200": { "description": "Updated chapter locking status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserChapterLockingStatus" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/unlock": { "post": { "tags": ["course-students"], "summary": "POST `/api/v0/main-frontend/courses/{course_id}/students/{user_id}/chapters/{chapter_id}/unlock`", "operationId": "teacherUnlockStudentChapter", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Target student id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "chapter_id", "in": "path", "description": "Chapter id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Updated chapter locking status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserChapterLockingStatus" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/submission-counts-by-exercise": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/submission-counts-by-exercise` - Returns submission counts grouped by weekday and hour.", "operationId": "getCourseSubmissionCountsByExercise", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course submission counts by exercise", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionCountByExercise" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/suspected-cheaters": { "get": { "tags": ["courses"], "summary": "\n GET /api/v0/main-frontend/courses/${course.id}/suspected-cheaters?status=Flagged - returns the suspected cheaters in the given review state for a course.", "operationId": "getCourseSuspectedCheaters", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "status", "in": "query", "description": "Which review state of suspected cheaters to fetch", "required": true, "schema": { "$ref": "#/components/schemas/SuspectedCheaterStatus" } } ], "responses": { "200": { "description": "Suspected cheaters for course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/SuspectedCheaters" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/suspected-cheaters/confirm/{user_id}": { "post": { "tags": ["courses"], "summary": "\n POST /api/v0/main-frontend/courses/${course.id}/suspected-cheaters/confirm/:user_id - confirms the student cheated (sets status to 'ConfirmedCheating') and fails the student.", "operationId": "confirmCourseSuspectedCheater", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Suspected cheater's user id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Cheating confirmed" } } } }, "/api/v0/main-frontend/courses/{course_id}/suspected-cheaters/dismiss/{user_id}": { "post": { "tags": ["courses"], "summary": "\n POST /api/v0/main-frontend/courses/${course.id}/suspected-cheaters/dismiss/:user_id - dismisses the suspicion as a false alarm (sets status to 'Dismissed').", "operationId": "dismissCourseSuspectedCheater", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "Suspected cheater's user id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Suspicion dismissed" } } } }, "/api/v0/main-frontend/courses/{course_id}/suspected-cheaters/flagged-count": { "get": { "tags": ["courses"], "summary": "\n GET /api/v0/main-frontend/courses/${course.id}/suspected-cheaters/flagged-count - number of suspected cheaters awaiting review (status flagged). Used to show a review notification to teachers.", "operationId": "getCourseFlaggedSuspectedCheatersCount", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Number of suspected cheaters awaiting review", "content": { "application/json": { "schema": { "type": "integer", "format": "int64" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/teacher-reset-course-progress-for-everyone": { "delete": { "tags": ["courses"], "summary": "\nDELETE `/api/v0/main-frontend/courses/${course.id}/teacher-reset-course-progress-for-everyone` - Can be used by teachers to reset the course progress for all students. Only works when the course is a draft and not published to students. Cannot be used to delete a course that some students have taken.\n\nDeletes submissions, user exercise states, and peer reviews etc. for all the course instances of this course.", "operationId": "resetCourseProgressForEveryone", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course progress reset for everyone", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/teacher-reset-course-progress-for-themselves": { "delete": { "tags": ["courses"], "summary": "\nDELETE `/api/v0/main-frontend/courses/${course.id}/teacher-reset-course-progress-for-themselves` - Allows a teacher to reset the course progress for themselves. Cannot be used to reset the course for others.\n\nDeletes submissions, user exercise states, and peer reviews etc. for all the course instances of this course.", "operationId": "resetCourseProgressForTeacherThemselves", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Teacher course progress reset", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/thresholds": { "get": { "tags": ["courses"], "summary": "\n GET /api/v0/main-frontend/courses/${course.id}/thresholds - get all thresholds for all modules in a course.", "operationId": "getCourseThresholds", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course thresholds", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleThresholdInfo" } } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/update-metadata": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:course_id/update-metadata` - Update metadata.", "operationId": "updateMetadata", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseMetadataUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseMetadata" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/update-peer-review-queue-reviews-received": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/${course_id}/update-peer-review-queue-reviews-received`\n\nUpdates reviews received for all the students in the peer review queue for a specific course. Updates only entries that have not received enough peer reviews in the table. Only available to admins.", "operationId": "updateCoursePeerReviewQueueReviewsReceived", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Peer review queue updated", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/upload": { "post": { "tags": ["courses"], "summary": "\nPOST `/api/v0/main-frontend/courses/:course_id/upload` - Uploads a media (image, audio, file) for the course from Gutenberg page edit.\n\nPut the the contents of the media in a form and add a content type header multipart/form-data.\n# Example\n\nRequest:\n```http\nPOST /api/v0/main-frontend/pages/d86cf910-4d26-40e9-8c9c-1cc35294fdbb/upload HTTP/1.1\nContent-Type: multipart/form-data\n\nBINARY_DATA\n```", "operationId": "uploadCourseMedia", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "string" } } }, "required": true }, "responses": { "200": { "description": "Uploaded media result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadResult" } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/user-settings/{user_id}": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:course_id/user-settings/:user_id` - Get current course settings for a specific user.", "operationId": "getCourseUserSettingsForUser", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User course settings", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/UserCourseSettings" } ] } } } } } } }, "/api/v0/main-frontend/courses/{course_id}/weekday-hour-submission-counts": { "get": { "tags": ["courses"], "summary": "\nGET `/api/v0/main-frontend/courses/:id/weekday-hour-submission-counts` - Returns submission counts grouped by weekday and hour.", "operationId": "getCourseWeekdayHourSubmissionCounts", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course weekday and hour submission counts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionCountByWeekAndHour" } } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/account-linking": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/account-linking` - The linking funnel, the\nper-realisation counters, the send-status totals and the stale-address list.", "operationId": "getAccountLinkingStats", "parameters": [ { "name": "window_days", "in": "query", "description": "Window for the windowed funnel steps, in days", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Where account linking stands", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountLinkingStats" } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/account-linking/manual-link": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/account-linking/manual-link` - Links a student\nnumber to an account on an admin's judgement.\n\nThe last resort, for a student whose mailbox host will not accept our mail at all. An admin's judgement\nstands in for proof of mailbox control, so the link is marked `admin_manual` forever, carries the\nreason and names the admin.", "operationId": "adminManuallyLinkStudentNumber", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminManuallyLinkStudentNumberPayload" } } }, "required": true }, "responses": { "200": { "description": "What the attempt did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminManuallyLinkStudentNumberResult" } } } }, "422": { "description": "No reason, no student number, or no person id from the preview" } } } }, "/api/v0/main-frontend/credit-registration-admin/account-linking/resend": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/account-linking/resend` - Sets off another\naccount-linking mail for one person on one course.\n\nThe mail goes to the addresses the study registry holds, and the recipient still has to open the link\nwhile signed in, so the ownership proof is intact. An override does not ask a cap for an exemption: it\nretires the ledger rows the cap is counting, as its own audited action, then runs the ordinary path.", "operationId": "adminResendAccountLinkingEmail", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminResendAccountLinkingEmailPayload" } } }, "required": true }, "responses": { "200": { "description": "What the attempt did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminResendAccountLinkingEmailResult" } } } }, "422": { "description": "An override without a reason, or too soon after the last resend" } } } }, "/api/v0/main-frontend/credit-registration-admin/account-linking/resolve-person": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/account-linking/resolve-person` - Looks one\nstudent number up in the study registry without changing anything.\n\nThe preview a manual link is gated on. Writes nothing but the call log row every study registry call\nwrites.", "operationId": "adminResolveStudentNumberForLinking", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminResolveStudentNumberPayload" } } }, "required": true }, "responses": { "200": { "description": "Who the study registry says the number belongs to", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminResolveStudentNumberResult" } } } }, "422": { "description": "No student number given" } } } }, "/api/v0/main-frontend/credit-registration-admin/materialize": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/materialize` - Creates ledger rows for eligible\ncompletions and recomputes preconditions, now.\n\nRuns the two database-only steps directly rather than through the phase dispatcher, because the\nphase-state row describes the worker loops: an admin pressing a button must not make a dead worker look\nalive.", "operationId": "adminMaterializeCreditRegistrations", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminMaterializePayload" } } }, "required": true }, "responses": { "200": { "description": "How many rows were created and moved", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminMaterializeResult" } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/overview": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/overview` - Everything the Overview tab and the\nalert banner render, in one request so the tiles cannot contradict each other.", "operationId": "getCreditRegistrationOverview", "responses": { "200": { "description": "Counts, throughput, phase heartbeats and the active alerts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditRegistrationOverview" } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/phases/{phase}/pause": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/phases/{phase}/pause` - Pauses one phase: the\nworker loop skips it on every tick until it is resumed.", "operationId": "adminPausePhase", "parameters": [ { "name": "phase", "in": "path", "description": "One of the twelve canonical phase names", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminPausePhasePayload" } } }, "required": true }, "responses": { "200": { "description": "The phase's status after pausing", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditRegistrationPhaseStatus" } } } }, "422": { "description": "No reason given, or not one of the canonical phase names" } } } }, "/api/v0/main-frontend/credit-registration-admin/phases/{phase}/resume": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/phases/{phase}/resume` - Resumes one paused\nphase.", "operationId": "adminResumePhase", "parameters": [ { "name": "phase", "in": "path", "description": "One of the twelve canonical phase names", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminPhaseActionPayload" } } }, "required": true }, "responses": { "200": { "description": "The phase's status after resuming", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditRegistrationPhaseStatus" } } } }, "422": { "description": "Not one of the canonical phase names" } } } }, "/api/v0/main-frontend/credit-registration-admin/phases/{phase}/run-now": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/phases/{phase}/run-now` - Makes one phase due\nimmediately: the worker loop picks it up on its next tick instead of waiting out `next_run_at`.", "operationId": "adminRunPhaseNow", "parameters": [ { "name": "phase", "in": "path", "description": "One of the twelve canonical phase names", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminPhaseActionPayload" } } }, "required": true }, "responses": { "200": { "description": "The phase's status after being made due", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreditRegistrationPhaseStatus" } } } }, "422": { "description": "Not one of the canonical phase names" } } } }, "/api/v0/main-frontend/credit-registration-admin/registrations": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/registrations` - A page of the ledger, filtered\nand sorted.", "operationId": "listCreditRegistrationsForAdmin", "parameters": [ { "name": "page", "in": "query", "description": "Page number, from 1", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Rows per page", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "state", "in": "query", "description": "Ledger states; repeat the parameter for several", "required": false, "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationState" } } }, { "name": "error_code", "in": "query", "description": "Error codes; repeat the parameter for several", "required": false, "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } } }, { "name": "course_id", "in": "query", "description": "Course filter", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_module_id", "in": "query", "description": "Course module filter", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "query", "description": "Student filter", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "student_number", "in": "query", "description": "Exact student number, frozen on the row or linked to the account", "required": false, "schema": { "type": "string" } }, { "name": "needs_admin_attention", "in": "query", "description": "Only rows asking for a human", "required": false, "schema": { "type": "boolean" } }, { "name": "submitted_after", "in": "query", "description": "Submitted at or after", "required": false, "schema": { "type": "string", "format": "date-time" } }, { "name": "submitted_before", "in": "query", "description": "Submitted at or before", "required": false, "schema": { "type": "string", "format": "date-time" } }, { "name": "search", "in": "query", "description": "Name, email, student number, attainment id, stored error text, or a uuid", "required": false, "schema": { "type": "string" } }, { "name": "include_superseded", "in": "query", "description": "Include replaced attempts", "required": false, "schema": { "type": "boolean" } }, { "name": "sort", "in": "query", "description": "last_activity, created, time_in_state or attempts", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of the ledger", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminCreditRegistrationsPage" } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/registrations/{credit_registration_id}": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/registrations/{credit_registration_id}` - One\nrow with its timeline, the calls that timeline refers to, the other attempts for the same completion,\nthe actions taken on it and its linking mails.", "operationId": "getCreditRegistrationForAdmin", "parameters": [ { "name": "credit_registration_id", "in": "path", "description": "Credit registration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The row and everything that happened to it", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminCreditRegistrationDetails" } } } }, "404": { "description": "No such registration" } } } }, "/api/v0/main-frontend/credit-registration-admin/registrations/{credit_registration_id}/transition": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/registrations/{credit_registration_id}/transition`\n- Moves one row by hand.\n\nThe escape hatch out of `submission_uncertain`, which the pipeline never leaves on its own because\nre-importing could put a second attainment on a real transcript. Resubmitting re-checks consent, because\na `misregistered` row sits outside the automatic machinery that would otherwise have checked it.", "operationId": "adminTransitionCreditRegistration", "parameters": [ { "name": "credit_registration_id", "in": "path", "description": "Credit registration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminTransitionCreditRegistrationPayload" } } }, "required": true }, "responses": { "200": { "description": "What the transition did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminTransitionCreditRegistrationResult" } } } }, "404": { "description": "No such registration" }, "422": { "description": "No reason given" } } } }, "/api/v0/main-frontend/credit-registration-admin/student-numbers": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/student-numbers` - A page of the live links, for\nspot-checking and support.", "operationId": "listVerifiedStudentNumbersForAdmin", "parameters": [ { "name": "page", "in": "query", "description": "Page number, from 1", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Rows per page", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "verified_via", "in": "query", "description": "How the link was established", "required": false, "schema": { "$ref": "#/components/schemas/StudentNumberVerificationMethod" } }, { "name": "search", "in": "query", "description": "Student number, name or email", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "description": "A page of the live links", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminVerifiedStudentNumbersPage" } } } } } } }, "/api/v0/main-frontend/credit-registration-admin/student-numbers/{verified_student_number_id}/unlink": { "post": { "tags": ["credit-registration-admin"], "summary": "\nPOST `/api/v0/main-frontend/credit-registration-admin/student-numbers/{id}/unlink` - Retires one link.\n\nA reason is required, so the request carries a body rather than being a `DELETE`. The row is\nsoft-deleted: the number a student once held is part of the audit trail.", "operationId": "adminUnlinkStudentNumber", "parameters": [ { "name": "verified_student_number_id", "in": "path", "description": "Verified student number id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminUnlinkStudentNumberPayload" } } }, "required": true }, "responses": { "200": { "description": "How many registrations went back to waiting", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminUnlinkStudentNumberResult" } } } }, "404": { "description": "No such link" }, "422": { "description": "No reason given" } } } }, "/api/v0/main-frontend/credit-registration-admin/suotar-health": { "get": { "tags": ["credit-registration-admin"], "summary": "\nGET `/api/v0/main-frontend/credit-registration-admin/suotar-health` - Per-endpoint call counts,\nsuccess rates and latency percentiles over an hour, a day and a week.", "operationId": "getSuotarHealth", "responses": { "200": { "description": "Study registry traffic per endpoint and window", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuotarHealth" } } } } } } }, "/api/v0/main-frontend/credit-registrations/courses/{course_id}/consent": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/courses/{course_id}/consent` - The signed-in\naccount's credit registration consent for one course.", "operationId": "getMyCourseCreditRegistrationConsent", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The caller's consent for the course", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MyCourseCreditRegistrationConsent" } } } } } }, "put": { "tags": ["credit-registrations"], "summary": "\nPUT `/api/v0/main-frontend/credit-registrations/courses/{course_id}/consent` - Records the signed-in\naccount's answer and applies it to that course's registrations at once.", "operationId": "setMyCourseCreditRegistrationConsent", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetMyCourseCreditRegistrationConsentPayload" } } }, "required": true }, "responses": { "200": { "description": "The recorded answer and what it unblocked", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetMyCourseCreditRegistrationConsentResult" } } } } } } }, "/api/v0/main-frontend/credit-registrations/my": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/my` - Every credit registration of the signed-in\naccount, newest completion first.", "operationId": "getMyCreditRegistrations", "responses": { "200": { "description": "The caller's credit registrations", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MyCreditRegistration" } } } } } } } }, "/api/v0/main-frontend/credit-registrations/my/by-course-module/{course_module_id}": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/my/by-course-module/{course_module_id}` - The\nsigned-in account's registration for one course module, or null when the pipeline has not created one\nyet.", "operationId": "getMyCreditRegistrationForCourseModule", "parameters": [ { "name": "course_module_id", "in": "path", "description": "Course module id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "The caller's registration for the module", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/MyCreditRegistrationForCourseModule" } ] } } } } } } }, "/api/v0/main-frontend/credit-registrations/my/consents": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/my/consents` - One row per course the signed-in\naccount is enrolled on that offers credit registration, asked or not.", "operationId": "getMyCreditRegistrationConsents", "responses": { "200": { "description": "The caller's per-course consents", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MyCreditRegistrationConsent" } } } } } } } }, "/api/v0/main-frontend/credit-registrations/my/student-number": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/my/student-number` - The student number linked to the\nsigned-in account, or null.", "operationId": "getMyVerifiedStudentNumber", "responses": { "200": { "description": "The caller's linked student number", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/MyVerifiedStudentNumber" } ] } } } } } }, "delete": { "tags": ["credit-registrations"], "summary": "\nDELETE `/api/v0/main-frontend/credit-registrations/my/student-number` - Unlinks the student number\nfrom the signed-in account.\n\nRegistrations that have not been sent go back to waiting; credits already in Sisu are untouched.", "operationId": "unlinkMyStudentNumber", "responses": { "200": { "description": "How many registrations went back to waiting", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UnlinkMyStudentNumberResult" } } } } } } }, "/api/v0/main-frontend/credit-registrations/my/{id}/recheck-enrolment": { "post": { "tags": ["credit-registrations"], "summary": "\nPOST `/api/v0/main-frontend/credit-registrations/my/{id}/recheck-enrolment` - Asks the pipeline to\nlook for an enrolment again, for a row parked because the study registry had none.", "operationId": "requestCreditRegistrationEnrolmentRecheck", "parameters": [ { "name": "id", "in": "path", "description": "Credit registration id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Whether a recheck was started", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestCreditRegistrationEnrolmentRecheckResult" } } } }, "400": { "description": "The registration is not waiting for an enrolment" }, "403": { "description": "Not the caller's registration" } } } }, "/api/v0/main-frontend/credit-registrations/student-number-verifications/{token}": { "get": { "tags": ["credit-registrations"], "summary": "\nGET `/api/v0/main-frontend/credit-registrations/student-number-verifications/{token}` - What the\nmailed link would link, without linking it.\n\nWrites nothing: the link has to survive a mail scanner fetching it.", "operationId": "previewStudentNumberVerificationToken", "parameters": [ { "name": "token", "in": "path", "description": "The mailed verification token", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "What the token would link", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StudentNumberVerificationTokenPreview" } } } }, "404": { "description": "No such token" } } } }, "/api/v0/main-frontend/credit-registrations/student-number-verifications/{token}/claim": { "post": { "tags": ["credit-registrations"], "summary": "\nPOST `/api/v0/main-frontend/credit-registrations/student-number-verifications/{token}/claim` - Spends\na mailed link and links the student number to the signed-in account.\n\nAny signed-in account may claim any valid token: holding it proves control of the Sisu-held mailbox,\nand the session says which of our accounts the person wants to use.", "operationId": "claimStudentNumberVerificationToken", "parameters": [ { "name": "token", "in": "path", "description": "The mailed verification token", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "What the claim did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClaimStudentNumberVerificationTokenResult" } } } }, "404": { "description": "No such token" } } } }, "/api/v0/main-frontend/email-templates": { "get": { "tags": ["email_templates"], "summary": "\nGET `/api/v0/main-frontend/email-templates`", "operationId": "getEmailTemplates", "responses": { "200": { "description": "Email templates", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/EmailTemplate" } } } } } } } }, "/api/v0/main-frontend/email-templates/{email_template_id}": { "delete": { "tags": ["email_templates"], "summary": "\nDELETE `/api/v0/main-frontend/email-templates/:id`", "operationId": "deleteEmailTemplate", "parameters": [ { "name": "email_template_id", "in": "path", "description": "Email template id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted email template", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailTemplate" } } } } } } }, "/api/v0/main-frontend/email-verification/request": { "post": { "tags": ["email-verification"], "summary": "\nPOST `/api/v0/main-frontend/email-verification/request` - Mails a fresh verification code to the\nsigned-in account's current address.", "operationId": "requestEmailVerificationCode", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestEmailVerificationPayload" } } }, "required": true }, "responses": { "200": { "description": "What the request did", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestEmailVerificationOutcome" } } } }, "404": { "description": "Email ownership verification is switched off" } } } }, "/api/v0/main-frontend/email-verification/status": { "get": { "tags": ["email-verification"], "summary": "\nGET `/api/v0/main-frontend/email-verification/status` - Whether the signed-in account's address is\nproven, and what we last mailed about it.", "operationId": "getMyEmailVerificationStatus", "responses": { "200": { "description": "Email verification status of the signed-in user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailVerificationStatus" } } } } } } }, "/api/v0/main-frontend/email-verification/test-mode-code": { "get": { "tags": ["email-verification"], "summary": "\nGET `/api/v0/main-frontend/email-verification/test-mode-code` - The signed-in account's own pending\nverification code.\n\nExists because the system tests have no mail capture. 404 unless `TEST_MODE` is on, and scoped to the\ncaller's own account, so an accidentally open gate only ever hands you your own code.", "operationId": "getEmailVerificationCodeForTestMode", "responses": { "200": { "description": "The caller's pending verification code", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "description": "Not in test mode, or no pending code" } } } }, "/api/v0/main-frontend/email-verification/verify": { "post": { "tags": ["email-verification"], "summary": "\nPOST `/api/v0/main-frontend/email-verification/verify` - Spends a mailed code and records the proof.\n\nAuthenticated and scoped to the caller's own account, so the code is the only secret involved and it\nnever has to identify anybody on its own.", "operationId": "verifyEmailOwnership", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyEmailOwnershipPayload" } } }, "required": true }, "responses": { "200": { "description": "Outcome of submitting the code", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyEmailOwnershipResult" } } } }, "404": { "description": "Email ownership verification is switched off" } } } }, "/api/v0/main-frontend/exams/{exam_id}/exam-exercises": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exam/:exam_id/exam-exercises` - Returns all the exercises with exam_id.", "operationId": "getExamExercises", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exam exercises", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Exercise" } } } } } } } }, "/api/v0/main-frontend/exams/{exam_id}/release-grades": { "post": { "tags": ["exams"], "summary": "\nPOST `/api/v0/main-frontend/exam/:exam_id/release-grades` - Publishes grading results of an exam by updating user_exercise_states according to teacher_grading_decisons and changes teacher_grading_decisions hidden field to false. Takes teacher grading decision ids as input.", "operationId": "releaseExamGrades", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "required": true }, "responses": { "200": { "description": "Exam grades released" } } } }, "/api/v0/main-frontend/exams/{exam_id}/submissions-with-exam-id": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exam/:exam_id/submissions-with-exam-id` - Returns all the exercise submissions and user exercise states with exam_id.", "operationId": "getExamSubmissionsWithExamId", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Exercise submissions with exam id", "content": { "application/json": { "schema": { "type": "array", "items": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionAndUserExerciseState" } } } } } } } } }, "/api/v0/main-frontend/exams/{exercise_id}/submissions-with-exercise-id": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exam/:exercise_id/submissions-with-exercise_id` - Returns all the exercise submissions and user exercise states with exercise_id.", "operationId": "getExamSubmissionsWithExerciseId", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int32", "minimum": 0 } } ], "responses": { "200": { "description": "Exercise submissions with exercise id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseSlideSubmissionAndUserExerciseStateList" } } } } } } }, "/api/v0/main-frontend/exams/{id}": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exams/:id", "operationId": "getExam", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exam", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Exam" } } } } } } }, "/api/v0/main-frontend/exams/{id}/duplicate": { "post": { "tags": ["exams"], "summary": "\n * POST `/api/v0/cms/exams/:exam_id/duplicate` - duplicates existing exam.", "operationId": "duplicateExam", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewExam" } } }, "required": true }, "responses": { "200": { "description": "Exam duplicated", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/exams/{id}/edit-exam": { "post": { "tags": ["exams"], "summary": "\nPOST `/api/v0/main-frontend/organizations/{organization_id}/edit-exam` - edits an exam.", "operationId": "editExam", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewExam" } } }, "required": true }, "responses": { "200": { "description": "Exam edited" } } } }, "/api/v0/main-frontend/exams/{id}/export-points": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exams/:id/export-points`", "operationId": "exportExamPointsCsv", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exam points CSV export", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/exams/{id}/export-submissions": { "get": { "tags": ["exams"], "summary": "\nGET `/api/v0/main-frontend/exams/:id/export-submissions`", "operationId": "exportExamSubmissionsCsv", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exam submissions CSV export", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/exams/{id}/set": { "post": { "tags": ["exams"], "summary": "\nPOST `/api/v0/main-frontend/exams/:id/set`", "operationId": "setExamCourse", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExamCourseInfo" } } }, "required": true }, "responses": { "200": { "description": "Course set for exam" } } } }, "/api/v0/main-frontend/exams/{id}/unset": { "post": { "tags": ["exams"], "summary": "\nPOST `/api/v0/main-frontend/exams/:id/unset`", "operationId": "unsetExamCourse", "parameters": [ { "name": "id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExamCourseInfo" } } }, "required": true }, "responses": { "200": { "description": "Course unset from exam" } } } }, "/api/v0/main-frontend/exercise-repositories/course/{course_id}": { "get": { "tags": ["exercise_repositories"], "summary": "\nGET `/api/v0/main-frontend/exercise-repositories/course/:id`", "operationId": "getExerciseRepositoriesForCourse", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise repositories for course", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseRepository" } } } } } } } }, "/api/v0/main-frontend/exercise-repositories/exam/{exam_id}": { "get": { "tags": ["exercise_repositories"], "summary": "\nGET `/api/v0/main-frontend/exercise-repositories/exam/:id`", "operationId": "getExerciseRepositoriesForExam", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise repositories for exam", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseRepository" } } } } } } } }, "/api/v0/main-frontend/exercise-repositories/new": { "post": { "tags": ["exercise_repositories"], "summary": "\nPOST `/api/v0/main-frontend/exercise-repositories/new", "operationId": "createExerciseRepository", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewExerciseRepository" } } }, "required": true }, "responses": { "200": { "description": "Created exercise repository id", "content": { "text/plain": { "schema": { "type": "string", "format": "uuid" } } } } } } }, "/api/v0/main-frontend/exercise-repositories/{id}": { "put": { "tags": ["exercise_repositories"], "summary": "\nPUT `/api/v0/main-frontend/exercise-repositories/:id`", "operationId": "updateExerciseRepository", "parameters": [ { "name": "id", "in": "path", "description": "Exercise repository id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseRepositoryUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated exercise repository", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } }, "delete": { "tags": ["exercise_repositories"], "summary": "\nDELETE `/api/v0/main-frontend/exercise-repositories/:id`", "operationId": "deleteExerciseRepository", "parameters": [ { "name": "id", "in": "path", "description": "Exercise repository id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted exercise repository", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/exercise-services/": { "get": { "tags": ["exercise_services"], "summary": "\nGET `/api/v0/main-frontend/exercise-services`", "operationId": "getExerciseServices", "responses": { "200": { "description": "Exercise services", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseService" } } } } } } }, "post": { "tags": ["exercise_services"], "summary": "\nPOST `/api/v0/main-frontend/exercise-services`", "operationId": "createExerciseService", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseServiceNewOrUpdate" } } }, "required": true }, "responses": { "200": { "description": "Created exercise service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseServiceWithError" } } } } } } }, "/api/v0/main-frontend/exercise-services/{exercise_service_id}": { "get": { "tags": ["exercise_services"], "summary": "\nGET `/api/v0/main-frontend/exercise-services/:id`", "operationId": "getExerciseServiceById", "parameters": [ { "name": "exercise_service_id", "in": "path", "description": "Exercise service id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseService" } } } } } }, "put": { "tags": ["exercise_services"], "summary": "\nPUT `/api/v0/main-frontend/exercise-services/:id`", "operationId": "updateExerciseService", "parameters": [ { "name": "exercise_service_id", "in": "path", "description": "Exercise service id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseServiceNewOrUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated exercise service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseServiceWithError" } } } } } }, "delete": { "tags": ["exercise_services"], "operationId": "deleteExerciseService", "parameters": [ { "name": "exercise_service_id", "in": "path", "description": "Exercise service id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted exercise service", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseService" } } } } } } }, "/api/v0/main-frontend/exercise-slide-submissions/add-teacher-grading-for-exam-submission": { "put": { "tags": ["exercise_slide_submissions"], "summary": "\nPUT `/api/v0/main-frontend/exercise-slide-submissions/add_teacher_grading\"` - Adds a new teacher grading decision, without updating user exercise state", "operationId": "addTeacherGradingForExamSubmission", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewTeacherGradingDecision" } } }, "required": true }, "responses": { "200": { "description": "Created teacher grading decision", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TeacherGradingDecision" } } } } } } }, "/api/v0/main-frontend/exercise-slide-submissions/{exam_id}/user-exercise-state-info": { "get": { "tags": ["exercise_slide_submissions"], "summary": "\nGET `/api/v0/main-frontend/exercise-slide-submissions/{exam_id}/{exercise_id}/{user_id}/user-exercise-state-info`-", "operationId": "getExamUserExerciseStateInfo", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "exercise_id", "in": "query", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "query", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User exercise state for the exam submission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserExerciseState" } } } } } } }, "/api/v0/main-frontend/exercise-slide-submissions/{submission_id}/info": { "get": { "tags": ["exercise_slide_submissions"], "summary": "\nGET `/api/v0/main-frontend/exercise-slide-submissions/{submission_id}/info\"`- Returns data necessary for rendering a submission.", "operationId": "getExerciseSlideSubmissionInfo", "parameters": [ { "name": "submission_id", "in": "path", "description": "Exercise slide submission id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise slide submission info", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseSlideSubmissionInfo" } } } } } } }, "/api/v0/main-frontend/exercises/{course_id}/exercises-by-course-id": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:course_id/exercises-by-course-id` - Returns all exercises for a course with course_id", "operationId": "getExercisesByCourseId", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercises by course id", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Exercise" } } } } } } } }, "/api/v0/main-frontend/exercises/{course_id}/reset-exercises-for-selected-users": { "post": { "tags": ["exercises"], "summary": "\nPOST `/api/v0/main-frontend/exercises/:course_id/reset-exercises-for-selected-users` - Resets all selected exercises for selected users and then logs the resets to exercise_reset_logs table", "operationId": "resetExercisesForSelectedUsers", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResetExercisesPayload" } } }, "required": true }, "responses": { "200": { "description": "Number of successful resets", "content": { "text/plain": { "schema": { "type": "integer", "format": "int32" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id` - Returns a single exercise.", "operationId": "getExercise", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Exercise" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/answers-requiring-attention": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/answers-requiring-attention` - Returns an exercise's answers requiring attention.", "operationId": "getExerciseAnswersRequiringAttention", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Answers requiring attention", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnswersRequiringAttention" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/csv-export-task-options": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/csv-export-task-options` - Returns available exercise tasks and CSV export support flags for each task's exercise service.", "operationId": "getExerciseCsvExportTaskOptions", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise CSV export task options", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseCsvExportTaskOption" } } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/export-answers-csv": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/export-answers-csv` - Exports all answers for one exercise task as CSV using the task's exercise service.", "operationId": "exportExerciseAnswersCsv", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "exercise_task_id", "in": "query", "description": "Exercise task id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "only_latest_per_user", "in": "query", "description": "Only include latest submission per user", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "Exercise answers CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/export-definitions-csv": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/export-definitions-csv` - Exports one exercise task definition as CSV using the task's exercise service.", "operationId": "exportExerciseDefinitionsCsv", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "exercise_task_id", "in": "query", "description": "Exercise task id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "only_latest_per_user", "in": "query", "description": "Only include latest submission per user", "required": false, "schema": { "type": "boolean" } } ], "responses": { "200": { "description": "Exercise definitions CSV", "content": { "text/csv": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/submissions": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/submissions` - Returns an exercise's submissions.", "operationId": "getExerciseSubmissions", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Exercise submissions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseSubmissions" } } } } } } }, "/api/v0/main-frontend/exercises/{exercise_id}/submissions/user/{user_id}": { "get": { "tags": ["exercises"], "summary": "\nGET `/api/v0/main-frontend/exercises/:exercise_id/submissions/user/:user_id` - Returns an exercise's submissions for a user.", "operationId": "getExerciseSubmissionsForUser", "parameters": [ { "name": "exercise_id", "in": "path", "description": "Exercise id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Exercise submissions for user", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmission" } } } } } } } }, "/api/v0/main-frontend/feedback/{feedback_id}": { "post": { "tags": ["feedback"], "summary": "\nPOST `/api/v0/main-frontend/feedback/:id` - Creates new feedback.", "operationId": "markFeedbackAsRead", "parameters": [ { "name": "feedback_id", "in": "path", "description": "Feedback id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MarkAsRead" } } }, "required": true }, "responses": { "200": { "description": "Feedback read state updated" } } } }, "/api/v0/main-frontend/global-stats/completion-stats-by-email-domain": { "get": { "tags": ["global-stats"], "summary": "\n * GET `/api/v0/main-frontend/global-stats/completion-stats-by-email-domain`\n *\n * Query parameters:\n * - year: Optional - Filter results to specific year (e.g. ?year=2023)", "operationId": "getCompletionStatsByEmailDomain", "parameters": [ { "name": "year", "in": "query", "description": "Optional year", "required": false, "schema": { "type": "integer", "format": "int32" } } ], "responses": { "200": { "description": "Completion stats by email domain", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DomainCompletionStats" } } } } } } } }, "/api/v0/main-frontend/global-stats/course-completion-stats-for-email-domain": { "get": { "tags": ["global-stats"], "summary": "\n * GET `/api/v0/main-frontend/global-stats/course-completion-stats-for-email-domain`\n *\n * Query parameters:\n * - email_domain: String - The email domain to get stats for (required)\n * - year: Optional - Filter results to specific year (e.g. ?year=2023)", "operationId": "getCourseCompletionStatsForEmailDomain", "parameters": [ { "name": "email_domain", "in": "query", "description": "Email domain", "required": true, "schema": { "type": "string" } }, { "name": "year", "in": "query", "description": "Optional year", "required": false, "schema": { "type": "integer", "format": "int32" } } ], "responses": { "200": { "description": "Course completion stats for email domain", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCompletionStats" } } } } } } } }, "/api/v0/main-frontend/global-stats/course-module-stats-by-completions-registered-to-study-registry": { "get": { "tags": ["global-stats"], "summary": "\n * GET `/api/v0/main-frontend/global-stats/course-module-stats-by-completions-registered-to-study-registry`\n *\n * Query parameters:\n * - granularity: String - Either \"year\" or \"month\" (defaults to \"year\")", "operationId": "getCourseModuleStatsByCompletionsRegisteredToStudyRegistry", "parameters": [ { "name": "granularity", "in": "query", "description": "Time granularity", "required": false, "schema": { "$ref": "#/components/schemas/TimeGranularity" } } ], "responses": { "200": { "description": "Course module completion stats", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GlobalCourseModuleStatEntry" } } } } } } } }, "/api/v0/main-frontend/global-stats/number-of-people-completed-a-course": { "get": { "tags": ["global-stats"], "summary": "\nGET `/api/v0/main-frontend/global-stats/number-of-people-completed-a-course`\n\nQuery parameters:\n- granularity: String - Either \"year\" or \"month\" (defaults to \"year\")", "operationId": "getNumberOfPeopleCompletedACourse", "parameters": [ { "name": "granularity", "in": "query", "description": "Time granularity", "required": false, "schema": { "$ref": "#/components/schemas/TimeGranularity" } } ], "responses": { "200": { "description": "Global completion stats", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GlobalStatEntry" } } } } } } } }, "/api/v0/main-frontend/global-stats/number-of-people-done-at-least-one-exercise": { "get": { "tags": ["global-stats"], "summary": "\nGET `/api/v0/main-frontend/global-stats/number-of-people-done-at-least-one-exercise`\n\nQuery parameters:\n- granularity: String - Either \"year\" or \"month\" (defaults to \"year\")", "operationId": "getNumberOfPeopleDoneAtLeastOneExercise", "parameters": [ { "name": "granularity", "in": "query", "description": "Time granularity", "required": false, "schema": { "$ref": "#/components/schemas/TimeGranularity" } } ], "responses": { "200": { "description": "Exercise participation stats", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GlobalStatEntry" } } } } } } } }, "/api/v0/main-frontend/global-stats/number-of-people-registered-completion-to-study-registry": { "get": { "tags": ["global-stats"], "summary": "\nGET `/api/v0/main-frontend/global-stats/number-of-people-registered-completion-to-study-registry`\n\nQuery parameters:\n- granularity: String - Either \"year\" or \"month\" (defaults to \"year\")", "operationId": "getNumberOfPeopleRegisteredCompletionToStudyRegistry", "parameters": [ { "name": "granularity", "in": "query", "description": "Time granularity", "required": false, "schema": { "$ref": "#/components/schemas/TimeGranularity" } } ], "responses": { "200": { "description": "Study registry completion stats", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GlobalStatEntry" } } } } } } } }, "/api/v0/main-frontend/global-stats/number-of-people-started-course": { "get": { "tags": ["global-stats"], "summary": "\nGET `/api/v0/main-frontend/global-stats/number-of-people-started-course`\n\nQuery parameters:\n- granularity: String - Either \"year\" or \"month\" (defaults to \"year\")", "operationId": "getNumberOfPeopleStartedCourse", "parameters": [ { "name": "granularity", "in": "query", "description": "Time granularity", "required": false, "schema": { "$ref": "#/components/schemas/TimeGranularity" } } ], "responses": { "200": { "description": "Course start stats", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/GlobalStatEntry" } } } } } } } }, "/api/v0/main-frontend/glossary/{term_id}": { "put": { "tags": ["glossary"], "operationId": "updateGlossaryTerm", "parameters": [ { "name": "term_id", "in": "path", "description": "Glossary term id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TermUpdate" } } }, "required": true }, "responses": { "200": { "description": "Glossary term updated" }, "401": { "description": "Authentication required" }, "403": { "description": "User is not allowed to manage glossary terms" } } }, "delete": { "tags": ["glossary"], "operationId": "deleteGlossaryTerm", "parameters": [ { "name": "term_id", "in": "path", "description": "Glossary term id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Glossary term deleted" }, "401": { "description": "Authentication required" }, "403": { "description": "User is not allowed to manage glossary terms" } } } }, "/api/v0/main-frontend/oauth/.well-known/openid-configuration": { "get": { "tags": ["oauth"], "summary": "Handles `/.well-known/openid-configuration` to expose OIDC discovery metadata.", "description": "This endpoint advertises the AS/OP capabilities so clients can auto-configure:\n- Endpoints (authorize, token, userinfo, jwks)\n- Supported response/grant types\n- Token endpoint auth methods\n- ID Token signing algs\n- PKCE and DPoP metadata\n\nFollows:\n- [OIDC Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html)\n- [RFC 8414 — OAuth 2.0 Authorization Server Metadata](https://www.rfc-editor.org/rfc/rfc8414)\n- [RFC 9449 — DPoP metadata](https://www.rfc-editor.org/rfc/rfc9449#name-authorization-server-metadata)\n\n# Example\n```http\nGET /api/v0/main-frontend/oauth/.well-known/openid-configuration HTTP/1.1\n```\n\nExample response (truncated):\n```json\n{\n \"issuer\": \"https://example.org/api/v0/main-frontend/oauth\",\n \"authorization_endpoint\": \"https://example.org/api/v0/main-frontend/oauth/authorize\",\n \"token_endpoint\": \"https://example.org/api/v0/main-frontend/oauth/token\",\n \"userinfo_endpoint\": \"https://example.org/api/v0/main-frontend/oauth/userinfo\",\n \"jwks_uri\": \"https://example.org/api/v0/main-frontend/oauth/jwks.json\",\n \"response_types_supported\": [\"code\"],\n \"grant_types_supported\": [\"authorization_code\",\"refresh_token\"],\n \"code_challenge_methods_supported\": [\"S256\"],\n \"token_endpoint_auth_methods_supported\": [\"none\",\"client_secret_post\"],\n \"id_token_signing_alg_values_supported\": [\"RS256\"],\n \"subject_types_supported\": [\"public\"],\n \"dpop_signing_alg_values_supported\": [\"ES256\",\"RS256\"]\n}\n```", "operationId": "getOauthOpenidConfiguration", "responses": { "200": { "description": "OAuth/OpenID Connect discovery document", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/oauth/authorize": { "get": { "tags": ["oauth"], "operationId": "authorizeOauthGet", "parameters": [ { "name": "response_type", "in": "query", "description": "OAuth response type", "required": false, "schema": { "type": "string" } }, { "name": "client_id", "in": "query", "description": "OAuth client id", "required": false, "schema": { "type": "string" } }, { "name": "redirect_uri", "in": "query", "description": "Redirect URI", "required": false, "schema": { "type": "string" } }, { "name": "scope", "in": "query", "description": "Requested scopes", "required": false, "schema": { "type": "string" } }, { "name": "state", "in": "query", "description": "OAuth state", "required": false, "schema": { "type": "string" } }, { "name": "nonce", "in": "query", "description": "OpenID Connect nonce", "required": false, "schema": { "type": "string" } }, { "name": "code_challenge", "in": "query", "description": "PKCE code challenge", "required": false, "schema": { "type": "string" } }, { "name": "code_challenge_method", "in": "query", "description": "PKCE code challenge method", "required": false, "schema": { "type": "string" } }, { "name": "prompt", "in": "query", "description": "Prompt behavior", "required": false, "schema": { "type": "string" } }, { "name": "request", "in": "query", "description": "Unsupported request object", "required": false, "schema": { "type": "string" } } ], "responses": { "302": { "description": "Redirect to login, consent, or client redirect URI" } } }, "post": { "tags": ["oauth"], "operationId": "authorizeOauthPost", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": {} } }, "required": true }, "responses": { "302": { "description": "Redirect to login, consent, or client redirect URI" } } } }, "/api/v0/main-frontend/oauth/authorized-clients": { "get": { "tags": ["oauth"], "operationId": "getOauthAuthorizedClients", "responses": { "200": { "description": "Authorized OAuth clients", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AuthorizedClientInfo" } } } } } } } }, "/api/v0/main-frontend/oauth/authorized-clients/{client_id}": { "delete": { "tags": ["oauth"], "operationId": "deleteOauthAuthorizedClient", "parameters": [ { "name": "client_id", "in": "path", "description": "OAuth client id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "204": { "description": "Authorized client revoked" } } } }, "/api/v0/main-frontend/oauth/consent": { "post": { "tags": ["oauth"], "summary": "Handles `/consent` approval after the user agrees to grant requested scopes.", "description": "This endpoint:\n- Validates the redirect URI and requested scopes against the registered client.\n- Records granted scopes for the user-client pair.\n- Redirects back to `/authorize` to continue the OAuth flow.\n\n# Example\n```http\nGET /api/v0/main-frontend/oauth/consent?client_id=test-client-id&redirect_uri=http://localhost&scopes=openid%20profile&state=random123&nonce=secure_nonce_abc HTTP/1.1\nCookie: session=abc123\n\n```\n\nRedirect back to `/authorize`:\n```http\nHTTP/1.1 302 Found\nLocation: /api/v0/main-frontend/oauth/authorize?client_id=...\n```", "operationId": "approveOauthConsent", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConsentQuery" } } }, "required": true }, "responses": { "200": { "description": "Consent approval response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConsentResponse" } } } } } } }, "/api/v0/main-frontend/oauth/consent/deny": { "post": { "tags": ["oauth"], "summary": "Handles `/consent/deny` when the user refuses to grant scopes.", "description": "This endpoint:\n- Redirects back to the client with `error=access_denied`.\n\n# Example\n```http\nGET /api/v0/main-frontend/oauth/consent/deny?redirect_uri=http://localhost&state=random123 HTTP/1.1\n\n```\n\nResponse:\n```http\nHTTP/1.1 302 Found\nLocation: http://localhost?error=access_denied&state=random123\n```", "operationId": "denyOauthConsent", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConsentDenyQuery" } } }, "required": true }, "responses": { "200": { "description": "Consent denial response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConsentResponse" } } } } } } }, "/api/v0/main-frontend/oauth/introspect": { "post": { "tags": ["oauth"], "summary": "Handles the `/introspect` endpoint for OAuth 2.0 token introspection (RFC 7662).", "description": "This endpoint allows resource servers to query the authorization server about\nthe active state and metadata of an access token.\n\n### Security Features\n- Client authentication is required (client_id and client_secret for confidential clients)\n- Returns `active: false` for invalid/expired tokens or authentication failures\n to prevent token enumeration attacks\n- Always returns 200 OK, even for invalid tokens (per RFC 7662)\n\n### Request Parameters\n- `token` (required): The token to be introspected\n- `token_type_hint` (optional): Hint about token type (\"access_token\" or \"refresh_token\")\n- `client_id` (required): Client identifier\n- `client_secret` (required for confidential clients): Client secret\n\n### Response\nReturns a JSON object with:\n- `active` (bool, required): Whether the token is active\n- Additional fields only present if `active: true`:\n - `scope`: Space-separated list of scopes\n - `client_id`: Client identifier\n - `username`/`sub`: User identifier (if token has user)\n - `exp`: Expiration timestamp (Unix time)\n - `iat`: Issued at timestamp (Unix time)\n - `aud`: Audience\n - `iss`: Issuer\n - `jti`: JWT ID\n - `token_type`: \"Bearer\" or \"DPoP\"\n\nFollows [RFC 7662 — OAuth 2.0 Token Introspection](https://datatracker.ietf.org/doc/html/rfc7662).\n\n# Example\n```http\nPOST /api/v0/main-frontend/oauth/introspect HTTP/1.1\nContent-Type: application/x-www-form-urlencoded\n\ntoken=ACCESS_TOKEN&client_id=test-client-id&client_secret=test-secret\n```\n\nSuccessful response:\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\nCache-Control: no-store\n\n{\n \"active\": true,\n \"scope\": \"openid profile email\",\n \"client_id\": \"test-client-id\",\n \"sub\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"username\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"exp\": 1735689600,\n \"iat\": 1735686000,\n \"iss\": \"https://example.com/api/v0/main-frontend/oauth\",\n \"jti\": \"123e4567-e89b-12d3-a456-426614174000\",\n \"token_type\": \"Bearer\"\n}\n```\n\nInactive token response:\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\nCache-Control: no-store\n\n{\n \"active\": false\n}\n```", "operationId": "introspectOauthToken", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": {} } }, "required": true }, "responses": { "200": { "description": "OAuth token introspection response", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/oauth/jwks.json": { "get": { "tags": ["oauth"], "summary": "Handles `/jwks.json` for returning the JSON Web Key Set (JWKS).", "description": "This endpoint:\n- Reads the configured ID Token signing public key (RS256).\n- Exposes it in JWKS format for clients to validate ID tokens.\n\nFollows [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517).\n\nNote: Currently exposes a single signing key. Key rotation (OIDC Core §10) is not implemented.\n\n# Example\n```http\nGET /api/v0/main-frontend/oauth/jwks.json HTTP/1.1\n```\n\nResponse:\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"keys\": [\n { \"kty\":\"RSA\",\"use\":\"sig\",\"alg\":\"RS256\",\"kid\":\"abc123\",\"n\":\"...\",\"e\":\"AQAB\" }\n ]\n}\n```", "operationId": "getOauthJwks", "responses": { "200": { "description": "OAuth JSON Web Key Set", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/oauth/revoke": { "post": { "tags": ["oauth"], "summary": "Handles the `/revoke` endpoint for OAuth 2.0 token revocation (RFC 7009).", "description": "This endpoint allows clients to revoke access tokens or refresh tokens.\n\n### Security Features\n- Client authentication is required (client_id and client_secret)\n- Always returns `200 OK` even for invalid/expired/already-revoked tokens\n to prevent token enumeration attacks\n- Validates that the token belongs to the authenticated client before revoking\n\n### Request Parameters\n- `token` (required): The token to be revoked\n- `token_type_hint` (optional): Hint about token type (\"access_token\" or \"refresh_token\")\n\nFollows [RFC 7009 — OAuth 2.0 Token Revocation](https://datatracker.ietf.org/doc/html/rfc7009).\n\n# Example\n```http\nPOST /api/v0/main-frontend/oauth/revoke HTTP/1.1\nContent-Type: application/x-www-form-urlencoded\n\ntoken=ACCESS_TOKEN_TO_REVOKE&token_type_hint=access_token&client_id=test-client-id&client_secret=test-secret\n```\n\nResponse (always 200 OK):\n```http\nHTTP/1.1 200 OK\n```", "operationId": "revokeOauthToken", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": {} } }, "required": true }, "responses": { "200": { "description": "OAuth token revocation acknowledged" } } } }, "/api/v0/main-frontend/oauth/token": { "post": { "tags": ["oauth"], "summary": "Handles the `/token` endpoint for exchanging authorization codes or refresh tokens.", "description": "This endpoint issues and rotates OAuth 2.0 and OpenID Connect tokens with support for\n**PKCE**, **DPoP sender-constrained tokens**, and **ID Token issuance**.\n\n### Authorization Code Grant\n- Validates client credentials (`client_id`, `client_secret`) or public client rules.\n- Verifies the authorization code, its redirect URI, PKCE binding (`code_verifier`), and expiration.\n- Optionally verifies a DPoP proof and binds the issued tokens to the DPoP JWK thumbprint (`dpop_jkt`).\n- Issues a new access token, refresh token, and (for OIDC requests) an ID token.\n\n### Refresh Token Grant\n- Validates the refresh token and client binding.\n- Verifies DPoP proof when applicable (must match the original `dpop_jkt`).\n- Rotates the refresh token (revokes the old one, inserts a new one linked to it).\n- Issues a new access token (and ID token if `openid` scope requested).\n\n### Security Features\n- **PKCE (RFC 7636)**: Enforced for public clients and optionally for confidential ones.\n- **DPoP (RFC 9449)**: Sender-constrains tokens to a JWK thumbprint.\n- **Refresh Token Rotation**: Prevents replay by revoking old RTs on use.\n- **OIDC ID Token**: Issued only if `openid` is in the granted scopes.\n\nFollows:\n- [RFC 6749 §3.2 — Token Endpoint](https://datatracker.ietf.org/doc/html/rfc6749#section-3.2)\n- [RFC 7636 — PKCE](https://datatracker.ietf.org/doc/html/rfc7636)\n- [RFC 9449 — DPoP](https://datatracker.ietf.org/doc/html/rfc9449)\n- [OIDC Core §3.1.3 — Token Endpoint](https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint)\n\n# Example\n```http\nPOST /api/v0/main-frontend/oauth/token HTTP/1.1\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=http://localhost&client_id=test-client-id&client_secret=test-secret&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\n```\n\nSuccessful response:\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"access_token\": \"2YotnFZFEjr1zCsicMWpAA\",\n \"refresh_token\": \"tGzv3JOkF0XG5Qx2TlKWIA\",\n \"id_token\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"token_type\": \"DPoP\",\n \"expires_in\": 3600\n}\n```\n\nExample error:\n```http\nHTTP/1.1 401 Unauthorized\nContent-Type: application/json\n\n{\n \"error\": \"invalid_client\",\n \"error_description\": \"invalid client secret\"\n}\n```\n\nExample DPoP error:\n```http\nHTTP/1.1 401 Unauthorized\nWWW-Authenticate: DPoP error=\"use_dpop_proof\", error_description=\"Missing DPoP header\"\n```", "operationId": "exchangeOauthToken", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": {} } }, "required": true }, "responses": { "200": { "description": "OAuth token response", "content": { "application/json": { "schema": {} } } }, "401": { "description": "OAuth token error" } } } }, "/api/v0/main-frontend/oauth/userinfo": { "get": { "tags": ["oauth"], "operationId": "getOauthUserInfo", "responses": { "200": { "description": "OAuth userinfo response", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Invalid token" } } }, "post": { "tags": ["oauth"], "operationId": "postOauthUserInfo", "responses": { "200": { "description": "OAuth userinfo response", "content": { "application/json": { "schema": {} } } }, "401": { "description": "Invalid token" } } } }, "/api/v0/main-frontend/org/{organization_slug}": { "get": { "tags": ["org"], "summary": "\nGET `/api/v0/main-frontend/org/:slug", "operationId": "getOrganizationBySlug", "parameters": [ { "name": "organization_slug", "in": "path", "description": "Organization slug", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Organization", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Organization" } } } } } } }, "/api/v0/main-frontend/organizations": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations` - Returns a list of all organizations.", "operationId": "getOrganizations", "responses": { "200": { "description": "Organizations", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Organization" } } } } } } }, "post": { "tags": ["organizations"], "summary": "POST `/api/v0/main-frontend/organizations`\nCreates a new organization with the given name, slug, and visibility status.", "description": "# Request body (JSON)\n{\n \"name\": \"Example Organization\",\n \"slug\": \"example-org\",\n \"hidden\": false\n}\n\n# Response\nReturns the created organization.\n\n# Permissions\nOnly users with the `Admin` role can access this endpoint.", "operationId": "createOrganization", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrganizationCreatePayload" } } }, "required": true }, "responses": { "200": { "description": "Created organization", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/organizations/{exam_id}/fetch_org_exam": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{exam_id}/fetch_org_exam", "operationId": "getOrganizationExamByExamId", "parameters": [ { "name": "exam_id", "in": "path", "description": "Exam id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization exam", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrgExam" } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{organization_id}` - Returns an organizations with id.", "operationId": "getOrganization", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Organization" } } } } } }, "put": { "tags": ["organizations"], "summary": "\nPUT `/api/v0/main-frontend/organizations/{organization_id}`\n\nUpdates an organization's name, hidden status, and slug.", "operationId": "updateOrganization", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrganizationUpdatePayload" } } }, "required": true }, "responses": { "200": { "description": "Organization updated" } } }, "patch": { "tags": ["organizations"], "operationId": "softDeleteOrganization", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization soft deleted" } } } }, "/api/v0/main-frontend/organizations/{organization_id}/course_exams": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{organization_id}/course_exams` - Returns an organizations exams in CourseExam form.", "operationId": "getOrganizationCourseExams", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization course exams", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CourseExam" } } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/courses": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{organization_id}/courses\"` - Returns a list of all courses in a organization.", "operationId": "getOrganizationCourses", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Organization courses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/courses/active": { "get": { "tags": ["organizations"], "operationId": "getOrganizationActiveCourses", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Active organization courses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/courses/active/count": { "get": { "tags": ["organizations"], "operationId": "getOrganizationActiveCourseCount", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Active organization course count", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCount" } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/courses/count": { "get": { "tags": ["organizations"], "operationId": "getOrganizationCourseCount", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization course count", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseCount" } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/courses/duplicatable": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{organization_id}/courses/duplicatable\"` - Returns a list of all courses in a organization that the current user has permission to duplicate.", "operationId": "getOrganizationDuplicatableCourses", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Duplicatable organization courses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } } } } } } } }, "/api/v0/main-frontend/organizations/{organization_id}/exams": { "post": { "tags": ["organizations"], "summary": "\nPOST `/api/v0/main-frontend/organizations/{organization_id}/exams` - Creates new exam for the organization.", "operationId": "createOrganizationExam", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewExam" } } }, "required": true }, "responses": { "200": { "description": "Organization exam created" } } } }, "/api/v0/main-frontend/organizations/{organization_id}/image": { "put": { "tags": ["organizations"], "summary": "\nPUT `/api/v0/main-frontend/organizations/:organizations_id/image` - Sets or updates the chapter image.\n\n# Example\n\nRequest:\n```http\nPUT /api/v0/main-frontend/organizations/d332f3d9-39a5-4a18-80f4-251727693c37/image HTTP/1.1\nContent-Type: multipart/form-data\n\nBINARY_DATA\n```", "operationId": "updateOrganizationImage", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "string", "format": "binary", "contentMediaType": "application/octet-stream" } } } } }, "required": true }, "responses": { "200": { "description": "Updated organization", "content": { "application/json": { "schema": {} } } } } }, "delete": { "tags": ["organizations"], "summary": "\nDELETE `/api/v0/main-frontend/organizations/:organizations_id/image` - Removes the organizations image.\n\n# Example\n\nRequest:\n```http\nDELETE /api/v0/main-frontend/organizations/d332f3d9-39a5-4a18-80f4-251727693c37/image HTTP/1.1\n```", "operationId": "deleteOrganizationImage", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization image removed" } } } }, "/api/v0/main-frontend/organizations/{organization_id}/org_exams": { "get": { "tags": ["organizations"], "summary": "\nGET `/api/v0/main-frontend/organizations/{organization_id}/exams` - Returns an organizations exams in Exam form.", "operationId": "getOrganizationExams", "parameters": [ { "name": "organization_id", "in": "path", "description": "Organization id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Organization exams", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/OrgExam" } } } } } } } }, "/api/v0/main-frontend/page_audio/{file_id}": { "delete": { "tags": ["page_audio"], "summary": "\nDELETE `/api/v0/main-frontend/page_audio/:file_id` - Removes the chapter image.\n\n# Example\n\nRequest:\n```http\nDELETE /api/v0/main-frontend/page_audio/d332f3d9-39a5-4a18-80f4-251727693c37 HTTP/1.1\n```", "operationId": "deletePageAudioFile", "parameters": [ { "name": "file_id", "in": "path", "description": "Page audio file id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Page audio deleted" } } } }, "/api/v0/main-frontend/page_audio/{page_id}": { "post": { "tags": ["page_audio"], "summary": "\nPOST `/api/v0/main-frontend/page_audio/:page_id` - Sets or updates the page audio.\n\n# Example\n\nRequest:\n```http\nPOST /api/v0/main-frontend/page_audio/d332f3d9-39a5-4a18-80f4-251727693c37 HTTP/1.1\nContent-Type: multipart/form-data\n\nBINARY_DATA\n```", "operationId": "createPageAudioFile", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 }, "contentMediaType": "application/octet-stream" } } } } }, "required": true }, "responses": { "200": { "description": "Page audio uploaded", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/page_audio/{page_id}/files": { "get": { "tags": ["page_audio"], "summary": "\nGET `/api/v0/main-fronted/page_audio/:page_id/files` - Get a page audio files\n\nRequest: `GET /api/v0/cms/page_audio/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02/files`", "operationId": "getPageAudioFiles", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Page audio files", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageAudioFile" } } } } } } } }, "/api/v0/main-frontend/pages": { "post": { "tags": ["pages"], "summary": "\nPOST `/api/v0/main-frontend/pages` - Create a new page.\n\nPlease note that this endpoint will change all the exercise and exercise task ids you've created. Make sure the use the updated ids from the response object.\n\nIf optional property front_page_of_chapter_id is set, this page will become the front page of the specified course part.\n\n# Example:\n\nRequest:\n```http\nPOST /api/v0/main-frontend/pages HTTP/1.1\nContent-Type: application/json\n\n{\n \"content\": [\n {\n \"type\": \"x\",\n \"id\": \"2a4e517d-a7d2-4d82-89fb-a1333d8d01d1\"\n }\n ],\n \"url_path\": \"/part-2/best-page\",\n \"title\": \"Hello world!\",\n \"course_id\": \"10363c5b-82b4-4121-8ef1-bae8fb42a5ce\",\n \"chapter_id\": \"2495ffa3-7ea9-4615-baa5-828023688c79\"\n}\n```", "operationId": "createPage", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewPage" } } }, "required": true }, "responses": { "200": { "description": "Created page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page" } } } } } } }, "/api/v0/main-frontend/pages/{course_id}/all-course-pages-for-course": { "get": { "tags": ["pages"], "summary": "\nGET `/api/v0/main-frontend/pages/:course_id/all-course-pages-for-course` - Get all pages of a course", "operationId": "getCoursePages", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course pages", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Page" } } } } } } } }, "/api/v0/main-frontend/pages/{page_id}": { "delete": { "tags": ["pages"], "summary": "\nDELETE `/api/v0/main-frontend/pages/:page_id` - Delete a page, related exercises, and related exercise tasks by id.\n\n\n# Example\n\nRequest: `DELETE /api/v0/main-frontend/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02`", "operationId": "deletePage", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page" } } } } } } }, "/api/v0/main-frontend/pages/{page_id}/history": { "get": { "tags": ["pages"], "summary": "\nGET /api/v0/main-frontend/pages/:page_id/history", "operationId": "getPageHistory", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Page history entries", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageHistory" } } } } } } } }, "/api/v0/main-frontend/pages/{page_id}/history_count": { "get": { "tags": ["pages"], "summary": "\nGET /api/v0/main-frontend/pages/:page_id/history_count", "operationId": "getPageHistoryCount", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Page history count", "content": { "text/plain": { "schema": { "type": "integer", "format": "int64" } } } } } } }, "/api/v0/main-frontend/pages/{page_id}/info": { "get": { "tags": ["pages"], "summary": "\nGET `/api/v0/main-fronted/pages/:page_id/info` - Get a pages's course id, course name, organization slug\n\nRequest: `GET /api/v0/cms/pages/40ca9bcf-8eaa-41ba-940e-0fd5dd0c3c02/info`", "operationId": "getPageInfo", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Page info", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PageInfo" } } } } } } }, "/api/v0/main-frontend/pages/{page_id}/page-details": { "put": { "tags": ["pages"], "summary": "\nPOST `/api/v0/main-frontend/pages/:page_id/page-details` - Update pages title and url_path.", "operationId": "updatePageDetails", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PageDetailsUpdate" } } }, "required": true }, "responses": { "200": { "description": "Updated page details", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/pages/{page_id}/restore": { "post": { "tags": ["pages"], "summary": "\nPOST /api/v0/main-frontend/pages/:page_id/restore", "operationId": "restorePageHistory", "parameters": [ { "name": "page_id", "in": "path", "description": "Page id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HistoryRestoreData" } } }, "required": true }, "responses": { "200": { "description": "Restored history id", "content": { "text/plain": { "schema": { "type": "string", "format": "uuid" } } } } } } }, "/api/v0/main-frontend/playground-views/grading/{websocket_id}": { "post": { "tags": ["playground-views"], "summary": "playground-views passes a URL pointing to this route to an exercise service when sending submissions so that if\nthe service has an update for a pending grading, it will be sent here and passed on to through the websocket", "operationId": "receivePlaygroundGrading", "parameters": [ { "name": "websocket_id", "in": "path", "description": "Playground websocket id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExerciseTaskGradingResult" } } }, "required": true }, "responses": { "200": { "description": "Grading forwarded to websocket client" } } } }, "/api/v0/main-frontend/playground-views/ws": { "get": { "tags": ["playground-views"], "summary": "Starts a new websocket connection.", "operationId": "getPlaygroundViewsWebsocket", "responses": { "101": { "description": "WebSocket connection upgraded" } } } }, "/api/v0/main-frontend/playground_examples": { "get": { "tags": ["playground-examples"], "summary": "\nGET `/api/v0/main-frontend/playground_examples` - Returns all playground examples that are not deleted.", "operationId": "getPlaygroundExamples", "responses": { "200": { "description": "Playground examples", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PlaygroundExample" } } } } } } }, "put": { "tags": ["playground-examples"], "summary": "\nPUT `/api/v0/main-frontend/playground_examples` - Updates existing playground example.", "operationId": "updatePlaygroundExample", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlaygroundExample" } } }, "required": true }, "responses": { "200": { "description": "Updated playground example", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlaygroundExample" } } } } } }, "post": { "tags": ["playground-examples"], "summary": "\nPOST `/api/v0/main-frontend/playground_examples` - Saves a playground example.", "operationId": "createPlaygroundExample", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlaygroundExampleData" } } }, "required": true }, "responses": { "200": { "description": "Created playground example", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlaygroundExample" } } } } } } }, "/api/v0/main-frontend/playground_examples/{playground_example_id}": { "delete": { "tags": ["playground-examples"], "summary": "\nDELETE `/api/v0/main-frontend/playground_examples` - Deletes a playground example if exists.", "operationId": "deletePlaygroundExample", "parameters": [ { "name": "playground_example_id", "in": "path", "description": "Playground example id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Deleted playground example", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlaygroundExample" } } } } } } }, "/api/v0/main-frontend/proposed-edits/course/{course_id}": { "get": { "tags": ["proposed_edits"], "summary": "\nGET `/api/v0/main-frontend/proposed-edits/course/:id?pending=true` - Returns feedback for the given course.", "operationId": "getEditProposals", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "pending", "in": "query", "description": "Whether to fetch pending proposals", "required": true, "schema": { "type": "boolean" } }, { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Edit proposals", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PageProposal" } } } } } } } }, "/api/v0/main-frontend/proposed-edits/course/{course_id}/count": { "get": { "tags": ["proposed_edits"], "summary": "\nGET `/api/v0/main-frontend/proposed-edits/course/:id/count` - Returns the amount of feedback for the given course.", "operationId": "getEditProposalCount", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Edit proposal counts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProposalCount" } } } } } } }, "/api/v0/main-frontend/proposed-edits/process-edit-proposal": { "post": { "tags": ["proposed_edits"], "summary": "\nPOST `/api/v0/main-frontend/proposed-edits/process-edit-proposal` - Processes the given edit proposal.", "operationId": "processEditProposal", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EditProposalInfo" } } }, "required": true }, "responses": { "200": { "description": "Processed edit proposal" } } } }, "/api/v0/main-frontend/regradings": { "get": { "tags": ["regradings"], "summary": "\nGET `/api/v0/main-frontend/regradings` - Returns a paginated list of all the regradings.", "operationId": "getRegradings", "parameters": [ { "name": "page", "in": "query", "description": "Page number", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "limit", "in": "query", "description": "Page size", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "Regradings", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Regrading" } } } } } } }, "post": { "tags": ["regradings"], "summary": "\nPOST `/api/v0/main-frontend/regradings` - Creates a new regrading for the supplied exercise task submission ids and returns the new regrading id.", "operationId": "createRegrading", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewRegrading" } } }, "required": true }, "responses": { "200": { "description": "Created regrading id", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/regradings/count": { "get": { "tags": ["regradings"], "summary": "\nGET `/api/v0/main-frontend/regradings/count` - Counts regradings", "operationId": "getRegradingsCount", "responses": { "200": { "description": "Regradings count", "content": { "text/plain": { "schema": { "type": "integer", "format": "int64" } } } } } } }, "/api/v0/main-frontend/regradings/{regrading_id}": { "get": { "tags": ["regradings"], "summary": "\nGET `/api/v0/main-frontend/regradings/{id}` - Returns relevant information about a regrading.", "operationId": "getRegradingInfo", "parameters": [ { "name": "regrading_id", "in": "path", "description": "Regrading id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Regrading info", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RegradingInfo" } } } } } } }, "/api/v0/main-frontend/roles": { "get": { "tags": ["roles"], "summary": "\n * GET /api/v0/main-frontend/roles - Get all roles for the given domain.", "operationId": "getRoles", "parameters": [ { "name": "global", "in": "query", "description": "Global domain", "required": false, "schema": { "type": "boolean" } }, { "name": "organization_id", "in": "query", "description": "Organization id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_id", "in": "query", "description": "Course id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_instance_id", "in": "query", "description": "Course instance id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "exam_id", "in": "query", "description": "Exam id", "required": false, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Roles", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RoleUser" } } } } } } } }, "/api/v0/main-frontend/roles/add": { "post": { "tags": ["roles"], "summary": "\n * POST /api/v0/main-frontend/roles/add - Give a role to a user.", "operationId": "addRole", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RoleInfo" } } }, "required": true }, "responses": { "200": { "description": "Role added" } } } }, "/api/v0/main-frontend/roles/pending": { "get": { "tags": ["roles"], "summary": "\n * GET /api/v0/main-frontend/roles - Get all pending roles for the given domain.", "operationId": "getPendingRoles", "parameters": [ { "name": "global", "in": "query", "description": "Global domain", "required": false, "schema": { "type": "boolean" } }, { "name": "organization_id", "in": "query", "description": "Organization id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_id", "in": "query", "description": "Course id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_instance_id", "in": "query", "description": "Course instance id", "required": false, "schema": { "type": "string", "format": "uuid" } }, { "name": "exam_id", "in": "query", "description": "Exam id", "required": false, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Pending roles", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PendingRole" } } } } } } } }, "/api/v0/main-frontend/roles/remove": { "post": { "tags": ["roles"], "summary": "\n * POST /api/v0/main-frontend/roles/remove - Remove a role from a user.", "operationId": "removeRole", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RoleInfo" } } }, "required": true }, "responses": { "200": { "description": "Role removed" } } } }, "/api/v0/main-frontend/status/cronjobs": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/cronjobs`\n\nReturns the status of all CronJobs in the current namespace.", "operationId": "getStatusCronjobs", "responses": { "200": { "description": "Cronjobs", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CronJobInfo" } } } } } } } }, "/api/v0/main-frontend/status/deployments": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/deployments`\n\nReturns the status of all Deployments in the current namespace.", "operationId": "getStatusDeployments", "responses": { "200": { "description": "Deployments", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DeploymentInfo" } } } } } } } }, "/api/v0/main-frontend/status/events": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/events`\n\nReturns the status of all Events in the current namespace.", "operationId": "getStatusEvents", "responses": { "200": { "description": "Events", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/EventInfo" } } } } } } } }, "/api/v0/main-frontend/status/health": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/health`\n\nReturns detailed system health status with issues list (admin only).", "operationId": "getStatusHealth", "responses": { "200": { "description": "Detailed system health", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SystemHealthStatus" } } } } } } }, "/api/v0/main-frontend/status/ingresses": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/ingresses`\n\nReturns the status of all Ingresses in the current namespace.", "operationId": "getStatusIngresses", "responses": { "200": { "description": "Ingresses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/IngressInfo" } } } } } } } }, "/api/v0/main-frontend/status/jobs": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/jobs`\n\nReturns the status of all Jobs in the current namespace.", "operationId": "getStatusJobs", "responses": { "200": { "description": "Jobs", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/JobInfo" } } } } } } } }, "/api/v0/main-frontend/status/pod-disruption-budgets": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/pod-disruption-budgets`\n\nReturns the status of all PodDisruptionBudgets in the current namespace.", "operationId": "getStatusPodDisruptionBudgets", "responses": { "200": { "description": "Pod disruption budgets", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PodDisruptionBudgetInfo" } } } } } } } }, "/api/v0/main-frontend/status/pods": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/pods`\n\nReturns the status of all Pods in the current namespace.", "operationId": "getStatusPods", "responses": { "200": { "description": "Pods", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PodInfo" } } } } } } } }, "/api/v0/main-frontend/status/pods/{pod_name}/logs": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/pods/{pod_name}/logs`\n\nReturns logs from a specific pod.\n\nQuery parameters:\n- container: Optional - Container name (if pod has multiple containers)\n- tail: Optional - Number of lines to tail from the end (default: 1000, max: 10000)", "operationId": "getStatusPodLogs", "parameters": [ { "name": "pod_name", "in": "path", "description": "Pod name", "required": true, "schema": { "type": "string" } }, { "name": "container", "in": "query", "description": "Container name", "required": false, "schema": { "type": "string" } }, { "name": "tail", "in": "query", "description": "Number of log lines", "required": false, "schema": { "type": "integer", "format": "int64", "minimum": 0 } } ], "responses": { "200": { "description": "Pod logs", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/status/services": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/services`\n\nReturns the status of all Services in the current namespace.", "operationId": "getStatusServices", "responses": { "200": { "description": "Services", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ServiceInfo" } } } } } } } }, "/api/v0/main-frontend/status/system-health": { "get": { "tags": ["status"], "summary": "\nGET `/api/v0/main-frontend/status/system-health` Returns a boolean indicating whether the system is healthy.\n\nUses the same underlying checking logic as the detailed health endpoint.\nUnauthenticated users get a boolean. Authenticated admins get error details on failure.", "operationId": "getStatusSystemHealth", "responses": { "200": { "description": "System health", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/teacher-grading-decisions": { "post": { "tags": ["teacher_grading_decisions"], "summary": "\nPOST `/api/v0/main-frontend/teacher-grading-decisions` - Creates a new teacher grading decision, overriding the points a user has received from an exercise.", "operationId": "createTeacherGradingDecision", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewTeacherGradingDecision" } } }, "required": true }, "responses": { "200": { "description": "Teacher grading decision created", "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/UserExerciseState" } ] } } } } } } }, "/api/v0/main-frontend/time": { "get": { "tags": ["time"], "summary": "\nGET `/api/v0/main-frontend/time` Returns the server's current UTC time as an RFC3339 timestamp string.\n\nResponse body example:\n`\"2026-02-18T12:34:56.789Z\"`", "operationId": "getCurrentTime", "responses": { "200": { "description": "Current server time", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/user-details/bulk-user-details": { "post": { "tags": ["user-details"], "summary": "\nPOST `/api/v0/main-frontend/user-details/bulk-user-details` - Get user details for a list of user IDs with course permission check\nOnly returns user details for users who are actually enrolled in the specified course", "operationId": "getBulkUserDetails", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkUserDetailsRequest" } } }, "required": true }, "responses": { "200": { "description": "Bulk user details", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } } } } } }, "/api/v0/main-frontend/user-details/search-by-email": { "post": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/search-by-email` - Allows to search user by their email", "operationId": "searchUserDetailsByEmail", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": true }, "responses": { "200": { "description": "User details search results", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } } } } } }, "/api/v0/main-frontend/user-details/search-by-other-details": { "post": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/search-by-other-details` - Allows to search user by their names etc.", "operationId": "searchUserDetailsByOtherDetails", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": true }, "responses": { "200": { "description": "User details search results", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } } } } } }, "/api/v0/main-frontend/user-details/search-fuzzy-match": { "post": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/search-fuzzy-match` - Allows to find the right user details in cases where there is a small typing error in the search query", "operationId": "searchUserDetailsFuzzyMatch", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": true }, "responses": { "200": { "description": "User details fuzzy search results", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } } } } } }, "/api/v0/main-frontend/user-details/update-user-info": { "post": { "tags": ["user-details"], "summary": "\nPOST `/api/v0/main-frontend/user-details/update-user-info` - Updates the users information such as email, name, country and email communication consent", "operationId": "updateUserInfo", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserInfoPayload" } } }, "required": true }, "responses": { "200": { "description": "Updated user details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetail" } } } } } } }, "/api/v0/main-frontend/user-details/user-by-courses": { "post": { "tags": ["user-details"], "summary": "\nPOST `/api/v0/main-frontend/user-details/user-by-courses` - Find user details by user id with multi-course permission check\nReturns user details if the user has permission to view user details through any of the specified courses", "operationId": "getUserDetailsByCourses", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetailsRequest" } } }, "required": true }, "responses": { "200": { "description": "User details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetail" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": {} } } }, "404": { "description": "User details not found", "content": { "application/json": { "schema": {} } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": {} } } } } } }, "/api/v0/main-frontend/user-details/user-details-for-user": { "get": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/user-details-for-user` - Get authenticated user's own details", "operationId": "getUserDetailsForAuthenticatedUser", "responses": { "200": { "description": "Authenticated user details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetail" } } } } } } }, "/api/v0/main-frontend/user-details/users-ip-country": { "get": { "tags": ["user-details"], "operationId": "getUsersIpCountry", "responses": { "200": { "description": "Country inferred from request IP", "content": { "text/plain": { "schema": { "type": "string" } } } } } } }, "/api/v0/main-frontend/user-details/{course_id}/get-users-by-course-id": { "get": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/get-users-by-course-id` - Get user details of users that are in the course", "operationId": "getUsersByCourseIdForUserDetails", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Users by course id", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } } } } } }, "/api/v0/main-frontend/user-details/{course_id}/user/{user_id}": { "get": { "tags": ["user-details"], "summary": "\nGET `/api/v0/main-frontend/user-details/{course_id}/user/{user_id}` - Find user details by user id with course permission check\nOnly returns user details if the user is enrolled in the specified course", "operationId": "getUserDetailsByCourseAndUserId", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetail" } } } } } } }, "/api/v0/main-frontend/users/change-password": { "post": { "tags": ["users"], "operationId": "changeUserPassword", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangePasswordData" } } }, "required": true }, "responses": { "200": { "description": "Password change status", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/users/get-user-research-consent": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/get-user-research-consent` - Gets users research consent.", "operationId": "getUserResearchConsent", "responses": { "200": { "description": "User research consent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserResearchConsent" } } } } } } }, "/api/v0/main-frontend/users/my-courses": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/my-courses` - Gets all the courses the user has either started or gotten a permission to.", "operationId": "getMyCourses", "responses": { "200": { "description": "Courses for authenticated user", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/MyCourse" } } } } } } } }, "/api/v0/main-frontend/users/my-courses/{course_id}/hide": { "post": { "tags": ["users"], "summary": "\nPOST `/api/v0/main-frontend/users/my-courses/:course_id/hide` - Hides a course from the\nauthenticated user's \"My courses\" list.", "operationId": "hideCourseFromMyCourses", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course hidden from the user's my-courses list" } } } }, "/api/v0/main-frontend/users/my-courses/{course_id}/unhide": { "post": { "tags": ["users"], "summary": "\nPOST `/api/v0/main-frontend/users/my-courses/:course_id/unhide` - Puts a previously hidden course\nback into the authenticated user's \"My courses\" list.", "operationId": "unhideCourseFromMyCourses", "parameters": [ { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "Course restored to the user's my-courses list" } } } }, "/api/v0/main-frontend/users/my-studies": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/my-studies` - The authenticated user's own study record: every\ncourse they are enrolled in, its modules, and their completions.\n\nNo user id parameter, so it cannot be pointed at another account. The teacher/admin equivalent is\n`getUserCourseEnrollments`.", "operationId": "getMyStudies", "responses": { "200": { "description": "The authenticated user's study record", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MyStudies" } } } } } } }, "/api/v0/main-frontend/users/reset-password": { "post": { "tags": ["users"], "operationId": "resetUserPassword", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResetPasswordData" } } }, "required": true }, "responses": { "200": { "description": "Password reset status", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/users/reset-password-token-status": { "post": { "tags": ["users"], "operationId": "getResetPasswordTokenStatus", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResetPasswordTokenPayload" } } }, "required": true }, "responses": { "200": { "description": "Reset password token validity", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/users/send-reset-password-email": { "post": { "tags": ["users"], "operationId": "sendResetPasswordEmail", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailData" } } }, "required": true }, "responses": { "200": { "description": "Reset password email accepted", "content": { "text/plain": { "schema": { "type": "boolean" } } } } } } }, "/api/v0/main-frontend/users/user-research-consents": { "post": { "tags": ["users"], "summary": "\nPOST `/api/v0/main-frontend/users/user-research-consents` - Adds a research consent for a student.", "operationId": "createUserResearchConsent", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConsentData" } } }, "required": true }, "responses": { "200": { "description": "User research consent", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserResearchConsent" } } } } } } }, "/api/v0/main-frontend/users/user-research-form-question-answers": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/get-user-research-consents` - Gets all users research consents for a course specific research form.", "operationId": "getUserResearchFormQuestionAnswers", "responses": { "200": { "description": "Research form answers for user", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ResearchFormQuestionAnswer" } } } } } } } }, "/api/v0/main-frontend/users/{user_id}": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id`", "operationId": "getUser", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } } }, "/api/v0/main-frontend/users/{user_id}/course-enrollments": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id/course-enrollments`", "operationId": "getUserCourseEnrollments", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User course enrollments", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CourseEnrollmentsInfo" } } } } } } }, "/api/v0/main-frontend/users/{user_id}/courses/{course_id}/submission-times": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id/courses/:course_id/submission-times` - A user's exercise\nsubmission times in a course, each tagged with its exercise and module. Teacher/admin (global) view.", "operationId": "getUserCourseSubmissionTimes", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "course_id", "in": "path", "description": "Course id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User course submission times", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserCourseSubmissionTime" } } } } } } } }, "/api/v0/main-frontend/users/{user_id}/roles": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id/roles` - All roles held by a user, across scopes. Teacher/admin\n(global) view; used to label the account (e.g. staff/teacher) on the user-details page.", "operationId": "getUserRoles", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User roles across scopes", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Role" } } } } } } } }, "/api/v0/main-frontend/users/{user_id}/suspected-cheaters": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id/suspected-cheaters` - Cross-course suspected-cheater records for\na user, each paired with the course's applicable duration threshold. Teacher/admin (global) view;\nread-only (confirm/dismiss happen on the per-course cheaters page).", "operationId": "getUserSuspectedCheaters", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User suspected-cheater records across courses", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserSuspectedCheaterInfo" } } } } } } } }, "/api/v0/main-frontend/users/{user_id}/user-reset-exercise-logs": { "get": { "tags": ["users"], "summary": "\nGET `/api/v0/main-frontend/users/:id/user-reset-exercise-logs` - Get all logs of reset exercises for a user", "operationId": "getUserResetExerciseLogs", "parameters": [ { "name": "user_id", "in": "path", "description": "User id", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "responses": { "200": { "description": "User reset exercise logs", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseResetLog" } } } } } } } } }, "components": { "schemas": { "AccountLinkingFailureDomain": { "type": "object", "description": "Hard send failures grouped by recipient domain.", "required": ["domain", "count"], "properties": { "count": { "type": "integer", "format": "int64" }, "domain": { "type": "string" } } }, "AccountLinkingFunnel": { "type": "object", "description": "The account-linking funnel. The `_last_run` steps come from counters the discovery phase overwrites\nwhole, the `_in_window` ones from the window: there is no single denominator.", "required": [ "persons_discovered_last_run", "already_linked_last_run", "mails_claimed_in_window", "mails_sent_in_window", "numbers_claimed_in_window", "manual_links_in_window", "suppressed_by_dedup_last_run", "suppressed_by_rate_cap_last_run", "no_address_in_study_registry_last_run" ], "properties": { "already_linked_last_run": { "type": "integer", "format": "int64" }, "mails_claimed_in_window": { "type": "integer", "format": "int64" }, "mails_sent_in_window": { "type": "integer", "format": "int64" }, "manual_links_in_window": { "type": "integer", "format": "int64", "description": "Never folded into the claimed count: an admin's judgement is not a claim." }, "no_address_in_study_registry_last_run": { "type": "integer", "format": "int64" }, "numbers_claimed_in_window": { "type": "integer", "format": "int64" }, "persons_discovered_last_run": { "type": "integer", "format": "int64" }, "suppressed_by_dedup_last_run": { "type": "integer", "format": "int64" }, "suppressed_by_rate_cap_last_run": { "type": "integer", "format": "int64" } } }, "AccountLinkingRealisationCounters": { "type": "object", "required": [ "course_id", "course_name", "course_module_id", "course_unit_realisation_id", "consecutive_listing_failures" ], "properties": { "already_linked_count": { "type": ["integer", "null"], "format": "int32" }, "consecutive_listing_failures": { "type": "integer", "format": "int32" }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "course_name": { "type": "string" }, "course_unit_realisation_id": { "type": "string" }, "label": { "type": ["string", "null"] }, "last_listed_at": { "type": ["string", "null"], "format": "date-time", "description": "When the counters below were collected. Not the last attempt: a failing realisation keeps the\nlast roster that arrived." }, "last_listing_attempted_at": { "type": ["string", "null"], "format": "date-time" }, "last_listing_error": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode", "description": "Set while the listing attempts since `last_listed_at` are failing, so an empty course and an\nunreachable one do not read alike." } ] }, "listed_person_count": { "type": ["integer", "null"], "format": "int32" }, "mailed_count": { "type": ["integer", "null"], "format": "int32" }, "no_address_count": { "type": ["integer", "null"], "format": "int32", "description": "Persons the registry holds no address for: the one population no remedy here can reach." }, "suppressed_by_dedup_count": { "type": ["integer", "null"], "format": "int32" }, "suppressed_by_rate_cap_count": { "type": ["integer", "null"], "format": "int32" }, "uh_course_code": { "type": ["string", "null"] } } }, "AccountLinkingSendStatusTotals": { "type": "object", "required": ["queued", "retrying", "sent", "send_failed"], "properties": { "queued": { "type": "integer", "format": "int64" }, "retrying": { "type": "integer", "format": "int64" }, "send_failed": { "type": "integer", "format": "int64" }, "sent": { "type": "integer", "format": "int64" } } }, "AccountLinkingStaleAddress": { "type": "object", "description": "A person mailed to the cap for one course whose number was never claimed.", "required": [ "student_number", "sisu_person_id", "course_id", "course_name", "mail_count", "first_sent_at", "last_sent_at", "addresses", "send_statuses" ], "properties": { "addresses": { "type": "array", "items": { "type": "string" }, "description": "In full, newest last, one per mail." }, "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "first_sent_at": { "type": "string", "format": "date-time" }, "last_sent_at": { "type": "string", "format": "date-time" }, "mail_count": { "type": "integer", "format": "int64" }, "send_statuses": { "type": "array", "items": { "$ref": "#/components/schemas/EmailSendStatus" } }, "sisu_person_id": { "type": "string" }, "student_number": { "type": "string" } } }, "AccountLinkingStats": { "type": "object", "required": [ "window_secs", "funnel", "send_status_totals", "hard_failure_domains", "realisations", "stale_addresses", "links_total_by_method", "links_in_window_by_method", "waiting_for_student_number_count", "max_mails_per_person_and_course", "quiet_period_secs" ], "properties": { "funnel": { "$ref": "#/components/schemas/AccountLinkingFunnel" }, "hard_failure_domains": { "type": "array", "items": { "$ref": "#/components/schemas/AccountLinkingFailureDomain" } }, "links_in_window_by_method": { "type": "array", "items": { "$ref": "#/components/schemas/VerifiedStudentNumberMethodTotal" } }, "links_total_by_method": { "type": "array", "items": { "$ref": "#/components/schemas/VerifiedStudentNumberMethodTotal" } }, "max_mails_per_person_and_course": { "type": "integer", "format": "int64" }, "quiet_period_secs": { "type": "integer", "format": "int64" }, "realisations": { "type": "array", "items": { "$ref": "#/components/schemas/AccountLinkingRealisationCounters" } }, "send_status_totals": { "$ref": "#/components/schemas/AccountLinkingSendStatusTotals" }, "stale_addresses": { "type": "array", "items": { "$ref": "#/components/schemas/AccountLinkingStaleAddress" } }, "waiting_for_student_number_count": { "type": "integer", "format": "int64", "description": "Accounts with a consented completion still waiting for a number." }, "window_secs": { "type": "integer", "format": "int64" } } }, "ActivityProgress": { "type": "string", "description": "\nIndicates what is the user's completion status for a exercise.\n\nAs close as possible to LTI's activity progress for compatibility: .", "enum": ["Initialized", "Started", "InProgress", "Submitted", "Completed"] }, "AddPlanMemberRequest": { "type": "object", "required": ["email"], "properties": { "email": { "type": "string", "format": "email" } } }, "AdminCreditRegistrationDetails": { "type": "object", "required": [ "registration", "attempts", "events", "suotar_api_calls", "actions", "linking_emails" ], "properties": { "actions": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationAdminActionRecord" }, "description": "Admin and teacher actions targeting this row." }, "attempts": { "type": "array", "items": { "$ref": "#/components/schemas/AdminCreditRegistrationRow" }, "description": "Every attempt for the same completion, newest first, this one included." }, "consent_given": { "type": ["boolean", "null"] }, "consent_withdrawn_at": { "type": ["string", "null"], "format": "date-time" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/AdminCreditRegistrationEvent" } }, "linking_emails": { "type": "array", "items": { "$ref": "#/components/schemas/AdminLinkingEmail" }, "description": "Every mail addressed to this person, on any course." }, "registration": { "$ref": "#/components/schemas/AdminCreditRegistrationRow" }, "suotar_api_calls": { "type": "array", "items": { "$ref": "#/components/schemas/AdminSuotarApiCall" }, "description": "The calls the timeline refers to, newest first." } } }, "AdminCreditRegistrationEvent": { "type": "object", "required": ["id", "created_at", "kind"], "properties": { "actor_user_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "details": { "description": "The `{request, response}` pair, scrubbed at write time: names, student numbers and email\naddresses read `[redacted]` while their keys survive. The values we sent are on the row." }, "error_code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "from_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] }, "id": { "type": "string", "format": "uuid" }, "kind": { "$ref": "#/components/schemas/CreditRegistrationEventKind" }, "message": { "type": ["string", "null"], "description": "Our own wording, written by the pipeline or by whoever acted." }, "suotar_api_call_id": { "type": ["string", "null"], "format": "uuid" }, "to_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] } } }, "AdminCreditRegistrationRow": { "type": "object", "required": [ "id", "created_at", "user_id", "course_id", "course_name", "course_module_id", "course_instance_id", "course_module_completion_id", "completion_date", "state", "state_entered_at", "needs_admin_attention", "next_attempt_at", "request_item_id", "submit_retry_count", "verify_attempt_count", "attempt_number", "superseded" ], "properties": { "attempt_number": { "type": "integer", "format": "int32" }, "completion_date": { "type": "string", "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "course_instance_id": { "type": "string", "format": "uuid" }, "course_module_completion_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "course_name": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "credits": { "type": ["number", "null"], "format": "float" }, "email": { "type": ["string", "null"], "description": "In full: masking it would leave support unable to answer the question they were asked." }, "error_code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "first_name": { "type": ["string", "null"] }, "grade_id": { "type": ["string", "null"] }, "grade_scale_id": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "last_attempt_at": { "type": ["string", "null"], "format": "date-time" }, "last_name": { "type": ["string", "null"] }, "needs_admin_attention": { "type": "boolean" }, "next_attempt_at": { "type": "string", "format": "date-time" }, "registered_at": { "type": ["string", "null"], "format": "date-time" }, "request_item_id": { "type": "string" }, "selected_enrolment_id": { "type": ["string", "null"] }, "sisu_attainment_id": { "type": ["string", "null"] }, "sisu_person_id": { "type": ["string", "null"] }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" }, "state_entered_at": { "type": "string", "format": "date-time" }, "student_number": { "type": ["string", "null"], "description": "Frozen on the row before it was sent, so it is what we actually submitted." }, "submit_retry_count": { "type": "integer", "format": "int32" }, "submitted_at": { "type": ["string", "null"], "format": "date-time" }, "submitted_attainment_id": { "type": ["string", "null"] }, "superseded": { "type": "boolean" }, "superseded_by_id": { "type": ["string", "null"], "format": "uuid" }, "terminal_at": { "type": ["string", "null"], "format": "date-time" }, "uh_course_code": { "type": ["string", "null"] }, "user_id": { "type": "string", "format": "uuid" }, "verified_student_number": { "type": ["string", "null"], "description": "The account's link now, which is not always the number frozen on the row." }, "verified_student_number_at": { "type": ["string", "null"], "format": "date-time" }, "verified_student_number_via": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/StudentNumberVerificationMethod", "description": "`admin_manual` means support established the link rather than the student proving it." } ] }, "verify_attempt_count": { "type": "integer", "format": "int32" } } }, "AdminCreditRegistrationTransitionTarget": { "type": "string", "description": "What an admin may move a row to; everything else is the pipeline's to decide.", "enum": ["ready_to_submit", "cancelled", "clear_needs_admin_attention", "check_now"] }, "AdminCreditRegistrationsPage": { "type": "object", "required": ["data", "total_count", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AdminCreditRegistrationRow" } }, "total_count": { "type": "integer", "format": "int64" }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "AdminLinkingEmail": { "type": "object", "required": [ "id", "course_id", "student_number", "sisu_person_id", "emailed_to", "claimed_at", "send_status" ], "properties": { "claimed_at": { "type": "string", "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "emailed_to": { "type": "string", "description": "In full." }, "id": { "type": "string", "format": "uuid" }, "send_status": { "$ref": "#/components/schemas/EmailSendStatusReport" }, "sisu_person_id": { "type": "string" }, "student_number": { "type": "string" }, "token_claimed_by_user_id": { "type": ["string", "null"], "format": "uuid" }, "token_expires_at": { "type": ["string", "null"], "format": "date-time" }, "token_used_at": { "type": ["string", "null"], "format": "date-time" } } }, "AdminManualLinkOutcome": { "type": "string", "enum": [ "linked", "student_number_not_found", "preview_mismatch", "already_linked_to_another_account", "already_linked_to_this_account", "study_registry_unavailable" ] }, "AdminManuallyLinkStudentNumberPayload": { "type": "object", "required": ["user_id", "student_number", "sisu_person_id", "reason"], "properties": { "reason": { "type": "string" }, "sisu_person_id": { "type": "string", "description": "From the preview. Re-resolved on arrival, and a mismatch is refused, so a typo cannot mint a\nlink to somebody else." }, "student_number": { "type": "string" }, "user_id": { "type": "string", "format": "uuid" } } }, "AdminManuallyLinkStudentNumberResult": { "type": "object", "required": ["outcome", "affected_registration_count"], "properties": { "affected_registration_count": { "type": "integer", "format": "int64", "description": "Registrations the link unblocked." }, "outcome": { "$ref": "#/components/schemas/AdminManualLinkOutcome" }, "verified_student_number_id": { "type": ["string", "null"], "format": "uuid" } } }, "AdminMaterializePayload": { "type": "object", "properties": { "reason": { "type": ["string", "null"] } } }, "AdminMaterializeResult": { "type": "object", "required": ["created_registration_count", "moved_registration_count"], "properties": { "created_registration_count": { "type": "integer", "format": "int64" }, "moved_registration_count": { "type": "integer", "format": "int64" } } }, "AdminPausePhasePayload": { "type": "object", "required": ["reason"], "properties": { "reason": { "type": "string" } } }, "AdminPhaseActionPayload": { "type": "object", "properties": { "reason": { "type": ["string", "null"] } } }, "AdminResendAccountLinkingEmailPayload": { "type": "object", "required": ["student_number", "course_id", "override_rate_caps"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "override_rate_caps": { "type": "boolean", "description": "Retires the mails a cap is counting, then runs the ordinary send path. Requires a reason." }, "reason": { "type": ["string", "null"] }, "student_number": { "type": "string" } } }, "AdminResendAccountLinkingEmailResult": { "type": "object", "required": [ "outcome", "retired_mail_count", "linking_emails", "mails_sent_for_this_course", "max_mails_per_person_and_course", "quiet_period_secs" ], "properties": { "linking_emails": { "type": "array", "items": { "$ref": "#/components/schemas/AdminLinkingEmail" } }, "mails_sent_for_this_course": { "type": "integer", "format": "int64" }, "max_mails_per_person_and_course": { "type": "integer", "format": "int64" }, "outcome": { "$ref": "#/components/schemas/AdminResendOutcome" }, "quiet_period_secs": { "type": "integer", "format": "int64" }, "retired_mail_count": { "type": "integer", "format": "int64", "description": "Mails retired to get past a cap. Always zero without an override." } } }, "AdminResendOutcome": { "type": "string", "enum": [ "queued", "already_mailed_to_every_known_address", "refused_by_rate_cap", "no_address_in_study_registry", "not_on_the_course_roster", "already_linked", "study_registry_unavailable" ] }, "AdminResolveStudentNumberPayload": { "type": "object", "required": ["student_number"], "properties": { "student_number": { "type": "string" } } }, "AdminResolveStudentNumberResult": { "type": "object", "description": "The preview a manual link is gated on. No addresses from the registry — `resolve-persons` answers\nwith a name and an id only — so the addresses here are the ones we mailed.", "required": ["found", "student_number", "study_registry_unavailable", "linking_emails"], "properties": { "already_linked_to_user_email": { "type": ["string", "null"] }, "already_linked_to_user_id": { "type": ["string", "null"], "format": "uuid" }, "already_linked_via": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/StudentNumberVerificationMethod" } ] }, "code": { "type": ["string", "null"], "description": "The registry's own per-item code, an identifier rather than prose." }, "first_names": { "type": ["string", "null"] }, "found": { "type": "boolean" }, "last_name": { "type": ["string", "null"] }, "linking_emails": { "type": "array", "items": { "$ref": "#/components/schemas/AdminLinkingEmail" } }, "sisu_person_id": { "type": ["string", "null"], "description": "Echoed back to the manual-link endpoint, which refuses without it." }, "student_number": { "type": "string" }, "study_registry_unavailable": { "type": "boolean" } } }, "AdminSuotarApiCall": { "type": "object", "required": [ "id", "endpoint", "started_at", "succeeded", "request_item_count", "ok_item_count", "error_item_count", "worker_name", "credit_registration_ids" ], "properties": { "credit_registration_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "duration_ms": { "type": ["integer", "null"], "format": "int32" }, "endpoint": { "$ref": "#/components/schemas/SuotarEndpoint" }, "error_item_count": { "type": "integer", "format": "int32" }, "http_status": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "ok_item_count": { "type": "integer", "format": "int32" }, "request_body_sample": { "description": "Scrubbed and sampled at write time." }, "request_item_count": { "type": "integer", "format": "int32" }, "request_level_error_code": { "type": ["string", "null"] }, "response_body_sample": {}, "started_at": { "type": "string", "format": "date-time" }, "succeeded": { "type": "boolean" }, "worker_name": { "type": "string" } } }, "AdminTransitionCreditRegistrationPayload": { "type": "object", "required": ["to_state", "reason"], "properties": { "reason": { "type": "string" }, "to_state": { "$ref": "#/components/schemas/AdminCreditRegistrationTransitionTarget" } } }, "AdminTransitionCreditRegistrationResult": { "type": "object", "required": ["outcome", "state", "needs_admin_attention"], "properties": { "needs_admin_attention": { "type": "boolean" }, "outcome": { "$ref": "#/components/schemas/AdminTransitionOutcome" }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" } } }, "AdminTransitionOutcome": { "type": "string", "enum": ["applied", "refused_without_consent", "no_change"] }, "AdminUnlinkStudentNumberPayload": { "type": "object", "required": ["reason"], "properties": { "reason": { "type": "string" } } }, "AdminUnlinkStudentNumberResult": { "type": "object", "required": ["affected_registration_count"], "properties": { "affected_registration_count": { "type": "integer", "format": "int64", "description": "Registrations that went back to waiting for a number." } } }, "AdminVerifiedStudentNumberRow": { "type": "object", "required": [ "id", "user_id", "student_number", "sisu_person_id", "verified_at", "verified_via", "live_registration_count" ], "properties": { "first_name": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "last_name": { "type": ["string", "null"] }, "link_reason": { "type": ["string", "null"] }, "linked_by_user_id": { "type": ["string", "null"], "format": "uuid" }, "live_registration_count": { "type": "integer", "format": "int64" }, "sisu_person_id": { "type": "string" }, "student_number": { "type": "string" }, "user_email": { "type": ["string", "null"], "description": "In full." }, "user_id": { "type": "string", "format": "uuid" }, "verified_at": { "type": "string", "format": "date-time" }, "verified_from_course_id": { "type": ["string", "null"], "format": "uuid" }, "verified_via": { "$ref": "#/components/schemas/StudentNumberVerificationMethod" }, "verified_via_email": { "type": ["string", "null"], "description": "The registry-held address the proof rests on, in full. `None` for an admin-established link." } } }, "AdminVerifiedStudentNumbersPage": { "type": "object", "required": ["data", "total_count", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AdminVerifiedStudentNumberRow" } }, "total_count": { "type": "integer", "format": "int64" }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "AnalysisCourseType": { "type": "string", "enum": ["compulsory", "elective"] }, "AnalysisWorkspaceV1": { "type": "object", "description": "Analysis stage form: course metadata, needs, wishes, market, resources, contributors.", "required": [ "mode_synchronous", "mode_asynchronous", "open_period_i", "open_period_ii", "open_period_iii", "open_period_iv", "open_period_all", "wishes_content_format_text", "wishes_content_format_video", "wishes_content_format_podcast", "wishes_content_format_xr" ], "properties": { "contributors_editors": { "type": ["string", "null"] }, "contributors_instructional_designer": { "type": ["string", "null"] }, "contributors_subject_matter_experts": { "type": ["string", "null"] }, "contributors_support_staff": { "type": ["string", "null"] }, "course_title": { "type": ["string", "null"] }, "course_type": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/AnalysisCourseType" } ] }, "credits": { "type": ["number", "null"], "format": "double" }, "degree_programme": { "type": ["string", "null"] }, "language": { "type": ["string", "null"] }, "market_results": { "type": ["string", "null"] }, "mode_asynchronous": { "type": "boolean" }, "mode_synchronous": { "type": "boolean" }, "open_period_all": { "type": "boolean" }, "open_period_i": { "type": "boolean" }, "open_period_ii": { "type": "boolean" }, "open_period_iii": { "type": "boolean" }, "open_period_iv": { "type": "boolean" }, "resources_purchase_budget": { "type": ["string", "null"] }, "resources_university": { "type": ["string", "null"] }, "responsible_teachers": { "type": ["string", "null"] }, "students_demographic_data": { "type": ["string", "null"] }, "target_group": { "type": ["string", "null"] }, "wishes_assessment_text": { "type": ["string", "null"] }, "wishes_content_format_notes": { "type": ["string", "null"] }, "wishes_content_format_podcast": { "type": "boolean" }, "wishes_content_format_text": { "type": "boolean" }, "wishes_content_format_video": { "type": "boolean" }, "wishes_content_format_xr": { "type": "boolean" }, "wishes_other_suggestions": { "type": ["string", "null"] }, "wishes_topics": { "type": ["string", "null"] } } }, "AnswerRequiringAttentionWithTasks": { "type": "object", "required": [ "id", "user_id", "created_at", "updated_at", "grading_progress", "submission_id", "exercise_id", "tasks", "given_peer_reviews", "received_peer_or_self_reviews", "received_peer_review_flagging_reports" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "data_json": {}, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_id": { "type": "string", "format": "uuid" }, "given_peer_reviews": { "type": "array", "items": { "$ref": "#/components/schemas/PeerReviewWithQuestionsAndAnswers" } }, "grading_progress": { "$ref": "#/components/schemas/GradingProgress" }, "id": { "type": "string", "format": "uuid" }, "received_peer_or_self_reviews": { "type": "array", "items": { "$ref": "#/components/schemas/PeerReviewWithQuestionsAndAnswers" } }, "received_peer_review_flagging_reports": { "type": "array", "items": { "$ref": "#/components/schemas/FlaggedAnswer" } }, "score_given": { "type": ["number", "null"], "format": "float" }, "submission_id": { "type": "string", "format": "uuid" }, "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/CourseMaterialExerciseTask" } }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "AnswersRequiringAttention": { "type": "object", "required": ["exercise_max_points", "data", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AnswerRequiringAttentionWithTasks" } }, "exercise_max_points": { "type": "integer", "format": "int32" }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "AuthorizedClientInfo": { "type": "object", "required": ["client_id", "client_name", "scopes"], "properties": { "client_id": { "type": "string", "format": "uuid" }, "client_name": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } } } }, "AutomaticCompletionRequirements": { "type": "object", "required": ["course_module_id", "requires_exam"], "properties": { "course_module_id": { "type": "string", "format": "uuid", "description": "Course module associated with these requirements." }, "number_of_exercises_attempted_treshold": { "type": ["integer", "null"], "format": "int32" }, "number_of_points_treshold": { "type": ["integer", "null"], "format": "int32" }, "requires_exam": { "type": "boolean" } } }, "AverageMetric": { "type": "object", "description": "A generic result representing an average metric over a time period.\nThe average value (e.g. average time in seconds) may be absent if no data is available.", "properties": { "average": { "type": ["number", "null"], "format": "double", "description": "The average value. For example, the average time (in seconds) from course start to first submission." }, "period": { "type": ["string", "null"], "format": "date-time", "description": "The start of the time period (e.g., day, week, month) associated with this metric." } } }, "BlockProposal": { "oneOf": [ { "allOf": [ { "$ref": "#/components/schemas/EditedBlockStillExistsData" }, { "type": "object", "required": ["type"], "properties": { "type": { "type": "string", "enum": ["edited-block-still-exists"] } } } ] }, { "allOf": [ { "$ref": "#/components/schemas/EditedBlockNoLongerExistsData" }, { "type": "object", "required": ["type"], "properties": { "type": { "type": "string", "enum": ["edited-block-no-longer-exists"] } } } ] } ] }, "BlockProposalAction": { "oneOf": [ { "type": "object", "required": ["data", "tag"], "properties": { "data": { "type": "string" }, "tag": { "type": "string", "enum": ["Accept"] } } }, { "type": "object", "required": ["tag"], "properties": { "tag": { "type": "string", "enum": ["Reject"] } } } ] }, "BlockProposalInfo": { "type": "object", "required": ["id", "action"], "properties": { "action": { "$ref": "#/components/schemas/BlockProposalAction" }, "id": { "type": "string", "format": "uuid" } } }, "BulkUserDetailsRequest": { "type": "object", "required": ["user_ids", "course_id"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "user_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "CertificateAllRequirements": { "type": "object", "required": ["certificate_configuration_id", "course_module_ids"], "properties": { "certificate_configuration_id": { "type": "string", "format": "uuid" }, "course_module_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "CertificateConfiguration": { "type": "object", "required": [ "id", "created_at", "updated_at", "certificate_owner_name_y_pos", "certificate_owner_name_x_pos", "certificate_owner_name_font_size", "certificate_owner_name_text_color", "certificate_owner_name_text_anchor", "certificate_validate_url_y_pos", "certificate_validate_url_x_pos", "certificate_validate_url_font_size", "certificate_validate_url_text_color", "certificate_validate_url_text_anchor", "certificate_date_y_pos", "certificate_date_x_pos", "certificate_date_font_size", "certificate_date_text_color", "certificate_date_text_anchor", "certificate_locale", "paper_size", "background_svg_path", "background_svg_file_upload_id", "render_certificate_grade" ], "properties": { "background_svg_file_upload_id": { "type": "string", "format": "uuid" }, "background_svg_path": { "type": "string" }, "certificate_date_font_size": { "type": "string" }, "certificate_date_text_anchor": { "$ref": "#/components/schemas/CertificateTextAnchor" }, "certificate_date_text_color": { "type": "string" }, "certificate_date_x_pos": { "type": "string" }, "certificate_date_y_pos": { "type": "string" }, "certificate_grade_font_size": { "type": ["string", "null"] }, "certificate_grade_text_anchor": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CertificateTextAnchor" } ] }, "certificate_grade_text_color": { "type": ["string", "null"] }, "certificate_grade_x_pos": { "type": ["string", "null"] }, "certificate_grade_y_pos": { "type": ["string", "null"] }, "certificate_locale": { "type": "string" }, "certificate_owner_name_font_size": { "type": "string" }, "certificate_owner_name_text_anchor": { "$ref": "#/components/schemas/CertificateTextAnchor" }, "certificate_owner_name_text_color": { "type": "string" }, "certificate_owner_name_x_pos": { "type": "string" }, "certificate_owner_name_y_pos": { "type": "string" }, "certificate_validate_url_font_size": { "type": "string" }, "certificate_validate_url_text_anchor": { "$ref": "#/components/schemas/CertificateTextAnchor" }, "certificate_validate_url_text_color": { "type": "string" }, "certificate_validate_url_x_pos": { "type": "string" }, "certificate_validate_url_y_pos": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "overlay_svg_file_upload_id": { "type": ["string", "null"], "format": "uuid" }, "overlay_svg_path": { "type": ["string", "null"] }, "paper_size": { "$ref": "#/components/schemas/PaperSize" }, "render_certificate_grade": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CertificateConfigurationAndRequirements": { "type": "object", "required": ["certificate_configuration", "requirements"], "properties": { "certificate_configuration": { "$ref": "#/components/schemas/CertificateConfiguration" }, "requirements": { "$ref": "#/components/schemas/CertificateAllRequirements" } } }, "CertificateConfigurationUpdate": { "type": "object", "required": ["course_module_id", "clear_overlay_svg_file", "render_certificate_grade"], "properties": { "background_svg_file_name": { "type": ["string", "null"] }, "certificate_date_font_size": { "type": ["string", "null"] }, "certificate_date_text_anchor": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CertificateTextAnchor" } ] }, "certificate_date_text_color": { "type": ["string", "null"] }, "certificate_date_x_pos": { "type": ["string", "null"] }, "certificate_date_y_pos": { "type": ["string", "null"] }, "certificate_grade_font_size": { "type": ["string", "null"] }, "certificate_grade_text_anchor": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CertificateTextAnchor" } ] }, "certificate_grade_text_color": { "type": ["string", "null"] }, "certificate_grade_x_pos": { "type": ["string", "null"] }, "certificate_grade_y_pos": { "type": ["string", "null"] }, "certificate_locale": { "type": ["string", "null"] }, "certificate_owner_name_font_size": { "type": ["string", "null"] }, "certificate_owner_name_text_anchor": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CertificateTextAnchor" } ] }, "certificate_owner_name_text_color": { "type": ["string", "null"] }, "certificate_owner_name_x_pos": { "type": ["string", "null"] }, "certificate_owner_name_y_pos": { "type": ["string", "null"] }, "certificate_validate_url_font_size": { "type": ["string", "null"] }, "certificate_validate_url_text_anchor": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CertificateTextAnchor" } ] }, "certificate_validate_url_text_color": { "type": ["string", "null"] }, "certificate_validate_url_x_pos": { "type": ["string", "null"] }, "certificate_validate_url_y_pos": { "type": ["string", "null"] }, "clear_overlay_svg_file": { "type": "boolean" }, "course_instance_id": { "type": ["string", "null"], "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "overlay_svg_file_name": { "type": ["string", "null"] }, "paper_size": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/PaperSize" } ] }, "render_certificate_grade": { "type": "boolean" } } }, "CertificateGenerationRequest": { "type": "object", "required": ["certificate_configuration_id", "name_on_certificate"], "properties": { "certificate_configuration_id": { "type": "string", "format": "uuid" }, "grade": { "type": ["string", "null"] }, "name_on_certificate": { "type": "string" } } }, "CertificateGridRow": { "type": "object", "required": ["user_id"], "properties": { "certificate_id": { "type": ["string", "null"], "format": "uuid" }, "date_issued": { "type": ["string", "null"], "format": "date-time" }, "name_on_certificate": { "type": ["string", "null"] }, "user_id": { "type": "string", "format": "uuid" }, "verification_id": { "type": ["string", "null"] } } }, "CertificateTextAnchor": { "type": "string", "description": "How text should be positioned relative to the given coordinates. See .", "enum": ["start", "middle", "end"] }, "CertificateUpdateRequest": { "type": "object", "required": ["date_issued"], "properties": { "date_issued": { "type": "string", "format": "date-time" }, "name_on_certificate": { "type": ["string", "null"] } } }, "ChangePasswordData": { "type": "object", "required": ["old_password", "new_password"], "properties": { "new_password": { "type": "string" }, "old_password": { "type": "string" } } }, "Chapter": { "type": "object", "required": [ "id", "created_at", "updated_at", "name", "course_id", "chapter_number", "course_module_id" ], "properties": { "chapter_image_url": { "type": ["string", "null"] }, "chapter_number": { "type": "integer", "format": "int32" }, "color": { "type": ["string", "null"] }, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deadline": { "type": ["string", "null"], "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "front_page_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "opens_at": { "type": ["string", "null"], "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ChapterAvailability": { "type": "object", "required": [ "chapter_id", "chapter_number", "chapter_name", "exercises_available", "points_available" ], "properties": { "chapter_id": { "type": "string", "format": "uuid" }, "chapter_name": { "type": "string" }, "chapter_number": { "type": "integer", "format": "int32" }, "exercises_available": { "type": "integer", "format": "int64" }, "points_available": { "type": "integer", "format": "int64" } } }, "ChapterLockStatusActionPayload": { "type": "object", "required": ["status"], "properties": { "status": { "$ref": "#/components/schemas/ChapterLockingStatus" } } }, "ChapterLockingStatus": { "type": "string", "enum": ["unlocked", "completed_and_locked", "not_unlocked_yet"] }, "ChapterScore": { "allOf": [ { "$ref": "#/components/schemas/DatabaseChapter" }, { "type": "object", "required": ["score_given", "score_total"], "properties": { "score_given": { "type": "number", "format": "float" }, "score_total": { "type": "integer", "format": "int32" } } } ] }, "ChapterUpdate": { "type": "object", "required": ["name"], "properties": { "color": { "type": ["string", "null"] }, "course_module_id": { "type": ["string", "null"], "format": "uuid", "description": "CHANGE TO NON NULL WHEN FRONTEND MODULE EDITING IMPLEMENTED" }, "deadline": { "type": ["string", "null"], "format": "date-time" }, "front_page_id": { "type": ["string", "null"], "format": "uuid" }, "name": { "type": "string" }, "opens_at": { "type": ["string", "null"], "format": "date-time" } } }, "ChatbotConfiguration": { "type": "object", "required": [ "id", "created_at", "updated_at", "enabled_to_students", "chatbot_name", "model_id", "prompt", "initial_message", "weekly_tokens_per_user", "daily_tokens_per_user", "temperature", "top_p", "frequency_penalty", "presence_penalty", "max_output_tokens", "verbosity", "reasoning_effort", "use_azure_search", "maintain_azure_search_index", "hide_citations", "use_semantic_reranking", "use_tools", "default_chatbot", "suggest_next_messages", "publicly_accessible" ], "properties": { "chatbot_name": { "type": "string" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "daily_tokens_per_user": { "type": "integer", "format": "int32" }, "default_chatbot": { "type": "boolean" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "enabled_to_students": { "type": "boolean" }, "frequency_penalty": { "type": "number", "format": "float" }, "hide_citations": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "initial_message": { "type": "string" }, "initial_suggested_messages": { "type": ["array", "null"], "items": { "type": "string" } }, "maintain_azure_search_index": { "type": "boolean" }, "max_output_tokens": { "type": "integer", "format": "int32" }, "model_id": { "type": "string", "format": "uuid" }, "presence_penalty": { "type": "number", "format": "float" }, "prompt": { "type": "string" }, "publicly_accessible": { "type": "boolean" }, "reasoning_effort": { "$ref": "#/components/schemas/ReasoningEffortLevel" }, "suggest_next_messages": { "type": "boolean" }, "temperature": { "type": "number", "format": "float" }, "top_p": { "type": "number", "format": "float" }, "updated_at": { "type": "string", "format": "date-time" }, "use_azure_search": { "type": "boolean" }, "use_semantic_reranking": { "type": "boolean" }, "use_tools": { "type": "boolean" }, "verbosity": { "$ref": "#/components/schemas/VerbosityLevel" }, "weekly_tokens_per_user": { "type": "integer", "format": "int32" } } }, "ChatbotConfigurationModel": { "type": "object", "required": [ "id", "created_at", "updated_at", "model", "model_type", "default_model", "context_size" ], "properties": { "context_size": { "type": "integer", "format": "int32" }, "created_at": { "type": "string", "format": "date-time" }, "default_model": { "type": "boolean" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "model": { "type": "string" }, "model_type": { "$ref": "#/components/schemas/ModelType" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ClaimStudentNumberVerificationTokenOutcome": { "type": "string", "enum": [ "linked", "already_linked_to_this_account", "expired", "already_used", "student_number_already_linked_to_another_account" ] }, "ClaimStudentNumberVerificationTokenResult": { "type": "object", "required": ["outcome", "newly_unblocked_registration_count"], "properties": { "linked_course_name": { "type": ["string", "null"] }, "newly_unblocked_registration_count": { "type": "integer", "format": "int64", "description": "Completions that stopped waiting for a student number because of this claim." }, "outcome": { "$ref": "#/components/schemas/ClaimStudentNumberVerificationTokenOutcome" }, "student_number": { "type": ["string", "null"] } } }, "CmsPageExercise": { "type": "object", "required": [ "id", "name", "order_number", "score_maximum", "limit_number_of_tries", "needs_peer_review", "needs_self_review", "use_course_default_peer_or_self_review_config", "teacher_reviews_answer_after_locking" ], "properties": { "deadline": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "limit_number_of_tries": { "type": "boolean" }, "max_tries_per_slide": { "type": ["integer", "null"], "format": "int32" }, "name": { "type": "string" }, "needs_peer_review": { "type": "boolean" }, "needs_self_review": { "type": "boolean" }, "order_number": { "type": "integer", "format": "int32" }, "peer_or_self_review_config": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CmsPeerOrSelfReviewConfig" } ] }, "peer_or_self_review_questions": { "type": ["array", "null"], "items": { "$ref": "#/components/schemas/CmsPeerOrSelfReviewQuestion" } }, "score_maximum": { "type": "integer", "format": "int32" }, "teacher_reviews_answer_after_locking": { "type": "boolean" }, "use_course_default_peer_or_self_review_config": { "type": "boolean" } } }, "CmsPageExerciseSlide": { "type": "object", "required": ["id", "exercise_id", "order_number"], "properties": { "exercise_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "order_number": { "type": "integer", "format": "int32" } } }, "CmsPageExerciseTask": { "type": "object", "required": ["id", "exercise_slide_id", "assignment", "exercise_type", "order_number"], "properties": { "assignment": {}, "exercise_slide_id": { "type": "string", "format": "uuid" }, "exercise_type": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "order_number": { "type": "integer", "format": "int32" }, "private_spec": {} } }, "CmsPeerOrSelfReviewConfig": { "type": "object", "required": [ "id", "course_id", "peer_reviews_to_give", "peer_reviews_to_receive", "accepting_threshold", "processing_strategy", "points_are_all_or_nothing", "reset_answer_if_zero_points_from_review" ], "properties": { "accepting_threshold": { "type": "number", "format": "float" }, "course_id": { "type": "string", "format": "uuid" }, "exercise_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "peer_reviews_to_give": { "type": "integer", "format": "int32" }, "peer_reviews_to_receive": { "type": "integer", "format": "int32" }, "points_are_all_or_nothing": { "type": "boolean" }, "processing_strategy": { "$ref": "#/components/schemas/PeerReviewProcessingStrategy" }, "reset_answer_if_zero_points_from_review": { "type": "boolean" }, "review_instructions": {} } }, "CmsPeerOrSelfReviewQuestion": { "type": "object", "required": [ "id", "peer_or_self_review_config_id", "order_number", "question", "question_type", "answer_required", "weight" ], "properties": { "answer_required": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "order_number": { "type": "integer", "format": "int32" }, "peer_or_self_review_config_id": { "type": "string", "format": "uuid" }, "question": { "type": "string" }, "question_type": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestionType" }, "weight": { "type": "number", "format": "float" } } }, "CodeGiveaway": { "type": "object", "required": ["id", "created_at", "updated_at", "course_id", "enabled", "name"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "enabled": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "require_course_specific_consent_form_question_id": { "type": ["string", "null"], "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CodeGiveawayCode": { "type": "object", "required": [ "id", "created_at", "updated_at", "code_giveaway_id", "added_by_user_id", "code" ], "properties": { "added_by_user_id": { "type": "string", "format": "uuid" }, "code": { "type": "string" }, "code_giveaway_id": { "type": "string", "format": "uuid" }, "code_given_to_user_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CohortActivity": { "type": "object", "description": "Represents cohort activity metrics for both weekly and daily cohorts.\nFor daily cohorts, `offset` will be populated (and `activity_period` may be computed from it);\nfor weekly cohorts, `offset` will be `None` and `activity_period` indicates the week start.", "required": ["active_users"], "properties": { "active_users": { "type": "integer", "format": "int64", "description": "The number of active users in this cohort for the given period." }, "activity_period": { "type": ["string", "null"], "format": "date-time", "description": "The activity period (for example, the start of the week or the computed activity day)." }, "cohort_start": { "type": ["string", "null"], "format": "date-time", "description": "The start date of the cohort (either day or week)." }, "offset": { "type": ["integer", "null"], "format": "int32", "description": "The day offset from the cohort start (only applicable for daily cohorts)." } } }, "CompleteCourseMetadata": { "type": "object", "required": [ "course", "course_instances", "default_module", "course_prerequisites", "course_audiences", "course_organization" ], "properties": { "course": { "$ref": "#/components/schemas/Course" }, "course_audiences": { "type": "array", "items": { "$ref": "#/components/schemas/CourseAudience" } }, "course_instances": { "type": "array", "items": { "$ref": "#/components/schemas/CourseInstance" } }, "course_organization": { "$ref": "#/components/schemas/DatabaseOrganization" }, "course_prerequisites": { "type": "array", "items": { "$ref": "#/components/schemas/CoursePrerequisite" } }, "default_module": { "$ref": "#/components/schemas/CourseModule" } } }, "CompletionGridRow": { "type": "object", "required": ["user_id", "module_id", "registered", "needs_to_be_reviewed"], "properties": { "grade": { "type": ["integer", "null"], "format": "int32" }, "module": { "type": ["string", "null"] }, "module_id": { "type": "string", "format": "uuid" }, "needs_to_be_reviewed": { "type": "boolean" }, "passed": { "type": ["boolean", "null"] }, "registered": { "type": "boolean" }, "user_id": { "type": "string", "format": "uuid" } } }, "CompletionPolicy": { "oneOf": [ { "allOf": [ { "$ref": "#/components/schemas/AutomaticCompletionRequirements" }, { "type": "object", "required": ["policy"], "properties": { "policy": { "type": "string", "enum": ["automatic"] } } } ] }, { "type": "object", "required": ["policy"], "properties": { "policy": { "type": "string", "enum": ["manual"] } } } ] }, "CompletionRegistrationLink": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string" } } }, "ConsentData": { "type": "object", "required": ["consent"], "properties": { "consent": { "type": "boolean" } } }, "ConsentDenyQuery": { "type": "object", "required": ["client_id", "redirect_uri", "state"], "properties": { "client_id": { "type": "string" }, "redirect_uri": { "type": "string" }, "state": { "type": "string" } } }, "ConsentQuery": { "type": "object", "required": ["client_id", "redirect_uri", "response_type", "scope", "state", "nonce"], "properties": { "client_id": { "type": "string" }, "code_challenge": { "type": ["string", "null"] }, "code_challenge_method": { "type": ["string", "null"] }, "nonce": { "type": "string" }, "redirect_uri": { "type": "string" }, "response_type": { "type": "string" }, "scope": { "type": "string" }, "state": { "type": "string" } } }, "ConsentResponse": { "type": "object", "required": ["redirect_uri"], "properties": { "redirect_uri": { "type": "string" } } }, "CopyCourseMode": { "oneOf": [ { "type": "object", "description": "Create a completely separate copy with a new course language group", "required": ["mode"], "properties": { "mode": { "type": "string", "enum": ["duplicate"] } } }, { "type": "object", "description": "Create a new language version within the same language group as the source", "required": ["mode"], "properties": { "mode": { "type": "string", "enum": ["same_language_group"] } } }, { "type": "object", "description": "Create a new language version in a specified language group", "required": ["target_course_id", "mode"], "properties": { "mode": { "type": "string", "enum": ["existing_language_group"] }, "target_course_id": { "type": "string", "format": "uuid" } } }, { "type": "object", "description": "Create a new language version in a new language group", "required": ["mode"], "properties": { "mode": { "type": "string", "enum": ["new_language_group"] } } } ] }, "CopyCourseRequest": { "allOf": [ { "$ref": "#/components/schemas/NewCourse" }, { "type": "object", "required": ["mode"], "properties": { "mode": { "$ref": "#/components/schemas/CopyCourseMode" } } } ] }, "CountResult": { "type": "object", "description": "A generic result representing a count metric over a time period.\nWhen the time period is not applicable (for overall totals), `period` will be `None`.", "required": ["count"], "properties": { "count": { "type": "integer", "format": "int64", "description": "The count (for example, the number of users)." }, "period": { "type": ["string", "null"], "format": "date-time", "description": "The start of the time period (e.g., day, week, month) associated with this count.\nFor overall totals, this will be `None`." } } }, "Course": { "type": "object", "required": [ "id", "slug", "created_at", "updated_at", "name", "organization_id", "language_code", "course_language_group_id", "is_draft", "is_test_mode", "is_unlisted", "base_module_completion_requires_n_submodule_completions", "can_add_chatbot", "is_joinable_by_code_only", "ask_marketing_consent", "flagged_answers_skip_manual_review_and_allow_retry", "chapter_locking_enabled", "cheater_detection_enabled", "ai_policy" ], "properties": { "ai_policy": { "$ref": "#/components/schemas/CourseAiPolicy" }, "ask_marketing_consent": { "type": "boolean" }, "base_module_completion_requires_n_submodule_completions": { "type": "integer", "format": "int32" }, "can_add_chatbot": { "type": "boolean" }, "chapter_locking_enabled": { "type": "boolean" }, "cheater_detection_enabled": { "type": "boolean" }, "closed_additional_message": { "type": ["string", "null"] }, "closed_at": { "type": ["string", "null"], "format": "date-time" }, "closed_course_successor_id": { "type": ["string", "null"], "format": "uuid" }, "content_search_language": { "type": ["string", "null"] }, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_language_group_id": { "type": "string", "format": "uuid" }, "course_material_ai_instructions": { "type": ["boolean", "null"] }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "flagged_answers_skip_manual_review_and_allow_retry": { "type": "boolean" }, "flagged_answers_threshold": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "is_draft": { "type": "boolean" }, "is_joinable_by_code_only": { "type": "boolean" }, "is_test_mode": { "type": "boolean" }, "is_unlisted": { "type": "boolean" }, "join_code": { "type": ["string", "null"] }, "language_code": { "type": "string" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "slug": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseAiPolicy": { "type": "string", "description": "The AI policy a teacher has selected for a course. Drives which variant of the student-facing\nAI usage notice is shown; `NotSet` (the default) keeps the generic default message.", "enum": ["NotSet", "NoAi", "PlanningOnly", "Limited", "FullUse", "Required"] }, "CourseAudience": { "type": "object", "required": ["id", "created_at", "updated_at", "course_id", "audience"], "properties": { "audience": { "type": "string" }, "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "embedding": { "type": ["array", "null"], "items": { "type": "number", "format": "float" } }, "id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseBreadcrumbInfo": { "type": "object", "required": [ "course_id", "course_name", "course_slug", "organization_slug", "organization_name" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "course_slug": { "type": "string" }, "organization_name": { "type": "string" }, "organization_slug": { "type": "string" } } }, "CourseCompletionStats": { "type": "object", "required": [ "course_id", "course_name", "total_completions", "unique_users", "registered_completions", "not_registered_completions", "users_with_some_registered_completions", "users_with_some_unregistered_completions", "registered_ects_credits", "not_registered_ects_credits" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "not_registered_completions": { "type": "integer", "format": "int64" }, "not_registered_ects_credits": { "type": "number", "format": "float" }, "registered_completion_percentage": { "type": ["number", "null"], "format": "double" }, "registered_completions": { "type": "integer", "format": "int64" }, "registered_ects_credits": { "type": "number", "format": "float" }, "total_completions": { "type": "integer", "format": "int64" }, "unique_users": { "type": "integer", "format": "int64" }, "users_with_some_registered_completions": { "type": "integer", "format": "int64" }, "users_with_some_unregistered_completions": { "type": "integer", "format": "int64" } } }, "CourseCount": { "type": "object", "required": ["count"], "properties": { "count": { "type": "integer", "format": "int32", "minimum": 0 } } }, "CourseCreditRegistration": { "type": "object", "required": [ "id", "user_id", "course_id", "course_module_id", "course_instance_id", "course_module_completion_id", "completion_date", "state", "state_entered_at", "student_facing_status", "needs_admin_attention", "next_attempt_at", "attempt_number", "superseded" ], "properties": { "attempt_number": { "type": "integer", "format": "int32" }, "completion_date": { "type": "string", "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "course_instance_id": { "type": "string", "format": "uuid" }, "course_module_completion_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "credits": { "type": ["number", "null"], "format": "float" }, "email": { "type": ["string", "null"] }, "enrolment_realisation_name": { "type": ["string", "null"] }, "error_code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "first_name": { "type": ["string", "null"] }, "grade_id": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "last_name": { "type": ["string", "null"] }, "linking_email": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TeacherLinkingEmailStatus", "description": "Only where we can join the account to a Sisu person, which needs a link past or present." } ] }, "needs_admin_attention": { "type": "boolean" }, "next_attempt_at": { "type": "string", "format": "date-time" }, "registered_at": { "type": ["string", "null"], "format": "date-time" }, "sisu_attainment_id": { "type": ["string", "null"] }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" }, "state_entered_at": { "type": "string", "format": "date-time" }, "student_facing_status": { "$ref": "#/components/schemas/StudentFacingCreditRegistrationStatus", "description": "The same collapsed stage the student is shown, so both audiences read one classification." }, "student_number": { "type": ["string", "null"], "description": "In full: a masked number cannot be checked against a student card." }, "student_number_verified_at": { "type": ["string", "null"], "format": "date-time" }, "student_number_verified_via": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/StudentNumberVerificationMethod", "description": "`admin_manual` means support established the link rather than the student proving it." } ] }, "superseded": { "type": "boolean" }, "user_id": { "type": "string", "format": "uuid" } } }, "CourseCreditRegistrationBlockedStudentCounts": { "type": "object", "description": "Why the course's enrolled students are not going to get credits. Neither count includes a student\nwho has both consented and linked a number.", "required": ["unlinked_consented_student_count", "no_consent_student_count"], "properties": { "no_consent_student_count": { "type": "integer", "format": "int64", "description": "Never asked or declined." }, "unlinked_consented_student_count": { "type": "integer", "format": "int64", "description": "Consented, but we hold no student number for them." } } }, "CourseCreditRegistrationEvent": { "type": "object", "description": "One event of the item timeline, without the stored request and response bodies: those are the\nadmin dashboard's, and the study registry's own wording is never rendered.", "required": ["id", "created_at", "kind"], "properties": { "actor_user_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "error_code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "from_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] }, "id": { "type": "string", "format": "uuid" }, "kind": { "$ref": "#/components/schemas/CreditRegistrationEventKind" }, "message": { "type": ["string", "null"], "description": "Our own wording, written by the pipeline or by whoever acted." }, "to_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] } } }, "CourseCreditRegistrationModuleConfigs": { "type": "object", "description": "Every module of the course with its Suotar configuration, for the module editor.", "required": ["modules", "realisations"], "properties": { "modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleCreditRegistrationConfig" } }, "realisations": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleSuotarRealisation" }, "description": "Every live realisation of every module of the course, to be grouped by `course_module_id`." } } }, "CourseCreditRegistrationModuleSummary": { "type": "object", "required": [ "course_module_id", "enabled", "paused", "counts_by_state", "success_count", "failed_permanent_count", "needs_admin_attention_count" ], "properties": { "counts_by_state": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationStateCount" } }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "enabled": { "type": "boolean" }, "failed_permanent_count": { "type": "integer", "format": "int64", "description": "`failed_permanent` only: a retrying row is still working and `misregistered` is not terminal." }, "needs_admin_attention_count": { "type": "integer", "format": "int64" }, "paused": { "type": "boolean" }, "success_count": { "type": "integer", "format": "int64", "description": "`registered`, `duplicate` and `not_improved`: the credit exists in Sisu." } } }, "CourseCreditRegistrationSummary": { "type": "object", "required": ["modules", "blocked_students", "linking_emails_failed_to_send_count"], "properties": { "blocked_students": { "$ref": "#/components/schemas/CourseCreditRegistrationBlockedStudentCounts" }, "linking_emails_failed_to_send_count": { "type": "integer", "format": "int64", "description": "Of the unlinked consented students, the ones whose linking mail we never managed to hand over." }, "modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCreditRegistrationModuleSummary" } } } }, "CourseCreditRegistrationUserIdsPayload": { "type": "object", "description": "Body for the students-tab batch: the users of the current identity-list page.", "required": ["user_ids"], "properties": { "course_instance_id": { "type": ["string", "null"], "format": "uuid" }, "user_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "CourseCreditRegistrationsPage": { "type": "object", "required": ["data", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCreditRegistration" } }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "CourseDesignerCourseSize": { "type": "string", "enum": ["small", "medium", "large"] }, "CourseDesignerPlan": { "type": "object", "required": ["id", "created_at", "updated_at", "created_by_user_id", "status"], "properties": { "active_stage": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CourseDesignerStage" } ] }, "created_at": { "type": "string", "format": "date-time" }, "created_by_user_id": { "type": "string", "format": "uuid" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "last_weekly_stage_email_sent_at": { "type": ["string", "null"], "format": "date-time" }, "name": { "type": ["string", "null"] }, "status": { "$ref": "#/components/schemas/CourseDesignerPlanStatus" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseDesignerPlanDetails": { "type": "object", "required": ["plan", "members", "stages"], "properties": { "members": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerPlanMember" } }, "plan": { "$ref": "#/components/schemas/CourseDesignerPlan" }, "stages": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerPlanStageWithTasks" } } } }, "CourseDesignerPlanMember": { "type": "object", "required": ["id", "created_at", "updated_at", "user_id"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "CourseDesignerPlanStage": { "type": "object", "required": [ "id", "created_at", "updated_at", "stage", "status", "planned_starts_on", "planned_ends_on" ], "properties": { "actual_completed_at": { "type": ["string", "null"], "format": "date-time" }, "actual_started_at": { "type": ["string", "null"], "format": "date-time" }, "created_at": { "type": "string", "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "planned_ends_on": { "type": "string", "format": "date" }, "planned_starts_on": { "type": "string", "format": "date" }, "stage": { "$ref": "#/components/schemas/CourseDesignerStage" }, "status": { "$ref": "#/components/schemas/CourseDesignerPlanStageStatus" }, "updated_at": { "type": "string", "format": "date-time" }, "workspace_data": {} } }, "CourseDesignerPlanStageStatus": { "type": "string", "enum": ["NotStarted", "InProgress", "Completed"] }, "CourseDesignerPlanStageTask": { "type": "object", "required": [ "id", "created_at", "updated_at", "course_designer_plan_stage_id", "title", "order_number", "is_completed", "is_auto_generated" ], "properties": { "completed_at": { "type": ["string", "null"], "format": "date-time" }, "completed_by_user_id": { "type": ["string", "null"], "format": "uuid" }, "course_designer_plan_stage_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "created_by_user_id": { "type": ["string", "null"], "format": "uuid" }, "description": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "is_auto_generated": { "type": "boolean" }, "is_completed": { "type": "boolean" }, "order_number": { "type": "integer", "format": "int32" }, "title": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseDesignerPlanStageWithTasks": { "allOf": [ { "$ref": "#/components/schemas/CourseDesignerPlanStage" }, { "type": "object", "required": ["tasks"], "properties": { "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerPlanStageTask" } } } } ] }, "CourseDesignerPlanStatus": { "type": "string", "enum": ["Draft", "Scheduling", "InProgress", "Completed", "Archived"] }, "CourseDesignerPlanSummary": { "type": "object", "required": [ "id", "created_at", "updated_at", "created_by_user_id", "status", "member_count", "stage_count" ], "properties": { "active_stage": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CourseDesignerStage" } ] }, "created_at": { "type": "string", "format": "date-time" }, "created_by_user_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "last_weekly_stage_email_sent_at": { "type": ["string", "null"], "format": "date-time" }, "member_count": { "type": "integer", "format": "int64" }, "name": { "type": ["string", "null"] }, "stage_count": { "type": "integer", "format": "int64" }, "status": { "$ref": "#/components/schemas/CourseDesignerPlanStatus" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseDesignerScheduleStageInput": { "type": "object", "required": ["stage", "planned_starts_on", "planned_ends_on"], "properties": { "planned_ends_on": { "type": "string", "format": "date" }, "planned_starts_on": { "type": "string", "format": "date" }, "stage": { "$ref": "#/components/schemas/CourseDesignerStage" } } }, "CourseDesignerScheduleSuggestionRequest": { "type": "object", "required": ["course_size", "starts_on"], "properties": { "course_size": { "$ref": "#/components/schemas/CourseDesignerCourseSize" }, "starts_on": { "type": "string", "format": "date" } } }, "CourseDesignerScheduleSuggestionResponse": { "type": "object", "required": ["stages"], "properties": { "stages": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerScheduleStageInput" } } } }, "CourseDesignerStage": { "type": "string", "enum": ["Analysis", "Design", "Development", "Implementation", "Evaluation"] }, "CourseDesignerStageWorkspace": { "oneOf": [ { "type": "object", "required": ["payload", "schema"], "properties": { "payload": { "$ref": "#/components/schemas/AnalysisWorkspaceV1" }, "schema": { "type": "string", "enum": ["analysis_v1"] } } } ], "description": "Discriminant for forward-compatible workspace payloads stored in `workspace_data`." }, "CourseEnrollmentInfo": { "type": "object", "required": [ "course_id", "course", "course_instances", "course_modules", "course_module_completions", "course_module_completions_needing_review", "first_enrolled_at", "is_current" ], "properties": { "course": { "$ref": "#/components/schemas/Course" }, "course_id": { "type": "string", "format": "uuid" }, "course_instances": { "type": "array", "items": { "$ref": "#/components/schemas/CourseInstance" } }, "course_module_completions": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleCompletion" } }, "course_module_completions_needing_review": { "type": "integer", "format": "int32" }, "course_modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleInfo" }, "description": "All non-deleted modules of the course, ordered by `order_number`." }, "first_enrolled_at": { "type": "string", "format": "date-time" }, "is_current": { "type": "boolean" }, "user_course_settings": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/UserCourseSettings" } ] } } }, "CourseEnrollmentsInfo": { "type": "object", "required": ["course_enrollments"], "properties": { "course_enrollments": { "type": "array", "items": { "$ref": "#/components/schemas/CourseEnrollmentInfo" } } } }, "CourseExam": { "type": "object", "required": ["id", "course_id", "course_name", "name"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" } } }, "CourseInstance": { "type": "object", "required": [ "id", "created_at", "updated_at", "course_id", "teacher_in_charge_name", "teacher_in_charge_email" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "ends_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": ["string", "null"] }, "starts_at": { "type": ["string", "null"], "format": "date-time" }, "support_email": { "type": ["string", "null"] }, "teacher_in_charge_email": { "type": "string" }, "teacher_in_charge_name": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseInstanceCompletionSummary": { "type": "object", "required": ["course_modules", "users_with_course_module_completions"], "properties": { "course_modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModule" } }, "users_with_course_module_completions": { "type": "array", "items": { "$ref": "#/components/schemas/UserWithModuleCompletions" } } } }, "CourseInstanceForm": { "type": "object", "required": ["teacher_in_charge_name", "teacher_in_charge_email"], "properties": { "closing_time": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "name": { "type": ["string", "null"] }, "opening_time": { "type": ["string", "null"], "format": "date-time" }, "support_email": { "type": ["string", "null"] }, "teacher_in_charge_email": { "type": "string" }, "teacher_in_charge_name": { "type": "string" } } }, "CourseMaterialExerciseTask": { "type": "object", "description": "Information necessary for the frontend to render an exercise task", "required": [ "id", "exercise_service_slug", "exercise_slide_id", "assignment", "order_number" ], "properties": { "assignment": {}, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_iframe_url": { "type": ["string", "null"], "description": "\n If none, the task is not completable at the moment because the service needs to\n be configured to the system." }, "exercise_service_slug": { "type": "string" }, "exercise_slide_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "model_solution_spec": {}, "order_number": { "type": "integer", "format": "int32" }, "previous_submission": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ExerciseTaskSubmission" } ] }, "previous_submission_grading": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ExerciseTaskGrading" } ] }, "pseudonumous_user_id": { "type": ["string", "null"], "format": "uuid", "description": "\n Unique for each (exercise_service, user) combo. If none, the task is not completable at the moment because the service needs to\n be configured to the system." }, "public_spec": {} } }, "CourseMetadata": { "type": "object", "required": ["course_audiences", "course_prerequisites"], "properties": { "course_audiences": { "type": "array", "items": { "$ref": "#/components/schemas/CourseAudience" } }, "course_description": { "type": ["string", "null"] }, "course_prerequisites": { "type": "array", "items": { "$ref": "#/components/schemas/CoursePrerequisite" } } } }, "CourseMetadataUpdate": { "type": "object", "required": ["course_audiences", "course_prerequisites"], "properties": { "course_audiences": { "type": "array", "items": { "$ref": "#/components/schemas/NewCourseAudience" } }, "course_description": { "type": ["string", "null"] }, "course_prerequisites": { "type": "array", "items": { "$ref": "#/components/schemas/NewCoursePrerequisite" } } } }, "CourseModule": { "type": "object", "description": "Like [CourseModulesSchema], but the automatic-completion columns are collapsed into\n`completion_policy`.", "required": [ "id", "created_at", "updated_at", "course_id", "order_number", "completion_policy", "enable_registering_completion_to_uh_open_university", "certification_enabled" ], "properties": { "certification_enabled": { "type": "boolean" }, "completion_policy": { "$ref": "#/components/schemas/CompletionPolicy" }, "completion_registration_link_override": { "type": ["string", "null"], "description": "If set, use this link rather than the default one when registering course completions." }, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "enable_registering_completion_to_uh_open_university": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": ["string", "null"] }, "order_number": { "type": "integer", "format": "int32" }, "uh_course_code": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseModuleCompletion": { "type": "object", "required": [ "id", "created_at", "updated_at", "course_id", "course_module_id", "user_id", "completion_date", "completion_language", "eligible_for_ects", "email", "passed", "prerequisite_modules_completed", "needs_to_be_reviewed" ], "properties": { "completion_date": { "type": "string", "format": "date-time" }, "completion_granter_user_id": { "type": ["string", "null"], "format": "uuid" }, "completion_language": { "type": "string" }, "completion_registration_attempt_date": { "type": ["string", "null"], "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "eligible_for_ects": { "type": "boolean" }, "email": { "type": "string" }, "grade": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "needs_to_be_reviewed": { "type": "boolean" }, "passed": { "type": "boolean" }, "prerequisite_modules_completed": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "CourseModuleCompletionWithRegistrationInfo": { "type": "object", "required": [ "course_module_id", "created_at", "passed", "prerequisite_modules_completed", "registered", "needs_to_be_reviewed", "user_id", "completion_date" ], "properties": { "completion_date": { "type": "string", "format": "date-time" }, "completion_registration_attempt_date": { "type": ["string", "null"], "format": "date-time", "description": "When the student has attempted to register the completion." }, "course_module_id": { "type": "string", "format": "uuid", "description": "ID of the course module." }, "created_at": { "type": "string", "format": "date-time", "description": "When the record was created" }, "grade": { "type": ["integer", "null"], "format": "int32", "description": "Grade that the student received for the completion." }, "needs_to_be_reviewed": { "type": "boolean", "description": "Whether or not the completion needs to be reviewed by the teacher." }, "passed": { "type": "boolean", "description": "Whether or not the student is eligible for credit for the completion." }, "prerequisite_modules_completed": { "type": "boolean", "description": "Whether or not the student is qualified for credit based on other modules in the course." }, "registered": { "type": "boolean", "description": "Whether or not the completion has been registered to a study registry." }, "user_id": { "type": "string", "format": "uuid", "description": "ID of the user for the completion." } } }, "CourseModuleCreditRegistrationConfig": { "type": "object", "description": "Per-module credit-registration configuration: the rollout switch and the module's own fields\nmerged with its `course_module_suotar_configurations` row. Every field of that row is optional\nhere because a module with no configuration row is a valid, unconfigured module.", "required": ["course_module_id", "course_id", "enable_credit_registration_via_suotar"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "credit_registration_config_check_message": { "type": ["string", "null"] }, "credit_registration_config_checked_at": { "type": ["string", "null"], "format": "date-time" }, "credit_registration_course_code_resolves": { "type": ["boolean", "null"], "description": "`None` means never checked, which is not the same as a failed check." }, "credit_registration_grade_scale_id": { "type": ["string", "null"], "description": "`None` means derive the grade scale from the completion." }, "credit_registration_pause_reason": { "type": ["string", "null"] }, "credit_registration_paused_at": { "type": ["string", "null"], "format": "date-time" }, "credit_registration_paused_by_user_id": { "type": ["string", "null"], "format": "uuid" }, "credit_registration_product_token_found": { "type": ["boolean", "null"] }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "enable_credit_registration_via_suotar": { "type": "boolean" }, "open_university_product_id": { "type": ["string", "null"] }, "uh_course_code": { "type": ["string", "null"] } } }, "CourseModuleCreditRegistrationEdit": { "type": "object", "description": "The module editor's writable half of the Suotar configuration. The pause and the\nconfig-validation verdict are not here: their writers are the admin dashboard and the pipeline.", "required": ["realisations"], "properties": { "grade_scale_id": { "type": ["string", "null"], "description": "`None` means derive the grade scale from the completion." }, "open_university_product_id": { "type": ["string", "null"] }, "realisations": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleSuotarRealisationEdit" }, "description": "The full set for the module; anything missing from it is soft-deleted." } } }, "CourseModuleInfo": { "type": "object", "description": "Slim module descriptor so the frontend can label per-module completions and show \"X of Y modules\"\nwithout a separate course-structure fetch. Default (base) module has `name = None`.", "required": [ "id", "order_number", "exercise_count", "daily_submissions", "enable_credit_registration_via_suotar" ], "properties": { "daily_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/DailySubmissionCount" }, "description": "This user's exercise submissions in this module bucketed by UTC day, ascending. Empty if none." }, "ects_credits": { "type": ["number", "null"], "format": "float", "description": "ECTS credits the module is worth. `None` when the module grants no credits." }, "enable_credit_registration_via_suotar": { "type": "boolean" }, "exercise_count": { "type": "integer", "format": "int32", "description": "Number of non-deleted exercises in this module. Submission density is divided by this so courses\nof very different size stay comparable. `0` if the module has no chapter-bound exercises." }, "first_submission_at": { "type": ["string", "null"], "format": "date-time", "description": "Earliest exercise submission by this user in this module. No module \"start\" is stored, so the\nfrontend uses this to infer when an additional module was first worked on. `None` if untouched." }, "id": { "type": "string", "format": "uuid" }, "name": { "type": ["string", "null"] }, "order_number": { "type": "integer", "format": "int32" }, "uh_course_code": { "type": ["string", "null"], "description": "The module's course code in the university's registry, e.g. `BSCS1001`." } } }, "CourseModuleSuotarRealisation": { "type": "object", "required": [ "id", "created_at", "updated_at", "course_module_id", "course_unit_realisation_id", "active", "consecutive_listing_failures" ], "properties": { "active": { "type": "boolean" }, "consecutive_listing_failures": { "type": "integer", "format": "int32" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_unit_realisation_id": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "label": { "type": ["string", "null"] }, "last_already_linked_count": { "type": ["integer", "null"], "format": "int32" }, "last_listed_at": { "type": ["string", "null"], "format": "date-time" }, "last_listed_person_count": { "type": ["integer", "null"], "format": "int32" }, "last_listing_attempted_at": { "type": ["string", "null"], "format": "date-time" }, "last_listing_error": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "last_mailed_count": { "type": ["integer", "null"], "format": "int32" }, "last_no_address_count": { "type": ["integer", "null"], "format": "int32" }, "last_suppressed_by_dedup_count": { "type": ["integer", "null"], "format": "int32" }, "last_suppressed_by_rate_cap_count": { "type": ["integer", "null"], "format": "int32" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseModuleSuotarRealisationEdit": { "type": "object", "required": ["course_unit_realisation_id", "active"], "properties": { "active": { "type": "boolean" }, "course_unit_realisation_id": { "type": "string" }, "label": { "type": ["string", "null"], "description": "Rendered to students as the name of the realisation their credits go against." } } }, "CourseModuleThresholdInfo": { "type": "object", "description": "Per-module threshold configuration plus the policy-derived limits the configuration UI needs to\nrender and validate the threshold form. Computed server-side so the exemption rule and the\nminimum/default values live in one place instead of being duplicated in the frontend.", "required": ["course_module_id", "minimum_duration_seconds", "default_duration_seconds"], "properties": { "configured_duration_seconds": { "type": ["integer", "null"], "format": "int32", "description": "The explicitly configured threshold in seconds, or `None` when the module has no threshold\nrow and [`Self::default_duration_seconds`] applies." }, "course_module_id": { "type": "string", "format": "uuid" }, "default_duration_seconds": { "type": "integer", "format": "int32", "description": "The threshold applied when none is configured." }, "minimum_duration_seconds": { "type": "integer", "format": "int32", "description": "The smallest threshold a teacher may save for this module: `0` for small (exempt) modules,\notherwise [`MINIMUM_CHEATER_THRESHOLD_SECONDS`]." } } }, "CoursePrerequisite": { "type": "object", "required": ["id", "created_at", "updated_at", "course_id", "prerequisite"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "embedding": { "type": ["array", "null"], "items": { "type": "number", "format": "float" } }, "id": { "type": "string", "format": "uuid" }, "prerequisite": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CourseStructure": { "type": "object", "required": ["course", "pages", "chapters", "modules"], "properties": { "chapters": { "type": "array", "items": { "$ref": "#/components/schemas/Chapter" } }, "course": { "$ref": "#/components/schemas/Course" }, "modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModule" } }, "pages": { "type": "array", "items": { "$ref": "#/components/schemas/Page" } } } }, "CourseStudentListRow": { "type": "object", "description": "One row of the paginated student identity list (one row per distinct enrolled user).", "required": ["user_id", "course_instances", "has_active_instance"], "properties": { "course_instances": { "type": "array", "items": { "type": "string" }, "description": "Names of the non-deleted course instances the user is enrolled in for this course." }, "email": { "type": ["string", "null"] }, "first_name": { "type": ["string", "null"] }, "has_active_instance": { "type": "boolean", "description": "Whether the user has any enrollment into a non-deleted instance. Separates the unnamed default\ninstance (true) from a since-deleted instance (false) when `course_instances` is empty." }, "last_name": { "type": ["string", "null"] }, "user_id": { "type": "string", "format": "uuid" } } }, "CourseStudentsProgressStructure": { "type": "object", "description": "Course-level progress structure for the Progress tab. Does not depend on which students are on\nthe current page, so it is fetched once and cached per course (not per identity page).", "required": ["chapter_locking_enabled", "chapters", "chapter_availability"], "properties": { "chapter_availability": { "type": "array", "items": { "$ref": "#/components/schemas/ChapterAvailability" } }, "chapter_locking_enabled": { "type": "boolean" }, "chapters": { "type": "array", "items": { "$ref": "#/components/schemas/DatabaseChapter" } } } }, "CourseStudentsProgressUsers": { "type": "object", "description": "Per-user progress detail for the Progress tab, scoped to the requested `user_ids`.", "required": ["user_chapter_progress", "user_chapter_locking_statuses"], "properties": { "user_chapter_locking_statuses": { "type": "array", "items": { "$ref": "#/components/schemas/UserChapterLockingStatus" } }, "user_chapter_progress": { "type": "array", "items": { "$ref": "#/components/schemas/UserChapterProgress" } } } }, "CourseUpdate": { "type": "object", "required": [ "name", "is_draft", "is_test_mode", "can_add_chatbot", "is_unlisted", "is_joinable_by_code_only", "ask_marketing_consent", "flagged_answers_threshold", "flagged_answers_skip_manual_review_and_allow_retry", "chapter_locking_enabled", "ai_policy" ], "properties": { "ai_policy": { "$ref": "#/components/schemas/CourseAiPolicy" }, "ask_marketing_consent": { "type": "boolean" }, "can_add_chatbot": { "type": "boolean" }, "chapter_locking_enabled": { "type": "boolean" }, "closed_additional_message": { "type": ["string", "null"] }, "closed_at": { "type": ["string", "null"], "format": "date-time" }, "closed_course_successor_id": { "type": ["string", "null"], "format": "uuid" }, "course_material_ai_instructions": { "type": ["boolean", "null"] }, "description": { "type": ["string", "null"] }, "flagged_answers_skip_manual_review_and_allow_retry": { "type": "boolean" }, "flagged_answers_threshold": { "type": "integer", "format": "int32" }, "is_draft": { "type": "boolean" }, "is_joinable_by_code_only": { "type": "boolean" }, "is_test_mode": { "type": "boolean" }, "is_unlisted": { "type": "boolean" }, "name": { "type": "string" } } }, "CreateCourseDesignerPlanRequest": { "type": "object", "properties": { "name": { "type": ["string", "null"] } } }, "CreateCourseDesignerStageTaskRequest": { "type": "object", "required": ["title"], "properties": { "description": { "type": ["string", "null"] }, "title": { "type": "string" } } }, "CreditRegistrationAdminAction": { "type": "string", "enum": [ "retry_item", "retry_failed_for_course", "force_recheck", "mark_resolved", "requeue_batch", "transition_item", "cancel_registration", "pause_course_module", "resume_course_module", "pause_phase", "resume_phase", "run_phase_now", "resend_link_email", "unlink_student_number", "manual_link_student_number", "override_rate_cap" ] }, "CreditRegistrationAdminActionRecord": { "type": "object", "required": [ "id", "created_at", "updated_at", "action", "target_kind", "actor_user_id", "actor_role" ], "properties": { "action": { "$ref": "#/components/schemas/CreditRegistrationAdminAction" }, "actor_course_id": { "type": ["string", "null"], "format": "uuid" }, "actor_role": { "type": "string" }, "actor_user_id": { "type": "string", "format": "uuid" }, "affected_row_count": { "type": ["integer", "null"], "format": "int32" }, "after_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] }, "before_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationState" } ] }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "details": {}, "id": { "type": "string", "format": "uuid" }, "reason": { "type": ["string", "null"] }, "target_id": { "type": ["string", "null"], "format": "uuid" }, "target_kind": { "$ref": "#/components/schemas/CreditRegistrationAdminActionTarget" }, "target_phase": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" } } }, "CreditRegistrationAdminActionTarget": { "type": "string", "enum": [ "credit_registration", "course_module", "course", "phase", "verified_student_number", "student_number_verification_token" ] }, "CreditRegistrationAlert": { "type": "object", "required": ["id", "severity", "count"], "properties": { "at": { "type": ["string", "null"], "format": "date-time", "description": "When it last happened, where the rule has an instant to point at." }, "count": { "type": "integer", "format": "int64", "description": "How many rows, calls or phases the rule found." }, "id": { "$ref": "#/components/schemas/CreditRegistrationAlertId" }, "severity": { "$ref": "#/components/schemas/CreditRegistrationAlertSeverity" }, "subject": { "type": ["string", "null"], "description": "An identifier the operator can act on — a phase name, a ledger state, a mail domain. Never a\nsentence, and never anything the study registry wrote." } } }, "CreditRegistrationAlertId": { "type": "string", "enum": [ "credentials_rejected", "study_registry_unreachable", "stuck_registrations", "linking_mail_send_failed", "phase_heartbeat_stale" ] }, "CreditRegistrationAlertSeverity": { "type": "string", "enum": ["warning", "critical"] }, "CreditRegistrationAlertThresholds": { "type": "object", "description": "Every number the rules used, so the UI can say \"N of M\" without holding a copy of M.", "required": [ "credential_rejection_window_secs", "unreachable_window_secs", "unreachable_consecutive_failures", "stuck_ready_to_submit_secs", "stuck_submitting_secs", "stuck_awaiting_verification_secs", "stuck_failed_retryable_secs", "stuck_critical_count", "linking_mail_window_secs", "phase_heartbeat_interval_multiplier" ], "properties": { "credential_rejection_window_secs": { "type": "integer", "format": "int64" }, "linking_mail_window_secs": { "type": "integer", "format": "int64" }, "phase_heartbeat_interval_multiplier": { "type": "integer", "format": "int32" }, "stuck_awaiting_verification_secs": { "type": "integer", "format": "int64" }, "stuck_critical_count": { "type": "integer", "format": "int64" }, "stuck_failed_retryable_secs": { "type": "integer", "format": "int64" }, "stuck_ready_to_submit_secs": { "type": "integer", "format": "int64" }, "stuck_submitting_secs": { "type": "integer", "format": "int64" }, "unreachable_consecutive_failures": { "type": "integer", "format": "int64" }, "unreachable_window_secs": { "type": "integer", "format": "int64" } } }, "CreditRegistrationCircuitBreakerState": { "type": "object", "description": "The circuit breaker as this web process holds it. The global key only — a narrowed run gets its own\n— and the counters live in process memory, so this says whether this server would currently skip a\nstudy registry call, not whether the workers would.", "required": ["open", "consecutive_failures", "trips_after_consecutive_failures"], "properties": { "consecutive_failures": { "type": "integer", "format": "int64" }, "open": { "type": "boolean" }, "open_for_secs": { "type": ["integer", "null"], "format": "int64" }, "trips_after_consecutive_failures": { "type": "integer", "format": "int64" } } }, "CreditRegistrationConsentModule": { "type": "object", "required": ["id"], "properties": { "ects_credits": { "type": ["number", "null"], "format": "float" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": ["string", "null"] }, "uh_course_code": { "type": ["string", "null"] } } }, "CreditRegistrationDetails": { "type": "object", "required": ["course_id", "course_name", "registration", "attempts", "events"], "properties": { "attempts": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCreditRegistration" }, "description": "Every attempt for the same completion, newest first, this one included." }, "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/CourseCreditRegistrationEvent" } }, "registration": { "$ref": "#/components/schemas/CourseCreditRegistration" } } }, "CreditRegistrationErrorCode": { "type": "string", "description": "Why a ledger row is where it is; `state` says what happens to it next.", "enum": [ "person_not_found", "course_code_not_found", "enrolment_not_found", "enrolment_not_accepted", "invalid_grade_for_grade_scale", "course_not_allowed", "invalid_credits", "study_right_not_valid", "acceptor_not_found", "sisu_validation_failed", "sisu_timeout", "sisu_temporarily_unavailable", "misregistered", "unauthorized", "malformed_request", "transport_error", "unexpected_response", "no_grade_scale_mapping", "missing_uh_course_code", "missing_ects_credits", "retry_window_expired", "unknown" ] }, "CreditRegistrationErrorCodeTotal": { "type": "object", "required": ["error_code", "in_flight_count", "terminal_failure_count"], "properties": { "error_code": { "$ref": "#/components/schemas/CreditRegistrationErrorCode" }, "in_flight_count": { "type": "integer", "format": "int64", "description": "Rows the pipeline is still working on." }, "terminal_failure_count": { "type": "integer", "format": "int64", "description": "Rows that ended on this code." } } }, "CreditRegistrationEventKind": { "type": "string", "enum": [ "created", "state_changed", "suotar_response", "retry_scheduled", "admin_action", "student_action", "cancelled" ] }, "CreditRegistrationHealth": { "type": "object", "required": ["status", "alerts", "thresholds"], "properties": { "alerts": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationAlert" }, "description": "Critical first, and a rejected credential first of all: nothing registers until it is fixed." }, "status": { "$ref": "#/components/schemas/HealthStatus" }, "thresholds": { "$ref": "#/components/schemas/CreditRegistrationAlertThresholds" } } }, "CreditRegistrationOldestNonTerminal": { "type": "object", "required": ["credit_registration_id", "state", "state_entered_at"], "properties": { "credit_registration_id": { "type": "string", "format": "uuid" }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" }, "state_entered_at": { "type": "string", "format": "date-time" } } }, "CreditRegistrationOverview": { "type": "object", "required": [ "health", "counts_by_state", "error_codes", "needs_admin_attention_count", "throughput", "throughput_days", "stuck", "endpoints", "circuit_breaker", "phases" ], "properties": { "circuit_breaker": { "$ref": "#/components/schemas/CreditRegistrationCircuitBreakerState" }, "counts_by_state": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationStateTotal" } }, "endpoints": { "type": "array", "items": { "$ref": "#/components/schemas/SuotarEndpointStanding" } }, "error_codes": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationErrorCodeTotal" } }, "health": { "$ref": "#/components/schemas/CreditRegistrationHealth" }, "needs_admin_attention_count": { "type": "integer", "format": "int64" }, "oldest_non_terminal": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationOldestNonTerminal" } ] }, "phases": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationPhaseStatus" } }, "stuck": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationStuckTotal" } }, "throughput": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationThroughputBucket" } }, "throughput_days": { "type": "integer", "format": "int64" } } }, "CreditRegistrationPhaseStatus": { "type": "object", "description": "One pipeline phase's heartbeat, written by the worker loops and by unscoped runs only, never by a\nnarrowed one.", "required": [ "phase", "process_name", "expected_interval_secs", "consecutive_failures", "implemented", "heartbeat_late" ], "properties": { "consecutive_failures": { "type": "integer", "format": "int32" }, "expected_interval_secs": { "type": "integer", "format": "int32" }, "heartbeat_late": { "type": "boolean", "description": "`seconds_since_heartbeat > expected_interval_secs * health.thresholds.phase_heartbeat_interval_multiplier`.\nAlways `false` while paused or never heartbeated." }, "implemented": { "type": "boolean", "description": "No implementation is registered for the phase yet, so it has never reported and will not." }, "items_failed_last_run": { "type": ["integer", "null"], "format": "int32" }, "items_processed_last_run": { "type": ["integer", "null"], "format": "int32" }, "last_heartbeat_at": { "type": ["string", "null"], "format": "date-time" }, "last_run_finished_at": { "type": ["string", "null"], "format": "date-time" }, "last_success_at": { "type": ["string", "null"], "format": "date-time" }, "pause_reason": { "type": ["string", "null"] }, "paused_at": { "type": ["string", "null"], "format": "date-time" }, "phase": { "type": "string" }, "process_name": { "type": "string" }, "seconds_since_heartbeat": { "type": ["integer", "null"], "format": "int64", "description": "Computed server-side: a page comparing its own clock against a server timestamp misjudges this\non a skewed client." } } }, "CreditRegistrationState": { "type": "string", "description": "What the pipeline does next with a ledger row.", "enum": [ "pending_prerequisites", "pending_consent", "pending_student_number", "ready_to_submit", "resolving_enrolment", "checking_enrolment", "no_usable_enrolment", "submitting", "submission_uncertain", "awaiting_verification", "registered", "duplicate", "not_improved", "misregistered", "failed_retryable", "failed_permanent", "blocked", "cancelled", "abandoned_by_consent_withdrawal" ] }, "CreditRegistrationStateCount": { "type": "object", "required": ["state", "count"], "properties": { "count": { "type": "integer", "format": "int64" }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" } } }, "CreditRegistrationStateTotal": { "type": "object", "required": ["state", "count"], "properties": { "count": { "type": "integer", "format": "int64" }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" } } }, "CreditRegistrationStuckTotal": { "type": "object", "required": ["state", "count", "severely_stuck_count"], "properties": { "count": { "type": "integer", "format": "int64" }, "oldest_state_entered_at": { "type": ["string", "null"], "format": "date-time" }, "severely_stuck_count": { "type": "integer", "format": "int64" }, "state": { "$ref": "#/components/schemas/CreditRegistrationState" } } }, "CreditRegistrationThroughputBucket": { "type": "object", "required": ["day", "registered_count", "other_success_count", "failed_count"], "properties": { "day": { "type": "string", "format": "date-time" }, "failed_count": { "type": "integer", "format": "int64" }, "other_success_count": { "type": "integer", "format": "int64", "description": "`duplicate` and `not_improved`: the credit exists, and we did not put it there." }, "registered_count": { "type": "integer", "format": "int64" } } }, "CronJobInfo": { "type": "object", "required": ["name", "schedule"], "properties": { "last_schedule_time": { "type": ["string", "null"] }, "name": { "type": "string" }, "schedule": { "type": "string" } } }, "DailySubmissionCount": { "type": "object", "description": "One UTC day's exercise-submission count for a module, used for the activity-density violins on the\ncross-course timeline. `day` is midnight of the day the submissions fall in.", "required": ["day", "count"], "properties": { "count": { "type": "integer", "format": "int32" }, "day": { "type": "string", "format": "date-time" } } }, "DatabaseChapter": { "type": "object", "required": [ "id", "created_at", "updated_at", "name", "course_id", "chapter_number", "course_module_id" ], "properties": { "chapter_image_path": { "type": ["string", "null"] }, "chapter_number": { "type": "integer", "format": "int32" }, "color": { "type": ["string", "null"] }, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deadline": { "type": ["string", "null"], "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "front_page_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "opens_at": { "type": ["string", "null"], "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "DatabaseOrganization": { "type": "object", "required": ["id", "slug", "created_at", "updated_at", "name", "hidden"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "hidden": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "organization_image_path": { "type": ["string", "null"] }, "slug": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "DeploymentInfo": { "type": "object", "required": ["name", "replicas", "ready_replicas", "selector_labels"], "properties": { "name": { "type": "string" }, "ready_replicas": { "type": "integer", "format": "int32" }, "replicas": { "type": "integer", "format": "int32" }, "selector_labels": { "type": "object", "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" } } } }, "DomainCompletionStats": { "type": "object", "required": [ "email_domain", "total_completions", "unique_users", "registered_completions", "not_registered_completions", "users_with_some_registered_completions", "users_with_some_unregistered_completions", "registered_ects_credits", "not_registered_ects_credits" ], "properties": { "email_domain": { "type": "string" }, "not_registered_completions": { "type": "integer", "format": "int64" }, "not_registered_ects_credits": { "type": "number", "format": "float" }, "registered_completion_percentage": { "type": ["number", "null"], "format": "double" }, "registered_completions": { "type": "integer", "format": "int64" }, "registered_ects_credits": { "type": "number", "format": "float" }, "total_completions": { "type": "integer", "format": "int64" }, "unique_users": { "type": "integer", "format": "int64" }, "users_with_some_registered_completions": { "type": "integer", "format": "int64" }, "users_with_some_unregistered_completions": { "type": "integer", "format": "int64" } } }, "EditProposalInfo": { "type": "object", "required": ["page_id", "page_proposal_id", "block_proposals"], "properties": { "block_proposals": { "type": "array", "items": { "$ref": "#/components/schemas/BlockProposalInfo" } }, "page_id": { "type": "string", "format": "uuid" }, "page_proposal_id": { "type": "string", "format": "uuid" } } }, "EditedBlockNoLongerExistsData": { "type": "object", "required": ["id", "block_id", "changed_text", "original_text", "status"], "properties": { "block_id": { "type": "string", "format": "uuid" }, "changed_text": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "original_text": { "type": "string" }, "status": { "$ref": "#/components/schemas/ProposalStatus" } } }, "EditedBlockStillExistsData": { "type": "object", "required": ["id", "block_id", "current_text", "changed_text", "original_text", "status"], "properties": { "accept_preview": { "type": ["string", "null"] }, "block_id": { "type": "string", "format": "uuid" }, "changed_text": { "type": "string" }, "current_text": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "original_text": { "type": "string" }, "status": { "$ref": "#/components/schemas/ProposalStatus" } } }, "EmailData": { "type": "object", "required": ["email", "language"], "properties": { "email": { "type": "string" }, "language": { "type": "string" } } }, "EmailSendStatus": { "type": "string", "description": "What we can honestly say about an email we queued.\n\nWe only hand messages to an SMTP relay, so copy rendering this must never say \"delivered\" or\n\"received\".", "enum": ["queued", "retrying", "sent", "send_failed"] }, "EmailSendStatusReport": { "type": "object", "description": "The shared payload for every surface that reports on a queued email.", "required": ["email_send_status", "retry_count"], "properties": { "email_send_status": { "$ref": "#/components/schemas/EmailSendStatus" }, "failure_code": { "type": ["string", "null"] }, "failure_is_transient": { "type": ["boolean", "null"] }, "last_attempt_at": { "type": ["string", "null"], "format": "date-time" }, "next_retry_at": { "type": ["string", "null"], "format": "date-time" }, "retry_count": { "type": "integer", "format": "int32" }, "sent_at": { "type": ["string", "null"], "format": "date-time" } } }, "EmailTemplate": { "type": "object", "required": ["id", "created_at", "updated_at", "template_type"], "properties": { "content": {}, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_completions_threshold": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "language": { "type": ["string", "null"] }, "points_threshold": { "type": ["integer", "null"], "format": "int32" }, "subject": { "type": ["string", "null"] }, "template_type": { "$ref": "#/components/schemas/EmailTemplateType" }, "updated_at": { "type": "string", "format": "date-time" } } }, "EmailTemplateNew": { "type": "object", "required": ["template_type"], "properties": { "content": {}, "language": { "type": ["string", "null"] }, "subject": { "type": ["string", "null"] }, "template_type": { "$ref": "#/components/schemas/EmailTemplateType" } } }, "EmailTemplateType": { "type": "string", "enum": [ "reset_password_email", "delete_user_email", "confirm_email_code", "generic", "credit_registration_account_linking", "verify_email_address", "credit_registration_action_needed", "credit_registration_registered", "credit_registration_student_number_linked" ] }, "EmailVerificationEmailInfo": { "type": "object", "description": "What we last mailed about the address the account holds now. Never a delivery confirmation: we\nhand messages to an SMTP relay and cannot see an inbox.", "required": ["sent_at", "expires_at"], "properties": { "expires_at": { "type": "string", "format": "date-time" }, "sent_at": { "type": "string", "format": "date-time" } } }, "EmailVerificationMethod": { "type": "string", "description": "How proof of control over [`UserDetail::email`] was obtained. `AdminAsserted` is the weakest.", "enum": ["emailed_code", "password_reset_backfill", "tmc_confirmed", "admin_asserted"] }, "EmailVerificationStatus": { "type": "object", "required": ["verification_enabled", "template_configured", "email"], "properties": { "email": { "type": "string" }, "email_verified_at": { "type": ["string", "null"], "format": "date-time" }, "email_verified_method": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/EmailVerificationMethod" } ] }, "latest_verification_email": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/EmailVerificationEmailInfo" } ] }, "template_configured": { "type": "boolean", "description": "False when `verification_enabled` but the deployment has no `verify_email_address`\ntemplate: requesting a code would 500, so the frontend hides the feature instead." }, "verification_enabled": { "type": "boolean", "description": "False switches the feature off entirely; the request and verify endpoints 404 then." } } }, "EventInfo": { "type": "object", "required": ["name"], "properties": { "count": { "type": ["integer", "null"], "format": "int32" }, "first_timestamp": { "type": ["string", "null"] }, "involved_object_kind": { "type": ["string", "null"] }, "involved_object_name": { "type": ["string", "null"] }, "last_timestamp": { "type": ["string", "null"] }, "message": { "type": ["string", "null"] }, "name": { "type": "string" }, "reason": { "type": ["string", "null"] }, "type_": { "type": ["string", "null"] } } }, "Exam": { "type": "object", "required": [ "id", "name", "instructions", "page_id", "courses", "time_minutes", "minimum_points_treshold", "language", "grade_manually" ], "properties": { "courses": { "type": "array", "items": { "$ref": "#/components/schemas/Course" } }, "ends_at": { "type": ["string", "null"], "format": "date-time" }, "grade_manually": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "instructions": {}, "language": { "type": "string" }, "minimum_points_treshold": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "page_id": { "type": "string", "format": "uuid" }, "starts_at": { "type": ["string", "null"], "format": "date-time" }, "time_minutes": { "type": "integer", "format": "int32" } } }, "ExamCourseInfo": { "type": "object", "required": ["course_id"], "properties": { "course_id": { "type": "string", "format": "uuid" } } }, "ExamEnrollment": { "type": "object", "required": [ "user_id", "exam_id", "started_at", "is_teacher_testing", "created_at", "updated_at" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "ended_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": "string", "format": "uuid" }, "is_teacher_testing": { "type": "boolean" }, "show_exercise_answers": { "type": ["boolean", "null"] }, "started_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "Exercise": { "type": "object", "required": [ "id", "created_at", "updated_at", "name", "page_id", "score_maximum", "order_number", "limit_number_of_tries", "needs_peer_review", "needs_self_review", "use_course_default_peer_or_self_review_config", "teacher_reviews_answer_after_locking" ], "properties": { "chapter_id": { "type": ["string", "null"], "format": "uuid" }, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deadline": { "type": ["string", "null"], "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_language_group_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "limit_number_of_tries": { "type": "boolean" }, "max_tries_per_slide": { "type": ["integer", "null"], "format": "int32" }, "name": { "type": "string" }, "needs_peer_review": { "type": "boolean" }, "needs_self_review": { "type": "boolean" }, "order_number": { "type": "integer", "format": "int32" }, "page_id": { "type": "string", "format": "uuid" }, "score_maximum": { "type": "integer", "format": "int32" }, "teacher_reviews_answer_after_locking": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "use_course_default_peer_or_self_review_config": { "type": "boolean" } } }, "ExerciseAnswersInCourseRequiringAttentionCount": { "type": "object", "required": ["id", "name", "page_id", "order_number"], "properties": { "chapter_id": { "type": ["string", "null"], "format": "uuid" }, "count": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "order_number": { "type": "integer", "format": "int32" }, "page_id": { "type": "string", "format": "uuid" } } }, "ExerciseCsvExportTaskOption": { "type": "object", "required": [ "exercise_task_id", "exercise_type", "order_number", "supports_csv_export_definitions", "supports_csv_export_answers" ], "properties": { "exercise_task_id": { "type": "string", "format": "uuid" }, "exercise_type": { "type": "string" }, "order_number": { "type": "integer", "format": "int32" }, "supports_csv_export_answers": { "type": "boolean" }, "supports_csv_export_definitions": { "type": "boolean" } } }, "ExerciseRepository": { "type": "object", "required": ["id", "url", "status"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "error_message": { "type": ["string", "null"] }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "status": { "$ref": "#/components/schemas/ExerciseRepositoryStatus" }, "url": { "type": "string" } } }, "ExerciseRepositoryStatus": { "type": "string", "enum": ["Pending", "Success", "Failure"] }, "ExerciseRepositoryUpdate": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string" } } }, "ExerciseResetLog": { "type": "object", "required": [ "id", "reset_for", "exercise_id", "exercise_name", "course_id", "reset_at", "created_at", "updated_at" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_name": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "reason": { "type": ["string", "null"] }, "reset_at": { "type": "string", "format": "date-time" }, "reset_by": { "type": ["string", "null"], "format": "uuid" }, "reset_by_first_name": { "type": ["string", "null"] }, "reset_by_last_name": { "type": ["string", "null"] }, "reset_for": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ExerciseService": { "type": "object", "required": [ "id", "created_at", "updated_at", "name", "slug", "public_url", "max_reprocessing_submissions_at_once" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "internal_url": { "type": ["string", "null"], "description": "This is needed because connecting to services directly inside the cluster with a special url is much for efficient than connecting to the same service with a url that would get routed though the internet. If not defined, use we can reach the service with the public url." }, "max_reprocessing_submissions_at_once": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "public_url": { "type": "string" }, "slug": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ExerciseServiceNewOrUpdate": { "type": "object", "required": ["name", "slug", "public_url", "max_reprocessing_submissions_at_once"], "properties": { "internal_url": { "type": ["string", "null"] }, "max_reprocessing_submissions_at_once": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "public_url": { "type": "string" }, "slug": { "type": "string" } } }, "ExerciseServiceUploadResultEntry": { "type": "object", "required": ["id", "url"], "properties": { "id": { "type": "string" }, "url": { "type": "string" } } }, "ExerciseServiceWithError": { "type": "object", "required": ["exercise_service"], "properties": { "exercise_service": { "$ref": "#/components/schemas/ExerciseService" }, "service_info_error": { "type": ["string", "null"] } } }, "ExerciseSlideSubmission": { "type": "object", "required": [ "id", "created_at", "updated_at", "exercise_slide_id", "exercise_id", "user_id", "user_points_update_strategy" ], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_slide_id": { "type": "string", "format": "uuid" }, "flag_count": { "type": ["integer", "null"], "format": "int32" }, "id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" }, "user_points_update_strategy": { "$ref": "#/components/schemas/UserPointsUpdateStrategy" } } }, "ExerciseSlideSubmissionAndUserExerciseState": { "type": "object", "required": [ "exercise", "exercise_slide_submission", "user_exercise_state", "user_exam_enrollment" ], "properties": { "exercise": { "$ref": "#/components/schemas/Exercise" }, "exercise_slide_submission": { "$ref": "#/components/schemas/ExerciseSlideSubmission" }, "teacher_grading_decision": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TeacherGradingDecision" } ] }, "user_exam_enrollment": { "$ref": "#/components/schemas/ExamEnrollment" }, "user_exercise_state": { "$ref": "#/components/schemas/UserExerciseState" } } }, "ExerciseSlideSubmissionAndUserExerciseStateList": { "type": "object", "required": ["data", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmissionAndUserExerciseState" } }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "ExerciseSlideSubmissionCount": { "type": "object", "properties": { "count": { "type": ["integer", "null"], "format": "int32" }, "date": { "type": ["string", "null"], "format": "date" } } }, "ExerciseSlideSubmissionCountByExercise": { "type": "object", "required": ["exercise_id", "exercise_name"], "properties": { "count": { "type": ["integer", "null"], "format": "int32" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_name": { "type": "string" } } }, "ExerciseSlideSubmissionCountByWeekAndHour": { "type": "object", "properties": { "count": { "type": ["integer", "null"], "format": "int32" }, "hour": { "type": ["integer", "null"], "format": "int32" }, "isodow": { "type": ["integer", "null"], "format": "int32" } } }, "ExerciseSlideSubmissionInfo": { "type": "object", "required": ["tasks", "exercise", "exercise_slide_submission"], "properties": { "exercise": { "$ref": "#/components/schemas/Exercise" }, "exercise_slide_submission": { "$ref": "#/components/schemas/ExerciseSlideSubmission" }, "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/CourseMaterialExerciseTask" } }, "user_exercise_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/UserExerciseState" } ] } } }, "ExerciseStatusSummaryForUser": { "type": "object", "required": [ "exercise", "exercise_slide_submissions", "given_peer_or_self_review_submissions", "given_peer_or_self_review_question_submissions", "received_peer_or_self_review_submissions", "received_peer_or_self_review_question_submissions", "peer_or_self_review_questions" ], "properties": { "exercise": { "$ref": "#/components/schemas/Exercise" }, "exercise_slide_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmission" } }, "given_peer_or_self_review_question_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestionSubmission" } }, "given_peer_or_self_review_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewSubmissionWithSubmissionOwner" } }, "peer_or_self_review_questions": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestion" } }, "peer_review_queue_entry": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/PeerReviewQueueEntry" } ] }, "received_peer_or_self_review_question_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestionSubmission" } }, "received_peer_or_self_review_submissions": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewSubmissionWithSubmissionOwner" } }, "teacher_grading_decision": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TeacherGradingDecision" } ] }, "user_exercise_state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/UserExerciseState" } ] } } }, "ExerciseSubmissions": { "type": "object", "required": ["data", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ExerciseSlideSubmission" } }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "ExerciseTaskGrading": { "type": "object", "required": [ "id", "created_at", "updated_at", "exercise_task_submission_id", "exercise_id", "exercise_task_id", "grading_priority", "grading_progress" ], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_task_id": { "type": "string", "format": "uuid" }, "exercise_task_submission_id": { "type": "string", "format": "uuid" }, "feedback_json": {}, "feedback_text": { "type": ["string", "null"] }, "grading_completed_at": { "type": ["string", "null"], "format": "date-time" }, "grading_priority": { "type": "integer", "format": "int32" }, "grading_progress": { "$ref": "#/components/schemas/GradingProgress" }, "grading_started_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "score_given": { "type": ["number", "null"], "format": "float" }, "unscaled_score_given": { "type": ["number", "null"], "format": "float" }, "unscaled_score_maximum": { "type": ["integer", "null"], "format": "int32" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ExerciseTaskGradingResult": { "type": "object", "required": ["grading_progress", "score_given", "score_maximum"], "properties": { "feedback_json": {}, "feedback_text": { "type": ["string", "null"] }, "grading_progress": { "$ref": "#/components/schemas/GradingProgress" }, "score_given": { "type": "number", "format": "float" }, "score_maximum": { "type": "integer", "format": "int32" }, "set_user_variables": { "type": ["object", "null"], "additionalProperties": {}, "propertyNames": { "type": "string" } } } }, "ExerciseTaskSubmission": { "type": "object", "required": [ "id", "created_at", "updated_at", "exercise_slide_submission_id", "exercise_task_id", "exercise_slide_id" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "data_json": {}, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_slide_id": { "type": "string", "format": "uuid" }, "exercise_slide_submission_id": { "type": "string", "format": "uuid" }, "exercise_task_grading_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_task_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "metadata": {}, "updated_at": { "type": "string", "format": "date-time" } } }, "ExerciseUserCounts": { "type": "object", "required": [ "exercise_name", "exercise_order_number", "page_order_number", "chapter_number", "exercise_id" ], "properties": { "chapter_number": { "type": "integer", "format": "int32" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_name": { "type": "string" }, "exercise_order_number": { "type": "integer", "format": "int32" }, "n_users_attempted": { "type": ["integer", "null"], "format": "int64" }, "n_users_with_max_points": { "type": ["integer", "null"], "format": "int64" }, "n_users_with_some_points": { "type": ["integer", "null"], "format": "int64" }, "page_order_number": { "type": "integer", "format": "int32" } } }, "ExtendStageRequest": { "type": "object", "required": ["months"], "properties": { "months": { "type": "integer", "format": "int32", "minimum": 0 } } }, "Feedback": { "type": "object", "required": [ "id", "course_id", "feedback_given", "marked_as_read", "created_at", "blocks", "page_title", "page_url_path" ], "properties": { "blocks": { "type": "array", "items": { "$ref": "#/components/schemas/FeedbackBlock" } }, "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "feedback_given": { "type": "string" }, "id": { "type": "string", "format": "uuid" }, "marked_as_read": { "type": "boolean" }, "page_id": { "type": ["string", "null"], "format": "uuid" }, "page_title": { "type": "string" }, "page_url_path": { "type": "string" }, "selected_text": { "type": ["string", "null"] }, "user_id": { "type": ["string", "null"], "format": "uuid" } } }, "FeedbackBlock": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "format": "uuid" }, "order_number": { "type": ["integer", "null"], "format": "int32" }, "text": { "type": ["string", "null"] } } }, "FeedbackCount": { "type": "object", "required": ["read", "unread"], "properties": { "read": { "type": "integer", "format": "int32", "minimum": 0 }, "unread": { "type": "integer", "format": "int32", "minimum": 0 } } }, "FlaggedAnswer": { "type": "object", "required": [ "id", "submission_id", "flagged_user", "flagged_by", "reason", "created_at", "updated_at" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "flagged_by": { "type": "string", "format": "uuid" }, "flagged_user": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "reason": { "$ref": "#/components/schemas/ReportReason" }, "submission_id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" } } }, "GeneratedCertificate": { "type": "object", "required": [ "id", "created_at", "updated_at", "user_id", "name_on_certificate", "verification_id", "certificate_configuration_id" ], "properties": { "certificate_configuration_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "name_on_certificate": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" }, "verification_id": { "type": "string" } } }, "GlobalCourseModuleStatEntry": { "type": "object", "required": [ "course_name", "course_id", "course_module_id", "organization_id", "organization_name", "year", "value" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_module_ects_credits": { "type": ["number", "null"], "format": "float" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "course_name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "organization_name": { "type": "string" }, "value": { "type": "integer", "format": "int64" }, "year": { "type": "string" } } }, "GlobalStatEntry": { "type": "object", "required": [ "course_name", "course_id", "organization_id", "organization_name", "year", "value" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "month": { "type": ["integer", "null"], "format": "int32" }, "organization_id": { "type": "string", "format": "uuid" }, "organization_name": { "type": "string" }, "value": { "type": "integer", "format": "int64" }, "year": { "type": "integer", "format": "int32" } } }, "GradingProgress": { "type": "string", "description": "\n\nTells what's the status of the grading progress for a user and exercise.\n\nAs close as possible LTI's grading progress for compatibility: ", "enum": ["Failed", "NotReady", "PendingManual", "Pending", "FullyGraded"] }, "GutenbergBlock": { "type": "object", "required": ["clientId", "name", "isValid", "attributes", "innerBlocks"], "properties": { "attributes": { "type": "object", "additionalProperties": {}, "propertyNames": { "type": "string" } }, "clientId": { "type": "string", "format": "uuid" }, "innerBlocks": { "type": "array", "items": { "$ref": "#/components/schemas/GutenbergBlock" } }, "isValid": { "type": "boolean" }, "name": { "type": "string" } } }, "HealthStatus": { "type": "string", "enum": ["healthy", "warning", "error"] }, "HistoryChangeReason": { "type": "string", "enum": ["PageSaved", "HistoryRestored", "PageDeleted"] }, "HistoryRestoreData": { "type": "object", "required": ["history_id"], "properties": { "history_id": { "type": "string", "format": "uuid" } } }, "IngressInfo": { "type": "object", "required": ["name", "hosts", "paths"], "properties": { "class_name": { "type": ["string", "null"] }, "hosts": { "type": "array", "items": { "type": "string" } }, "name": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } } } }, "JobInfo": { "type": "object", "required": ["name"], "properties": { "active": { "type": ["integer", "null"], "format": "int32" }, "failed": { "type": ["integer", "null"], "format": "int32" }, "name": { "type": "string" }, "succeeded": { "type": ["integer", "null"], "format": "int32" } } }, "JoinCourseWithJoinCodePayload": { "type": "object", "required": ["join_code"], "properties": { "join_code": { "type": "string" } } }, "LinkingEmailStatus": { "type": "object", "description": "What we can honestly say about the linking mail: our send status, never a delivery.", "required": ["email_send_status", "emailed_to_masked"], "properties": { "email_send_status": { "$ref": "#/components/schemas/EmailSendStatus" }, "emailed_to_masked": { "type": "string" }, "sent_at": { "type": ["string", "null"], "format": "date-time" } } }, "ManualCompletionPreview": { "type": "object", "required": [ "already_completed_users", "first_time_completing_users", "non_enrolled_users" ], "properties": { "already_completed_users": { "type": "array", "items": { "$ref": "#/components/schemas/ManualCompletionPreviewUser" } }, "first_time_completing_users": { "type": "array", "items": { "$ref": "#/components/schemas/ManualCompletionPreviewUser" } }, "non_enrolled_users": { "type": "array", "items": { "$ref": "#/components/schemas/ManualCompletionPreviewUser" } } } }, "ManualCompletionPreviewUser": { "type": "object", "required": ["user_id", "passed"], "properties": { "first_name": { "type": ["string", "null"] }, "grade": { "type": ["integer", "null"], "format": "int32" }, "last_name": { "type": ["string", "null"] }, "passed": { "type": "boolean" }, "previous_best_grade": { "type": ["integer", "null"], "format": "int32" }, "user_id": { "type": "string", "format": "uuid" } } }, "MarkAsRead": { "type": "object", "required": ["read"], "properties": { "read": { "type": "boolean" } } }, "MaterialReference": { "type": "object", "required": ["id", "course_id", "citation_key", "reference", "created_at", "updated_at"], "properties": { "citation_key": { "type": "string" }, "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "reference": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "ModelType": { "type": "string", "enum": ["GPTThinking", "GPTNonThinking", "GPTHardThinking", "Mistral"] }, "ModifiedModule": { "type": "object", "required": [ "id", "order_number", "completion_policy", "enable_registering_completion_to_uh_open_university", "enable_credit_registration_via_suotar", "credit_registration" ], "properties": { "completion_policy": { "$ref": "#/components/schemas/CompletionPolicy" }, "completion_registration_link_override": { "type": ["string", "null"] }, "credit_registration": { "$ref": "#/components/schemas/CourseModuleCreditRegistrationEdit" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "enable_credit_registration_via_suotar": { "type": "boolean" }, "enable_registering_completion_to_uh_open_university": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": ["string", "null"] }, "order_number": { "type": "integer", "format": "int32" }, "uh_course_code": { "type": ["string", "null"] } } }, "Module": { "type": "object", "required": ["course_code", "description", "prerequisites"], "properties": { "course_code": { "type": "string" }, "description": { "type": "string" }, "prerequisites": { "type": "array", "items": { "type": "string" } } } }, "ModuleUpdates": { "type": "object", "required": ["new_modules", "deleted_modules", "modified_modules", "moved_chapters"], "properties": { "deleted_modules": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "modified_modules": { "type": "array", "items": { "$ref": "#/components/schemas/ModifiedModule" } }, "moved_chapters": { "type": "array", "items": { "type": "array", "items": false, "prefixItems": [ { "type": "string", "format": "uuid" }, { "type": "string", "format": "uuid" } ] } }, "new_modules": { "type": "array", "items": { "$ref": "#/components/schemas/NewModule" } } } }, "MyCourse": { "allOf": [ { "$ref": "#/components/schemas/Course" }, { "type": "object", "required": ["can_hide"], "properties": { "can_hide": { "type": "boolean", "description": "Whether the course can be hidden from the \"My courses\" list. False for courses the user has\nnot enrolled in or has a role in." } } } ] }, "MyCourseCreditRegistrationConsent": { "type": "object", "required": [ "course_id", "course_name", "asked", "credit_registration_enabled_for_course", "modules", "registrable_completion_count" ], "properties": { "asked": { "type": "boolean", "description": "False means never asked, which is not the same as asked and declined." }, "consent_given": { "type": ["boolean", "null"] }, "consent_given_at": { "type": ["string", "null"], "format": "date-time" }, "consent_withdrawn_at": { "type": ["string", "null"], "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "credit_registration_enabled_for_course": { "type": "boolean" }, "modules": { "type": "array", "items": { "$ref": "#/components/schemas/CreditRegistrationConsentModule" } }, "registrable_completion_count": { "type": "integer", "format": "int64", "description": "Completions already waiting on consent, so the dialog can say how many one click registers." } } }, "MyCreditRegistration": { "type": "object", "required": [ "id", "course_id", "course_name", "course_slug", "course_module_id", "completion_date", "student_facing_status", "consent_withdrawn_while_in_flight", "status_is_moving", "next_attempt_at", "attempt_number", "superseded", "can_request_enrolment_recheck" ], "properties": { "attempt_number": { "type": "integer", "format": "int32" }, "can_request_enrolment_recheck": { "type": "boolean" }, "completion_date": { "type": "string", "format": "date-time" }, "consent_withdrawn_while_in_flight": { "type": "boolean", "description": "The one thing the page needs beyond the status: the outcome of an import that was already in\nflight is unknown, so it gets its own copy.\n\nThe ledger state itself is deliberately not on the wire. Eligibility includes\n`NOT needs_to_be_reviewed`, so `blocked` would tell a student they have been flagged as a\nsuspected cheater — which `users.rs` hides from them for that exact reason. Every cause of\n`not_registering` has to stay indistinguishable here." }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": ["string", "null"] }, "course_name": { "type": "string" }, "course_slug": { "type": "string" }, "credits": { "type": ["number", "null"], "format": "float" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "enrolment_link": { "type": ["string", "null"], "description": "The open university enrolment page, for a row the study registry has no enrolment for." }, "enrolment_realisation_name": { "type": ["string", "null"] }, "error_code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CreditRegistrationErrorCode" } ] }, "grade_id": { "type": ["string", "null"] }, "grade_scale_id": { "type": ["string", "null"], "description": "Names the scale `grade_id` is on, without which \"1\" reads as a one out of five when it means\na pass." }, "id": { "type": "string", "format": "uuid" }, "linking_email": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/LinkingEmailStatus", "description": "Only on a row waiting for a student number whose account was linked at some point: the mail is\naddressed to a Sisu person, and a never-linked account names none." } ] }, "next_attempt_at": { "type": "string", "format": "date-time" }, "registered_at": { "type": ["string", "null"], "format": "date-time" }, "sisu_attainment_id": { "type": ["string", "null"] }, "status_is_moving": { "type": "boolean", "description": "Whether the pipeline is still expected to move this row: drives the status page's polling." }, "student_facing_status": { "$ref": "#/components/schemas/StudentFacingCreditRegistrationStatus" }, "superseded": { "type": "boolean" }, "uh_course_code": { "type": ["string", "null"] } } }, "MyCreditRegistrationConsent": { "type": "object", "required": [ "course_id", "course_name", "registrable_completion_count", "registered_count" ], "properties": { "asked_at": { "type": ["string", "null"], "format": "date-time" }, "consent_given": { "type": ["boolean", "null"] }, "consent_given_at": { "type": ["string", "null"], "format": "date-time" }, "consent_withdrawn_at": { "type": ["string", "null"], "format": "date-time" }, "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "registered_count": { "type": "integer", "format": "int64" }, "registrable_completion_count": { "type": "integer", "format": "int64" } } }, "MyCreditRegistrationForCourseModule": { "type": "object", "description": "The live registration for one course module, with the attempts a newer one replaced.", "required": ["registration", "earlier_attempts"], "properties": { "earlier_attempts": { "type": "array", "items": { "$ref": "#/components/schemas/MyCreditRegistration" }, "description": "The module's other rows, newest completion first. Shown because the study registry may hold an\nearlier attempt's attainment as well as the current one's." }, "registration": { "$ref": "#/components/schemas/MyCreditRegistration" } } }, "MyStudies": { "type": "object", "required": ["any_module_supports_credit_registration", "courses", "totals"], "properties": { "any_module_supports_credit_registration": { "type": "boolean", "description": "Drives whether the profile's credit-registration tab renders. Covers hidden courses too:\nhiding a course must not take away access to registering its credits." }, "courses": { "type": "array", "items": { "$ref": "#/components/schemas/MyStudiesCourse" } }, "totals": { "$ref": "#/components/schemas/MyStudiesTotals" } } }, "MyStudiesCompletion": { "type": "object", "description": "A completion as the student may see it. `needs_to_be_reviewed` ones are excluded so a student\ncannot infer that they are under suspicion.", "required": [ "course_module_completion_id", "completion_date", "passed", "prerequisite_modules_completed" ], "properties": { "completion_date": { "type": "string", "format": "date-time" }, "course_module_completion_id": { "type": "string", "format": "uuid" }, "grade": { "type": ["integer", "null"], "format": "int32", "description": "`None` on pass/fail modules; the frontend falls back to `passed`." }, "passed": { "type": "boolean" }, "prerequisite_modules_completed": { "type": "boolean" } } }, "MyStudiesCourse": { "type": "object", "required": [ "course_id", "course_name", "course_slug", "organization_slug", "language_code", "first_enrolled_at", "is_current", "hidden", "supports_credit_registration", "modules" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "course_slug": { "type": "string" }, "current_course_instance_id": { "type": ["string", "null"], "format": "uuid", "description": "The instance the per-module progress is fetched for. `None` if the enrolment has no instance." }, "current_course_instance_name": { "type": ["string", "null"] }, "first_enrolled_at": { "type": "string", "format": "date-time" }, "hidden": { "type": "boolean", "description": "Hidden courses are included here, unlike in `getMyCourses`, so the profile can offer unhiding." }, "is_current": { "type": "boolean", "description": "False when the student's active version of this course is a different language version." }, "language_code": { "type": "string" }, "modules": { "type": "array", "items": { "$ref": "#/components/schemas/MyStudiesCourseModule" } }, "organization_slug": { "type": "string" }, "supports_credit_registration": { "type": "boolean" } } }, "MyStudiesCourseModule": { "type": "object", "description": "A course module as the student's own profile shows it, with their best visible completion.", "required": ["course_module_id", "order_number", "supports_credit_registration"], "properties": { "completion": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/MyStudiesCompletion", "description": "`None` when no completion may be shown to the student. May be a failed one, so check `passed`." } ] }, "course_module_id": { "type": "string", "format": "uuid" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "name": { "type": ["string", "null"], "description": "`None` for the course's default module; the frontend labels those with the course name." }, "order_number": { "type": "integer", "format": "int32" }, "supports_credit_registration": { "type": "boolean" }, "uh_course_code": { "type": ["string", "null"] } } }, "MyStudiesTotals": { "type": "object", "description": "Summarises the courses the profile lists, i.e. the non-hidden ones.", "required": ["courses", "completions", "ects"], "properties": { "completions": { "type": "integer", "format": "int32", "description": "Counts passed completions only." }, "courses": { "type": "integer", "format": "int32" }, "ects": { "type": "number", "format": "float", "description": "Summed over passed completions only." } } }, "MyVerifiedStudentNumber": { "type": "object", "description": "The account's linked student number, unmasked: it is the holder's own.", "required": ["student_number", "verified_at", "verified_via"], "properties": { "first_names": { "type": ["string", "null"] }, "last_name": { "type": ["string", "null"] }, "student_number": { "type": "string" }, "verified_at": { "type": "string", "format": "date-time" }, "verified_via": { "$ref": "#/components/schemas/StudentNumberVerificationMethod" }, "verified_via_email_masked": { "type": ["string", "null"], "description": "The Sisu-held address the proof rests on, masked; `None` when support linked it by hand." } } }, "NewChapter": { "type": "object", "required": ["name", "course_id", "chapter_number"], "properties": { "chapter_number": { "type": "integer", "format": "int32" }, "color": { "type": ["string", "null"] }, "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": ["string", "null"], "format": "uuid", "description": "If undefined when creating a chapter, will use the course default one.\nCHANGE TO NON NULL WHEN FRONTEND MODULE EDITING IMPLEMENTED" }, "deadline": { "type": ["string", "null"], "format": "date-time" }, "front_page_id": { "type": ["string", "null"], "format": "uuid" }, "name": { "type": "string" }, "opens_at": { "type": ["string", "null"], "format": "date-time" } } }, "NewChatbotConf": { "type": "object", "required": [ "enabled_to_students", "chatbot_name", "model_id", "prompt", "initial_message", "weekly_tokens_per_user", "daily_tokens_per_user", "temperature", "top_p", "frequency_penalty", "presence_penalty", "max_output_tokens", "verbosity", "reasoning_effort", "use_azure_search", "maintain_azure_search_index", "hide_citations", "use_semantic_reranking", "use_tools", "default_chatbot", "suggest_next_messages", "publicly_accessible" ], "properties": { "chatbot_name": { "type": "string" }, "chatbotconf_id": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "daily_tokens_per_user": { "type": "integer", "format": "int32" }, "default_chatbot": { "type": "boolean" }, "enabled_to_students": { "type": "boolean" }, "frequency_penalty": { "type": "number", "format": "float" }, "hide_citations": { "type": "boolean" }, "initial_message": { "type": "string" }, "initial_suggested_messages": { "type": ["array", "null"], "items": { "type": "string" } }, "maintain_azure_search_index": { "type": "boolean" }, "max_output_tokens": { "type": "integer", "format": "int32" }, "model_id": { "type": "string", "format": "uuid" }, "presence_penalty": { "type": "number", "format": "float" }, "prompt": { "type": "string" }, "publicly_accessible": { "type": "boolean" }, "reasoning_effort": { "$ref": "#/components/schemas/ReasoningEffortLevel" }, "suggest_next_messages": { "type": "boolean" }, "temperature": { "type": "number", "format": "float" }, "top_p": { "type": "number", "format": "float" }, "use_azure_search": { "type": "boolean" }, "use_semantic_reranking": { "type": "boolean" }, "use_tools": { "type": "boolean" }, "verbosity": { "$ref": "#/components/schemas/VerbosityLevel" }, "weekly_tokens_per_user": { "type": "integer", "format": "int32" } } }, "NewCodeGiveaway": { "type": "object", "required": ["course_id", "name"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": ["string", "null"], "format": "uuid" }, "name": { "type": "string" }, "require_course_specific_consent_form_question_id": { "type": ["string", "null"], "format": "uuid" } } }, "NewCourse": { "type": "object", "description": "Represents the subset of page fields that are required to create a new course.", "required": [ "name", "slug", "organization_id", "language_code", "teacher_in_charge_name", "teacher_in_charge_email", "description", "is_draft", "is_test_mode", "is_unlisted", "copy_user_permissions", "is_joinable_by_code_only", "ask_marketing_consent", "can_add_chatbot" ], "properties": { "ask_marketing_consent": { "type": "boolean" }, "can_add_chatbot": { "type": "boolean" }, "copy_user_permissions": { "type": "boolean", "description": "If true, copies all user permissions from the original course to the new one." }, "description": { "type": "string" }, "flagged_answers_threshold": { "type": ["integer", "null"], "format": "int32" }, "is_draft": { "type": "boolean" }, "is_joinable_by_code_only": { "type": "boolean" }, "is_test_mode": { "type": "boolean" }, "is_unlisted": { "type": "boolean" }, "join_code": { "type": ["string", "null"] }, "language_code": { "type": "string" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "slug": { "type": "string" }, "teacher_in_charge_email": { "type": "string", "description": "Email of the teacher who is responsible for the course. Must be a valid email." }, "teacher_in_charge_name": { "type": "string", "description": "Name of the teacher who is responsible for the course. Must be a valid name." } } }, "NewCourseAudience": { "type": "object", "required": ["audience"], "properties": { "audience": { "type": "string" } } }, "NewCoursePrerequisite": { "type": "object", "required": ["prerequisite"], "properties": { "prerequisite": { "type": "string" } } }, "NewExam": { "type": "object", "required": [ "name", "time_minutes", "organization_id", "minimum_points_treshold", "grade_manually" ], "properties": { "ends_at": { "type": ["string", "null"], "format": "date-time" }, "grade_manually": { "type": "boolean" }, "minimum_points_treshold": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "starts_at": { "type": ["string", "null"], "format": "date-time" }, "time_minutes": { "type": "integer", "format": "int32" } } }, "NewExerciseRepository": { "type": "object", "required": ["git_url"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "deploy_key": { "type": ["string", "null"] }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "git_url": { "type": "string" }, "public_key": { "type": ["string", "null"] } } }, "NewMaterialReference": { "type": "object", "required": ["citation_key", "reference"], "properties": { "citation_key": { "type": "string" }, "reference": { "type": "string" } } }, "NewModule": { "type": "object", "required": [ "name", "order_number", "chapters", "completion_policy", "enable_registering_completion_to_uh_open_university", "enable_credit_registration_via_suotar", "credit_registration" ], "properties": { "chapters": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "completion_policy": { "$ref": "#/components/schemas/CompletionPolicy" }, "completion_registration_link_override": { "type": ["string", "null"] }, "credit_registration": { "$ref": "#/components/schemas/CourseModuleCreditRegistrationEdit" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "enable_credit_registration_via_suotar": { "type": "boolean" }, "enable_registering_completion_to_uh_open_university": { "type": "boolean" }, "name": { "type": "string" }, "order_number": { "type": "integer", "format": "int32" }, "uh_course_code": { "type": ["string", "null"] } } }, "NewPage": { "type": "object", "description": "Represents the subset of page fields that are required to create a new page.", "required": [ "exercises", "exercise_slides", "exercise_tasks", "content", "url_path", "title", "hidden" ], "properties": { "chapter_id": { "type": ["string", "null"], "format": "uuid" }, "content": { "type": "array", "items": { "$ref": "#/components/schemas/GutenbergBlock" } }, "content_search_language": { "type": ["string", "null"], "description": "Read from the course's settings if None. If course_id is None as well, defaults to \"simple\"" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_slides": { "type": "array", "items": { "$ref": "#/components/schemas/CmsPageExerciseSlide" } }, "exercise_tasks": { "type": "array", "items": { "$ref": "#/components/schemas/CmsPageExerciseTask" } }, "exercises": { "type": "array", "items": { "$ref": "#/components/schemas/CmsPageExercise" } }, "front_page_of_chapter_id": { "type": ["string", "null"], "format": "uuid", "description": "If set, set this page to be the front page of this course part." }, "hidden": { "type": "boolean" }, "title": { "type": "string" }, "url_path": { "type": "string" } } }, "NewRegrading": { "type": "object", "required": ["user_points_update_strategy", "ids", "id_type"], "properties": { "id_type": { "$ref": "#/components/schemas/NewRegradingIdType" }, "ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "user_points_update_strategy": { "$ref": "#/components/schemas/UserPointsUpdateStrategy" } } }, "NewRegradingIdType": { "type": "string", "enum": ["ExerciseTaskSubmissionId", "ExerciseId"] }, "NewTeacherGradingDecision": { "type": "object", "required": ["user_exercise_state_id", "exercise_id", "action", "hidden"], "properties": { "action": { "$ref": "#/components/schemas/TeacherDecisionType" }, "exercise_id": { "type": "string", "format": "uuid" }, "hidden": { "type": "boolean" }, "justification": { "type": ["string", "null"] }, "manual_points": { "type": ["number", "null"], "format": "float" }, "user_exercise_state_id": { "type": "string", "format": "uuid" } } }, "OrgExam": { "type": "object", "required": [ "id", "created_at", "updated_at", "name", "instructions", "time_minutes", "organization_id", "minimum_points_treshold", "grade_manually" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "ends_at": { "type": ["string", "null"], "format": "date-time" }, "grade_manually": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "instructions": {}, "language": { "type": ["string", "null"] }, "minimum_points_treshold": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "organization_id": { "type": "string", "format": "uuid" }, "starts_at": { "type": ["string", "null"], "format": "date-time" }, "time_minutes": { "type": "integer", "format": "int32" }, "updated_at": { "type": "string", "format": "date-time" } } }, "Organization": { "type": "object", "required": ["id", "slug", "created_at", "updated_at", "name", "hidden"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "description": { "type": ["string", "null"] }, "hidden": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "organization_image_url": { "type": ["string", "null"] }, "slug": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "OrganizationCreatePayload": { "type": "object", "required": ["name", "slug", "hidden"], "properties": { "hidden": { "type": "boolean" }, "name": { "type": "string" }, "slug": { "type": "string" } } }, "OrganizationUpdatePayload": { "type": "object", "required": ["name", "hidden", "slug"], "properties": { "hidden": { "type": "boolean" }, "name": { "type": "string" }, "slug": { "type": "string" } } }, "Page": { "type": "object", "required": [ "id", "created_at", "updated_at", "url_path", "title", "content", "order_number", "hidden" ], "properties": { "chapter_id": { "type": ["string", "null"], "format": "uuid" }, "content": {}, "copied_from": { "type": ["string", "null"], "format": "uuid" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "hidden": { "type": "boolean" }, "id": { "type": "string", "format": "uuid" }, "order_number": { "type": "integer", "format": "int32" }, "page_language_group_id": { "type": ["string", "null"], "format": "uuid" }, "title": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" }, "url_path": { "type": "string" } } }, "PageAudioFile": { "type": "object", "required": ["id", "page_id", "created_at", "path", "mime_type"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "mime_type": { "type": "string" }, "page_id": { "type": "string", "format": "uuid" }, "path": { "type": "string" } } }, "PageDetailsUpdate": { "type": "object", "description": "Represents the subset of page fields that can be updated from the main frontend dialog \"Edit page details\".", "required": ["title", "url_path"], "properties": { "title": { "type": "string" }, "url_path": { "type": "string" } } }, "PageHistory": { "type": "object", "required": [ "id", "created_at", "updated_at", "title", "content", "history_change_reason", "author_user_id", "page_id" ], "properties": { "author_user_id": { "type": "string", "format": "uuid" }, "content": {}, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "history_change_reason": { "$ref": "#/components/schemas/HistoryChangeReason" }, "id": { "type": "string", "format": "uuid" }, "page_id": { "type": "string", "format": "uuid" }, "restored_from_id": { "type": ["string", "null"], "format": "uuid" }, "title": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "PageInfo": { "type": "object", "required": ["page_id", "page_title"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "course_name": { "type": ["string", "null"] }, "course_slug": { "type": ["string", "null"] }, "organization_slug": { "type": ["string", "null"] }, "page_id": { "type": "string", "format": "uuid" }, "page_title": { "type": "string" } } }, "PageProposal": { "type": "object", "required": [ "id", "page_id", "pending", "created_at", "block_proposals", "page_title", "page_url_path" ], "properties": { "block_proposals": { "type": "array", "items": { "$ref": "#/components/schemas/BlockProposal" } }, "created_at": { "type": "string", "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "page_id": { "type": "string", "format": "uuid" }, "page_title": { "type": "string" }, "page_url_path": { "type": "string" }, "pending": { "type": "boolean" }, "user_id": { "type": ["string", "null"], "format": "uuid" } } }, "PageVisitDatumSummaryByCourse": { "type": "object", "required": ["id", "created_at", "updated_at", "num_visitors", "visit_date"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "num_visitors": { "type": "integer", "format": "int32" }, "referrer": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" }, "utm_campaign": { "type": ["string", "null"] }, "utm_content": { "type": ["string", "null"] }, "utm_medium": { "type": ["string", "null"] }, "utm_source": { "type": ["string", "null"] }, "utm_term": { "type": ["string", "null"] }, "visit_date": { "type": "string", "format": "date" } } }, "PageVisitDatumSummaryByCourseDeviceTypes": { "type": "object", "required": ["id", "created_at", "updated_at", "num_visitors", "visit_date"], "properties": { "browser": { "type": ["string", "null"] }, "browser_version": { "type": ["string", "null"] }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "device_type": { "type": ["string", "null"] }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "num_visitors": { "type": "integer", "format": "int32" }, "operating_system": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" }, "visit_date": { "type": "string", "format": "date" } } }, "PageVisitDatumSummaryByCoursesCountries": { "type": "object", "required": ["id", "created_at", "updated_at", "num_visitors", "visit_date"], "properties": { "country": { "type": ["string", "null"] }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "num_visitors": { "type": "integer", "format": "int32" }, "updated_at": { "type": "string", "format": "date-time" }, "visit_date": { "type": "string", "format": "date" } } }, "PageVisitDatumSummaryByPages": { "type": "object", "required": ["id", "created_at", "updated_at", "page_id", "num_visitors", "visit_date"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "num_visitors": { "type": "integer", "format": "int32" }, "page_id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "visit_date": { "type": "string", "format": "date" } } }, "PaperSize": { "type": "string", "enum": ["horizontal-a4", "vertical-a4"] }, "PeerOrSelfReviewAnswer": { "oneOf": [ { "type": "object", "required": ["type"], "properties": { "type": { "type": "string", "enum": ["no-answer"] } } }, { "type": "object", "required": ["value", "type"], "properties": { "type": { "type": "string", "enum": ["essay"] }, "value": { "type": "string" } } }, { "type": "object", "required": ["value", "type"], "properties": { "type": { "type": "string", "enum": ["scale"] }, "value": { "type": "number", "format": "float" } } } ] }, "PeerOrSelfReviewQuestion": { "type": "object", "required": [ "id", "created_at", "updated_at", "peer_or_self_review_config_id", "order_number", "question", "question_type", "answer_required", "weight" ], "properties": { "answer_required": { "type": "boolean" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "order_number": { "type": "integer", "format": "int32" }, "peer_or_self_review_config_id": { "type": "string", "format": "uuid" }, "question": { "type": "string" }, "question_type": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestionType" }, "updated_at": { "type": "string", "format": "date-time" }, "weight": { "type": "number", "format": "float" } } }, "PeerOrSelfReviewQuestionAndAnswer": { "type": "object", "required": [ "peer_or_self_review_config_id", "peer_or_self_review_question_id", "peer_or_self_review_submission_id", "peer_review_question_submission_id", "order_number", "question", "answer", "answer_required" ], "properties": { "answer": { "$ref": "#/components/schemas/PeerOrSelfReviewAnswer" }, "answer_required": { "type": "boolean" }, "order_number": { "type": "integer", "format": "int32" }, "peer_or_self_review_config_id": { "type": "string", "format": "uuid" }, "peer_or_self_review_question_id": { "type": "string", "format": "uuid" }, "peer_or_self_review_submission_id": { "type": "string", "format": "uuid" }, "peer_review_question_submission_id": { "type": "string", "format": "uuid" }, "question": { "type": "string" } } }, "PeerOrSelfReviewQuestionSubmission": { "type": "object", "required": [ "id", "created_at", "updated_at", "peer_or_self_review_question_id", "peer_or_self_review_submission_id" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "number_data": { "type": ["number", "null"], "format": "float" }, "peer_or_self_review_question_id": { "type": "string", "format": "uuid" }, "peer_or_self_review_submission_id": { "type": "string", "format": "uuid" }, "text_data": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" } } }, "PeerOrSelfReviewQuestionType": { "type": "string", "enum": ["Essay", "Scale"] }, "PeerOrSelfReviewSubmission": { "type": "object", "required": [ "id", "created_at", "updated_at", "user_id", "exercise_id", "course_id", "peer_or_self_review_config_id", "exercise_slide_submission_id" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_id": { "type": "string", "format": "uuid" }, "exercise_slide_submission_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "peer_or_self_review_config_id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "PeerOrSelfReviewSubmissionWithSubmissionOwner": { "allOf": [ { "$ref": "#/components/schemas/PeerOrSelfReviewSubmission" }, { "type": "object", "properties": { "submission_owner_user_id": { "type": ["string", "null"], "format": "uuid" } } } ], "description": "Same as PeerOrSelfReviewSubmission with optional submission owner (user who received the review). Used for \"given\" reviews." }, "PeerReviewProcessingStrategy": { "type": "string", "description": "\nDetermines how we will treat the answer being peer reviewed once it has received enough reviews and the student has given enough peer reviews.\n\nSome strategies compare the overall received peer review likert answer (1-5) average to peer_reviews.accepting threshold.", "enum": [ "AutomaticallyGradeByAverage", "AutomaticallyGradeOrManualReviewByAverage", "ManualReviewEverything" ] }, "PeerReviewQueueEntry": { "type": "object", "required": [ "id", "created_at", "updated_at", "user_id", "exercise_id", "course_id", "receiving_peer_reviews_exercise_slide_submission_id", "received_enough_peer_reviews", "peer_review_priority", "removed_from_queue_for_unusual_reason" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exercise_id": { "type": "string", "format": "uuid" }, "id": { "type": "string", "format": "uuid" }, "peer_review_priority": { "type": "integer", "format": "int32" }, "received_enough_peer_reviews": { "type": "boolean" }, "receiving_peer_reviews_exercise_slide_submission_id": { "type": "string", "format": "uuid" }, "removed_from_queue_for_unusual_reason": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "PeerReviewWithQuestionsAndAnswers": { "type": "object", "required": [ "peer_or_self_review_submission_id", "peer_review_giver_user_id", "questions_and_answers" ], "properties": { "peer_or_self_review_submission_id": { "type": "string", "format": "uuid" }, "peer_review_giver_user_id": { "type": "string", "format": "uuid" }, "questions_and_answers": { "type": "array", "items": { "$ref": "#/components/schemas/PeerOrSelfReviewQuestionAndAnswer" } } } }, "PendingRole": { "type": "object", "required": ["id", "created_at", "updated_at", "user_email", "role", "expires_at"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "course_instance_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "expires_at": { "type": "string", "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "role": { "$ref": "#/components/schemas/UserRole" }, "updated_at": { "type": "string", "format": "date-time" }, "user_email": { "type": "string" } } }, "PlanMemberWithDetails": { "type": "object", "required": ["id", "user_id", "email", "created_at"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "email": { "type": "string", "format": "email" }, "first_name": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "last_name": { "type": ["string", "null"] }, "user_id": { "type": "string", "format": "uuid" } } }, "PlaygroundExample": { "type": "object", "required": ["id", "created_at", "updated_at", "name", "url", "width", "data"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "data": {}, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" }, "url": { "type": "string" }, "width": { "type": "integer", "format": "int32" } } }, "PlaygroundExampleData": { "type": "object", "required": ["name", "url", "width", "data"], "properties": { "data": {}, "name": { "type": "string" }, "url": { "type": "string" }, "width": { "type": "integer", "format": "int32" } } }, "PodDisruptionBudgetInfo": { "type": "object", "required": [ "name", "current_healthy", "desired_healthy", "disruptions_allowed", "expected_pods", "selector_labels" ], "properties": { "current_healthy": { "type": "integer", "format": "int32" }, "desired_healthy": { "type": "integer", "format": "int32" }, "disruptions_allowed": { "type": "integer", "format": "int32" }, "expected_pods": { "type": "integer", "format": "int32" }, "name": { "type": "string" }, "selector_labels": { "type": "object", "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" } } } }, "PodInfo": { "type": "object", "required": ["name", "phase", "labels"], "properties": { "labels": { "type": "object", "additionalProperties": { "type": "string" }, "propertyNames": { "type": "string" } }, "name": { "type": "string" }, "phase": { "type": "string" }, "ready": { "type": ["boolean", "null"] } } }, "PointMap": { "type": "object", "additionalProperties": { "type": "number", "format": "float" }, "propertyNames": { "type": "string", "format": "uuid" } }, "Points": { "type": "object", "required": ["chapter_points", "users", "user_chapter_points"], "properties": { "chapter_points": { "type": "array", "items": { "$ref": "#/components/schemas/ChapterScore" } }, "user_chapter_points": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/PointMap" }, "propertyNames": { "type": "string", "format": "uuid" } }, "users": { "type": "array", "items": { "$ref": "#/components/schemas/UserDetail" } } } }, "ProposalCount": { "type": "object", "required": ["pending", "handled"], "properties": { "handled": { "type": "integer", "format": "int32", "minimum": 0 }, "pending": { "type": "integer", "format": "int32", "minimum": 0 } } }, "ProposalStatus": { "type": "string", "enum": ["Pending", "Accepted", "Rejected"] }, "ReasoningEffortLevel": { "type": "string", "enum": ["none", "minimal", "low", "medium", "high", "xhigh"] }, "Regrading": { "type": "object", "required": [ "id", "created_at", "updated_at", "total_grading_progress", "user_points_update_strategy" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "error_message": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "regrading_completed_at": { "type": ["string", "null"], "format": "date-time" }, "regrading_started_at": { "type": ["string", "null"], "format": "date-time" }, "total_grading_progress": { "$ref": "#/components/schemas/GradingProgress" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": ["string", "null"], "format": "uuid" }, "user_points_update_strategy": { "$ref": "#/components/schemas/UserPointsUpdateStrategy" } } }, "RegradingInfo": { "type": "object", "required": ["regrading", "submission_infos"], "properties": { "regrading": { "$ref": "#/components/schemas/Regrading" }, "submission_infos": { "type": "array", "items": { "$ref": "#/components/schemas/RegradingSubmissionInfo" } } } }, "RegradingSubmissionInfo": { "type": "object", "required": ["exercise_task_submission_id", "grading_before_regrading"], "properties": { "exercise_task_submission_id": { "type": "string", "format": "uuid" }, "grading_after_regrading": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ExerciseTaskGrading" } ] }, "grading_before_regrading": { "$ref": "#/components/schemas/ExerciseTaskGrading" } } }, "ReportReason": { "type": "string", "enum": ["Spam", "HarmfulContent", "AiGenerated"] }, "RequestCreditRegistrationEnrolmentRecheckResult": { "type": "object", "required": ["recheck_started"], "properties": { "next_recheck_allowed_at": { "type": ["string", "null"], "format": "date-time" }, "recheck_started": { "type": "boolean", "description": "False when we looked so recently that asking again would tell the student nothing new." } } }, "RequestEmailVerificationOutcome": { "type": "string", "enum": ["queued", "already_verified", "recently_sent"] }, "RequestEmailVerificationPayload": { "type": "object", "required": ["language"], "properties": { "language": { "type": "string", "description": "Which language to mail. Falls back to English when no template exists for it." } } }, "ResearchFormQuestionAnswer": { "type": "object", "required": [ "id", "user_id", "course_id", "research_form_question_id", "research_consent", "created_at", "updated_at" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "research_consent": { "type": "boolean" }, "research_form_question_id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "ResendLinkingEmailOutcome": { "type": "string", "enum": [ "queued", "already_mailed_to_every_known_address", "refused_by_rate_cap", "no_address_in_study_registry", "not_on_the_course_roster", "no_student_number_known", "already_linked", "study_registry_unavailable" ] }, "ResendLinkingEmailPayload": { "type": "object", "properties": { "reason": { "type": ["string", "null"] }, "student_number": { "type": ["string", "null"] }, "user_id": { "type": ["string", "null"], "format": "uuid", "description": "One of the two names the person; `user_id` only resolves for an account that has held a number." } } }, "ResendLinkingEmailResult": { "type": "object", "required": ["outcome", "mails_sent_for_this_course", "max_mails_per_person_and_course"], "properties": { "linking_email": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TeacherLinkingEmailStatus", "description": "The latest mail for this person and course after the attempt, whatever the outcome." } ] }, "mails_sent_for_this_course": { "type": "integer", "format": "int64" }, "max_mails_per_person_and_course": { "type": "integer", "format": "int64" }, "outcome": { "$ref": "#/components/schemas/ResendLinkingEmailOutcome" } } }, "ResetExercisesPayload": { "type": "object", "required": [ "user_ids", "exercise_ids", "reset_all_below_max_points", "reset_only_locked_peer_reviews" ], "properties": { "exercise_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "reset_all_below_max_points": { "type": "boolean" }, "reset_only_locked_peer_reviews": { "type": "boolean" }, "threshold": { "type": ["number", "null"], "format": "double" }, "user_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "ResetPasswordData": { "type": "object", "required": ["token", "new_password"], "properties": { "new_password": { "type": "string" }, "token": { "type": "string" } } }, "ResetPasswordTokenPayload": { "type": "object", "required": ["token"], "properties": { "token": { "type": "string" } } }, "ReviewingStage": { "type": "string", "description": "\nTells what stage of reviewing the user is currently in. Used for for peer review, self review, and manual review. If an exercise does not involve reviewing, the value of this stage will always be `NotStarted`.", "enum": [ "NotStarted", "PeerReview", "SelfReview", "WaitingForPeerReviews", "WaitingForManualGrading", "ReviewedAndLocked", "Locked", "NotAnsweredAndLocked" ] }, "Role": { "type": "object", "required": ["is_global", "role", "user_id"], "properties": { "course_id": { "type": ["string", "null"], "format": "uuid" }, "course_instance_id": { "type": ["string", "null"], "format": "uuid" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "is_global": { "type": "boolean" }, "organization_id": { "type": ["string", "null"], "format": "uuid" }, "role": { "$ref": "#/components/schemas/UserRole" }, "user_id": { "type": "string", "format": "uuid" } } }, "RoleDomain": { "oneOf": [ { "type": "object", "required": ["tag"], "properties": { "tag": { "type": "string", "enum": ["Global"] } } }, { "type": "object", "required": ["id", "tag"], "properties": { "id": { "type": "string", "format": "uuid" }, "tag": { "type": "string", "enum": ["Organization"] } } }, { "type": "object", "required": ["id", "tag"], "properties": { "id": { "type": "string", "format": "uuid" }, "tag": { "type": "string", "enum": ["Course"] } } }, { "type": "object", "required": ["id", "tag"], "properties": { "id": { "type": "string", "format": "uuid" }, "tag": { "type": "string", "enum": ["CourseInstance"] } } }, { "type": "object", "required": ["id", "tag"], "properties": { "id": { "type": "string", "format": "uuid" }, "tag": { "type": "string", "enum": ["Exam"] } } } ] }, "RoleInfo": { "type": "object", "required": ["email", "role", "domain"], "properties": { "domain": { "$ref": "#/components/schemas/RoleDomain" }, "email": { "type": "string" }, "role": { "$ref": "#/components/schemas/UserRole" } } }, "RoleUser": { "type": "object", "required": ["user_id", "email", "role"], "properties": { "email": { "type": "string" }, "first_name": { "type": ["string", "null"] }, "last_name": { "type": ["string", "null"] }, "role": { "$ref": "#/components/schemas/UserRole" }, "user_id": { "type": "string", "format": "uuid" } } }, "SaveCourseDesignerScheduleRequest": { "type": "object", "required": ["stages"], "properties": { "name": { "type": ["string", "null"] }, "stages": { "type": "array", "items": { "$ref": "#/components/schemas/CourseDesignerScheduleStageInput" } } } }, "SearchRequest": { "type": "object", "required": ["query"], "properties": { "query": { "type": "string" } } }, "ServiceInfo": { "type": "object", "required": ["name", "ports"], "properties": { "cluster_ip": { "type": ["string", "null"] }, "name": { "type": "string" }, "ports": { "type": "array", "items": { "$ref": "#/components/schemas/ServicePortInfo" } } } }, "ServicePortInfo": { "type": "object", "required": ["port"], "properties": { "name": { "type": ["string", "null"] }, "port": { "type": "integer", "format": "int32" }, "protocol": { "type": ["string", "null"] }, "target_port": { "type": ["string", "null"] } } }, "SetMyCourseCreditRegistrationConsentPayload": { "type": "object", "required": ["consent_given"], "properties": { "consent_given": { "type": "boolean" } } }, "SetMyCourseCreditRegistrationConsentResult": { "type": "object", "required": ["consent_given", "newly_unblocked_registration_count"], "properties": { "consent_given": { "type": "boolean" }, "consent_given_at": { "type": ["string", "null"], "format": "date-time" }, "consent_withdrawn_at": { "type": ["string", "null"], "format": "date-time" }, "newly_unblocked_registration_count": { "type": "integer", "format": "int64" } } }, "SisuDescriptionResponse": { "type": "object", "required": ["course_description", "audience", "modules"], "properties": { "audience": { "type": "array", "items": { "type": "string" } }, "course_description": { "type": "string" }, "modules": { "type": "array", "items": { "$ref": "#/components/schemas/Module" } } } }, "StudentFacingCreditRegistrationStatus": { "type": "string", "description": "The stage a student sees.", "enum": [ "waiting_for_completion", "needs_consent", "needs_student_number", "in_progress", "needs_enrolment", "waiting_for_sisu", "registered", "failed", "not_registering" ] }, "StudentNumberVerificationMethod": { "type": "string", "description": "How a student number was proven to belong to an account.", "enum": ["emailed_link", "email_match_fast_track", "admin_manual"] }, "StudentNumberVerificationTokenPreview": { "type": "object", "description": "What a mailed link would do, without doing it. Read-only on purpose: a mail scanner must not be\nable to spend the token.", "required": [ "student_number", "emailed_to_masked", "expires_at", "expired", "already_used", "already_used_by_this_account", "conflicts_with_other_account", "target_account_email", "claimable" ], "properties": { "already_used": { "type": "boolean" }, "already_used_by_this_account": { "type": "boolean", "description": "So the page can say \"you already used this link\" rather than accusing someone else." }, "claimable": { "type": "boolean" }, "conflicts_with_other_account": { "type": "boolean", "description": "A support case, not something the student can resolve: moving a number between accounts on\nmailbox access alone would let anyone detach another account's link." }, "course_name": { "type": ["string", "null"] }, "current_student_number": { "type": ["string", "null"], "description": "What this account is linked to now. Claiming replaces it." }, "emailed_to_masked": { "type": "string" }, "expired": { "type": "boolean" }, "expires_at": { "type": "string", "format": "date-time" }, "first_names": { "type": ["string", "null"] }, "last_name": { "type": ["string", "null"] }, "student_number": { "type": "string" }, "target_account_email": { "type": "string", "description": "Shown in the confirmation: being signed in to the wrong account is the common mistake." } } }, "StudentsByCountryTotalsResult": { "type": "object", "required": ["count"], "properties": { "count": { "type": "integer", "format": "int64" }, "country": { "type": ["string", "null"] } } }, "StudentsListPage": { "type": "object", "description": "A page of the student identity list plus the total number of pages for the current filters.", "required": ["data", "total_pages"], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/CourseStudentListRow" } }, "total_pages": { "type": "integer", "format": "int32", "minimum": 0 } } }, "SuotarEndpoint": { "type": "string", "enum": [ "resolve_persons", "resolve_enrolments", "import_attainments", "verify_attainments", "product_access_tokens", "list_by_course" ] }, "SuotarEndpointStanding": { "type": "object", "description": "Where one study registry endpoint stands, over all time.", "required": ["endpoint", "consecutive_failures"], "properties": { "consecutive_failures": { "type": "integer", "format": "int64" }, "endpoint": { "$ref": "#/components/schemas/SuotarEndpoint" }, "last_failure_at": { "type": ["string", "null"], "format": "date-time" }, "last_success_at": { "type": ["string", "null"], "format": "date-time" } } }, "SuotarEndpointWindowStats": { "type": "object", "required": [ "endpoint", "call_count", "failed_call_count", "in_flight_count", "ok_item_count", "error_item_count" ], "properties": { "call_count": { "type": "integer", "format": "int64" }, "endpoint": { "$ref": "#/components/schemas/SuotarEndpoint" }, "error_item_count": { "type": "integer", "format": "int64" }, "failed_call_count": { "type": "integer", "format": "int64" }, "in_flight_count": { "type": "integer", "format": "int64" }, "last_failure_at": { "type": ["string", "null"], "format": "date-time" }, "last_request_level_error_code": { "type": ["string", "null"], "description": "The registry's own request-level code, an identifier rather than prose." }, "last_success_at": { "type": ["string", "null"], "format": "date-time" }, "ok_item_count": { "type": "integer", "format": "int64" }, "p50_duration_ms": { "type": ["integer", "null"], "format": "int32" }, "p95_duration_ms": { "type": ["integer", "null"], "format": "int32" } } }, "SuotarHealth": { "type": "object", "required": ["windows"], "properties": { "windows": { "type": "array", "items": { "$ref": "#/components/schemas/SuotarHealthWindow" } } } }, "SuotarHealthWindow": { "type": "object", "required": ["window_secs", "endpoints"], "properties": { "endpoints": { "type": "array", "items": { "$ref": "#/components/schemas/SuotarEndpointWindowStats" } }, "window_secs": { "type": "integer", "format": "int64" } } }, "SuspectedCheaterStatus": { "type": "string", "description": "Review state of a suspected cheater.", "enum": ["Flagged", "ConfirmedCheating", "Dismissed"] }, "SuspectedCheaters": { "type": "object", "required": ["id", "user_id", "course_id", "created_at", "total_points", "status"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "course_module_id": { "type": ["string", "null"], "format": "uuid", "description": "The module completion that triggered the flag. `None` only for legacy rows the backfill\ncouldn't map to a default module." }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "status": { "$ref": "#/components/schemas/SuspectedCheaterStatus" }, "total_duration_seconds": { "type": ["integer", "null"], "format": "int32" }, "total_points": { "type": "integer", "format": "int32" }, "updated_at": { "type": ["string", "null"], "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "SystemHealthStatus": { "type": "object", "required": ["status", "issues"], "properties": { "issues": { "type": "array", "items": { "type": "string" } }, "status": { "$ref": "#/components/schemas/HealthStatus" } } }, "TeacherDecisionType": { "type": "string", "enum": [ "FullPoints", "ZeroPoints", "CustomPoints", "SuspectedPlagiarism", "RejectAndReset" ] }, "TeacherGradingDecision": { "type": "object", "required": [ "id", "user_exercise_state_id", "created_at", "updated_at", "score_given", "teacher_decision" ], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "hidden": { "type": ["boolean", "null"] }, "id": { "type": "string", "format": "uuid" }, "justification": { "type": ["string", "null"] }, "score_given": { "type": "number", "format": "float" }, "teacher_decision": { "$ref": "#/components/schemas/TeacherDecisionType" }, "updated_at": { "type": "string", "format": "date-time" }, "user_exercise_state_id": { "type": "string", "format": "uuid" }, "user_id": { "type": ["string", "null"], "format": "uuid" } } }, "TeacherLinkingEmailStatus": { "type": "object", "description": "What we can honestly say about a linking mail: our send status and the address's domain.", "required": ["email_send_status", "retry_count", "emailed_to_masked"], "properties": { "email_send_status": { "$ref": "#/components/schemas/EmailSendStatus" }, "emailed_to_masked": { "type": "string" }, "last_attempt_at": { "type": ["string", "null"], "format": "date-time" }, "next_retry_at": { "type": ["string", "null"], "format": "date-time" }, "retry_count": { "type": "integer", "format": "int32" }, "sent_at": { "type": ["string", "null"], "format": "date-time" } } }, "TeacherManualCompletion": { "type": "object", "required": ["user_id", "passed"], "properties": { "completion_date": { "type": ["string", "null"], "format": "date-time" }, "grade": { "type": ["integer", "null"], "format": "int32" }, "passed": { "type": "boolean" }, "user_id": { "type": "string", "format": "uuid" } } }, "TeacherManualCompletionRequest": { "type": "object", "required": ["course_module_id", "new_completions", "skip_duplicate_completions"], "properties": { "course_module_id": { "type": "string", "format": "uuid" }, "new_completions": { "type": "array", "items": { "$ref": "#/components/schemas/TeacherManualCompletion" } }, "skip_duplicate_completions": { "type": "boolean" } } }, "Term": { "type": "object", "required": ["id", "created_at", "updated_at", "term", "definition", "course_id"], "properties": { "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "definition": { "type": "string" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "term": { "type": "string" }, "updated_at": { "type": "string", "format": "date-time" } } }, "TermUpdate": { "type": "object", "required": ["term", "definition"], "properties": { "definition": { "type": "string" }, "term": { "type": "string" } } }, "ThresholdData": { "type": "object", "required": ["duration_seconds"], "properties": { "duration_seconds": { "type": "integer", "format": "int32" } } }, "TimeGranularity": { "type": "string", "enum": ["Year", "Month", "Day"] }, "UnlinkMyStudentNumberResult": { "type": "object", "required": ["affected_registration_count"], "properties": { "affected_registration_count": { "type": "integer", "format": "int64", "description": "Registrations that went back to waiting for a student number." } } }, "UpdateCourseDesignerStageTaskRequest": { "type": "object", "properties": { "description": { "type": ["string", "null"] }, "is_completed": { "type": ["boolean", "null"] }, "title": { "type": ["string", "null"] } } }, "UploadResult": { "type": "object", "description": "Result of a image upload. Tells where the uploaded image can be retrieved from.", "required": ["url"], "properties": { "url": { "type": "string" } } }, "User": { "type": "object", "required": ["id", "created_at", "updated_at"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "email_domain": { "type": ["string", "null"] }, "id": { "type": "string", "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "upstream_id": { "type": ["integer", "null"], "format": "int32" } } }, "UserChapterLockingStatus": { "type": "object", "required": [ "id", "created_at", "updated_at", "user_id", "chapter_id", "course_id", "status" ], "properties": { "chapter_id": { "type": "string", "format": "uuid" }, "course_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "status": { "$ref": "#/components/schemas/ChapterLockingStatus" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserChapterProgress": { "type": "object", "required": [ "user_id", "chapter_id", "chapter_number", "chapter_name", "points_obtained", "exercises_attempted" ], "properties": { "chapter_id": { "type": "string", "format": "uuid" }, "chapter_name": { "type": "string" }, "chapter_number": { "type": "integer", "format": "int32" }, "exercises_attempted": { "type": "integer", "format": "int64" }, "points_obtained": { "type": "number", "format": "double" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserCompletionInformation": { "type": "object", "required": [ "course_module_completion_id", "course_name", "email", "enable_registering_completion_to_uh_open_university", "enable_credit_registration_via_suotar" ], "properties": { "course_module_completion_id": { "type": "string", "format": "uuid" }, "course_name": { "type": "string" }, "ects_credits": { "type": ["number", "null"], "format": "float" }, "email": { "type": "string" }, "enable_credit_registration_via_suotar": { "type": "boolean" }, "enable_registering_completion_to_uh_open_university": { "type": "boolean" }, "uh_course_code": { "type": ["string", "null"], "description": "`None` only on a module registering through credit registration." } } }, "UserCourseProgress": { "type": "object", "required": [ "course_module_id", "course_module_name", "course_module_order_number", "score_given" ], "properties": { "attempted_exercises": { "type": ["integer", "null"], "format": "int32" }, "attempted_exercises_required": { "type": ["integer", "null"], "format": "int32" }, "course_module_id": { "type": "string", "format": "uuid" }, "course_module_name": { "type": "string" }, "course_module_order_number": { "type": "integer", "format": "int32" }, "score_given": { "type": "number", "format": "float" }, "score_maximum": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "score_required": { "type": ["integer", "null"], "format": "int32" }, "total_exercises": { "type": ["integer", "null"], "format": "int32", "minimum": 0 } } }, "UserCourseSettings": { "type": "object", "required": [ "user_id", "course_language_group_id", "created_at", "updated_at", "current_course_id", "current_course_instance_id", "hidden" ], "properties": { "course_language_group_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "current_course_id": { "type": "string", "format": "uuid" }, "current_course_instance_id": { "type": "string", "format": "uuid" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "hidden": { "type": "boolean", "description": "Whether the user has hidden this course from their personal \"My courses\" list. Does not\naffect course progress." }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserCourseSubmissionTime": { "type": "object", "description": "A single submission's time, its exercise, and the module that exercise sits in (via its chapter).\nUsed to plot a user's submission activity within a course.", "required": ["created_at", "exercise_id"], "properties": { "course_module_id": { "type": ["string", "null"], "format": "uuid", "description": "Module the exercise's chapter belongs to; `None` for exercises not placed in a chapter." }, "created_at": { "type": "string", "format": "date-time" }, "exercise_id": { "type": "string", "format": "uuid" } } }, "UserDetail": { "type": "object", "required": ["user_id", "created_at", "updated_at", "email"], "properties": { "country": { "type": ["string", "null"] }, "created_at": { "type": "string", "format": "date-time" }, "email": { "type": "string" }, "email_communication_consent": { "type": ["boolean", "null"] }, "email_verified_at": { "type": ["string", "null"], "format": "date-time", "description": "When the user last proved control of the address in `email`. `None` means unproven. Cleared\nby a database trigger on every address change, so a value here always refers to `email`." }, "email_verified_method": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/EmailVerificationMethod" } ] }, "first_name": { "type": ["string", "null"] }, "last_name": { "type": ["string", "null"] }, "search_helper": { "type": ["string", "null"] }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserDetailsRequest": { "type": "object", "required": ["user_id", "course_ids"], "properties": { "course_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }, "user_id": { "type": "string", "format": "uuid" } } }, "UserExerciseState": { "type": "object", "required": [ "id", "user_id", "exercise_id", "created_at", "updated_at", "grading_progress", "activity_progress", "reviewing_stage" ], "properties": { "activity_progress": { "$ref": "#/components/schemas/ActivityProgress" }, "course_id": { "type": ["string", "null"], "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "exam_id": { "type": ["string", "null"], "format": "uuid" }, "exercise_id": { "type": "string", "format": "uuid" }, "grading_progress": { "$ref": "#/components/schemas/GradingProgress" }, "id": { "type": "string", "format": "uuid" }, "reviewing_stage": { "$ref": "#/components/schemas/ReviewingStage" }, "score_given": { "type": ["number", "null"], "format": "float" }, "selected_exercise_slide_id": { "type": ["string", "null"], "format": "uuid" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserIdsPayload": { "type": "object", "description": "Body for the batch detail endpoints: the users of the current identity-list page.", "required": ["user_ids"], "properties": { "user_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } } } }, "UserInfoPayload": { "type": "object", "required": ["email", "first_name", "last_name", "country", "email_communication_consent"], "properties": { "country": { "type": "string" }, "email": { "type": "string" }, "email_communication_consent": { "type": "boolean" }, "first_name": { "type": "string" }, "last_name": { "type": "string" } } }, "UserPointsUpdateStrategy": { "type": "string", "enum": ["CanAddPointsButCannotRemovePoints", "CanAddPointsAndCanRemovePoints"] }, "UserResearchConsent": { "type": "object", "required": ["id", "user_id", "research_consent", "created_at", "updated_at"], "properties": { "created_at": { "type": "string", "format": "date-time" }, "deleted_at": { "type": ["string", "null"], "format": "date-time" }, "id": { "type": "string", "format": "uuid" }, "research_consent": { "type": "boolean" }, "updated_at": { "type": "string", "format": "date-time" }, "user_id": { "type": "string", "format": "uuid" } } }, "UserRole": { "type": "string", "enum": [ "Reviewer", "Assistant", "Teacher", "Admin", "CourseOrExamCreator", "MaterialViewer", "TeachingAndLearningServices", "StatsViewer" ] }, "UserSuspectedCheaterInfo": { "type": "object", "description": "A user's suspected-cheater record in one course, paired with that course's duration threshold.\nRead-only, for the cross-course \"Completion review\" list on the user-details page.", "required": [ "course_id", "status", "total_points", "first_flagged_at", "threshold_seconds" ], "properties": { "course_id": { "type": "string", "format": "uuid" }, "first_flagged_at": { "type": "string", "format": "date-time", "description": "When first flagged in this course (record `created_at`, unchanged on re-flag)." }, "status": { "$ref": "#/components/schemas/SuspectedCheaterStatus" }, "threshold_seconds": { "type": "integer", "format": "int32", "description": "Threshold (seconds) of the module that triggered the flag; the student completed faster." }, "total_duration_seconds": { "type": ["integer", "null"], "format": "int32" }, "total_points": { "type": "integer", "format": "int32" } } }, "UserWithModuleCompletions": { "type": "object", "required": ["completed_modules", "email", "user_id"], "properties": { "completed_modules": { "type": "array", "items": { "$ref": "#/components/schemas/CourseModuleCompletionWithRegistrationInfo" } }, "email": { "type": "string" }, "first_name": { "type": ["string", "null"] }, "last_name": { "type": ["string", "null"] }, "user_id": { "type": "string", "format": "uuid" } } }, "VerbosityLevel": { "type": "string", "enum": ["low", "medium", "high"] }, "VerifiedStudentNumberMethodTotal": { "type": "object", "required": ["verified_via", "count"], "properties": { "count": { "type": "integer", "format": "int64" }, "verified_via": { "$ref": "#/components/schemas/StudentNumberVerificationMethod" } } }, "VerifyEmailOwnershipPayload": { "type": "object", "required": ["code"], "properties": { "code": { "type": "string" } } }, "VerifyEmailOwnershipResult": { "type": "string", "description": "Outcome of submitting a code. Wrong, expired, superseded and spent are one value: they are\nindistinguishable to someone typing digits, and telling them apart only helps a guesser.", "enum": ["verified", "already_verified", "invalid"] } } }, "tags": [ { "name": "glossary", "description": "Glossary endpoints used by main-frontend" } ] }