diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 073d6084814a..2a4b4f5fa4f2 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -16,18 +16,136 @@ securityDefinitions: security: - Basic: [] paths: + /badges/v1/assertions/user/{username}/: + get: + operationId: badges_v1_assertions_user_read + summary: '**Use Cases**' + description: |- + Request a list of assertions for a user, optionally constrained to a course. + + **Example Requests** + + GET /api/badges/v1/assertions/user/{username}/ + + **Response Values** + + Body comprised of a list of objects with the following fields: + + * badge_class: The badge class the assertion was awarded for. Represented as an object + with the following fields: + * slug: The identifier for the badge class + * issuing_component: The software component responsible for issuing this badge. + * display_name: The display name of the badge. + * course_id: The course key of the course this badge is scoped to, or null if it isn't scoped to a course. + * description: A description of the award and its significance. + * criteria: A description of what is needed to obtain this award. + * image_url: A URL to the icon image used to represent this award. + * image_url: The baked assertion image derived from the badge_class icon-- contains metadata about the award + in its headers. + * assertion_url: The URL to the OpenBadges BadgeAssertion object, for verification by compatible tools + and software. + + **Params** + + * slug (optional): The identifier for a particular badge class to filter by. + * issuing_component (optional): The issuing component for a particular badge class to filter by + (requires slug to have been specified, or this will be ignored.) If slug is provided and this is not, + assumes the issuing_component should be empty. + * course_id (optional): Returns assertions that were awarded as part of a particular course. If slug is + provided, and this field is not specified, assumes that the target badge has an empty course_id field. + '*' may be used to get all badges with the specified slug, issuing_component combination across all courses. + + **Returns** + + * 200 on success, with a list of Badge Assertion objects. + * 403 if a user who does not have permission to masquerade as + another user specifies a username other than their own. + * 404 if the specified user does not exist + + { + "count": 7, + "previous": null, + "num_pages": 1, + "results": [ + { + "badge_class": { + "slug": "special_award", + "issuing_component": "openedx__course", + "display_name": "Very Special Award", + "course_id": "course-v1:edX+DemoX+Demo_Course", + "description": "Awarded for people who did something incredibly special", + "criteria": "Do something incredibly special.", + "image": "http://example.com/media/badge_classes/badges/special_xdpqpBv_9FYOZwN.png" + }, + "image_url": "http://badges.example.com/media/issued/cd75b69fc1c979fcc1697c8403da2bdf.png", + "assertion_url": "http://badges.example.com/public/assertions/07020647-e772-44dd-98b7-d13d34335ca6" + }, + ... + ] + } + parameters: + - name: page + in: query + description: A page number within the paginated result set. + required: false + type: integer + - name: page_size + in: query + description: Number of results to return per page. + required: false + type: integer + responses: + '200': + description: '' + schema: + required: + - count + - results + type: object + properties: + count: + type: integer + next: + type: string + format: uri + x-nullable: true + previous: + type: string + format: uri + x-nullable: true + results: + type: array + items: + $ref: '#/definitions/BadgeAssertion' + tags: + - badges + parameters: + - name: username + in: path + required: true + type: string /bookmarks/v1/bookmarks/: get: operationId: bookmarks_v1_bookmarks_list summary: Get a paginated list of bookmarks for a user. - description: "The list can be filtered by passing parameter \"course_id=\"\ - \nto only include bookmarks from a particular course.\n\nThe bookmarks are\ - \ always sorted in descending order by creation date.\n\nEach page in the\ - \ list contains 10 bookmarks by default. The page\nsize can be altered by\ - \ passing parameter \"page_size=\".\n\nTo include the optional\ - \ fields pass the values in \"fields\" parameter\nas a comma separated list.\ - \ Possible values are:\n\n* \"display_name\"\n* \"path\"\n\n**Example Requests**\n\ - \nGET /api/bookmarks/v1/bookmarks/?course_id={course_id1}&fields=display_name,path" + description: |- + The list can be filtered by passing parameter "course_id=" + to only include bookmarks from a particular course. + + The bookmarks are always sorted in descending order by creation date. + + Each page in the list contains 10 bookmarks by default. The page + size can be altered by passing parameter "page_size=". + + To include the optional fields pass the values in "fields" parameter + as a comma separated list. Possible values are: + + * "display_name" + * "path" + + **Example Requests** + + GET /api/bookmarks/v1/bookmarks/?course_id={course_id1}&fields=display_name,path parameters: - name: page in: query @@ -55,11 +173,17 @@ paths: post: operationId: bookmarks_v1_bookmarks_create summary: Create a new bookmark for a user. - description: "The POST request only needs to contain one parameter \"usage_id\"\ - .\n\nHttp400 is returned if the format of the request is not correct,\nthe\ - \ usage_id is invalid or a block corresponding to the usage_id\ncould not\ - \ be found.\n\n**Example Requests**\n\nPOST /api/bookmarks/v1/bookmarks/\n\ - Request data: {\"usage_id\": }" + description: |- + The POST request only needs to contain one parameter "usage_id". + + Http400 is returned if the format of the request is not correct, + the usage_id is invalid or a block corresponding to the usage_id + could not be found. + + **Example Requests** + + POST /api/bookmarks/v1/bookmarks/ + Request data: {"usage_id": } parameters: [] responses: '201': @@ -71,7 +195,10 @@ paths: get: operationId: bookmarks_v1_bookmarks_read summary: Get a specific bookmark for a user. - description: "**Example Requests**\n\nGET /api/bookmarks/v1/bookmarks/{username},{usage_id}?fields=display_name,path" + description: |- + **Example Requests** + + GET /api/bookmarks/v1/bookmarks/{username},{usage_id}?fields=display_name,path parameters: [] responses: '200': @@ -96,31 +223,209 @@ paths: in: path required: true type: string + /bulk_enroll/v1/bulk_enroll: + post: + operationId: bulk_enroll_v1_bulk_enroll_create + summary: '**Use Case**' + description: |- + Enroll multiple users in one or more courses. + + **Example Request** + + POST /api/bulk_enroll/v1/bulk_enroll/ { + "auto_enroll": true, + "email_students": true, + "action": "enroll", + "courses": "course-v1:edX+Demo+123,course-v1:edX+Demo2+456", + "cohorts": "cohortA,cohortA", + "identifiers": "brandon@example.com,yamilah@example.com" + } + + **POST Parameters** + + A POST request can include the following parameters. + + * auto_enroll: When set to `true`, students will be enrolled as soon + as they register. + * email_students: When set to `true`, students will be sent email + notifications upon enrollment. + * action: Can either be set to "enroll" or "unenroll". This determines the behavior + * cohorts: Optional. If provided, the number of items in the list should be equal to + the number of courses. first cohort coressponds with the first course and so on. + The learners will be added to the corresponding cohort. + + **Response Values** + + If the supplied course data is valid and the enrollments were + successful, an HTTP 200 "OK" response is returned. + + The HTTP 200 response body contains a list of response data for each + enrollment. (See the `instructor.views.api.students_update_enrollment` + docstring for the specifics of the response data available for each + enrollment) + + If a cohorts list is provided, additional 'cohort' keys will be added + to the 'before' and 'after' states. + parameters: [] + responses: + '201': + description: '' + tags: + - bulk_enroll + parameters: [] + /ccx/v0/ccx/: + get: + operationId: ccx_v0_ccx_list + summary: Gets a list of CCX Courses for a given Master Course. + description: Additional parameters are allowed for pagination purposes. + parameters: + - name: page + in: query + description: A page number within the paginated result set. + required: false + type: integer + - name: page_size + in: query + description: Number of results to return per page. + required: false + type: integer + responses: + '200': + description: '' + schema: + required: + - count + - results + type: object + properties: + count: + type: integer + next: + type: string + format: uri + x-nullable: true + previous: + type: string + format: uri + x-nullable: true + results: + type: array + items: + $ref: '#/definitions/CCXCourse' + tags: + - ccx + post: + operationId: ccx_v0_ccx_create + description: Creates a new CCX course for a given Master Course. + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/CCXCourse' + responses: + '201': + description: '' + schema: + $ref: '#/definitions/CCXCourse' + tags: + - ccx + parameters: [] + /ccx/v0/ccx/{ccx_course_id}/: + get: + operationId: ccx_v0_ccx_read + description: Gets a CCX Course information. + parameters: [] + responses: + '200': + description: '' + schema: + $ref: '#/definitions/CCXCourse' + tags: + - ccx + patch: + operationId: ccx_v0_ccx_partial_update + description: Modifies a CCX course. + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/CCXCourse' + responses: + '200': + description: '' + schema: + $ref: '#/definitions/CCXCourse' + tags: + - ccx + delete: + operationId: ccx_v0_ccx_delete + description: Deletes a CCX course. + parameters: [] + responses: + '204': + description: '' + tags: + - ccx + parameters: + - name: ccx_course_id + in: path + required: true + type: string /certificates/v0/certificates/{username}/: get: operationId: certificates_v0_certificates_read summary: Get a paginated list of bookmarks for a user. - description: "**Use Case**\n\nGet the list of viewable course certificates for\ - \ a specific user.\n\n**Example Request**\n\nGET /api/certificates/v0/certificates/{username}\n\ - \n**GET Response Values**\n\n If the request for information about the\ - \ user's certificates is successful,\n an HTTP 200 \"OK\" response is returned.\n\ - \n The HTTP 200 response contains a list of dicts with the following keys/values.\n\ - \n * username: A string representation of an user's username passed in\ - \ the request.\n\n * course_id: A string representation of a Course ID.\n\ - \n * course_display_name: A string representation of the Course name.\n\ - \n * course_organization: A string representation of the organization associated\ - \ with the Course.\n\n * certificate_type: A string representation of the\ - \ certificate type.\n Can be honor|verified|professional\n\n * created_date:\ - \ Date/time the certificate was created, in ISO-8661 format.\n\n * status:\ - \ A string representation of the certificate status.\n\n * is_passing:\ - \ True if the certificate has a passing status, False if not.\n\n * download_url:\ - \ A string representation of the certificate url.\n\n * grade: A string\ - \ representation of a float for the user's course grade.\n\n**Example GET\ - \ Response**\n\n [{\n \"username\": \"bob\",\n \"course_id\"\ - : \"edX/DemoX/Demo_Course\",\n \"certificate_type\": \"verified\",\n\ - \ \"created_date\": \"2015-12-03T13:14:28+0000\",\n \"status\"\ - : \"downloadable\",\n \"is_passing\": true,\n \"download_url\"\ - : \"http://www.example.com/cert.pdf\",\n \"grade\": \"0.98\"\n }]" + description: |- + **Use Case** + + Get the list of viewable course certificates for a specific user. + + **Example Request** + + GET /api/certificates/v0/certificates/{username} + + **GET Response Values** + + If the request for information about the user's certificates is successful, + an HTTP 200 "OK" response is returned. + + The HTTP 200 response contains a list of dicts with the following keys/values. + + * username: A string representation of an user's username passed in the request. + + * course_id: A string representation of a Course ID. + + * course_display_name: A string representation of the Course name. + + * course_organization: A string representation of the organization associated with the Course. + + * certificate_type: A string representation of the certificate type. + Can be honor|verified|professional + + * created_date: Date/time the certificate was created, in ISO-8661 format. + + * status: A string representation of the certificate status. + + * is_passing: True if the certificate has a passing status, False if not. + + * download_url: A string representation of the certificate url. + + * grade: A string representation of a float for the user's course grade. + + **Example GET Response** + + [{ + "username": "bob", + "course_id": "edX/DemoX/Demo_Course", + "certificate_type": "verified", + "created_date": "2015-12-03T13:14:28+0000", + "status": "downloadable", + "is_passing": true, + "download_url": "http://www.example.com/cert.pdf", + "grade": "0.98" + }] parameters: - name: username in: path @@ -267,9 +572,10 @@ paths: /cohorts/v1/courses/{course_key_string}/users: post: operationId: cohorts_v1_courses_users_create - description: "View method that accepts an uploaded file (using key \"uploaded-file\"\ - )\ncontaining cohort assignments for users. This method spawns a celery task\n\ - to do the assignments, and a CSV file with results is provided via data downloads." + description: |- + View method that accepts an uploaded file (using key "uploaded-file") + containing cohort assignments for users. This method spawns a celery task + to do the assignments, and a CSV file with results is provided via data downloads. parameters: [] responses: '201': @@ -426,13 +732,32 @@ paths: post: operationId: completion_v1_completion-batch_create summary: Inserts a batch of completions. - description: "REST Endpoint Format:\n```\n{\n \"username\": \"username\",\n\ - \ \"course_key\": \"course-key\",\n \"blocks\": {\n \"block_key1\": 0.0,\n\ - \ \"block_key2\": 1.0,\n \"block_key3\": 1.0,\n }\n}\n```\n\n**Returns**\n\ - \nA Response object, with an appropriate status code.\n\nIf successful, status\ - \ code is 200.\n```\n{\n \"detail\" : _(\"ok\")\n}\n```\n\nOtherwise, a\ - \ 400 or 404 may be returned, and the \"detail\" content will explain the\ - \ error." + description: |- + REST Endpoint Format: + ``` + { + "username": "username", + "course_key": "course-key", + "blocks": { + "block_key1": 0.0, + "block_key2": 1.0, + "block_key3": 1.0, + } + } + ``` + + **Returns** + + A Response object, with an appropriate status code. + + If successful, status code is 200. + ``` + { + "detail" : _("ok") + } + ``` + + Otherwise, a 400 or 404 may be returned, and the "detail" content will explain the error. parameters: [] responses: '201': @@ -467,17 +792,28 @@ paths: : get: operationId: course_experience_v1_course_deadlines_info_+]+api_course_experience_v1_course_deadlines_info_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request course deadline info for mobile\n\n**Example Requests**\n\ - \n GET api/course_experience/v1/course_deadlines_info/{course_key}\n\n\ - **Response Values**\n\n Body consists of the following fields:\n\n dates_banner_info:\ - \ (obj)\n missed_deadlines: (bool) Whether the user has missed any\ - \ graded content deadlines for the given course.\n missed_gated_content:\ - \ (bool) Whether the user has missed any gated content for the given course.\n\ - \ content_type_gating_enabled: (bool) Whether content type gating is\ - \ enabled for this enrollment.\n verified_upgrade_link: (str) The URL\ - \ to ecommerce IDA for purchasing the verified upgrade.\n\n**Returns**\n\n\ - \ * 200 on success with above fields.\n * 401 if the user is not authenticated.\n\ - \ * 404 if the course is not available or cannot be seen." + description: |- + Request course deadline info for mobile + + **Example Requests** + + GET api/course_experience/v1/course_deadlines_info/{course_key} + + **Response Values** + + Body consists of the following fields: + + dates_banner_info: (obj) + missed_deadlines: (bool) Whether the user has missed any graded content deadlines for the given course. + missed_gated_content: (bool) Whether the user has missed any gated content for the given course. + content_type_gating_enabled: (bool) Whether content type gating is enabled for this enrollment. + verified_upgrade_link: (str) The URL to ecommerce IDA for purchasing the verified upgrade. + + **Returns** + + * 200 on success with above fields. + * 401 if the user is not authenticated. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -498,7 +834,17 @@ paths: /course_experience/v1/reset_course_deadlines: post: operationId: course_experience_v1_reset_course_deadlines_create - description: '' + description: |- + Set the start_date of a schedule to today, which in turn will adjust due dates for + sequentials belonging to a self paced course + + Request Parameters: + course_key: course key + research_event_data: any data that should be included in the research tracking event + Example: sending the location of where the reset deadlines banner (i.e. outline-tab) + + IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines` + function in common/djangoapps/util/views.py as well. parameters: [] responses: '201': @@ -510,13 +856,20 @@ paths: get: operationId: course_goals_v0_course_goals_list summary: API calls to create and update a course goal. - description: "Validates incoming data to ensure that course_key maps to an actual\n\ - course and that the goal_key is a valid option.\n\n**Use Case**\n * Create\ - \ a new goal for a user.\n * Update an existing goal for a user\n\n**Example\ - \ Requests**\n POST /api/course_goals/v0/course_goals/\n Request\ - \ data: {\"course_key\": , \"goal_key\": \"\", \"user\"\ - : \"\"}\n\nReturns Http400 response if the course_key does not map\ - \ to a known\ncourse or if the goal_key does not map to a valid goal key." + description: |- + Validates incoming data to ensure that course_key maps to an actual + course and that the goal_key is a valid option. + + **Use Case** + * Create a new goal for a user. + * Update an existing goal for a user + + **Example Requests** + POST /api/course_goals/v0/course_goals/ + Request data: {"course_key": , "goal_key": "", "user": ""} + + Returns Http400 response if the course_key does not map to a known + course or if the goal_key does not map to a valid goal key. parameters: - name: page in: query @@ -575,13 +928,20 @@ paths: get: operationId: course_goals_v0_course_goals_read summary: API calls to create and update a course goal. - description: "Validates incoming data to ensure that course_key maps to an actual\n\ - course and that the goal_key is a valid option.\n\n**Use Case**\n * Create\ - \ a new goal for a user.\n * Update an existing goal for a user\n\n**Example\ - \ Requests**\n POST /api/course_goals/v0/course_goals/\n Request\ - \ data: {\"course_key\": , \"goal_key\": \"\", \"user\"\ - : \"\"}\n\nReturns Http400 response if the course_key does not map\ - \ to a known\ncourse or if the goal_key does not map to a valid goal key." + description: |- + Validates incoming data to ensure that course_key maps to an actual + course and that the goal_key is a valid option. + + **Use Case** + * Create a new goal for a user. + * Update an existing goal for a user + + **Example Requests** + POST /api/course_goals/v0/course_goals/ + Request data: {"course_key": , "goal_key": "", "user": ""} + + Returns Http400 response if the course_key does not map to a known + course or if the goal_key does not map to a valid goal key. parameters: [] responses: '200': @@ -593,13 +953,20 @@ paths: put: operationId: course_goals_v0_course_goals_update summary: API calls to create and update a course goal. - description: "Validates incoming data to ensure that course_key maps to an actual\n\ - course and that the goal_key is a valid option.\n\n**Use Case**\n * Create\ - \ a new goal for a user.\n * Update an existing goal for a user\n\n**Example\ - \ Requests**\n POST /api/course_goals/v0/course_goals/\n Request\ - \ data: {\"course_key\": , \"goal_key\": \"\", \"user\"\ - : \"\"}\n\nReturns Http400 response if the course_key does not map\ - \ to a known\ncourse or if the goal_key does not map to a valid goal key." + description: |- + Validates incoming data to ensure that course_key maps to an actual + course and that the goal_key is a valid option. + + **Use Case** + * Create a new goal for a user. + * Update an existing goal for a user + + **Example Requests** + POST /api/course_goals/v0/course_goals/ + Request data: {"course_key": , "goal_key": "", "user": ""} + + Returns Http400 response if the course_key does not map to a known + course or if the goal_key does not map to a valid goal key. parameters: - name: data in: body @@ -616,13 +983,20 @@ paths: patch: operationId: course_goals_v0_course_goals_partial_update summary: API calls to create and update a course goal. - description: "Validates incoming data to ensure that course_key maps to an actual\n\ - course and that the goal_key is a valid option.\n\n**Use Case**\n * Create\ - \ a new goal for a user.\n * Update an existing goal for a user\n\n**Example\ - \ Requests**\n POST /api/course_goals/v0/course_goals/\n Request\ - \ data: {\"course_key\": , \"goal_key\": \"\", \"user\"\ - : \"\"}\n\nReturns Http400 response if the course_key does not map\ - \ to a known\ncourse or if the goal_key does not map to a valid goal key." + description: |- + Validates incoming data to ensure that course_key maps to an actual + course and that the goal_key is a valid option. + + **Use Case** + * Create a new goal for a user. + * Update an existing goal for a user + + **Example Requests** + POST /api/course_goals/v0/course_goals/ + Request data: {"course_key": , "goal_key": "", "user": ""} + + Returns Http400 response if the course_key does not map to a known + course or if the goal_key does not map to a valid goal key. parameters: - name: data in: body @@ -639,13 +1013,20 @@ paths: delete: operationId: course_goals_v0_course_goals_delete summary: API calls to create and update a course goal. - description: "Validates incoming data to ensure that course_key maps to an actual\n\ - course and that the goal_key is a valid option.\n\n**Use Case**\n * Create\ - \ a new goal for a user.\n * Update an existing goal for a user\n\n**Example\ - \ Requests**\n POST /api/course_goals/v0/course_goals/\n Request\ - \ data: {\"course_key\": , \"goal_key\": \"\", \"user\"\ - : \"\"}\n\nReturns Http400 response if the course_key does not map\ - \ to a known\ncourse or if the goal_key does not map to a valid goal key." + description: |- + Validates incoming data to ensure that course_key maps to an actual + course and that the goal_key is a valid option. + + **Use Case** + * Create a new goal for a user. + * Update an existing goal for a user + + **Example Requests** + POST /api/course_goals/v0/course_goals/ + Request data: {"course_key": , "goal_key": "", "user": ""} + + Returns Http400 response if the course_key does not map to a known + course or if the goal_key does not map to a valid goal key. parameters: [] responses: '204': @@ -662,22 +1043,39 @@ paths: : get: operationId: course_home_v1_course_metadata_+]+api_course_home_v1_course_metadata_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request Course metadata details for the Course Home MFE that every\ - \ page needs.\n\n**Example Requests**\n\n GET api/course_home/v1/course_metadata/{course_key}\n\ - \n**Response Values**\n\n Body consists of the following fields:\n\n \ - \ course_id: (str) The Course's id (Course Run key)\n is_enrolled: (bool)\ - \ Indicates if the user is enrolled in the course\n is_self_paced: (bool)\ - \ Indicates if the course is self paced\n is_staff: (bool) Indicates if\ - \ the user is staff\n original_user_is_staff: (bool) Indicates if the original\ - \ user has staff access\n Used for when masquerading to distinguish\ - \ between the original requesting user\n and the user being masqueraded\ - \ as.\n number: (str) The Course's number\n org: (str) The Course's\ - \ organization\n tabs: List of Course Tabs to display. They are serialized\ - \ as:\n tab_id: (str) The tab's id\n title: (str) The title\ - \ of the tab to display\n url: (str) The url to view the tab\n title:\ - \ (str) The Course's display title\n\n**Returns**\n\n * 200 on success\ - \ with above fields.\n * 404 if the course is not available or cannot be\ - \ seen." + description: |- + Request Course metadata details for the Course Home MFE that every page needs. + + **Example Requests** + + GET api/course_home/v1/course_metadata/{course_key} + + **Response Values** + + Body consists of the following fields: + + course_id: (str) The Course's id (Course Run key) + username: (str) The requesting (or masqueraded) user. Returns None for an + unauthenticated user. + is_enrolled: (bool) Indicates if the user is enrolled in the course + is_self_paced: (bool) Indicates if the course is self paced + is_staff: (bool) Indicates if the user is staff + original_user_is_staff: (bool) Indicates if the original user has staff access + Used for when masquerading to distinguish between the original requesting user + and the user being masqueraded as. + number: (str) The Course's number + org: (str) The Course's organization + tabs: List of Course Tabs to display. They are serialized as: + tab_id: (str) The tab's id + title: (str) The title of the tab to display + url: (str) The url to view the tab + title: (str) The Course's display title + celebrations: (dict) a dict of celebration data + + **Returns** + + * 200 on success with above fields. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -699,29 +1097,41 @@ paths: : get: operationId: course_home_v1_dates_+]+api_course_home_v1_dates_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request details for the Dates Tab\n\n**Example Requests**\n\n\ - \ GET api/course_home/v1/dates/{course_key}\n\n**Response Values**\n\n\ - \ Body consists of the following fields:\n\n course_date_blocks: List\ - \ of serialized DateSummary objects. Each serialization has the following\ - \ fields:\n complete: (bool) Meant to only be used by assignments.\ - \ Indicates completeness for an\n assignment.\n date: (datetime)\ - \ The date time corresponding for the event\n date_type: (str) The\ - \ type of date (ex. course-start-date, assignment-due-date, etc.)\n \ - \ description: (str) The description for the date event\n learner_has_access:\ - \ (bool) Indicates if the learner has access to the date event\n link:\ - \ (str) An absolute link to content related to the date event\n \ - \ (ex. verified link or link to assignment)\n title: (str) The title\ - \ of the date event\n dates_banner_info: (obj)\n content_type_gating_enabled:\ - \ (bool) Whether content type gating is enabled for this enrollment.\n \ - \ missed_deadlines: (bool) Indicates whether the user missed any graded\ - \ content deadlines\n missed_gated_content: (bool) Indicates whether\ - \ the user missed gated content\n verified_upgrade_link: (str) The\ - \ link for upgrading to the Verified track in a course\n has_ended: (bool)\ - \ Indicates whether course has ended\n learner_is_full_access: (bool) Indicates\ - \ if the user is verified in the course\n user_timezone: (str) The user's\ - \ preferred timezone\n\n**Returns**\n\n * 200 on success with above fields.\n\ - \ * 401 if the user is not authenticated.\n * 404 if the course is not\ - \ available or cannot be seen." + description: |- + Request details for the Dates Tab + + **Example Requests** + + GET api/course_home/v1/dates/{course_key} + + **Response Values** + + Body consists of the following fields: + + course_date_blocks: List of serialized DateSummary objects. Each serialization has the following fields: + complete: (bool) Meant to only be used by assignments. Indicates completeness for an + assignment. + date: (datetime) The date time corresponding for the event + date_type: (str) The type of date (ex. course-start-date, assignment-due-date, etc.) + description: (str) The description for the date event + learner_has_access: (bool) Indicates if the learner has access to the date event + link: (str) An absolute link to content related to the date event + (ex. verified link or link to assignment) + title: (str) The title of the date event + dates_banner_info: (obj) + content_type_gating_enabled: (bool) Whether content type gating is enabled for this enrollment. + missed_deadlines: (bool) Indicates whether the user missed any graded content deadlines + missed_gated_content: (bool) Indicates whether the user missed gated content + verified_upgrade_link: (str) The link for upgrading to the Verified track in a course + has_ended: (bool) Indicates whether course has ended + learner_is_full_access: (bool) Indicates if the user is verified in the course + user_timezone: (str) The user's preferred timezone + + **Returns** + + * 200 on success with above fields. + * 401 if the user is not authenticated. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -754,54 +1164,83 @@ paths: : get: operationId: course_home_v1_outline_+]+api_course_home_v1_outline_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request details for the Outline Tab\n\n**Example Requests**\n\n\ - \ GET api/course_home/v1/outline/{course_key}\n\n**Response Values**\n\n\ - \ Body consists of the following fields:\n\n course_blocks:\n \ - \ blocks: List of serialized Course Block objects. Each serialization has\ - \ the following fields:\n id: (str) The usage ID of the block.\n\ - \ type: (str) The type of block. Possible values the names of any\n\ - \ XBlock type in the system, including custom blocks. Examples\ - \ are\n course, chapter, sequential, vertical, html, problem,\ - \ video, and\n discussion.\n display_name: (str)\ - \ The display name of the block.\n lms_web_url: (str) The URL to\ - \ the navigational container of the\n xBlock on the web LMS.\n\ - \ children: (list) If the block has child blocks, a list of IDs\ - \ of\n the child blocks.\n resume_block: (bool)\ - \ Whether the block is the resume block\n course_goals:\n goal_options:\ - \ (list) A list of goals where each goal is represented as a tuple (goal_key,\ - \ goal_string)\n selected_goal:\n key: (str) The unique\ - \ id given to the user's selected goal.\n text: (str) The display\ - \ text for the user's selected goal.\n course_tools: List of serialized\ - \ Course Tool objects. Each serialization has the following fields:\n \ - \ analytics_id: (str) The unique id given to the tool.\n title:\ - \ (str) The display title of the tool.\n url: (str) The link to access\ - \ the tool.\n dates_banner_info: (obj)\n content_type_gating_enabled:\ - \ (bool) Whether content type gating is enabled for this enrollment.\n \ - \ missed_deadlines: (bool) Whether the user has missed any graded content\ - \ deadlines for the given course.\n missed_gated_content: (bool) Whether\ - \ the user has missed any gated content for the given course.\n verified_upgrade_link:\ - \ (str) The URL to ecommerce IDA for purchasing the verified upgrade.\n \ - \ dates_widget:\n course_date_blocks: List of serialized Course Dates\ - \ objects. Each serialization has the following fields:\n complete:\ - \ (bool) Meant to only be used by assignments. Indicates completeness for\ - \ an\n assignment.\n date: (datetime) The date time\ - \ corresponding for the event\n date_type: (str) The type of date\ - \ (ex. course-start-date, assignment-due-date, etc.)\n description:\ - \ (str) The description for the date event\n learner_has_access:\ - \ (bool) Indicates if the learner has access to the date event\n \ - \ link: (str) An absolute link to content related to the date event\n \ - \ (ex. verified link or link to assignment)\n title:\ - \ (str) The title of the date event\n dates_tab_link: (str) The URL\ - \ to the Dates Tab\n user_timezone: (str) The timezone of the given\ - \ user\n enroll_alert:\n can_enroll: (bool) Whether the user can\ - \ enroll in the given course\n extra_text: (str)\n handouts_html:\ - \ (str) Raw HTML for the handouts section of the course info\n has_ended:\ - \ (bool) Indicates whether course has ended\n resume_course:\n has_visited_course:\ - \ (bool) Whether the user has ever visited the course\n url: (str)\ - \ The display name of the course block to resume\n welcome_message_html:\ - \ (str) Raw HTML for the course updates banner\n\n**Returns**\n\n * 200\ - \ on success with above fields.\n * 403 if the user is not authenticated.\n\ - \ * 404 if the course is not available or cannot be seen." + description: |- + Request details for the Outline Tab + + **Example Requests** + + GET api/course_home/v1/outline/{course_key} + + **Response Values** + + Body consists of the following fields: + + access_expiration: An object detailing when access to this course will expire + expiration_date: (str) When the access expires, in ISO 8601 notation + masquerading_expired_course: (bool) Whether this course is expired for the masqueraded user + upgrade_deadline: (str) Last chance to upgrade, in ISO 8601 notation (or None if can't upgrade anymore) + upgrade_url: (str) Upgrade linke (or None if can't upgrade anymore) + course_blocks: + blocks: List of serialized Course Block objects. Each serialization has the following fields: + id: (str) The usage ID of the block. + type: (str) The type of block. Possible values the names of any + XBlock type in the system, including custom blocks. Examples are + course, chapter, sequential, vertical, html, problem, video, and + discussion. + display_name: (str) The display name of the block. + lms_web_url: (str) The URL to the navigational container of the + xBlock on the web LMS. + children: (list) If the block has child blocks, a list of IDs of + the child blocks. + resume_block: (bool) Whether the block is the resume block + course_goals: + goal_options: (list) A list of goals where each goal is represented as a tuple (goal_key, goal_string) + selected_goal: + key: (str) The unique id given to the user's selected goal. + text: (str) The display text for the user's selected goal. + course_tools: List of serialized Course Tool objects. Each serialization has the following fields: + analytics_id: (str) The unique id given to the tool. + title: (str) The display title of the tool. + url: (str) The link to access the tool. + dates_banner_info: (obj) + content_type_gating_enabled: (bool) Whether content type gating is enabled for this enrollment. + missed_deadlines: (bool) Whether the user has missed any graded content deadlines for the given course. + missed_gated_content: (bool) Whether the user has missed any gated content for the given course. + verified_upgrade_link: (str) The URL to ecommerce IDA for purchasing the verified upgrade. + dates_widget: + course_date_blocks: List of serialized Course Dates objects. Each serialization has the following fields: + complete: (bool) Meant to only be used by assignments. Indicates completeness for an + assignment. + date: (datetime) The date time corresponding for the event + date_type: (str) The type of date (ex. course-start-date, assignment-due-date, etc.) + description: (str) The description for the date event + learner_has_access: (bool) Indicates if the learner has access to the date event + link: (str) An absolute link to content related to the date event + (ex. verified link or link to assignment) + title: (str) The title of the date event + dates_tab_link: (str) The URL to the Dates Tab + user_timezone: (str) The timezone of the given user + enroll_alert: + can_enroll: (bool) Whether the user can enroll in the given course + extra_text: (str) + handouts_html: (str) Raw HTML for the handouts section of the course info + has_ended: (bool) Indicates whether course has ended + offer: An object detailing upgrade discount information + code: (str) Checkout code + expiration_date: (str) Expiration of offer, in ISO 8601 notation + original_price: (str) Full upgrade price without checkout code; includes currency symbol + discounted_price: (str) Upgrade price with checkout code; includes currency symbol + percentage: (int) Amount of discount + upgrade_url: (str) Checkout URL + resume_course: + has_visited_course: (bool) Whether the user has ever visited the course + url: (str) The display name of the course block to resume + welcome_message_html: (str) Raw HTML for the course updates banner + + **Returns** + + * 200 on success with above fields. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -823,51 +1262,70 @@ paths: : get: operationId: course_home_v1_progress_+]+api_course_home_v1_progress_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request details for the Progress Tab\n\n**Example Requests**\n\ - \n GET api/course_home/v1/progress/{course_key}\n\n**Response Values**\n\ - \n Body consists of the following fields:\n\n certificate_data: Object\ - \ containing information about the user's certificate status\n cert_web_view_url:\ - \ (str) the url to view the certificate\n download_url: (str) the url\ - \ to download the certificate\n is_downloadable: (bool) true if the\ - \ status is downloadable and the download url is not None\n is_requestable:\ - \ (bool) true if status is requesting and request_cert_url is not None\n \ - \ msg: (str) message for the certificate status\n title: (str)\ - \ title of the certificate status\n credit_course_requirements: An object\ - \ containing the following fields\n dashboard_url: (str) the url to\ - \ the user's dashboard\n eligibility_status: (str) the user's eligibility\ - \ to receive a course credit\n requirements: object containing the\ - \ following fields\n display_name: (str) the name of the requirement\ - \ that should be displayed\n namespace: (str) the type that the\ - \ requirement is\n min_grade: (float) the percentage formatted\ - \ minimum grade needed for this requirement\n status: (str) the\ - \ status of the requirement\n status_date: (str) the date the status\ - \ was set\n credit_support_url: (str) the url to the support docs for purchasing\ - \ a credit\n courseware_summary: List of serialized Chapters. each Chapter\ - \ has the following fields:\n display_name: (str) a str of what the\ - \ name of the Chapter is for displaying on the site\n subsections:\ - \ List of serialized Subsections, each has the following fields:\n \ - \ display_name: (str) a str of what the name of the Subsection is for\ - \ displaying on the site\n due: (str) a DateTime string for when\ - \ the Subsection is due\n format: (str) the format, if any, of\ - \ the Subsection (Homework, Exam, etc)\n graded: (bool) whether\ - \ or not the Subsection is graded\n graded_total: an object containing\ - \ the following fields\n earned: (float) the amount of points\ - \ the user earned\n possible: (float) the amount of points\ - \ the user could have earned\n percent_graded: (float) the percentage\ - \ of the points the user received for the subsection\n show_correctness:\ - \ (str) a str representing whether to show the problem/practice scores based\ - \ on due date\n show_grades: (bool) a bool for whether to show\ - \ grades based on the access the user has\n url: (str) the absolute\ - \ path url to the Subsection\n enrollment_mode: (str) a str representing\ - \ the enrollment the user has ('audit', 'verified', ...)\n studio_url:\ - \ (str) a str of the link to the grading in studio for the course\n user_timezone:\ - \ (str) The user's preferred timezone\n verification_data: an object containing\n\ - \ link: (str) the link to either start or retry verification\n \ - \ status: (str) the status of the verification\n status_date: (str)\ - \ the date time string of when the verification status was set\n\n\n\n**Returns**\n\ - \n * 200 on success with above fields.\n * 302 if the user is not enrolled.\n\ - \ * 403 if the user is not authenticated.\n * 404 if the course is not\ - \ available or cannot be seen." + description: |- + Request details for the Progress Tab + + **Example Requests** + + GET api/course_home/v1/progress/{course_key} + + **Response Values** + + Body consists of the following fields: + + end: (date) end date of the course + user_has_passing_grade: (bool) boolean on if the user has a passing grade in the course + has_scheduled_content: (bool) boolean on if the course has content scheduled with a release date in the future + certificate_data: Object containing information about the user's certificate status + cert_status: (str) the status of a user's certificate (full list of statuses are defined in + lms/djangoapps/certificates/models.py) + cert_web_view_url: (str) the url to view the certificate + download_url: (str) the url to download the certificate + completion_summary: Object containing unit completion counts with the following fields: + complete_count: (float) number of complete units + incomplete_count: (float) number of incomplete units + locked_count: (float) number of units where contains_gated_content is True + course_grade: Object containing the following fields: + is_passing: (bool) whether the user's grade is above the passing grade cutoff + letter_grade: (str) the user's letter grade based on the set grade range. + If user is passing, value may be 'A', 'B', 'C', 'D', 'Pass', otherwise none + percent: (float) the user's total graded percent in the course + section_scores: List of serialized Chapters. Each Chapter has the following fields: + display_name: (str) a str of what the name of the Chapter is for displaying on the site + subsections: List of serialized Subsections, each has the following fields: + assignment_type: (str) the format, if any, of the Subsection (Homework, Exam, etc) + display_name: (str) a str of what the name of the Subsection is for displaying on the site + has_graded_assignment: (bool) whether or not the Subsection is a graded assignment + num_points_earned: (int) the amount of points the user has earned for the given subsection + num_points_possible: (int) the total amount of points possible for the given subsection + percent_graded: (float) the percentage of total points the user has received a grade for in a given subsection + show_correctness: (str) a str representing whether to show the problem/practice scores based on due date + ('always', 'never', 'past_due', values defined in + common/lib/xmodule/xmodule/modulestore/inheritance.py) + show_grades: (bool) a bool for whether to show grades based on the access the user has + url: (str) the absolute path url to the Subsection + enrollment_mode: (str) a str representing the enrollment the user has ('audit', 'verified', ...) + grading_policy: + assignment_policies: List of serialized assignment grading policy objects, each has the following fields: + num_droppable: (int) the number of lowest scored assignments that will not be counted towards the final grade + short_label: (str) the abbreviated name given to the assignment type + type: (str) the assignment type + weight: (float) the percent weight the given assigment type has on the overall grade + grade_range: an object containing the grade range cutoffs. The exact keys in the object can vary, but they + range from just 'Pass', to a combination of 'A', 'B', 'C', and 'D'. If a letter grade is present, + 'Pass' is not included. + studio_url: (str) a str of the link to the grading in studio for the course + verification_data: an object containing + link: (str) the link to either start or retry verification + status: (str) the status of the verification + status_date: (str) the date time string of when the verification status was set + + **Returns** + + * 200 on success with above fields. + * 302 if the user is not enrolled. + * 401 if the user is not authenticated. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -900,28 +1358,46 @@ paths: get: operationId: course_modes_v1_courses_read summary: View to list or create course modes for a course. - description: "**Use Case**\n\n List all course modes for a course, or create\ - \ a new\n course mode.\n\n**Example Requests**\n\n GET /api/course_modes/v1/courses/{course_id}/\n\ - \n Returns a list of all existing course modes for a course.\n\n \ - \ POST /api/course_modes/v1/courses/{course_id}/\n\n Creates a new\ - \ course mode in a course.\n\n**Response Values**\n\n For each HTTP verb\ - \ below, an HTTP 404 \"Not Found\" response is returned if the\n requested\ - \ course id does not exist.\n\n GET: If the request is successful, an HTTP\ - \ 200 \"OK\" response is returned\n along with a list of course mode dictionaries\ - \ within a course.\n The details are contained in a JSON dictionary as\ - \ follows:\n\n * course_id: The course identifier.\n * mode_slug:\ - \ The short name for the course mode.\n * mode_display_name: The verbose\ - \ name for the course mode.\n * min_price: The minimum price for which\ - \ a user can\n enroll in this mode.\n * currency: The currency\ - \ of the listed prices.\n * expiration_datetime: The date and time after\ - \ which\n users cannot enroll in the course in this mode (not required\ - \ for POST).\n * expiration_datetime_is_explicit: Whether the expiration_datetime\ - \ field was\n explicitly set (not required for POST).\n * description:\ - \ A description of this mode (not required for POST).\n * sku: The SKU\ - \ for this mode (for ecommerce purposes, not required for POST).\n *\ - \ bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required\ - \ for POST).\n\n POST: If the request is successful, an HTTP 201 \"Created\"\ - \ response is returned." + description: |- + **Use Case** + + List all course modes for a course, or create a new + course mode. + + **Example Requests** + + GET /api/course_modes/v1/courses/{course_id}/ + + Returns a list of all existing course modes for a course. + + POST /api/course_modes/v1/courses/{course_id}/ + + Creates a new course mode in a course. + + **Response Values** + + For each HTTP verb below, an HTTP 404 "Not Found" response is returned if the + requested course id does not exist. + + GET: If the request is successful, an HTTP 200 "OK" response is returned + along with a list of course mode dictionaries within a course. + The details are contained in a JSON dictionary as follows: + + * course_id: The course identifier. + * mode_slug: The short name for the course mode. + * mode_display_name: The verbose name for the course mode. + * min_price: The minimum price for which a user can + enroll in this mode. + * currency: The currency of the listed prices. + * expiration_datetime: The date and time after which + users cannot enroll in the course in this mode (not required for POST). + * expiration_datetime_is_explicit: Whether the expiration_datetime field was + explicitly set (not required for POST). + * description: A description of this mode (not required for POST). + * sku: The SKU for this mode (for ecommerce purposes, not required for POST). + * bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required for POST). + + POST: If the request is successful, an HTTP 201 "Created" response is returned. parameters: [] responses: '200': @@ -935,28 +1411,46 @@ paths: post: operationId: course_modes_v1_courses_create summary: View to list or create course modes for a course. - description: "**Use Case**\n\n List all course modes for a course, or create\ - \ a new\n course mode.\n\n**Example Requests**\n\n GET /api/course_modes/v1/courses/{course_id}/\n\ - \n Returns a list of all existing course modes for a course.\n\n \ - \ POST /api/course_modes/v1/courses/{course_id}/\n\n Creates a new\ - \ course mode in a course.\n\n**Response Values**\n\n For each HTTP verb\ - \ below, an HTTP 404 \"Not Found\" response is returned if the\n requested\ - \ course id does not exist.\n\n GET: If the request is successful, an HTTP\ - \ 200 \"OK\" response is returned\n along with a list of course mode dictionaries\ - \ within a course.\n The details are contained in a JSON dictionary as\ - \ follows:\n\n * course_id: The course identifier.\n * mode_slug:\ - \ The short name for the course mode.\n * mode_display_name: The verbose\ - \ name for the course mode.\n * min_price: The minimum price for which\ - \ a user can\n enroll in this mode.\n * currency: The currency\ - \ of the listed prices.\n * expiration_datetime: The date and time after\ - \ which\n users cannot enroll in the course in this mode (not required\ - \ for POST).\n * expiration_datetime_is_explicit: Whether the expiration_datetime\ - \ field was\n explicitly set (not required for POST).\n * description:\ - \ A description of this mode (not required for POST).\n * sku: The SKU\ - \ for this mode (for ecommerce purposes, not required for POST).\n *\ - \ bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required\ - \ for POST).\n\n POST: If the request is successful, an HTTP 201 \"Created\"\ - \ response is returned." + description: |- + **Use Case** + + List all course modes for a course, or create a new + course mode. + + **Example Requests** + + GET /api/course_modes/v1/courses/{course_id}/ + + Returns a list of all existing course modes for a course. + + POST /api/course_modes/v1/courses/{course_id}/ + + Creates a new course mode in a course. + + **Response Values** + + For each HTTP verb below, an HTTP 404 "Not Found" response is returned if the + requested course id does not exist. + + GET: If the request is successful, an HTTP 200 "OK" response is returned + along with a list of course mode dictionaries within a course. + The details are contained in a JSON dictionary as follows: + + * course_id: The course identifier. + * mode_slug: The short name for the course mode. + * mode_display_name: The verbose name for the course mode. + * min_price: The minimum price for which a user can + enroll in this mode. + * currency: The currency of the listed prices. + * expiration_datetime: The date and time after which + users cannot enroll in the course in this mode (not required for POST). + * expiration_datetime_is_explicit: Whether the expiration_datetime field was + explicitly set (not required for POST). + * description: A description of this mode (not required for POST). + * sku: The SKU for this mode (for ecommerce purposes, not required for POST). + * bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required for POST). + + POST: If the request is successful, an HTTP 201 "Created" response is returned. parameters: - name: data in: body @@ -979,35 +1473,54 @@ paths: get: operationId: course_modes_v1_courses_read summary: View to retrieve, update, or delete a specific course mode for a course. - description: "**Use Case**\n\n Get or update course mode details for a specific\ - \ course mode on a course.\n Or you may delete a specific course mode from\ - \ a course.\n\n**Example Requests**\n\n GET /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\ - \n Returns details on an existing course mode for a course.\n\n \ - \ PATCH /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\n Updates\ - \ (via merge) details of an existing course mode for a course.\n\n DELETE\ - \ /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\n Deletes\ - \ an existing course mode for a course.\n\n**Response Values**\n\n For\ - \ each HTTP verb below, an HTTP 404 \"Not Found\" response is returned if\ - \ the\n requested course id does not exist, or the mode slug does not exist\ - \ within the course.\n\n GET: If the request is successful, an HTTP 200\ - \ \"OK\" response is returned\n along with a details for a single course\ - \ mode within a course. The details are contained\n in a JSON dictionary\ - \ as follows:\n\n * course_id: The course identifier.\n * mode_slug:\ - \ The short name for the course mode.\n * mode_display_name: The verbose\ - \ name for the course mode.\n * min_price: The minimum price for which\ - \ a user can\n enroll in this mode.\n * currency: The currency\ - \ of the listed prices.\n * expiration_datetime: The date and time after\ - \ which\n users cannot enroll in the course in this mode (not required\ - \ for PATCH).\n * expiration_datetime_is_explicit: Whether the expiration_datetime\ - \ field was\n explicitly set (not required for PATCH).\n * description:\ - \ A description of this mode (not required for PATCH).\n * sku: The SKU\ - \ for this mode (for ecommerce purposes, not required for PATCH).\n *\ - \ bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required\ - \ for PATCH).\n\n PATCH: If the request is successful, an HTTP 204 \"No\ - \ Content\" response is returned.\n If \"application/merge-patch+json\"\ - \ is not the specified content type,\n a 415 \"Unsupported Media Type\"\ - \ response is returned.\n\n DELETE: If the request is successful, an HTTP\ - \ 204 \"No Content\" response is returned." + description: |- + **Use Case** + + Get or update course mode details for a specific course mode on a course. + Or you may delete a specific course mode from a course. + + **Example Requests** + + GET /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Returns details on an existing course mode for a course. + + PATCH /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Updates (via merge) details of an existing course mode for a course. + + DELETE /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Deletes an existing course mode for a course. + + **Response Values** + + For each HTTP verb below, an HTTP 404 "Not Found" response is returned if the + requested course id does not exist, or the mode slug does not exist within the course. + + GET: If the request is successful, an HTTP 200 "OK" response is returned + along with a details for a single course mode within a course. The details are contained + in a JSON dictionary as follows: + + * course_id: The course identifier. + * mode_slug: The short name for the course mode. + * mode_display_name: The verbose name for the course mode. + * min_price: The minimum price for which a user can + enroll in this mode. + * currency: The currency of the listed prices. + * expiration_datetime: The date and time after which + users cannot enroll in the course in this mode (not required for PATCH). + * expiration_datetime_is_explicit: Whether the expiration_datetime field was + explicitly set (not required for PATCH). + * description: A description of this mode (not required for PATCH). + * sku: The SKU for this mode (for ecommerce purposes, not required for PATCH). + * bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required for PATCH). + + PATCH: If the request is successful, an HTTP 204 "No Content" response is returned. + If "application/merge-patch+json" is not the specified content type, + a 415 "Unsupported Media Type" response is returned. + + DELETE: If the request is successful, an HTTP 204 "No Content" response is returned. parameters: [] responses: '200': @@ -1039,35 +1552,54 @@ paths: delete: operationId: course_modes_v1_courses_delete summary: View to retrieve, update, or delete a specific course mode for a course. - description: "**Use Case**\n\n Get or update course mode details for a specific\ - \ course mode on a course.\n Or you may delete a specific course mode from\ - \ a course.\n\n**Example Requests**\n\n GET /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\ - \n Returns details on an existing course mode for a course.\n\n \ - \ PATCH /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\n Updates\ - \ (via merge) details of an existing course mode for a course.\n\n DELETE\ - \ /api/course_modes/v1/courses/{course_id}/{mode_slug}\n\n Deletes\ - \ an existing course mode for a course.\n\n**Response Values**\n\n For\ - \ each HTTP verb below, an HTTP 404 \"Not Found\" response is returned if\ - \ the\n requested course id does not exist, or the mode slug does not exist\ - \ within the course.\n\n GET: If the request is successful, an HTTP 200\ - \ \"OK\" response is returned\n along with a details for a single course\ - \ mode within a course. The details are contained\n in a JSON dictionary\ - \ as follows:\n\n * course_id: The course identifier.\n * mode_slug:\ - \ The short name for the course mode.\n * mode_display_name: The verbose\ - \ name for the course mode.\n * min_price: The minimum price for which\ - \ a user can\n enroll in this mode.\n * currency: The currency\ - \ of the listed prices.\n * expiration_datetime: The date and time after\ - \ which\n users cannot enroll in the course in this mode (not required\ - \ for PATCH).\n * expiration_datetime_is_explicit: Whether the expiration_datetime\ - \ field was\n explicitly set (not required for PATCH).\n * description:\ - \ A description of this mode (not required for PATCH).\n * sku: The SKU\ - \ for this mode (for ecommerce purposes, not required for PATCH).\n *\ - \ bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required\ - \ for PATCH).\n\n PATCH: If the request is successful, an HTTP 204 \"No\ - \ Content\" response is returned.\n If \"application/merge-patch+json\"\ - \ is not the specified content type,\n a 415 \"Unsupported Media Type\"\ - \ response is returned.\n\n DELETE: If the request is successful, an HTTP\ - \ 204 \"No Content\" response is returned." + description: |- + **Use Case** + + Get or update course mode details for a specific course mode on a course. + Or you may delete a specific course mode from a course. + + **Example Requests** + + GET /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Returns details on an existing course mode for a course. + + PATCH /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Updates (via merge) details of an existing course mode for a course. + + DELETE /api/course_modes/v1/courses/{course_id}/{mode_slug} + + Deletes an existing course mode for a course. + + **Response Values** + + For each HTTP verb below, an HTTP 404 "Not Found" response is returned if the + requested course id does not exist, or the mode slug does not exist within the course. + + GET: If the request is successful, an HTTP 200 "OK" response is returned + along with a details for a single course mode within a course. The details are contained + in a JSON dictionary as follows: + + * course_id: The course identifier. + * mode_slug: The short name for the course mode. + * mode_display_name: The verbose name for the course mode. + * min_price: The minimum price for which a user can + enroll in this mode. + * currency: The currency of the listed prices. + * expiration_datetime: The date and time after which + users cannot enroll in the course in this mode (not required for PATCH). + * expiration_datetime_is_explicit: Whether the expiration_datetime field was + explicitly set (not required for PATCH). + * description: A description of this mode (not required for PATCH). + * sku: The SKU for this mode (for ecommerce purposes, not required for PATCH). + * bulk_sku: The bulk SKU for this mode (for ecommerce purposes, not required for PATCH). + + PATCH: If the request is successful, an HTTP 204 "No Content" response is returned. + If "application/merge-patch+json" is not the specified content type, + a 415 "Unsupported Media Type" response is returned. + + DELETE: If the request is successful, an HTTP 204 "No Content" response is returned. parameters: [] responses: '204': @@ -1089,22 +1621,41 @@ paths: get: operationId: courses_v1_blocks_list summary: '**Use Case**' - description: "Returns the blocks in the course according to the requesting user's\n\ - \ access level.\n\n**Example requests**:\n\n GET /api/courses/v1/blocks/?course_id=\n\ - \ GET /api/courses/v1/blocks/?course_id=\n &username=anjali\n\ - \ &depth=all\n &requested_fields=graded,format,student_view_multi_device,lti_url\n\ - \ &block_counts=video\n &student_view_data=video\n &block_types_filter=problem,html\n\ - \n**Parameters**:\n\n This view redirects to /api/courses/v1/blocks//\ - \ for the\n root usage key of the course specified by course_id. The view\ - \ accepts\n all parameters accepted by :class:`BlocksView`, plus the following\n\ - \ required parameter\n\n * course_id: (string, required) The ID of the\ - \ course whose block data\n we want to return\n\n**Response Values**\n\ - \n Responses are identical to those returned by :class:`BlocksView` when\n\ - \ passed the root_usage_key of the requested course.\n\n If the course_id\ - \ is not supplied, a 400: Bad Request is returned, with\n a message indicating\ - \ that course_id is required.\n\n If an invalid course_id is supplied,\ - \ a 400: Bad Request is returned,\n with a message indicating that the\ - \ course_id is not valid." + description: |- + Returns the blocks in the course according to the requesting user's + access level. + + **Example requests**: + + GET /api/courses/v1/blocks/?course_id= + GET /api/courses/v1/blocks/?course_id= + &username=anjali + &depth=all + &requested_fields=graded,format,student_view_multi_device,lti_url + &block_counts=video + &student_view_data=video + &block_types_filter=problem,html + + **Parameters**: + + This view redirects to /api/courses/v1/blocks// for the + root usage key of the course specified by course_id. The view accepts + all parameters accepted by :class:`BlocksView`, plus the following + required parameter + + * course_id: (string, required) The ID of the course whose block data + we want to return + + **Response Values** + + Responses are identical to those returned by :class:`BlocksView` when + passed the root_usage_key of the requested course. + + If the course_id is not supplied, a 400: Bad Request is returned, with + a message indicating that course_id is required. + + If an invalid course_id is supplied, a 400: Bad Request is returned, + with a message indicating that the course_id is not valid. parameters: - name: page in: query @@ -1126,100 +1677,180 @@ paths: : get: operationId: courses_v1_blocks_courses_v1_blocks__[_]+_[_]+_[_]+_[@]+(:@[_read summary: '**Use Case**' - description: "Returns the blocks within the requested block tree according to\ - \ the\n requesting user's access level.\n\n**Example requests**:\n\n \ - \ GET /api/courses/v1/blocks//?depth=all\n GET /api/courses/v1/blocks//?\n\ - \ username=anjali\n &depth=all\n &requested_fields=graded,format,student_view_multi_device,lti_url,due\n\ - \ &block_counts=video\n &student_view_data=video\n &block_types_filter=problem,html\n\ - \n**Parameters**:\n\n * all_blocks: (boolean) Provide a value of \"true\"\ - \ to return all\n blocks. Returns all blocks only if the requesting user\ - \ has course\n staff permissions. Blocks that are visible only to specific\ - \ learners\n (for example, based on group membership or randomized content)\ - \ are\n all included. If all_blocks is not specified, you must specify\ - \ the\n username for the user whose course blocks are requested.\n\n\ - \ * username: (string) Required, unless ``all_blocks`` is specified.\n\ - \ Specify the username for the user whose course blocks are requested.\n\ - \ A blank/empty username can be used to request the blocks accessible\n\ - \ to anonymous users (for public courses). Only users with course staff\n\ - \ permissions can specify other users' usernames. If a username is\n\ - \ specified, results include blocks that are visible to that user,\n\ - \ including those based on group or cohort membership or randomized\n\ - \ content assigned to that user.\n\n Example: username=anjali\n\ - \ username=''\n username\n\n * student_view_data:\ - \ (list) Indicates for which block types to return\n student_view_data.\n\ - \n Example: student_view_data=video\n\n * block_counts: (list) Indicates\ - \ for which block types to return the\n aggregate count of the blocks.\n\ - \n Example: block_counts=video,problem\n\n * requested_fields: (list)\ - \ Indicates which additional fields to return\n for each block. For\ - \ a list of available fields see under `Response\n Values -> blocks`,\ - \ below.\n\n The following fields are always returned: id, type, display_name\n\ - \n Example: requested_fields=graded,format,student_view_multi_device\n\ - \n * depth: (integer or all) Indicates how deep to traverse into the blocks\n\ - \ hierarchy. A value of all means the entire hierarchy.\n\n Default\ - \ is 0\n\n Example: depth=all\n\n * nav_depth: (integer)\n\n \ - \ WARNING: nav_depth is not supported, and may be removed at any time.\n\n\ - \ Indicates how far deep to traverse into the\n course hierarchy\ - \ before bundling all the descendants.\n\n Default is 3 since typical\ - \ navigational views of the course show a\n maximum of chapter->sequential->vertical.\n\ - \n Example: nav_depth=3\n\n * return_type (string) Indicates in what\ - \ data type to return the\n blocks.\n\n Default is dict. Supported\ - \ values are: dict, list\n\n Example: return_type=dict\n\n * block_types_filter:\ - \ (list) Requested types of blocks used to filter the final result\n \ - \ of returned blocks. Possible values include sequential, vertical, html,\ - \ problem,\n video, and discussion.\n\n Example: block_types_filter=vertical,html\n\ - \n**Response Values**\n\n The following fields are returned with a successful\ - \ response.\n\n * root: The ID of the root node of the requested course\ - \ block\n structure.\n\n * blocks: A dictionary or list, based on\ - \ the value of the\n \"return_type\" parameter. Maps block usage IDs\ - \ to a collection of\n information about each block. Each block contains\ - \ the following\n fields.\n\n * id: (string) The usage ID of the\ - \ block.\n\n * type: (string) The type of block. Possible values the\ - \ names of any\n XBlock type in the system, including custom blocks.\ - \ Examples are\n course, chapter, sequential, vertical, html, problem,\ - \ video, and\n discussion.\n\n * display_name: (string) The display\ - \ name of the block.\n\n * children: (list) If the block has child blocks,\ - \ a list of IDs of\n the child blocks. Returned only if \"children\"\ - \ is included in the\n \"requested_fields\" parameter.\n\n * completion:\ - \ (float or None) The level of completion of the block.\n Its value\ - \ can vary between 0.0 and 1.0 or be equal to None\n if block is not\ - \ completable. Returned only if \"completion\"\n is included in the\ - \ \"requested_fields\" parameter.\n\n * block_counts: (dict) For each\ - \ block type specified in the\n block_counts parameter to the endpoint,\ - \ the aggregate number of\n blocks of that type for this block and\ - \ all of its descendants.\n\n * graded (boolean) Whether or not the block\ - \ or any of its descendants\n is graded. Returned only if \"graded\"\ - \ is included in the\n \"requested_fields\" parameter.\n\n * format:\ - \ (string) The assignment type of the block. Possible values\n can\ - \ be \"Homework\", \"Lab\", \"Midterm Exam\", and \"Final Exam\".\n \ - \ Returned only if \"format\" is included in the \"requested_fields\"\n \ - \ parameter.\n\n * student_view_data: (dict) The JSON data for\ - \ this block.\n Returned only if the \"student_view_data\" input parameter\ - \ contains\n this block's type.\n\n * student_view_url: (string)\ - \ The URL to retrieve the HTML rendering\n of this block's student\ - \ view. The HTML could include CSS and\n Javascript code. This field\ - \ can be used in combination with the\n student_view_multi_device field\ - \ to decide whether to display this\n content to the user.\n\n \ - \ This URL can be used as a fallback if the student_view_data for\n \ - \ this block type is not supported by the client or the block.\n\n \ - \ * student_view_multi_device: (boolean) Whether or not the HTML of\n \ - \ the student view that is rendered at \"student_view_url\" supports\n\ - \ responsive web layouts, touch-based inputs, and interactive state\n\ - \ management for a variety of device sizes and types, including\n \ - \ mobile and touch devices. Returned only if\n \"student_view_multi_device\"\ - \ is included in the \"requested_fields\"\n parameter.\n\n * lms_web_url:\ - \ (string) The URL to the navigational container of the\n xBlock on\ - \ the web LMS. This URL can be used as a further fallback\n if the\ - \ student_view_url and the student_view_data fields are not\n supported.\n\ - \n * lti_url: The block URL for an LTI consumer. Returned only if the\n\ - \ \"ENABLE_LTI_PROVIDER\" Django settign is set to \"True\".\n\n \ - \ * due: The due date of the block. Returned only if \"due\" is included\n\ - \ in the \"requested_fields\" parameter.\n\n * show_correctness:\ - \ Whether to show scores/correctness to learners for the current sequence\ - \ or problem.\n Returned only if \"show_correctness\" is included in\ - \ the \"requested_fields\" parameter.\n\n * Additional XBlock fields\ - \ can be included in the response if they are\n configured via the\ - \ COURSE_BLOCKS_API_EXTRA_FIELDS Django setting and\n requested via\ - \ the \"requested_fields\" parameter." + description: |- + Returns the blocks within the requested block tree according to the + requesting user's access level. + + **Example requests**: + + GET /api/courses/v1/blocks//?depth=all + GET /api/courses/v1/blocks//? + username=anjali + &depth=all + &requested_fields=graded,format,student_view_multi_device,lti_url,due + &block_counts=video + &student_view_data=video + &block_types_filter=problem,html + + **Parameters**: + + * all_blocks: (boolean) Provide a value of "true" to return all + blocks. Returns all blocks only if the requesting user has course + staff permissions. Blocks that are visible only to specific learners + (for example, based on group membership or randomized content) are + all included. If all_blocks is not specified, you must specify the + username for the user whose course blocks are requested. + + * username: (string) Required, unless ``all_blocks`` is specified. + Specify the username for the user whose course blocks are requested. + A blank/empty username can be used to request the blocks accessible + to anonymous users (for public courses). Only users with course staff + permissions can specify other users' usernames. If a username is + specified, results include blocks that are visible to that user, + including those based on group or cohort membership or randomized + content assigned to that user. + + Example: username=anjali + username='' + username + + * student_view_data: (list) Indicates for which block types to return + student_view_data. + + Example: student_view_data=video + + * block_counts: (list) Indicates for which block types to return the + aggregate count of the blocks. + + Example: block_counts=video,problem + + * requested_fields: (list) Indicates which additional fields to return + for each block. For a list of available fields see under `Response + Values -> blocks`, below. + + The following fields are always returned: id, type, display_name + + Example: requested_fields=graded,format,student_view_multi_device + + * depth: (integer or all) Indicates how deep to traverse into the blocks + hierarchy. A value of all means the entire hierarchy. + + Default is 0 + + Example: depth=all + + * nav_depth: (integer) + + WARNING: nav_depth is not supported, and may be removed at any time. + + Indicates how far deep to traverse into the + course hierarchy before bundling all the descendants. + + Default is 3 since typical navigational views of the course show a + maximum of chapter->sequential->vertical. + + Example: nav_depth=3 + + * return_type (string) Indicates in what data type to return the + blocks. + + Default is dict. Supported values are: dict, list + + Example: return_type=dict + + * block_types_filter: (list) Requested types of blocks used to filter the final result + of returned blocks. Possible values include sequential, vertical, html, problem, + video, and discussion. + + Example: block_types_filter=vertical,html + + **Response Values** + + The following fields are returned with a successful response. + + * root: The ID of the root node of the requested course block + structure. + + * blocks: A dictionary or list, based on the value of the + "return_type" parameter. Maps block usage IDs to a collection of + information about each block. Each block contains the following + fields. + + * id: (string) The usage ID of the block. + + * type: (string) The type of block. Possible values the names of any + XBlock type in the system, including custom blocks. Examples are + course, chapter, sequential, vertical, html, problem, video, and + discussion. + + * display_name: (string) The display name of the block. + + * children: (list) If the block has child blocks, a list of IDs of + the child blocks. Returned only if "children" is included in the + "requested_fields" parameter. + + * completion: (float or None) The level of completion of the block. + Its value can vary between 0.0 and 1.0 or be equal to None + if block is not completable. Returned only if "completion" + is included in the "requested_fields" parameter. + + * block_counts: (dict) For each block type specified in the + block_counts parameter to the endpoint, the aggregate number of + blocks of that type for this block and all of its descendants. + + * graded (boolean) Whether or not the block or any of its descendants + is graded. Returned only if "graded" is included in the + "requested_fields" parameter. + + * format: (string) The assignment type of the block. Possible values + can be "Homework", "Lab", "Midterm Exam", and "Final Exam". + Returned only if "format" is included in the "requested_fields" + parameter. + + * student_view_data: (dict) The JSON data for this block. + Returned only if the "student_view_data" input parameter contains + this block's type. + + * student_view_url: (string) The URL to retrieve the HTML rendering + of this block's student view. The HTML could include CSS and + Javascript code. This field can be used in combination with the + student_view_multi_device field to decide whether to display this + content to the user. + + This URL can be used as a fallback if the student_view_data for + this block type is not supported by the client or the block. + + * student_view_multi_device: (boolean) Whether or not the HTML of + the student view that is rendered at "student_view_url" supports + responsive web layouts, touch-based inputs, and interactive state + management for a variety of device sizes and types, including + mobile and touch devices. Returned only if + "student_view_multi_device" is included in the "requested_fields" + parameter. + + * lms_web_url: (string) The URL to the navigational container of the + xBlock on the web. This URL can be used as a further fallback + if the student_view_url and the student_view_data fields are not + supported. Will direct to either the "New" (micro-frontend) or + "Legacy" (Django-template-rendered) frontend experience depending + on which experience is active. + + * legacy_web_url: (string) Like `lms_web_url`, but always directs to + the "Legacy" frontend experience. Should only be used for + transitional purposes; will be removed as part of DEPR-109. + + * lti_url: The block URL for an LTI consumer. Returned only if the + "ENABLE_LTI_PROVIDER" Django settign is set to "True". + + * due: The due date of the block. Returned only if "due" is included + in the "requested_fields" parameter. + + * show_correctness: Whether to show scores/correctness to learners for the current sequence or problem. + Returned only if "show_correctness" is included in the "requested_fields" parameter. + + * Additional XBlock fields can be included in the response if they are + configured via the COURSE_BLOCKS_API_EXTRA_FIELDS Django setting and + requested via the "requested_fields" parameter. parameters: - name: page in: query @@ -1249,26 +1880,54 @@ paths: get: operationId: courses_v1_course_ids_list summary: '**Use Cases**' - description: "Request a list of course IDs for all courses the specified user\ - \ can\n access based on the provided parameters.\n\n**Example Requests**\n\ - \n GET /api/courses/v1/courses_ids/\n\n**Response Values**\n\n Body\ - \ comprises a list of course ids and pagination details.\n\n**Parameters**\n\ - \n username (optional):\n The username of the specified user whose\ - \ visible courses we\n want to see.\n\n role (required):\n \ - \ Course ids are filtered such that only those for which the\n user\ - \ has the specified role are returned. Role can be \"staff\"\n or \"\ - instructor\".\n Case-insensitive.\n\n**Returns**\n\n * 200 on success,\ - \ with a list of course ids and pagination details\n * 400 if an invalid\ - \ parameter was sent or the username was not provided\n for an authenticated\ - \ request.\n * 403 if a user who does not have permission to masquerade\ - \ as\n another user who specifies a username other than their own.\n\ - \ * 404 if the specified user does not exist, or the requesting user does\n\ - \ not have permission to view their courses.\n\n Example response:\n\ - \n {\n \"results\":\n [\n \ - \ \"course-v1:edX+DemoX+Demo_Course\"\n ],\n \ - \ \"pagination\": {\n \"previous\": null,\n \ - \ \"num_pages\": 1,\n \"next\": null,\n \"\ - count\": 1\n }\n }" + description: |- + Request a list of course IDs for all courses the specified user can + access based on the provided parameters. + + **Example Requests** + + GET /api/courses/v1/courses_ids/ + + **Response Values** + + Body comprises a list of course ids and pagination details. + + **Parameters** + + username (optional): + The username of the specified user whose visible courses we + want to see. + + role (required): + Course ids are filtered such that only those for which the + user has the specified role are returned. Role can be "staff" + or "instructor". + Case-insensitive. + + **Returns** + + * 200 on success, with a list of course ids and pagination details + * 400 if an invalid parameter was sent or the username was not provided + for an authenticated request. + * 403 if a user who does not have permission to masquerade as + another user who specifies a username other than their own. + * 404 if the specified user does not exist, or the requesting user does + not have permission to view their courses. + + Example response: + + { + "results": + [ + "course-v1:edX+DemoX+Demo_Course" + ], + "pagination": { + "previous": null, + "num_pages": 1, + "next": null, + "count": 1 + } + } parameters: - name: page in: query @@ -1310,36 +1969,68 @@ paths: get: operationId: courses_v1_courses_list summary: '**Use Cases**' - description: "Request information on all courses visible to the specified user.\n\ - \n**Example Requests**\n\n GET /api/courses/v1/courses/\n\n**Response Values**\n\ - \n Body comprises a list of objects as returned by `CourseDetailView`.\n\ - \n**Parameters**\n\n search_term (optional):\n Search term to filter\ - \ courses (used by ElasticSearch).\n\n username (optional):\n The\ - \ username of the specified user whose visible courses we\n want to\ - \ see. The username is not required only if the API is\n requested\ - \ by an Anonymous user.\n\n org (optional):\n If specified, visible\ - \ `CourseOverview` objects are filtered\n such that only those belonging\ - \ to the organization with the\n provided org code (e.g., \"HarvardX\"\ - ) are returned.\n Case-insensitive.\n\n**Returns**\n\n * 200 on\ - \ success, with a list of course discovery objects as returned\n by `CourseDetailView`.\n\ - \ * 400 if an invalid parameter was sent or the username was not provided\n\ - \ for an authenticated request.\n * 403 if a user who does not have\ - \ permission to masquerade as\n another user specifies a username other\ - \ than their own.\n * 404 if the specified user does not exist, or the\ - \ requesting user does\n not have permission to view their courses.\n\ - \n Example response:\n\n [\n {\n \"blocks_url\"\ - : \"/api/courses/v1/blocks/?course_id=edX%2Fexample%2F2012_Fall\",\n \ - \ \"media\": {\n \"course_image\": {\n \"\ - uri\": \"/c4x/edX/example/asset/just_a_test.jpg\",\n \"name\"\ - : \"Course Image\"\n }\n },\n \"description\"\ - : \"An example course.\",\n \"end\": \"2015-09-19T18:00:00Z\",\n\ - \ \"enrollment_end\": \"2015-07-15T00:00:00Z\",\n \"\ - enrollment_start\": \"2015-06-15T00:00:00Z\",\n \"course_id\":\ - \ \"edX/example/2012_Fall\",\n \"name\": \"Example Course\",\n\ - \ \"number\": \"example\",\n \"org\": \"edX\",\n \ - \ \"start\": \"2015-07-17T12:00:00Z\",\n \"start_display\"\ - : \"July 17, 2015\",\n \"start_type\": \"timestamp\"\n \ - \ }\n ]" + description: |- + Request information on all courses visible to the specified user. + + **Example Requests** + + GET /api/courses/v1/courses/ + + **Response Values** + + Body comprises a list of objects as returned by `CourseDetailView`. + + **Parameters** + + search_term (optional): + Search term to filter courses (used by ElasticSearch). + + username (optional): + The username of the specified user whose visible courses we + want to see. The username is not required only if the API is + requested by an Anonymous user. + + org (optional): + If specified, visible `CourseOverview` objects are filtered + such that only those belonging to the organization with the + provided org code (e.g., "HarvardX") are returned. + Case-insensitive. + + **Returns** + + * 200 on success, with a list of course discovery objects as returned + by `CourseDetailView`. + * 400 if an invalid parameter was sent or the username was not provided + for an authenticated request. + * 403 if a user who does not have permission to masquerade as + another user specifies a username other than their own. + * 404 if the specified user does not exist, or the requesting user does + not have permission to view their courses. + + Example response: + + [ + { + "blocks_url": "/api/courses/v1/blocks/?course_id=edX%2Fexample%2F2012_Fall", + "media": { + "course_image": { + "uri": "/c4x/edX/example/asset/just_a_test.jpg", + "name": "Course Image" + } + }, + "description": "An example course.", + "end": "2015-09-19T18:00:00Z", + "enrollment_end": "2015-07-15T00:00:00Z", + "enrollment_start": "2015-06-15T00:00:00Z", + "course_id": "edX/example/2012_Fall", + "name": "Example Course", + "number": "example", + "org": "edX", + "start": "2015-07-17T12:00:00Z", + "start_display": "July 17, 2015", + "start_type": "timestamp" + } + ] parameters: - name: page in: query @@ -1381,51 +2072,88 @@ paths: : get: operationId: courses_v1_courses_+]+api_courses_v1_courses_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request details for a course\n\n**Example Requests**\n\n GET\ - \ /api/courses/v1/courses/{course_key}/\n\n**Response Values**\n\n Body\ - \ consists of the following fields:\n\n * effort: A textual description\ - \ of the weekly hours of effort expected\n in the course.\n * end:\ - \ Date the course ends, in ISO 8601 notation\n * enrollment_end: Date enrollment\ - \ ends, in ISO 8601 notation\n * enrollment_start: Date enrollment begins,\ - \ in ISO 8601 notation\n * id: A unique identifier of the course; a serialized\ - \ representation\n of the opaque key identifying the course.\n *\ - \ media: An object that contains named media items. Included here:\n \ - \ * course_image: An image to show for the course. Represented\n \ - \ as an object with the following fields:\n * uri: The location\ - \ of the image\n * name: Name of the course\n * number: Catalog number\ - \ of the course\n * org: Name of the organization that owns the course\n\ - \ * overview: A possibly verbose HTML textual description of the course.\n\ - \ Note: this field is only included in the Course Detail view, not\n\ - \ the Course List view.\n * short_description: A textual description\ - \ of the course\n * start: Date the course begins, in ISO 8601 notation\n\ - \ * start_display: Readably formatted start of the course\n * start_type:\ - \ Hint describing how `start_display` is set. One of:\n * `\"string\"\ - `: manually set by the course author\n * `\"timestamp\"`: generated\ - \ from the `start` timestamp\n * `\"empty\"`: no start date is specified\n\ - \ * pacing: Course pacing. Possible values: instructor, self\n\n Deprecated\ - \ fields:\n\n * blocks_url: Used to fetch the course blocks\n * course_id:\ - \ Course key (use 'id' instead)\n\n**Parameters:**\n\n username (optional):\n\ - \ The username of the specified user for whom the course data\n \ - \ is being accessed. The username is not only required if the API is\n\ - \ requested by an Anonymous user.\n\n**Returns**\n\n * 200 on success\ - \ with above fields.\n * 400 if an invalid parameter was sent or the username\ - \ was not provided\n for an authenticated request.\n * 403 if a user\ - \ who does not have permission to masquerade as\n another user specifies\ - \ a username other than their own.\n * 404 if the course is not available\ - \ or cannot be seen.\n\n Example response:\n\n {\n \"\ - blocks_url\": \"/api/courses/v1/blocks/?course_id=edX%2Fexample%2F2012_Fall\"\ - ,\n \"media\": {\n \"course_image\": {\n \ - \ \"uri\": \"/c4x/edX/example/asset/just_a_test.jpg\",\n \ - \ \"name\": \"Course Image\"\n }\n \ - \ },\n \"description\": \"An example course.\",\n \"\ - end\": \"2015-09-19T18:00:00Z\",\n \"enrollment_end\": \"2015-07-15T00:00:00Z\"\ - ,\n \"enrollment_start\": \"2015-06-15T00:00:00Z\",\n \ - \ \"course_id\": \"edX/example/2012_Fall\",\n \"name\": \"Example\ - \ Course\",\n \"number\": \"example\",\n \"org\": \"\ - edX\",\n \"overview: \"

A verbose description of the course.

\"\ - \n \"start\": \"2015-07-17T12:00:00Z\",\n \"start_display\"\ - : \"July 17, 2015\",\n \"start_type\": \"timestamp\",\n \ - \ \"pacing\": \"instructor\"\n }" + description: |- + Request details for a course + + **Example Requests** + + GET /api/courses/v1/courses/{course_key}/ + + **Response Values** + + Body consists of the following fields: + + * effort: A textual description of the weekly hours of effort expected + in the course. + * end: Date the course ends, in ISO 8601 notation + * enrollment_end: Date enrollment ends, in ISO 8601 notation + * enrollment_start: Date enrollment begins, in ISO 8601 notation + * id: A unique identifier of the course; a serialized representation + of the opaque key identifying the course. + * media: An object that contains named media items. Included here: + * course_image: An image to show for the course. Represented + as an object with the following fields: + * uri: The location of the image + * name: Name of the course + * number: Catalog number of the course + * org: Name of the organization that owns the course + * overview: A possibly verbose HTML textual description of the course. + Note: this field is only included in the Course Detail view, not + the Course List view. + * short_description: A textual description of the course + * start: Date the course begins, in ISO 8601 notation + * start_display: Readably formatted start of the course + * start_type: Hint describing how `start_display` is set. One of: + * `"string"`: manually set by the course author + * `"timestamp"`: generated from the `start` timestamp + * `"empty"`: no start date is specified + * pacing: Course pacing. Possible values: instructor, self + + Deprecated fields: + + * blocks_url: Used to fetch the course blocks + * course_id: Course key (use 'id' instead) + + **Parameters:** + + username (optional): + The username of the specified user for whom the course data + is being accessed. The username is not only required if the API is + requested by an Anonymous user. + + **Returns** + + * 200 on success with above fields. + * 400 if an invalid parameter was sent or the username was not provided + for an authenticated request. + * 403 if a user who does not have permission to masquerade as + another user specifies a username other than their own. + * 404 if the course is not available or cannot be seen. + + Example response: + + { + "blocks_url": "/api/courses/v1/blocks/?course_id=edX%2Fexample%2F2012_Fall", + "media": { + "course_image": { + "uri": "/c4x/edX/example/asset/just_a_test.jpg", + "name": "Course Image" + } + }, + "description": "An example course.", + "end": "2015-09-19T18:00:00Z", + "enrollment_end": "2015-07-15T00:00:00Z", + "enrollment_start": "2015-06-15T00:00:00Z", + "course_id": "edX/example/2012_Fall", + "name": "Example Course", + "number": "example", + "org": "edX", + "overview: "

A verbose description of the course.

" + "start": "2015-07-17T12:00:00Z", + "start_display": "July 17, 2015", + "start_type": "timestamp", + "pacing": "instructor" + } parameters: [] responses: '200': @@ -1447,22 +2175,41 @@ paths: get: operationId: courses_v2_blocks_list summary: '**Use Case**' - description: "Returns the blocks in the course according to the requesting user's\n\ - \ access level.\n\n**Example requests**:\n\n GET /api/courses/v1/blocks/?course_id=\n\ - \ GET /api/courses/v1/blocks/?course_id=\n &username=anjali\n\ - \ &depth=all\n &requested_fields=graded,format,student_view_multi_device,lti_url\n\ - \ &block_counts=video\n &student_view_data=video\n &block_types_filter=problem,html\n\ - \n**Parameters**:\n\n This view redirects to /api/courses/v1/blocks//\ - \ for the\n root usage key of the course specified by course_id. The view\ - \ accepts\n all parameters accepted by :class:`BlocksView`, plus the following\n\ - \ required parameter\n\n * course_id: (string, required) The ID of the\ - \ course whose block data\n we want to return\n\n**Response Values**\n\ - \n Responses are identical to those returned by :class:`BlocksView` when\n\ - \ passed the root_usage_key of the requested course.\n\n If the course_id\ - \ is not supplied, a 400: Bad Request is returned, with\n a message indicating\ - \ that course_id is required.\n\n If an invalid course_id is supplied,\ - \ a 400: Bad Request is returned,\n with a message indicating that the\ - \ course_id is not valid." + description: |- + Returns the blocks in the course according to the requesting user's + access level. + + **Example requests**: + + GET /api/courses/v1/blocks/?course_id= + GET /api/courses/v1/blocks/?course_id= + &username=anjali + &depth=all + &requested_fields=graded,format,student_view_multi_device,lti_url + &block_counts=video + &student_view_data=video + &block_types_filter=problem,html + + **Parameters**: + + This view redirects to /api/courses/v1/blocks// for the + root usage key of the course specified by course_id. The view accepts + all parameters accepted by :class:`BlocksView`, plus the following + required parameter + + * course_id: (string, required) The ID of the course whose block data + we want to return + + **Response Values** + + Responses are identical to those returned by :class:`BlocksView` when + passed the root_usage_key of the requested course. + + If the course_id is not supplied, a 400: Bad Request is returned, with + a message indicating that course_id is required. + + If an invalid course_id is supplied, a 400: Bad Request is returned, + with a message indicating that the course_id is not valid. parameters: - name: page in: query @@ -1484,100 +2231,180 @@ paths: : get: operationId: courses_v2_blocks_courses_v2_blocks__[_]+_[_]+_[_]+_[@]+(:@[_read summary: '**Use Case**' - description: "Returns the blocks within the requested block tree according to\ - \ the\n requesting user's access level.\n\n**Example requests**:\n\n \ - \ GET /api/courses/v1/blocks//?depth=all\n GET /api/courses/v1/blocks//?\n\ - \ username=anjali\n &depth=all\n &requested_fields=graded,format,student_view_multi_device,lti_url,due\n\ - \ &block_counts=video\n &student_view_data=video\n &block_types_filter=problem,html\n\ - \n**Parameters**:\n\n * all_blocks: (boolean) Provide a value of \"true\"\ - \ to return all\n blocks. Returns all blocks only if the requesting user\ - \ has course\n staff permissions. Blocks that are visible only to specific\ - \ learners\n (for example, based on group membership or randomized content)\ - \ are\n all included. If all_blocks is not specified, you must specify\ - \ the\n username for the user whose course blocks are requested.\n\n\ - \ * username: (string) Required, unless ``all_blocks`` is specified.\n\ - \ Specify the username for the user whose course blocks are requested.\n\ - \ A blank/empty username can be used to request the blocks accessible\n\ - \ to anonymous users (for public courses). Only users with course staff\n\ - \ permissions can specify other users' usernames. If a username is\n\ - \ specified, results include blocks that are visible to that user,\n\ - \ including those based on group or cohort membership or randomized\n\ - \ content assigned to that user.\n\n Example: username=anjali\n\ - \ username=''\n username\n\n * student_view_data:\ - \ (list) Indicates for which block types to return\n student_view_data.\n\ - \n Example: student_view_data=video\n\n * block_counts: (list) Indicates\ - \ for which block types to return the\n aggregate count of the blocks.\n\ - \n Example: block_counts=video,problem\n\n * requested_fields: (list)\ - \ Indicates which additional fields to return\n for each block. For\ - \ a list of available fields see under `Response\n Values -> blocks`,\ - \ below.\n\n The following fields are always returned: id, type, display_name\n\ - \n Example: requested_fields=graded,format,student_view_multi_device\n\ - \n * depth: (integer or all) Indicates how deep to traverse into the blocks\n\ - \ hierarchy. A value of all means the entire hierarchy.\n\n Default\ - \ is 0\n\n Example: depth=all\n\n * nav_depth: (integer)\n\n \ - \ WARNING: nav_depth is not supported, and may be removed at any time.\n\n\ - \ Indicates how far deep to traverse into the\n course hierarchy\ - \ before bundling all the descendants.\n\n Default is 3 since typical\ - \ navigational views of the course show a\n maximum of chapter->sequential->vertical.\n\ - \n Example: nav_depth=3\n\n * return_type (string) Indicates in what\ - \ data type to return the\n blocks.\n\n Default is dict. Supported\ - \ values are: dict, list\n\n Example: return_type=dict\n\n * block_types_filter:\ - \ (list) Requested types of blocks used to filter the final result\n \ - \ of returned blocks. Possible values include sequential, vertical, html,\ - \ problem,\n video, and discussion.\n\n Example: block_types_filter=vertical,html\n\ - \n**Response Values**\n\n The following fields are returned with a successful\ - \ response.\n\n * root: The ID of the root node of the requested course\ - \ block\n structure.\n\n * blocks: A dictionary or list, based on\ - \ the value of the\n \"return_type\" parameter. Maps block usage IDs\ - \ to a collection of\n information about each block. Each block contains\ - \ the following\n fields.\n\n * id: (string) The usage ID of the\ - \ block.\n\n * type: (string) The type of block. Possible values the\ - \ names of any\n XBlock type in the system, including custom blocks.\ - \ Examples are\n course, chapter, sequential, vertical, html, problem,\ - \ video, and\n discussion.\n\n * display_name: (string) The display\ - \ name of the block.\n\n * children: (list) If the block has child blocks,\ - \ a list of IDs of\n the child blocks. Returned only if \"children\"\ - \ is included in the\n \"requested_fields\" parameter.\n\n * completion:\ - \ (float or None) The level of completion of the block.\n Its value\ - \ can vary between 0.0 and 1.0 or be equal to None\n if block is not\ - \ completable. Returned only if \"completion\"\n is included in the\ - \ \"requested_fields\" parameter.\n\n * block_counts: (dict) For each\ - \ block type specified in the\n block_counts parameter to the endpoint,\ - \ the aggregate number of\n blocks of that type for this block and\ - \ all of its descendants.\n\n * graded (boolean) Whether or not the block\ - \ or any of its descendants\n is graded. Returned only if \"graded\"\ - \ is included in the\n \"requested_fields\" parameter.\n\n * format:\ - \ (string) The assignment type of the block. Possible values\n can\ - \ be \"Homework\", \"Lab\", \"Midterm Exam\", and \"Final Exam\".\n \ - \ Returned only if \"format\" is included in the \"requested_fields\"\n \ - \ parameter.\n\n * student_view_data: (dict) The JSON data for\ - \ this block.\n Returned only if the \"student_view_data\" input parameter\ - \ contains\n this block's type.\n\n * student_view_url: (string)\ - \ The URL to retrieve the HTML rendering\n of this block's student\ - \ view. The HTML could include CSS and\n Javascript code. This field\ - \ can be used in combination with the\n student_view_multi_device field\ - \ to decide whether to display this\n content to the user.\n\n \ - \ This URL can be used as a fallback if the student_view_data for\n \ - \ this block type is not supported by the client or the block.\n\n \ - \ * student_view_multi_device: (boolean) Whether or not the HTML of\n \ - \ the student view that is rendered at \"student_view_url\" supports\n\ - \ responsive web layouts, touch-based inputs, and interactive state\n\ - \ management for a variety of device sizes and types, including\n \ - \ mobile and touch devices. Returned only if\n \"student_view_multi_device\"\ - \ is included in the \"requested_fields\"\n parameter.\n\n * lms_web_url:\ - \ (string) The URL to the navigational container of the\n xBlock on\ - \ the web LMS. This URL can be used as a further fallback\n if the\ - \ student_view_url and the student_view_data fields are not\n supported.\n\ - \n * lti_url: The block URL for an LTI consumer. Returned only if the\n\ - \ \"ENABLE_LTI_PROVIDER\" Django settign is set to \"True\".\n\n \ - \ * due: The due date of the block. Returned only if \"due\" is included\n\ - \ in the \"requested_fields\" parameter.\n\n * show_correctness:\ - \ Whether to show scores/correctness to learners for the current sequence\ - \ or problem.\n Returned only if \"show_correctness\" is included in\ - \ the \"requested_fields\" parameter.\n\n * Additional XBlock fields\ - \ can be included in the response if they are\n configured via the\ - \ COURSE_BLOCKS_API_EXTRA_FIELDS Django setting and\n requested via\ - \ the \"requested_fields\" parameter." + description: |- + Returns the blocks within the requested block tree according to the + requesting user's access level. + + **Example requests**: + + GET /api/courses/v1/blocks//?depth=all + GET /api/courses/v1/blocks//? + username=anjali + &depth=all + &requested_fields=graded,format,student_view_multi_device,lti_url,due + &block_counts=video + &student_view_data=video + &block_types_filter=problem,html + + **Parameters**: + + * all_blocks: (boolean) Provide a value of "true" to return all + blocks. Returns all blocks only if the requesting user has course + staff permissions. Blocks that are visible only to specific learners + (for example, based on group membership or randomized content) are + all included. If all_blocks is not specified, you must specify the + username for the user whose course blocks are requested. + + * username: (string) Required, unless ``all_blocks`` is specified. + Specify the username for the user whose course blocks are requested. + A blank/empty username can be used to request the blocks accessible + to anonymous users (for public courses). Only users with course staff + permissions can specify other users' usernames. If a username is + specified, results include blocks that are visible to that user, + including those based on group or cohort membership or randomized + content assigned to that user. + + Example: username=anjali + username='' + username + + * student_view_data: (list) Indicates for which block types to return + student_view_data. + + Example: student_view_data=video + + * block_counts: (list) Indicates for which block types to return the + aggregate count of the blocks. + + Example: block_counts=video,problem + + * requested_fields: (list) Indicates which additional fields to return + for each block. For a list of available fields see under `Response + Values -> blocks`, below. + + The following fields are always returned: id, type, display_name + + Example: requested_fields=graded,format,student_view_multi_device + + * depth: (integer or all) Indicates how deep to traverse into the blocks + hierarchy. A value of all means the entire hierarchy. + + Default is 0 + + Example: depth=all + + * nav_depth: (integer) + + WARNING: nav_depth is not supported, and may be removed at any time. + + Indicates how far deep to traverse into the + course hierarchy before bundling all the descendants. + + Default is 3 since typical navigational views of the course show a + maximum of chapter->sequential->vertical. + + Example: nav_depth=3 + + * return_type (string) Indicates in what data type to return the + blocks. + + Default is dict. Supported values are: dict, list + + Example: return_type=dict + + * block_types_filter: (list) Requested types of blocks used to filter the final result + of returned blocks. Possible values include sequential, vertical, html, problem, + video, and discussion. + + Example: block_types_filter=vertical,html + + **Response Values** + + The following fields are returned with a successful response. + + * root: The ID of the root node of the requested course block + structure. + + * blocks: A dictionary or list, based on the value of the + "return_type" parameter. Maps block usage IDs to a collection of + information about each block. Each block contains the following + fields. + + * id: (string) The usage ID of the block. + + * type: (string) The type of block. Possible values the names of any + XBlock type in the system, including custom blocks. Examples are + course, chapter, sequential, vertical, html, problem, video, and + discussion. + + * display_name: (string) The display name of the block. + + * children: (list) If the block has child blocks, a list of IDs of + the child blocks. Returned only if "children" is included in the + "requested_fields" parameter. + + * completion: (float or None) The level of completion of the block. + Its value can vary between 0.0 and 1.0 or be equal to None + if block is not completable. Returned only if "completion" + is included in the "requested_fields" parameter. + + * block_counts: (dict) For each block type specified in the + block_counts parameter to the endpoint, the aggregate number of + blocks of that type for this block and all of its descendants. + + * graded (boolean) Whether or not the block or any of its descendants + is graded. Returned only if "graded" is included in the + "requested_fields" parameter. + + * format: (string) The assignment type of the block. Possible values + can be "Homework", "Lab", "Midterm Exam", and "Final Exam". + Returned only if "format" is included in the "requested_fields" + parameter. + + * student_view_data: (dict) The JSON data for this block. + Returned only if the "student_view_data" input parameter contains + this block's type. + + * student_view_url: (string) The URL to retrieve the HTML rendering + of this block's student view. The HTML could include CSS and + Javascript code. This field can be used in combination with the + student_view_multi_device field to decide whether to display this + content to the user. + + This URL can be used as a fallback if the student_view_data for + this block type is not supported by the client or the block. + + * student_view_multi_device: (boolean) Whether or not the HTML of + the student view that is rendered at "student_view_url" supports + responsive web layouts, touch-based inputs, and interactive state + management for a variety of device sizes and types, including + mobile and touch devices. Returned only if + "student_view_multi_device" is included in the "requested_fields" + parameter. + + * lms_web_url: (string) The URL to the navigational container of the + xBlock on the web. This URL can be used as a further fallback + if the student_view_url and the student_view_data fields are not + supported. Will direct to either the "New" (micro-frontend) or + "Legacy" (Django-template-rendered) frontend experience depending + on which experience is active. + + * legacy_web_url: (string) Like `lms_web_url`, but always directs to + the "Legacy" frontend experience. Should only be used for + transitional purposes; will be removed as part of DEPR-109. + + * lti_url: The block URL for an LTI consumer. Returned only if the + "ENABLE_LTI_PROVIDER" Django settign is set to "True". + + * due: The due date of the block. Returned only if "due" is included + in the "requested_fields" parameter. + + * show_correctness: Whether to show scores/correctness to learners for the current sequence or problem. + Returned only if "show_correctness" is included in the "requested_fields" parameter. + + * Additional XBlock fields can be included in the response if they are + configured via the COURSE_BLOCKS_API_EXTRA_FIELDS Django setting and + requested via the "requested_fields" parameter. parameters: - name: page in: query @@ -1626,47 +2453,92 @@ paths: : get: operationId: courseware_course_+]+api_courseware_course_+]+(_|+)[_]+)_read summary: '**Use Cases**' - description: "Request details for a course\n\n**Example Requests**\n\n GET\ - \ /api/courseware/course/{course_key}\n\n**Response Values**\n\n Body consists\ - \ of the following fields:\n\n * effort: A textual description of the weekly\ - \ hours of effort expected\n in the course.\n * end: Date the course\ - \ ends, in ISO 8601 notation\n * enrollment_end: Date enrollment ends,\ - \ in ISO 8601 notation\n * enrollment_start: Date enrollment begins, in\ - \ ISO 8601 notation\n * id: A unique identifier of the course; a serialized\ - \ representation\n of the opaque key identifying the course.\n *\ - \ media: An object that contains named media items. Included here:\n \ - \ * course_image: An image to show for the course. Represented\n \ - \ as an object with the following fields:\n * uri: The location\ - \ of the image\n * name: Name of the course\n * number: Catalog number\ - \ of the course\n * org: Name of the organization that owns the course\n\ - \ * short_description: A textual description of the course\n * start:\ - \ Date the course begins, in ISO 8601 notation\n * start_display: Readably\ - \ formatted start of the course\n * start_type: Hint describing how `start_display`\ - \ is set. One of:\n * `\"string\"`: manually set by the course author\n\ - \ * `\"timestamp\"`: generated from the `start` timestamp\n \ - \ * `\"empty\"`: no start date is specified\n * pacing: Course pacing.\ - \ Possible values: instructor, self\n * tabs: Course tabs\n * enrollment:\ - \ Enrollment status of authenticated user\n * mode: `audit`, `verified`,\ - \ etc\n * is_active: boolean\n * can_load_course: Whether the user\ - \ can view the course (AccessResponse object)\n * is_staff: Whether the\ - \ effective user has staff access to the course\n * original_user_is_staff:\ - \ Whether the original user has staff access to the course\n * user_has_passing_grade:\ - \ Whether or not the effective user's grade is equal to or above the courses\ - \ minimum\n passing grade\n * course_exit_page_is_active: Flag for\ - \ the learning mfe on whether or not the course exit page should display\n\ - \ * certificate_data: data regarding the effective user's certificate for\ - \ the given course\n * verify_identity_url: URL for a learner to verify\ - \ their identity. Only returned for learners enrolled in a\n verified\ - \ mode. Will update to reverify URL if necessary.\n * linkedin_add_to_profile_url:\ - \ URL to add the effective user's certificate to a LinkedIn Profile.\n\n**Parameters:**\n\ - \n requested_fields (optional) comma separated list:\n If set, then\ - \ only those fields will be returned.\n username (optional) username to\ - \ masquerade as (if requesting user is staff)\n\n**Returns**\n\n * 200\ - \ on success with above fields.\n * 400 if an invalid parameter was sent\ - \ or the username was not provided\n for an authenticated request.\n\ - \ * 403 if a user who does not have permission to masquerade as\n \ - \ another user specifies a username other than their own.\n * 404 if the\ - \ course is not available or cannot be seen." + description: |- + Request details for a course + + **Example Requests** + + GET /api/courseware/course/{course_key} + + **Response Values** + + Body consists of the following fields: + + * access_expiration: An object detailing when access to this course will expire + * expiration_date: (str) When the access expires, in ISO 8601 notation + * masquerading_expired_course: (bool) Whether this course is expired for the masqueraded user + * upgrade_deadline: (str) Last chance to upgrade, in ISO 8601 notation (or None if can't upgrade anymore) + * upgrade_url: (str) Upgrade linke (or None if can't upgrade anymore) + * effort: A textual description of the weekly hours of effort expected + in the course. + * end: Date the course ends, in ISO 8601 notation + * enrollment: Enrollment status of authenticated user + * mode: `audit`, `verified`, etc + * is_active: boolean + * enrollment_end: Date enrollment ends, in ISO 8601 notation + * enrollment_start: Date enrollment begins, in ISO 8601 notation + * id: A unique identifier of the course; a serialized representation + of the opaque key identifying the course. + * media: An object that contains named media items. Included here: + * course_image: An image to show for the course. Represented + as an object with the following fields: + * uri: The location of the image + * name: Name of the course + * number: Catalog number of the course + * offer: An object detailing upgrade discount information + * code: (str) Checkout code + * expiration_date: (str) Expiration of offer, in ISO 8601 notation + * original_price: (str) Full upgrade price without checkout code; includes currency symbol + * discounted_price: (str) Upgrade price with checkout code; includes currency symbol + * percentage: (int) Amount of discount + * upgrade_url: (str) Checkout URL + * org: Name of the organization that owns the course + * related_programs: A list of objects that contains program data related to the given course including: + * progress: An object containing program progress: + * complete: (int) Number of complete courses in the program (a course is completed if the user has + earned a certificate for any of the nested course runs) + * in_progress: (int) Number of courses in the program that are in progress (a course is in progress if + the user has enrolled in any of the nested course runs) + * not_started: (int) Number of courses in the program that have not been started + * slug: (str) The program type + * title: (str) The title of the program + * url: (str) The link to the program's landing page + * uuid: (str) A unique identifier of the program + * short_description: A textual description of the course + * start: Date the course begins, in ISO 8601 notation + * start_display: Readably formatted start of the course + * start_type: Hint describing how `start_display` is set. One of: + * `"string"`: manually set by the course author + * `"timestamp"`: generated from the `start` timestamp + * `"empty"`: no start date is specified + * pacing: Course pacing. Possible values: instructor, self + * tabs: Course tabs + * user_timezone: User's chosen timezone setting (or null for browser default) + * can_load_course: Whether the user can view the course (AccessResponse object) + * is_staff: Whether the effective user has staff access to the course + * original_user_is_staff: Whether the original user has staff access to the course + * user_has_passing_grade: Whether or not the effective user's grade is equal to or above the courses minimum + passing grade + * course_exit_page_is_active: Flag for the learning mfe on whether or not the course exit page should display + * certificate_data: data regarding the effective user's certificate for the given course + * verify_identity_url: URL for a learner to verify their identity. Only returned for learners enrolled in a + verified mode. Will update to reverify URL if necessary. + * linkedin_add_to_profile_url: URL to add the effective user's certificate to a LinkedIn Profile. + + **Parameters:** + + requested_fields (optional) comma separated list: + If set, then only those fields will be returned. + username (optional) username to masquerade as (if requesting user is staff) + + **Returns** + + * 200 on success with above fields. + * 400 if an invalid parameter was sent or the username was not provided + for an authenticated request. + * 403 if a user who does not have permission to masquerade as + another user specifies a username other than their own. + * 404 if the course is not available or cannot be seen. parameters: [] responses: '200': @@ -1971,8 +2843,9 @@ paths: /discussion/v1/comments/: get: operationId: discussion_v1_comments_list - description: "Implements the GET method for the list endpoint as described in\ - \ the\nclass docstring." + description: |- + Implements the GET method for the list endpoint as described in the + class docstring. parameters: [] responses: '200': @@ -1984,8 +2857,9 @@ paths: - discussion post: operationId: discussion_v1_comments_create - description: "Implements the POST method for the list endpoint as described\ - \ in the\nclass docstring." + description: |- + Implements the POST method for the list endpoint as described in the + class docstring. parameters: [] responses: '201': @@ -2011,8 +2885,9 @@ paths: - discussion patch: operationId: discussion_v1_comments_partial_update - description: "Implements the PATCH method for the instance endpoint as described\ - \ in\nthe class docstring." + description: |- + Implements the PATCH method for the instance endpoint as described in + the class docstring. parameters: [] responses: '200': @@ -2024,8 +2899,9 @@ paths: - discussion delete: operationId: discussion_v1_comments_delete - description: "Implements the DELETE method for the instance endpoint as described\ - \ in\nthe class docstring" + description: |- + Implements the DELETE method for the instance endpoint as described in + the class docstring parameters: [] responses: '204': @@ -2139,8 +3015,9 @@ paths: /discussion/v1/threads/: get: operationId: discussion_v1_threads_list - description: "Implements the GET method for the list endpoint as described in\ - \ the\nclass docstring." + description: |- + Implements the GET method for the list endpoint as described in the + class docstring. parameters: [] responses: '200': @@ -2152,8 +3029,9 @@ paths: - discussion post: operationId: discussion_v1_threads_create - description: "Implements the POST method for the list endpoint as described\ - \ in the\nclass docstring." + description: |- + Implements the POST method for the list endpoint as described in the + class docstring. parameters: [] responses: '201': @@ -2179,8 +3057,9 @@ paths: - discussion patch: operationId: discussion_v1_threads_partial_update - description: "Implements the PATCH method for the instance endpoint as described\ - \ in\nthe class docstring." + description: |- + Implements the PATCH method for the instance endpoint as described in + the class docstring. parameters: [] responses: '200': @@ -2192,8 +3071,9 @@ paths: - discussion delete: operationId: discussion_v1_threads_delete - description: "Implements the DELETE method for the instance endpoint as described\ - \ in\nthe class docstring" + description: |- + Implements the DELETE method for the instance endpoint as described in + the class docstring parameters: [] responses: '204': @@ -2267,8 +3147,9 @@ paths: /edx_proctoring/v1/proctored_exam/allowance: get: operationId: edx_proctoring_v1_proctored_exam_allowance_list - description: "HTTP GET handler. Get all allowances for a course.\nCourse and\ - \ Global staff can view both timed and proctored exam allowances." + description: |- + HTTP GET handler. Get all allowances for a course. + Course and Global staff can view both timed and proctored exam allowances. parameters: [] responses: '200': @@ -2314,11 +3195,10 @@ paths: tags: - edx_proctoring parameters: [] - /edx_proctoring/v1/proctored_exam/attempt/course_id/{course_id}: + /edx_proctoring/v1/proctored_exam/attempt/grouped/course_id/{course_id}: get: - operationId: edx_proctoring_v1_proctored_exam_attempt_course_id_read - description: "HTTP GET Handler. Returns the status of the exam attempt.\nCourse\ - \ and Global staff can view both timed and proctored exam attempts." + operationId: edx_proctoring_v1_proctored_exam_attempt_grouped_course_id_read + description: HTTP GET Handler. parameters: [] responses: '200': @@ -2330,11 +3210,10 @@ paths: in: path required: true type: string - /edx_proctoring/v1/proctored_exam/attempt/course_id/{course_id}/search/{search_by}: + /edx_proctoring/v1/proctored_exam/attempt/grouped/course_id/{course_id}/search/{search_by}: get: - operationId: edx_proctoring_v1_proctored_exam_attempt_course_id_search_read - description: "HTTP GET Handler. Returns the status of the exam attempt.\nCourse\ - \ and Global staff can view both timed and proctored exam attempts." + operationId: edx_proctoring_v1_proctored_exam_attempt_grouped_course_id_search_read + description: HTTP GET Handler. parameters: [] responses: '200': @@ -2362,7 +3241,7 @@ paths: - edx_proctoring put: operationId: edx_proctoring_v1_proctored_exam_attempt_update - description: HTTP POST handler. To stop an exam. + description: HTTP PUT handler to update exam attempt status based on an action. parameters: [] responses: '200': @@ -2386,7 +3265,7 @@ paths: /edx_proctoring/v1/proctored_exam/attempt/{attempt_id}/review_status: put: operationId: edx_proctoring_v1_proctored_exam_attempt_review_status_update - description: Update the is_status_acknowledge flag for the specific attempt + description: Update the is_status_acknowledged flag for the specific attempt parameters: [] responses: '200': @@ -2416,8 +3295,9 @@ paths: /edx_proctoring/v1/proctored_exam/attempt/{external_id}/reviewed: post: operationId: edx_proctoring_v1_proctored_exam_attempt_reviewed_create - description: "Called when 3rd party proctoring service has finished its review\ - \ of\nan attempt." + description: |- + Called when 3rd party proctoring service has finished its review of + an attempt. parameters: [] responses: '201': @@ -2432,8 +3312,11 @@ paths: /edx_proctoring/v1/proctored_exam/exam: get: operationId: edx_proctoring_v1_proctored_exam_exam_list - description: "HTTP GET handler.\n Scenarios:\n by exam_id: calls get_exam_by_id()\n\ - \ by course_id, content_id: get_exam_by_content_id()" + description: |- + HTTP GET handler. + Scenarios: + by exam_id: calls get_exam_by_id() + by course_id, content_id: get_exam_by_content_id() parameters: [] responses: '200': @@ -2451,7 +3334,9 @@ paths: - edx_proctoring put: operationId: edx_proctoring_v1_proctored_exam_exam_update - description: "HTTP PUT handler. To update an exam.\ncalls the update_exam" + description: |- + HTTP PUT handler. To update an exam. + calls the update_exam parameters: [] responses: '200': @@ -2462,8 +3347,11 @@ paths: /edx_proctoring/v1/proctored_exam/exam/course_id/{course_id}: get: operationId: edx_proctoring_v1_proctored_exam_exam_course_id_read - description: "HTTP GET handler.\n Scenarios:\n by exam_id: calls get_exam_by_id()\n\ - \ by course_id, content_id: get_exam_by_content_id()" + description: |- + HTTP GET handler. + Scenarios: + by exam_id: calls get_exam_by_id() + by course_id, content_id: get_exam_by_content_id() parameters: [] responses: '200': @@ -2481,7 +3369,9 @@ paths: - edx_proctoring put: operationId: edx_proctoring_v1_proctored_exam_exam_course_id_update - description: "HTTP PUT handler. To update an exam.\ncalls the update_exam" + description: |- + HTTP PUT handler. To update an exam. + calls the update_exam parameters: [] responses: '200': @@ -2496,8 +3386,11 @@ paths: /edx_proctoring/v1/proctored_exam/exam/course_id/{course_id}/content_id/{content_id}: get: operationId: edx_proctoring_v1_proctored_exam_exam_course_id_content_id_read - description: "HTTP GET handler.\n Scenarios:\n by exam_id: calls get_exam_by_id()\n\ - \ by course_id, content_id: get_exam_by_content_id()" + description: |- + HTTP GET handler. + Scenarios: + by exam_id: calls get_exam_by_id() + by course_id, content_id: get_exam_by_content_id() parameters: [] responses: '200': @@ -2515,7 +3408,9 @@ paths: - edx_proctoring put: operationId: edx_proctoring_v1_proctored_exam_exam_course_id_content_id_update - description: "HTTP PUT handler. To update an exam.\ncalls the update_exam" + description: |- + HTTP PUT handler. To update an exam. + calls the update_exam parameters: [] responses: '200': @@ -2534,8 +3429,11 @@ paths: /edx_proctoring/v1/proctored_exam/exam/exam_id/{exam_id}: get: operationId: edx_proctoring_v1_proctored_exam_exam_exam_id_read - description: "HTTP GET handler.\n Scenarios:\n by exam_id: calls get_exam_by_id()\n\ - \ by course_id, content_id: get_exam_by_content_id()" + description: |- + HTTP GET handler. + Scenarios: + by exam_id: calls get_exam_by_id() + by course_id, content_id: get_exam_by_content_id() parameters: [] responses: '200': @@ -2553,7 +3451,9 @@ paths: - edx_proctoring put: operationId: edx_proctoring_v1_proctored_exam_exam_exam_id_update - description: "HTTP PUT handler. To update an exam.\ncalls the update_exam" + description: |- + HTTP PUT handler. To update an exam. + calls the update_exam parameters: [] responses: '200': @@ -2565,11 +3465,32 @@ paths: in: path required: true type: string + /edx_proctoring/v1/proctored_exam/exam_id/{exam_id}/user_id/{user_id}/reset_attempts: + delete: + operationId: edx_proctoring_v1_proctored_exam_exam_id_user_id_reset_attempts_delete + description: HTTP DELETE handler, deletes all attempts for a given exam and + username + parameters: [] + responses: + '204': + description: '' + tags: + - edx_proctoring + parameters: + - name: exam_id + in: path + required: true + type: string + - name: user_id + in: path + required: true + type: string /edx_proctoring/v1/proctored_exam/{course_id}/allowance: get: operationId: edx_proctoring_v1_proctored_exam_allowance_list - description: "HTTP GET handler. Get all allowances for a course.\nCourse and\ - \ Global staff can view both timed and proctored exam allowances." + description: |- + HTTP GET handler. Get all allowances for a course. + Course and Global staff can view both timed and proctored exam allowances. parameters: [] responses: '200': @@ -2602,8 +3523,9 @@ paths: /edx_proctoring/v1/retire_backend_user/{user_id}/: post: operationId: edx_proctoring_v1_retire_backend_user_create - description: "Deletes all user data for the particular user_id\nfrom all configured\ - \ backends" + description: |- + Deletes all user data for the particular user_id + from all configured backends parameters: [] responses: '201': @@ -2630,6 +3552,32 @@ paths: in: path required: true type: string + /edx_proctoring/v1/user_onboarding/status: + get: + operationId: edx_proctoring_v1_user_onboarding_status_list + description: HTTP GET handler. Returns the learner's onboarding status. + parameters: [] + responses: + '200': + description: '' + tags: + - edx_proctoring + parameters: [] + /edx_proctoring/v1/user_onboarding/status/course_id/{course_id}: + get: + operationId: edx_proctoring_v1_user_onboarding_status_course_id_read + description: HTTP GET handler. + parameters: [] + responses: + '200': + description: '' + tags: + - edx_proctoring + parameters: + - name: course_id + in: path + required: true + type: string /edxnotes/v1/retire_user/: post: operationId: edxnotes_v1_retire_user_create @@ -2641,6 +3589,17 @@ paths: tags: - edxnotes parameters: [] + /embargo/v1/course_access/: + get: + operationId: embargo_v1_course_access_list + description: GET /api/embargo/v1/course_access/ + parameters: [] + responses: + '200': + description: '' + tags: + - embargo + parameters: [] /enrollment/v1/course/{course_id}: get: operationId: enrollment_v1_course_read @@ -2661,17 +3620,20 @@ paths: get: operationId: enrollment_v1_enrollment_list summary: Gets a list of all course enrollments for a user. - description: "Returns a list for the currently logged in user, or for the user\ - \ named by the 'user' GET\nparameter. If the username does not match that\ - \ of the currently logged in user, only\ncourses for which the currently logged\ - \ in user has the Staff or Admin role are listed.\nAs a result, a course team\ - \ member can find out which of their own courses a particular\nlearner is\ - \ enrolled in.\n\nOnly the Staff or Admin role (granted on the Django administrative\ - \ console as the staff\nor instructor permission) in individual courses gives\ - \ the requesting user access to\nenrollment data. Permissions granted at the\ - \ organizational level do not give a user\naccess to enrollment data for all\ - \ of that organization's courses.\n\nUsers who have the global staff permission\ - \ can access all enrollment data for all\ncourses." + description: |- + Returns a list for the currently logged in user, or for the user named by the 'user' GET + parameter. If the username does not match that of the currently logged in user, only + courses for which the currently logged in user has the Staff or Admin role are listed. + As a result, a course team member can find out which of their own courses a particular + learner is enrolled in. + + Only the Staff or Admin role (granted on the Django administrative console as the staff + or instructor permission) in individual courses gives the requesting user access to + enrollment data. Permissions granted at the organizational level do not give a user + access to enrollment data for all of that organization's courses. + + Users who have the global staff permission can access all enrollment data for all + courses. parameters: [] responses: '200': @@ -2681,9 +3643,9 @@ paths: post: operationId: enrollment_v1_enrollment_create summary: Enrolls the currently logged-in user in a course. - description: "Server-to-server calls may deactivate or modify the mode of existing\ - \ enrollments. All other requests\ngo through `add_enrollment()`, which allows\ - \ creation of new and reactivation of old enrollments." + description: |- + Server-to-server calls may deactivate or modify the mode of existing enrollments. All other requests + go through `add_enrollment()`, which allows creation of new and reactivation of old enrollments. parameters: [] responses: '201': @@ -2695,9 +3657,9 @@ paths: get: operationId: enrollment_v1_enrollment_read summary: Create, read, or update enrollment information for a user. - description: "HTTP Endpoint for all CRUD operations for a user course enrollment.\ - \ Allows creation, reading, and\nupdates of the current enrollment for a particular\ - \ course." + description: |- + HTTP Endpoint for all CRUD operations for a user course enrollment. Allows creation, reading, and + updates of the current enrollment for a particular course. parameters: [] responses: '200': @@ -2713,9 +3675,9 @@ paths: get: operationId: enrollment_v1_enrollment_read summary: Create, read, or update enrollment information for a user. - description: "HTTP Endpoint for all CRUD operations for a user course enrollment.\ - \ Allows creation, reading, and\nupdates of the current enrollment for a particular\ - \ course." + description: |- + HTTP Endpoint for all CRUD operations for a user course enrollment. Allows creation, reading, and + updates of the current enrollment for a particular course. parameters: [] responses: '200': @@ -2735,35 +3697,66 @@ paths: get: operationId: enrollment_v1_enrollments_list summary: '**Use Cases**' - description: "Get a list of all course enrollments, optionally filtered by a\ - \ course ID or list of usernames.\n\n**Example Requests**\n\n GET /api/enrollment/v1/enrollments\n\ - \n GET /api/enrollment/v1/enrollments?course_id={course_id}\n\n GET\ - \ /api/enrollment/v1/enrollments?username={username},{username},{username}\n\ - \n GET /api/enrollment/v1/enrollments?course_id={course_id}&username={username}\n\ - \n**Query Parameters for GET**\n\n * course_id: Filters the result to course\ - \ enrollments for the course corresponding to the\n given course ID.\ - \ The value must be URL encoded. Optional.\n\n * username: List of comma-separated\ - \ usernames. Filters the result to the course enrollments\n of the given\ - \ users. Optional.\n\n * page_size: Number of results to return per page.\ - \ Optional.\n\n * page: Page number to retrieve. Optional.\n\n**Response\ - \ Values**\n\n If the request for information about the course enrollments\ - \ is successful, an HTTP 200 \"OK\" response\n is returned.\n\n The\ - \ HTTP 200 response has the following values.\n\n * results: A list of\ - \ the course enrollments matching the request.\n\n * created: Date\ - \ and time when the course enrollment was created.\n\n * mode: Mode\ - \ for the course enrollment.\n\n * is_active: Whether the course enrollment\ - \ is active or not.\n\n * user: Username of the user in the course\ - \ enrollment.\n\n * course_id: Course ID of the course in the course\ - \ enrollment.\n\n * next: The URL to the next page of results, or null\ - \ if this is the\n last page.\n\n * previous: The URL to the next\ - \ page of results, or null if this\n is the first page.\n\n If the\ - \ user is not logged in, a 401 error is returned.\n\n If the user is not\ - \ global staff, a 403 error is returned.\n\n If the specified course_id\ - \ is not valid or any of the specified usernames\n are not valid, a 400\ - \ error is returned.\n\n If the specified course_id does not correspond\ - \ to a valid course or if all the specified\n usernames do not correspond\ - \ to valid users, an HTTP 200 \"OK\" response is returned with an\n empty\ - \ 'results' field." + description: |- + Get a list of all course enrollments, optionally filtered by a course ID or list of usernames. + + **Example Requests** + + GET /api/enrollment/v1/enrollments + + GET /api/enrollment/v1/enrollments?course_id={course_id} + + GET /api/enrollment/v1/enrollments?username={username},{username},{username} + + GET /api/enrollment/v1/enrollments?course_id={course_id}&username={username} + + **Query Parameters for GET** + + * course_id: Filters the result to course enrollments for the course corresponding to the + given course ID. The value must be URL encoded. Optional. + + * username: List of comma-separated usernames. Filters the result to the course enrollments + of the given users. Optional. + + * page_size: Number of results to return per page. Optional. + + * page: Page number to retrieve. Optional. + + **Response Values** + + If the request for information about the course enrollments is successful, an HTTP 200 "OK" response + is returned. + + The HTTP 200 response has the following values. + + * results: A list of the course enrollments matching the request. + + * created: Date and time when the course enrollment was created. + + * mode: Mode for the course enrollment. + + * is_active: Whether the course enrollment is active or not. + + * user: Username of the user in the course enrollment. + + * course_id: Course ID of the course in the course enrollment. + + * next: The URL to the next page of results, or null if this is the + last page. + + * previous: The URL to the next page of results, or null if this + is the first page. + + If the user is not logged in, a 401 error is returned. + + If the user is not global staff, a 403 error is returned. + + If the specified course_id is not valid or any of the specified usernames + are not valid, a 400 error is returned. + + If the specified course_id does not correspond to a valid course or if all the specified + usernames do not correspond to valid users, an HTTP 200 "OK" response is returned with an + empty 'results' field. parameters: - name: cursor in: query @@ -2819,8 +3812,9 @@ paths: /entitlements/v1/entitlements/: get: operationId: entitlements_v1_entitlements_list - description: "Override the list method to expire records that are past the\n\ - policy and requested via the API before returning those records." + description: |- + Override the list method to expire records that are past the + policy and requested via the API before returning those records. parameters: - name: uuid in: query @@ -2887,8 +3881,9 @@ paths: /entitlements/v1/entitlements/{uuid}/: get: operationId: entitlements_v1_entitlements_read - description: "Override the retrieve method to expire a record that is past the\n\ - policy and is requested via the API before returning that record." + description: |- + Override the retrieve method to expire a record that is past the + policy and is requested via the API before returning that record. parameters: [] responses: '200': @@ -2947,12 +3942,15 @@ paths: /entitlements/v1/entitlements/{uuid}/enrollments: post: operationId: entitlements_v1_entitlements_enrollments_create - description: "On POST this method will be called and will handle enrolling a\ - \ user in the\nprovided course_run_id from the data. This is called on a specific\ - \ entitlement\nUUID so the course_run_id has to correspond to the Course that\ - \ is assigned to\nthe Entitlement.\n\nWhen this API is called for a user who\ - \ is already enrolled in a run that User\nwill be unenrolled from their current\ - \ run and enrolled in the new run if it is\navailable." + description: |- + On POST this method will be called and will handle enrolling a user in the + provided course_run_id from the data. This is called on a specific entitlement + UUID so the course_run_id has to correspond to the Course that is assigned to + the Entitlement. + + When this API is called for a user who is already enrolled in a run that User + will be unenrolled from their current run and enrolled in the new run if it is + available. parameters: [] responses: '201': @@ -2963,8 +3961,9 @@ paths: operationId: entitlements_v1_entitlements_enrollments_delete summary: On DELETE call to this API we will unenroll the course enrollment for the provided uuid - description: "If is_refund parameter is provided then unenroll the user, set\ - \ Entitlement expiration, and issue\na refund" + description: |- + If is_refund parameter is provided then unenroll the user, set Entitlement expiration, and issue + a refund parameters: [] responses: '204': @@ -3316,8 +4315,9 @@ paths: /grades/v1/gradebook/{course_id}/: get: operationId: grades_v1_gradebook_read - description: "Checks for course author access for the given course by the requesting\ - \ user.\nCalls the view function if has access, otherwise raises a 403." + description: |- + Checks for course author access for the given course by the requesting user. + Calls the view function if has access, otherwise raises a 403. parameters: [] responses: '200': @@ -3332,8 +4332,9 @@ paths: /grades/v1/gradebook/{course_id}/bulk-update: post: operationId: grades_v1_gradebook_bulk-update_create - description: "Checks for course author access for the given course by the requesting\ - \ user.\nCalls the view function if has access, otherwise raises a 403." + description: |- + Checks for course author access for the given course by the requesting user. + Calls the view function if has access, otherwise raises a 403. parameters: [] responses: '201': @@ -3348,8 +4349,9 @@ paths: /grades/v1/gradebook/{course_id}/grading-info: get: operationId: grades_v1_gradebook_grading-info_list - description: "Checks for course author access for the given course by the requesting\ - \ user.\nCalls the view function if has access, otherwise raises a 403." + description: |- + Checks for course author access for the given course by the requesting user. + Calls the view function if has access, otherwise raises a 403. parameters: - name: page in: query @@ -3375,14 +4377,25 @@ paths: get: operationId: grades_v1_policy_courses_read summary: '**Use Case**' - description: "Get the course grading policy.\n\n**Example requests**:\n\n \ - \ GET /api/grades/v1/policy/courses/{course_id}/\n\n**Response Values**\n\ - \n * assignment_type: The type of the assignment, as configured by course\n\ - \ staff. For example, course staff might make the assignment types Homework,\n\ - \ Quiz, and Exam.\n\n * count: The number of assignments of the type.\n\ - \n * dropped: Number of assignments of the type that are dropped.\n\n \ - \ * weight: The weight, or effect, of the assignment type on the learner's\n\ - \ final grade." + description: |- + Get the course grading policy. + + **Example requests**: + + GET /api/grades/v1/policy/courses/{course_id}/ + + **Response Values** + + * assignment_type: The type of the assignment, as configured by course + staff. For example, course staff might make the assignment types Homework, + Quiz, and Exam. + + * count: The number of assignments of the type. + + * dropped: Number of assignments of the type that are dropped. + + * weight: The weight, or effect, of the assignment type on the learner's + final grade. parameters: - name: page in: query @@ -3407,8 +4420,9 @@ paths: /grades/v1/subsection/{subsection_id}/: get: operationId: grades_v1_subsection_read - description: "Returns subection grade data, override grade data and a history\ - \ of changes made to\na specific users specific subsection grade." + description: |- + Returns subection grade data, override grade data and a history of changes made to + a specific users specific subsection grade. parameters: [] responses: '200': @@ -3420,82 +4434,782 @@ paths: in: path required: true type: string - /learning_sequences/v1/course_outline/{course_key_str}: + /instructor/v1/reports/{course_id}: get: - operationId: learning_sequences_v1_course_outline_read - summary: The CourseOutline, customized for a given user. - description: Currently restricted to global staff. - parameters: [] + operationId: instructor_v1_reports_read + summary: List report CSV files that are available for download for this course. + description: |- + **Use Cases** + + Lists reports available for download + + **Example Requests**: + + GET /api/instructor/v1/reports/{course_id} + + **Response Values** + ```json + { + "downloads": [ + { + "url": "https://1.mock.url", + "link": "mock_file_name_1", + "name": "mock_file_name_1" + } + ] + } + ``` + + The report name will depend on the type of report generated. For example a + problem responses report for an entire course might be called: + + edX_DemoX_Demo_Course_student_state_from_block-v1_edX+DemoX+Demo_Course+type@course+block@course_2021-04-30-0918.csv + parameters: + - name: course_id + in: path + description: ID for the course whose reports need to be listed. + type: string + required: true + - name: report_name + in: query + description: Filter results to only return details of for the report with + the specified name. + type: string responses: '200': description: '' + schema: + $ref: '#/definitions/ReportDownloadsList' + '401': + description: The requesting user is not authenticated. + '403': + description: The requesting user lacks access to the course. + '404': + description: The requested course does not exist. tags: - - learning_sequences + - instructor parameters: - - name: course_key_str + - name: course_id in: path required: true type: string - /organizations/v0/organizations/: - get: - operationId: organizations_v0_organizations_list - description: "Organization view to:\n - fetch list organization data or single\ - \ organization using organization short name.\n - create or update an organization\ - \ via the PUT endpoint." + /instructor/v1/reports/{course_id}/generate/problem_responses: + post: + operationId: instructor_v1_reports_generate_problem_responses_create + summary: Initiate generation of a CSV file containing all student answers + description: |- + to a given problem. + + **Example requests** + + POST /api/instructor/v1/reports/{course_id}/generate/problem_responses { + "problem_locations": [ + "{usage_key1}", + "{usage_key2}", + "{usage_key3}" + ] + } + POST /api/instructor/v1/reports/{course_id}/generate/problem_responses { + "problem_locations": ["{usage_key}"], + "problem_types_filter": ["problem"] + } + + **POST Parameters** + + A POST request can include the following parameters: + + * problem_location: A list of usage keys for the blocks to include in + the report. If the location is a block that contains other blocks, + (such as the course, section, subsection, or unit blocks) then all + blocks under that block will be included in the report. + * problem_types_filter: Optional. A comma-separated list of block types + to include in the report. If set, only blocks of the specified types + will be included in the report. + + To get data on all the poll and survey blocks in a course, you could + POST the usage key of the course for `problem_location`, and + "poll, survey" as the value for `problem_types_filter`. + + + **Example Response:** + If initiation is successful (or generation task is already running): + ```json + { + "status": "The problem responses report is being created. ...", + "task_id": "4e49522f-31d9-431a-9cff-dd2a2bf4c85a" + } + ``` + + Responds with BadRequest if any of the provided problem locations are faulty. parameters: - - name: page - in: query - description: A page number within the paginated result set. - required: false - type: integer - - name: page_size - in: query - description: Number of results to return per page. - required: false - type: integer + - name: data + in: body + required: true + schema: + $ref: '#/definitions/ProblemResponseReportPostParams' + - name: course_id + in: path + description: ID of the course for which report is to be generate. + type: string + required: true responses: '200': description: '' schema: - required: - - count - - results - type: object - properties: - count: - type: integer - next: - type: string - format: uri - x-nullable: true - previous: - type: string - format: uri - x-nullable: true - results: - type: array - items: - $ref: '#/definitions/Organization' + $ref: '#/definitions/ProblemResponsesReportStatus' + '400': + description: The provided parameters were invalid. Make sure you've provided + at least one valid usage key for `problem_locations`. + '401': + description: The requesting user is not authenticated. + '403': + description: The requesting user lacks access to the course. tags: - - organizations - parameters: [] - /organizations/v0/organizations/{short_name}/: + - instructor + parameters: + - name: course_id + in: path + required: true + type: string + /instructor/v1/tasks/{course_id}: get: - operationId: organizations_v0_organizations_read - description: "Organization view to:\n - fetch list organization data or single\ - \ organization using organization short name.\n - create or update an organization\ - \ via the PUT endpoint." - parameters: [] + operationId: instructor_v1_tasks_read + summary: List instructor tasks filtered by `course_id`. + description: |- + **Use Cases** + + Lists currently running instructor tasks + + **Parameters** + - With no arguments, lists running tasks. + - `problem_location_str` lists task history for problem + - `problem_location_str` and `unique_student_identifier` lists task + history for problem AND student (intersection) + + **Example Requests**: + + GET /courses/{course_id}/instructor/api/v0/tasks + + **Response Values** + ```json + { + "tasks": [ + { + "status": "Incomplete", + "task_type": "grade_problems", + "task_id": "2519ff31-22d9-4a62-91e2-55495895b355", + "created": "2019-01-15T18:00:15.902470+00:00", + "task_input": "{}", + "duration_sec": "unknown", + "task_message": "No status information available", + "requester": "staff", + "task_state": "PROGRESS" + } + ] + } + ``` + parameters: + - name: course_id + in: path + description: ID for the course whose tasks need to be listed. + type: string + required: true + - name: problem_location_str + in: query + description: Filter instructor tasks to this problem location. + type: string + - name: unique_student_identifier + in: query + description: Filter tasks to a singe problem and a single student. Must + be used in combination with `problem_location_str`. + type: string responses: '200': description: '' schema: - $ref: '#/definitions/Organization' + $ref: '#/definitions/InstructorTasksList' + '401': + description: The requesting user is not authenticated. + '403': + description: The requesting user lacks access to the course. + '404': + description: The requested course does not exist. tags: - - organizations - put: - operationId: organizations_v0_organizations_update - description: We perform both Update and Create action via the PUT method. + - instructor + parameters: + - name: course_id + in: path + required: true + type: string + /learning_sequences/v1/course_outline/{course_key_str}: + get: + operationId: learning_sequences_v1_course_outline_read + summary: The CourseOutline, customized for a given user. + description: Currently restricted to global staff. + parameters: [] + responses: + '200': + description: '' + tags: + - learning_sequences + parameters: + - name: course_key_str + in: path + required: true + type: string + /lti_consumer/v1/lti/{lti_config_id}/lti-ags: + get: + operationId: lti_consumer_v1_lti_lti-ags_list + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: [] + responses: + '200': + description: '' + schema: + type: array + items: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + post: + operationId: lti_consumer_v1_lti_lti-ags_create + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/LtiAgsLineItem' + responses: + '201': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + parameters: + - name: lti_config_id + in: path + required: true + type: string + /lti_consumer/v1/lti/{lti_config_id}/lti-ags/{id}: + get: + operationId: lti_consumer_v1_lti_lti-ags_read + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: [] + responses: + '200': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + put: + operationId: lti_consumer_v1_lti_lti-ags_update + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/LtiAgsLineItem' + responses: + '200': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + patch: + operationId: lti_consumer_v1_lti_lti-ags_partial_update + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/LtiAgsLineItem' + responses: + '200': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + delete: + operationId: lti_consumer_v1_lti_lti-ags_delete + summary: LineItem endpoint implementation from LTI Advantage. + description: 'See full documentation at:' + parameters: [] + responses: + '204': + description: '' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.lineitemcontainer+json + - application/vnd.ims.lis.v2.lineitem+json + tags: + - lti_consumer + parameters: + - name: id + in: path + required: true + type: string + - name: lti_config_id + in: path + required: true + type: string + /lti_consumer/v1/lti/{lti_config_id}/lti-ags/{id}/results/{user_id}: + get: + operationId: lti_consumer_v1_lti_lti-ags_results + summary: Return a Result list for an LtiAgsLineItem + description: |- + URL Parameters: + * user_id (string): String external user id representation. + + Query Parameters: + * limit (integer): The maximum number of records to return. Records are + sorted with most recent timestamp first + parameters: [] + responses: + '200': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v2.lineitem+json + produces: + - application/vnd.ims.lis.v2.resultcontainer+json + tags: + - lti_consumer + parameters: + - name: id + in: path + required: true + type: string + - name: lti_config_id + in: path + required: true + type: string + - name: user_id + in: path + required: true + type: string + /lti_consumer/v1/lti/{lti_config_id}/lti-ags/{id}/scores: + post: + operationId: lti_consumer_v1_lti_lti-ags_scores + description: Create a Score record for an LtiAgsLineItem + parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/LtiAgsLineItem' + responses: + '201': + description: '' + schema: + $ref: '#/definitions/LtiAgsLineItem' + consumes: + - application/vnd.ims.lis.v1.score+json + produces: + - application/vnd.ims.lis.v1.score+json + tags: + - lti_consumer + parameters: + - name: id + in: path + required: true + type: string + - name: lti_config_id + in: path + required: true + type: string + /mfe_context: + get: + operationId: mfe_context_list + description: |- + Returns the context for third party auth providers, user country code + and the currently running pipeline. + parameters: [] + responses: + '200': + description: '' + tags: + - mfe_context + parameters: [] + /mobile/{api_version}/course_info/{course_id}/handouts: + get: + operationId: mobile_course_info_handouts_list + summary: '**Use Case**' + description: |- + Get the HTML for course handouts. + + **Example Request** + + GET /api/mobile/v0.5/course_info/{course_id}/handouts + + **Response Values** + + If the request is successful, the request returns an HTTP 200 "OK" + response along with the following value. + + * handouts_html: The HTML for course handouts. + parameters: + - name: page + in: query + description: A page number within the paginated result set. + required: false + type: integer + - name: page_size + in: query + description: Number of results to return per page. + required: false + type: integer + responses: + '200': + description: '' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + - name: course_id + in: path + required: true + type: string + /mobile/{api_version}/course_info/{course_id}/updates: + get: + operationId: mobile_course_info_updates_list + summary: '**Use Case**' + description: |- + Get the content for course updates. + + **Example Request** + + GET /api/mobile/v0.5/course_info/{course_id}/updates + + **Response Values** + + If the request is successful, the request returns an HTTP 200 "OK" + response along with an array of course updates. Each course update + contains the following values. + + * content: The content, as an HTML string, of the course update. + * date: The date of the course update. + * id: The unique identifier of the update. + * status: Whether the update is visible or not. + parameters: + - name: page + in: query + description: A page number within the paginated result set. + required: false + type: integer + - name: page_size + in: query + description: Number of results to return per page. + required: false + type: integer + responses: + '200': + description: '' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + - name: course_id + in: path + required: true + type: string + /mobile/{api_version}/my_user_info: + get: + operationId: mobile_my_user_info_list + description: Redirect to the currently-logged-in user's info page + parameters: [] + responses: + '200': + description: '' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + /mobile/{api_version}/users/{username}: + get: + operationId: mobile_users_read + summary: '**Use Case**' + description: |- + Get information about the specified user and access other resources + the user has permissions for. + + Users are redirected to this endpoint after they sign in. + + You can use the **course_enrollments** value in the response to get a + list of courses the user is enrolled in. + + **Example Request** + + GET /api/mobile/{version}/users/{username} + + **Response Values** + + If the request is successful, the request returns an HTTP 200 "OK" response. + + The HTTP 200 response has the following values. + + * course_enrollments: The URI to list the courses the currently signed + in user is enrolled in. + * email: The email address of the currently signed in user. + * id: The ID of the user. + * name: The full name of the currently signed in user. + * username: The username of the currently signed in user. + parameters: [] + responses: + '200': + description: '' + schema: + $ref: '#/definitions/mobile_api.User' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + - name: username + in: path + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + required: true + type: string + pattern: ^[\w.@+-]+$ + /mobile/{api_version}/users/{username}/course_enrollments/: + get: + operationId: mobile_users_course_enrollments_list + summary: '**Use Case**' + description: |- + Get information about the courses that the currently signed in user is + enrolled in. + + v1 differs from v0.5 version by returning ALL enrollments for + a user rather than only the enrollments the user has access to (that haven't expired). + An additional attribute "expiration" has been added to the response, which lists the date + when access to the course will expire or null if it doesn't expire. + + **Example Request** + + GET /api/mobile/v1/users/{username}/course_enrollments/ + + **Response Values** + + If the request for information about the user is successful, the + request returns an HTTP 200 "OK" response. + + The HTTP 200 response has the following values. + + * expiration: The course expiration date for given user course pair + or null if the course does not expire. + * certificate: Information about the user's earned certificate in the + course. + * course: A collection of the following data about the course. + + * courseware_access: A JSON representation with access information for the course, + including any access errors. + + * course_about: The URL to the course about page. + * course_sharing_utm_parameters: Encoded UTM parameters to be included in course sharing url + * course_handouts: The URI to get data for course handouts. + * course_image: The path to the course image. + * course_updates: The URI to get data for course updates. + * discussion_url: The URI to access data for course discussions if + it is enabled, otherwise null. + * end: The end date of the course. + * id: The unique ID of the course. + * name: The name of the course. + * number: The course number. + * org: The organization that created the course. + * start: The date and time when the course starts. + * start_display: + If start_type is a string, then the advertised_start date for the course. + If start_type is a timestamp, then a formatted date for the start of the course. + If start_type is empty, then the value is None and it indicates that the course has not yet started. + * start_type: One of either "string", "timestamp", or "empty" + * subscription_id: A unique "clean" (alphanumeric with '_') ID of + the course. + * video_outline: The URI to get the list of all videos that the user + can access in the course. + + * created: The date the course was created. + * is_active: Whether the course is currently active. Possible values + are true or false. + * mode: The type of certificate registration for this course (honor or + certified). + * url: URL to the downloadable version of the certificate, if exists. + parameters: [] + responses: + '200': + description: '' + schema: + type: array + items: + $ref: '#/definitions/CourseEnrollment' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + - name: username + in: path + required: true + type: string + ? /mobile/{api_version}/users/{username}/course_status_info/(P{course_id}[/+]+{var}[/+]+api/mobile/{api_version}/users/{username}/course_status_info/(P{course_id}[/+]+(/|+)[/+]+{var}[/]+) + : get: + operationId: mobile_users_course_status_info_+]+api_mobile_users_course_status_info_+]+(_|+)[_]+)_list + description: Get the ID of the module that the specified user last visited in + the specified course. + parameters: [] + responses: + '200': + description: '' + tags: + - mobile + patch: + operationId: mobile_users_course_status_info_+]+api_mobile_users_course_status_info_+]+(_|+)[_]+)_partial_update + description: Update the ID of the module that the specified user last visited + in the specified course. + parameters: [] + responses: + '200': + description: '' + tags: + - mobile + parameters: + - name: api_version + in: path + required: true + type: string + - name: course_id + in: path + required: true + type: string + - name: username + in: path + required: true + type: string + - name: var + in: path + required: true + type: string + /organizations/v0/organizations/: + get: + operationId: organizations_v0_organizations_list + description: |- + Organization view to: + - list organization data (GET .../) + - retrieve single organization (GET .../) + - create or update an organization via the PUT endpoint (PUT .../) + parameters: + - name: page + in: query + description: A page number within the paginated result set. + required: false + type: integer + - name: page_size + in: query + description: Number of results to return per page. + required: false + type: integer + responses: + '200': + description: '' + schema: + required: + - count + - results + type: object + properties: + count: + type: integer + next: + type: string + format: uri + x-nullable: true + previous: + type: string + format: uri + x-nullable: true + results: + type: array + items: + $ref: '#/definitions/Organization' + tags: + - organizations + parameters: [] + /organizations/v0/organizations/{short_name}/: + get: + operationId: organizations_v0_organizations_read + description: |- + Organization view to: + - list organization data (GET .../) + - retrieve single organization (GET .../) + - create or update an organization via the PUT endpoint (PUT .../) + parameters: [] + responses: + '200': + description: '' + schema: + $ref: '#/definitions/Organization' + tags: + - organizations + put: + operationId: organizations_v0_organizations_update + summary: We perform both Update and Create action via the PUT method. + description: |- + The 'active' field may not be specified via the HTTP API, since it + is always assumed to be True. So: + (1) new organizations created through the API are always Active, and + (2) existing organizations updated through the API always end up Active, + regardless of whether or not they were previously active. parameters: - name: data in: body @@ -3529,8 +5243,9 @@ paths: parameters: - name: short_name in: path - description: Please do not use spaces or special characters. Only allowed - special characters are period (.), hyphen (-) and underscore (_). + description: Unique, short string identifier for organization. Please do not + use spaces or special characters. Only allowed special characters are period + (.), hyphen (-) and underscore (_). required: true type: string /profile_images/v1/{username}/remove: @@ -3739,8 +5454,9 @@ paths: /program_enrollments/v1/programs/{program_uuid}/overview/: get: operationId: program_enrollments_v1_programs_overview_read - description: "A view for getting data associated with a user's course enrollments\n\ - as part of a program enrollment." + description: |- + A view for getting data associated with a user's course enrollments + as part of a program enrollment. parameters: [] responses: '200': @@ -3759,41 +5475,66 @@ paths: operationId: program_enrollments_v1_users_programs_courses_list summary: Get an overview of each of a user's course enrollments associated with a program. - description: "This endpoint exists to get an overview of each course-run enrollment\n\ - that a user has for course-runs within a given program.\nFields included are\ - \ the title, upcoming due dates, etc.\nThis API endpoint is intended for use\ - \ with the\n[Program Learner Portal MFE](https://github.com/edx/frontend-app-learner-portal-programs).\n\ - \nIt is important to note that the set of enrollments that this endpoint returns\n\ - is different than a user's set of *program-course-run enrollments*.\nSpecifically,\ - \ this endpoint may include course runs that are *within*\nthe specified program\ - \ but were not *enrolled in* via the specified program.\n\n**Example Response:**\n\ - ```json\n{\n \"next\": null,\n \"previous\": null,\n \"results\"\ - : [\n {\n \"course_run_id\": \"edX+AnimalsX+Aardvarks\"\ - ,\n \"display_name\": \"Astonishing Aardvarks\",\n \"\ - course_run_url\": \"https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/course/\"\ - ,\n \"start_date\": \"2017-02-05T05:00:00Z\",\n \"end_date\"\ - : \"2018-02-05T05:00:00Z\",\n \"course_run_status\": \"completed\"\ - \n \"emails_enabled\": true,\n \"due_dates\": [\n \ - \ {\n \"name\": \"Introduction: What even\ - \ is an aardvark?\",\n \"url\": \"https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/jump_to/\n\ - \ block-v1:edX+AnimalsX+Aardvarks+type@chapter+block@1414ffd5143b4b508f739b563ab468b7\"\ - ,\n \"date\": \"2017-05-01T05:00:00Z\"\n \ - \ },\n {\n \"name\": \"Quiz: Aardvark or\ - \ Anteater?\",\n \"url\": \"https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/jump_to/\n\ - \ block-v1:edX+AnimalsX+Aardvarks+type@sequential+block@edx_introduction\"\ - ,\n \"date\": \"2017-03-05T00:00:00Z\"\n \ - \ }\n ],\n \"micromasters_title\": \"Animals\",\n \ - \ \"certificate_download_url\": \"https://courses.edx.org/certificates/123\"\ - \n },\n {\n \"course_run_id\": \"edX+AnimalsX+Baboons\"\ - ,\n \"display_name\": \"Breathtaking Baboons\",\n \"\ - course_run_url\": \"https://courses.edx.org/courses/course-v1:edX+AnimalsX+Baboons/course/\"\ - ,\n \"start_date\": \"2018-02-05T05:00:00Z\",\n \"end_date\"\ - : null,\n \"course_run_status\": \"in_progress\"\n \"\ - emails_enabled\": false,\n \"due_dates\": [],\n \"micromasters_title\"\ - : \"Animals\",\n \"certificate_download_url\": \"https://courses.edx.org/certificates/123\"\ - ,\n \"resume_course_run_url\": \"https://courses.edx.org/courses/course-v1:edX+AnimalsX+Baboons/jump_to/\n\ - \ block-v1:edX+AnimalsX+Baboons+type@sequential+block@edx_introduction\"\ - \n }\n ]\n}\n```" + description: |- + This endpoint exists to get an overview of each course-run enrollment + that a user has for course-runs within a given program. + Fields included are the title, upcoming due dates, etc. + This API endpoint is intended for use with the + [Program Learner Portal MFE](https://github.com/edx/frontend-app-learner-portal-programs). + + It is important to note that the set of enrollments that this endpoint returns + is different than a user's set of *program-course-run enrollments*. + Specifically, this endpoint may include course runs that are *within* + the specified program but were not *enrolled in* via the specified program. + + **Example Response:** + ```json + { + "next": null, + "previous": null, + "results": [ + { + "course_run_id": "edX+AnimalsX+Aardvarks", + "display_name": "Astonishing Aardvarks", + "course_run_url": "https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/course/", + "start_date": "2017-02-05T05:00:00Z", + "end_date": "2018-02-05T05:00:00Z", + "course_run_status": "completed" + "emails_enabled": true, + "due_dates": [ + { + "name": "Introduction: What even is an aardvark?", + "url": "https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/jump_to/ + block-v1:edX+AnimalsX+Aardvarks+type@chapter+block@1414ffd5143b4b508f739b563ab468b7", + "date": "2017-05-01T05:00:00Z" + }, + { + "name": "Quiz: Aardvark or Anteater?", + "url": "https://courses.edx.org/courses/course-v1:edX+AnimalsX+Aardvarks/jump_to/ + block-v1:edX+AnimalsX+Aardvarks+type@sequential+block@edx_introduction", + "date": "2017-03-05T00:00:00Z" + } + ], + "micromasters_title": "Animals", + "certificate_download_url": "https://courses.edx.org/certificates/123" + }, + { + "course_run_id": "edX+AnimalsX+Baboons", + "display_name": "Breathtaking Baboons", + "course_run_url": "https://courses.edx.org/courses/course-v1:edX+AnimalsX+Baboons/course/", + "start_date": "2018-02-05T05:00:00Z", + "end_date": null, + "course_run_status": "in_progress" + "emails_enabled": false, + "due_dates": [], + "micromasters_title": "Animals", + "certificate_download_url": "https://courses.edx.org/certificates/123", + "resume_course_run_url": "https://courses.edx.org/courses/course-v1:edX+AnimalsX+Baboons/jump_to/ + block-v1:edX+AnimalsX+Baboons+type@sequential+block@edx_introduction" + } + ] + } + ``` parameters: - name: cursor in: query @@ -4064,10 +5805,18 @@ paths: get: operationId: third_party_auth_v0_providers_user_status_list summary: GET /api/third_party_auth/v0/providers/user_status/ - description: "**GET Response Values**\n```\n{\n \"accepts_logins\": true,\n\ - \ \"name\": \"Google\",\n \"disconnect_url\": \"/auth/disconnect/google-oauth2/?\"\ - ,\n \"connect_url\": \"/auth/login/google-oauth2/?auth_entry=account_settings&next=%2Faccount%2Fsettings\"\ - ,\n \"connected\": false,\n \"id\": \"oa2-google-oauth2\"\n}\n```" + description: |- + **GET Response Values** + ``` + { + "accepts_logins": true, + "name": "Google", + "disconnect_url": "/auth/disconnect/google-oauth2/?", + "connect_url": "/auth/login/google-oauth2/?auth_entry=account_settings&next=%2Faccount%2Fsettings", + "connected": false, + "id": "oa2-google-oauth2" + } + ``` parameters: [] responses: '200': @@ -4079,39 +5828,73 @@ paths: get: operationId: third_party_auth_v0_providers_users_list summary: Map between the third party auth account IDs (remote_id) and EdX username. - description: "This API is intended to be a server-to-server endpoint. An on-campus\ - \ middleware or system should consume this.\n\n**Use Case**\n\n Get a paginated\ - \ list of mappings between edX users and remote user IDs for all users currently\n\ - \ linked to the given backend.\n\n The list can be filtered by edx username\ - \ or third party ids. The filter is limited by the max length of URL.\n \ - \ It is suggested to query no more than 50 usernames or remote_ids in each\ - \ request to stay within above\n limitation\n\n The page size can be\ - \ changed by specifying `page_size` parameter in the request.\n\n**Example\ - \ Requests**\n\n GET /api/third_party_auth/v0/providers/{provider_id}/users\n\ - \n GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1},{username2}\n\ - \n GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1}&usernames={username2}\n\ - \n GET /api/third_party_auth/v0/providers/{provider_id}/users?remote_id={remote_id1},{remote_id2}\n\ - \n GET /api/third_party_auth/v0/providers/{provider_id}/users?remote_id={remote_id1}&remote_id={remote_id2}\n\ - \n GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1}&remote_id={remote_id1}\n\ - \n**URL Parameters**\n\n * provider_id: The unique identifier of third_party_auth\ - \ provider (e.g. \"saml-ubc\", \"oa2-google\", etc.\n This is not the\ - \ same thing as the backend_name.). (Optional/future: We may also want to\ - \ allow\n this to be an 'external domain' like 'ssl:MIT' so that this\ - \ API can also search the legacy\n ExternalAuthMap table used by Standford/MIT)\n\ - \n**Query Parameters**\n\n * remote_ids: Optional. List of comma separated\ - \ remote (third party) user IDs to filter the result set.\n e.g. ?remote_ids=8721384623\n\ - \n * usernames: Optional. List of comma separated edX usernames to filter\ - \ the result set.\n e.g. ?usernames=bob123,jane456\n\n * page, page_size:\ - \ Optional. Used for paging the result set, especially when getting\n \ - \ an unfiltered list.\n\n**Response Values**\n\n If the request for information\ - \ about the user is successful, an HTTP 200 \"OK\" response\n is returned.\n\ - \n The HTTP 200 response has the following values:\n\n * count: The\ - \ number of mappings for the backend.\n\n * next: The URI to the next page\ - \ of the mappings.\n\n * previous: The URI to the previous page of the\ - \ mappings.\n\n * num_pages: The number of pages listing the mappings.\n\ - \n * results: A list of mappings returned. Each collection in the list\n\ - \ contains these fields.\n\n * username: The edx username\n\n\ - \ * remote_id: The Id from third party auth provider" + description: |- + This API is intended to be a server-to-server endpoint. An on-campus middleware or system should consume this. + + **Use Case** + + Get a paginated list of mappings between edX users and remote user IDs for all users currently + linked to the given backend. + + The list can be filtered by edx username or third party ids. The filter is limited by the max length of URL. + It is suggested to query no more than 50 usernames or remote_ids in each request to stay within above + limitation + + The page size can be changed by specifying `page_size` parameter in the request. + + **Example Requests** + + GET /api/third_party_auth/v0/providers/{provider_id}/users + + GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1},{username2} + + GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1}&usernames={username2} + + GET /api/third_party_auth/v0/providers/{provider_id}/users?remote_id={remote_id1},{remote_id2} + + GET /api/third_party_auth/v0/providers/{provider_id}/users?remote_id={remote_id1}&remote_id={remote_id2} + + GET /api/third_party_auth/v0/providers/{provider_id}/users?username={username1}&remote_id={remote_id1} + + **URL Parameters** + + * provider_id: The unique identifier of third_party_auth provider (e.g. "saml-ubc", "oa2-google", etc. + This is not the same thing as the backend_name.). (Optional/future: We may also want to allow + this to be an 'external domain' like 'ssl:MIT' so that this API can also search the legacy + ExternalAuthMap table used by Standford/MIT) + + **Query Parameters** + + * remote_ids: Optional. List of comma separated remote (third party) user IDs to filter the result set. + e.g. ?remote_ids=8721384623 + + * usernames: Optional. List of comma separated edX usernames to filter the result set. + e.g. ?usernames=bob123,jane456 + + * page, page_size: Optional. Used for paging the result set, especially when getting + an unfiltered list. + + **Response Values** + + If the request for information about the user is successful, an HTTP 200 "OK" response + is returned. + + The HTTP 200 response has the following values: + + * count: The number of mappings for the backend. + + * next: The URI to the next page of the mappings. + + * previous: The URI to the previous page of the mappings. + + * num_pages: The number of pages listing the mappings. + + * results: A list of mappings returned. Each collection in the list + contains these fields. + + * username: The edx username + + * remote_id: The Id from third party auth provider parameters: - name: page in: query @@ -4188,8 +5971,9 @@ paths: /third_party_auth_context: get: operationId: third_party_auth_context_list - description: Returns the context for third party auth providers and the currently - running pipeline. + description: |- + Returns the context for third party auth providers, user country code + and the currently running pipeline. parameters: [] responses: '200': @@ -4200,7 +5984,7 @@ paths: /toggles/v0/state/: get: operationId: toggles_v0_state_list - description: An endpoint for displaying the state of toggles in edx-platform. + description: Expose toggle state report dict as a view. parameters: [] responses: '200': @@ -4221,8 +6005,15 @@ paths: post: operationId: user_v1_account_login_session_create summary: Log in a user. - description: "See `login_user` for details.\n\nExample Usage:\n\n POST /api/user/v1/login_session\n\ - \ with POST params `email`, `password`.\n\n 200 {'success': true}" + description: |- + See `login_user` for details. + + Example Usage: + + POST /api/user/v1/login_session + with POST params `email`, `password`. + + 200 {'success': true} parameters: [] responses: '201': @@ -4242,6 +6033,17 @@ paths: tags: - user parameters: [] + /user/v1/account/password_reset/token/validate/: + post: + operationId: user_v1_account_password_reset_token_validate_create + description: HTTP end-point to validate password reset token. + parameters: [] + responses: + '201': + description: '' + tags: + - user + parameters: [] /user/v1/account/registration/: get: operationId: user_v1_account_registration_list @@ -4255,9 +6057,11 @@ paths: post: operationId: user_v1_account_registration_create summary: Create the user's account. - description: "You must send all required form fields with the request.\n\nYou\ - \ can optionally send a \"course_id\" param to indicate in analytics\nevents\ - \ that the user registered while enrolling in a particular course." + description: |- + You must send all required form fields with the request. + + You can optionally send a "course_id" param to indicate in analytics + events that the user registered while enrolling in a particular course. parameters: [] responses: '201': @@ -4268,13 +6072,15 @@ paths: /user/v1/accounts: get: operationId: user_v1_accounts_list - description: "GET /api/user/v1/accounts?username={username1,username2}\nGET\ - \ /api/user/v1/accounts?email={user_email}" + description: |- + GET /api/user/v1/accounts?username={username1},{username2} + GET /api/user/v1/accounts?email={user_email1},{user_email2} parameters: [] responses: '200': description: '' consumes: + - application/json - application/merge-patch+json tags: - user @@ -4283,8 +6089,9 @@ paths: post: operationId: user_v1_accounts_deactivate_logout_create summary: POST /api/user/v1/accounts/deactivate_logout/ - description: "Marks the user as having no password set for deactivation purposes,\n\ - and logs the user out." + description: |- + Marks the user as having no password set for deactivation purposes, + and logs the user out. parameters: [] responses: '201': @@ -4295,17 +6102,39 @@ paths: /user/v1/accounts/replace_usernames/: post: operationId: user_v1_accounts_replace_usernames_create - description: "POST /api/user/v1/accounts/replace_usernames/\n```\n{\n \"\ - username_mappings\": [\n {\"current_username_1\": \"desired_username_1\"\ - },\n {\"current_username_2\": \"desired_username_2\"}\n ]\n}\n```\n\ - \n**POST Parameters**\n\nA POST request must include the following parameter.\n\ - \n* username_mappings: Required. A list of objects that map the current username\ - \ (key)\n to the desired username (value)\n\n**POST Response Values**\n\n\ - As long as data validation passes, the request will return a 200 with a new\ - \ mapping\nof old usernames (key) to new username (value)\n\n```\n{\n \"\ - successful_replacements\": [\n {\"old_username_1\": \"new_username_1\"\ - }\n ],\n \"failed_replacements\": [\n {\"old_username_2\": \"\ - new_username_2\"}\n ]\n}\n```" + description: |- + POST /api/user/v1/accounts/replace_usernames/ + ``` + { + "username_mappings": [ + {"current_username_1": "desired_username_1"}, + {"current_username_2": "desired_username_2"} + ] + } + ``` + + **POST Parameters** + + A POST request must include the following parameter. + + * username_mappings: Required. A list of objects that map the current username (key) + to the desired username (value) + + **POST Response Values** + + As long as data validation passes, the request will return a 200 with a new mapping + of old usernames (key) to new username (value) + + ``` + { + "successful_replacements": [ + {"old_username_1": "new_username_1"} + ], + "failed_replacements": [ + {"old_username_2": "new_username_2"} + ] + } + ``` parameters: [] responses: '201': @@ -4317,9 +6146,16 @@ paths: post: operationId: user_v1_accounts_post summary: POST /api/user/v1/accounts/retire/ - description: "```\n{\n 'username': 'user_to_retire'\n}\n```\n\nRetires the\ - \ user with the given username. This includes\nretiring this username, the\ - \ associated email address, and\nany other PII associated with this user." + description: |- + ``` + { + 'username': 'user_to_retire' + } + ``` + + Retires the user with the given username. This includes + retiring this username, the associated email address, and + any other PII associated with this user. parameters: [] responses: '201': @@ -4331,8 +6167,14 @@ paths: post: operationId: user_v1_accounts_post summary: POST /api/user/v1/accounts/retire_misc/ - description: "```\n{\n 'username': 'user_to_retire'\n}\n```\n\nRetires the\ - \ user with the given username in the LMS." + description: |- + ``` + { + 'username': 'user_to_retire' + } + ``` + + Retires the user with the given username in the LMS. parameters: [] responses: '201': @@ -4344,8 +6186,14 @@ paths: post: operationId: user_v1_accounts_cleanup summary: POST /api/user/v1/accounts/retirement_cleanup/ - description: "```\n{\n 'usernames': ['user1', 'user2', ...]\n}\n```\n\nDeletes\ - \ a batch of retirement requests by username." + description: |- + ``` + { + 'usernames': ['user1', 'user2', ...] + } + ``` + + Deletes a batch of retirement requests by username. parameters: [] responses: '201': @@ -4357,9 +6205,10 @@ paths: post: operationId: user_v1_accounts_retirement_partner_report_create summary: POST /api/user/v1/accounts/retirement_partner_report/ - description: "Returns the list of UserRetirementPartnerReportingStatus users\n\ - that are not already being processed and updates their status\nto indicate\ - \ they are currently being processed." + description: |- + Returns the list of UserRetirementPartnerReportingStatus users + that are not already being processed and updates their status + to indicate they are currently being processed. parameters: [] responses: '201': @@ -4369,9 +6218,15 @@ paths: put: operationId: user_v1_accounts_retirement_partner_report_update summary: PUT /api/user/v1/accounts/retirement_partner_report/ - description: "```\n{\n 'username': 'user_to_retire'\n}\n```\n\nCreates a\ - \ UserRetirementPartnerReportingStatus object for the given user\nas part\ - \ of the retirement pipeline." + description: |- + ``` + { + 'username': 'user_to_retire' + } + ``` + + Creates a UserRetirementPartnerReportingStatus object for the given user + as part of the retirement pipeline. parameters: [] responses: '200': @@ -4383,9 +6238,11 @@ paths: post: operationId: user_v1_accounts_retirement_partner_cleanup summary: POST /api/user/v1/accounts/retirement_partner_report_cleanup/ - description: "[{'original_username': 'user1'}, {'original_username': 'user2'},\ - \ ...]\n\nDeletes UserRetirementPartnerReportingStatus objects for a list\ - \ of users\nthat have been reported on." + description: |- + [{'original_username': 'user1'}, {'original_username': 'user2'}, ...] + + Deletes UserRetirementPartnerReportingStatus objects for a list of users + that have been reported on. parameters: [] responses: '201': @@ -4396,10 +6253,12 @@ paths: /user/v1/accounts/retirement_queue/: get: operationId: user_v1_accounts_retirement_queue - summary: "GET /api/user/v1/accounts/retirement_queue/\n{'cool_off_days': 7,\ - \ 'states': ['PENDING', 'COMPLETE']}" - description: "Returns the list of RetirementStatus users in the given states\ - \ that were\ncreated in the retirement queue at least `cool_off_days` ago." + summary: |- + GET /api/user/v1/accounts/retirement_queue/ + {'cool_off_days': 7, 'states': ['PENDING', 'COMPLETE']} + description: |- + Returns the list of RetirementStatus users in the given states that were + created in the retirement queue at least `cool_off_days` ago. parameters: [] responses: '200': @@ -4410,11 +6269,14 @@ paths: /user/v1/accounts/retirements_by_status_and_date/: get: operationId: user_v1_accounts_retirements_by_status_and_date - summary: "GET /api/user/v1/accounts/retirements_by_status_and_date/\n?start_date=2018-09-05&end_date=2018-09-07&state=COMPLETE" - description: "Returns a list of UserRetirementStatusSerializer serialized\n\ - RetirementStatus rows in the given state that were created in the\nretirement\ - \ queue between the dates given. Date range is inclusive,\nso to get one day\ - \ you would set both dates to that day." + summary: |- + GET /api/user/v1/accounts/retirements_by_status_and_date/ + ?start_date=2018-09-05&end_date=2018-09-07&state=COMPLETE + description: |- + Returns a list of UserRetirementStatusSerializer serialized + RetirementStatus rows in the given state that were created in the + retirement queue between the dates given. Date range is inclusive, + so to get one day you would set both dates to that day. parameters: [] responses: '200': @@ -4422,17 +6284,45 @@ paths: tags: - user parameters: [] + /user/v1/accounts/search_emails: + post: + operationId: user_v1_accounts_search_emails + description: |- + POST /api/user/v1/accounts/search_emails + Content Type: "application/json" + { + "emails": ["edx@example.com", "staff@example.com"] + } + parameters: [] + responses: + '201': + description: '' + consumes: + - application/json + - application/merge-patch+json + tags: + - user + parameters: [] /user/v1/accounts/update_retirement_status/: patch: operationId: user_v1_accounts_update_retirement_status_partial_update summary: PATCH /api/user/v1/accounts/update_retirement_status/ - description: "```\n{\n 'username': 'user_to_retire',\n 'new_state': 'LOCKING_COMPLETE',\n\ - \ 'response': 'User account locked and logged out.'\n}\n```\n\nUpdates\ - \ the RetirementStatus row for the given user to the new\nstatus, and append\ - \ any messages to the message log.\n\nNote that this implementation DOES NOT\ - \ use the \"merge patch\"\nimplementation seen in AccountViewSet. Slumber,\ - \ the project\nwe use to power edx-rest-api-client, does not currently support\n\ - it. The content type for this request is 'application/json'." + description: |- + ``` + { + 'username': 'user_to_retire', + 'new_state': 'LOCKING_COMPLETE', + 'response': 'User account locked and logged out.' + } + ``` + + Updates the RetirementStatus row for the given user to the new + status, and append any messages to the message log. + + Note that this implementation DOES NOT use the "merge patch" + implementation seen in AccountViewSet. Slumber, the project + we use to power edx-rest-api-client, does not currently support + it. The content type for this request is 'application/json'. parameters: [] responses: '200': @@ -4449,6 +6339,7 @@ paths: '200': description: '' consumes: + - application/json - application/merge-patch+json tags: - user @@ -4462,6 +6353,7 @@ paths: '200': description: '' consumes: + - application/json - application/merge-patch+json tags: - user @@ -4519,8 +6411,10 @@ paths: /user/v1/accounts/{username}/retirement_status/: get: operationId: user_v1_accounts_retirement_status_read - description: "GET /api/user/v1/accounts/{username}/retirement_status/\nReturns\ - \ the RetirementStatus of a given user, or 404 if that row\ndoesn't exist." + description: |- + GET /api/user/v1/accounts/{username}/retirement_status/ + Returns the RetirementStatus of a given user, or 404 if that row + doesn't exist. parameters: [] responses: '200': @@ -4534,8 +6428,8 @@ paths: type: string /user/v1/accounts/{username}/verification_status/: get: - operationId: user_v1_accounts_verification_status_read - description: IDVerificationStatus detail endpoint. + operationId: user_v1_accounts_verification_status_list + description: IDVerification Status endpoint parameters: [] responses: '200': @@ -4621,6 +6515,7 @@ paths: '200': description: '' consumes: + - application/json - application/merge-patch+json tags: - user @@ -4629,8 +6524,9 @@ paths: post: operationId: user_v1_preferences_email_opt_in_create summary: Post function for updating the email opt in preference. - description: "Allows the modification or creation of the email opt in preference\ - \ at an\norganizational level." + description: |- + Allows the modification or creation of the email opt in preference at an + organizational level. parameters: [] responses: '201': @@ -4642,17 +6538,28 @@ paths: get: operationId: user_v1_preferences_time_zones_list summary: '**Use Cases**' - description: "Retrieves a list of all time zones, by default, or common time\ - \ zones for country, if given\n\n The country is passed in as its ISO 3166-1\ - \ Alpha-2 country code as an\n optional 'country_code' argument. The country\ - \ code is also case-insensitive.\n\n**Example Requests**\n\n GET /api/user/v1/preferences/time_zones/\n\ - \n GET /api/user/v1/preferences/time_zones/?country_code=FR\n\n**Example\ - \ GET Response**\n\n If the request is successful, an HTTP 200 \"OK\" response\ - \ is returned along with a\n list of time zone dictionaries for all time\ - \ zones or just for time zones commonly\n used in a country, if given.\n\ - \n Each time zone dictionary contains the following values.\n\n \ - \ * time_zone: The name of the time zone.\n * description: The display\ - \ version of the time zone" + description: |- + Retrieves a list of all time zones, by default, or common time zones for country, if given + + The country is passed in as its ISO 3166-1 Alpha-2 country code as an + optional 'country_code' argument. The country code is also case-insensitive. + + **Example Requests** + + GET /api/user/v1/preferences/time_zones/ + + GET /api/user/v1/preferences/time_zones/?country_code=FR + + **Example GET Response** + + If the request is successful, an HTTP 200 "OK" response is returned along with a + list of time zone dictionaries for all time zones or just for time zones commonly + used in a country, if given. + + Each time zone dictionary contains the following values. + + * time_zone: The name of the time zone. + * description: The display version of the time zone parameters: [] responses: '200': @@ -4906,13 +6813,22 @@ paths: post: operationId: user_v1_validation_registration_create summary: POST /api/user/v1/validation/registration/ - description: "Expects request of the form\n```\n{\n \"name\": \"Dan the Validator\"\ - ,\n \"username\": \"mslm\",\n \"email\": \"mslm@gmail.com\",\n \"\ - confirm_email\": \"mslm@gmail.com\",\n \"password\": \"password123\",\n\ - \ \"country\": \"PK\"\n}\n```\nwhere each key is the appropriate form field\ - \ name and the value is\nuser input. One may enter individual inputs if needed.\ - \ Some inputs\ncan get extra verification checks if entered along with others,\n\ - like when the password may not equal the username." + description: |- + Expects request of the form + ``` + { + "name": "Dan the Validator", + "username": "mslm", + "email": "mslm@gmail.com", + "confirm_email": "mslm@gmail.com", + "password": "password123", + "country": "PK" + } + ``` + where each key is the appropriate form field name and the value is + user input. One may enter individual inputs if needed. Some inputs + can get extra verification checks if entered along with others, + like when the password may not equal the username. parameters: [] responses: '201': @@ -4933,9 +6849,11 @@ paths: post: operationId: user_v2_account_registration_create summary: Create the user's account. - description: "You must send all required form fields with the request.\n\nYou\ - \ can optionally send a \"course_id\" param to indicate in analytics\nevents\ - \ that the user registered while enrolling in a particular course." + description: |- + You must send all required form fields with the request. + + You can optionally send a "course_id" param to indicate in analytics + events that the user registered while enrolling in a particular course. parameters: [] responses: '201': @@ -5005,18 +6923,34 @@ paths: operationId: val_v0_videos_missing-hls_create summary: 'Retrieve video IDs that are missing HLS profiles. This endpoint supports 2 types of input data:' - description: "1. If we want a batch of video ids which are missing HLS profile\ - \ irrespective of their courses, the request\n data should be in following\ - \ format:\n {\n 'batch_size': 50,\n 'offset':\ - \ 0\n }\n And response will be in following format:\n {\n\ - \ 'videos': ['video_id1', 'video_id2', 'video_id3', ... , video_id50],\n\ - \ 'total': 300,\n 'offset': 50,\n 'batch_size':\ - \ 50\n }\n\n2. If we want all the videos which are missing HLS profiles\ - \ in a set of specific courses, the request data\n should be in following\ - \ format:\n {\n 'courses': [\n 'course_id1',\n\ - \ 'course_id2',\n ...\n ]\n \ - \ }\n And response will be in following format:\n {\n \ - \ 'videos': ['video_id1', 'video_id2', 'video_id3', ...]\n }" + description: |- + 1. If we want a batch of video ids which are missing HLS profile irrespective of their courses, the request + data should be in following format: + { + 'batch_size': 50, + 'offset': 0 + } + And response will be in following format: + { + 'videos': ['video_id1', 'video_id2', 'video_id3', ... , video_id50], + 'total': 300, + 'offset': 50, + 'batch_size': 50 + } + + 2. If we want all the videos which are missing HLS profiles in a set of specific courses, the request data + should be in following format: + { + 'courses': [ + 'course_id1', + 'course_id2', + ... + ] + } + And response will be in following format: + { + 'videos': ['video_id1', 'video_id2', 'video_id3', ...] + } parameters: [] responses: '201': @@ -5026,10 +6960,19 @@ paths: put: operationId: val_v0_videos_missing-hls_update summary: Update a single profile for a given video. - description: "Example request data:\n ```\n {\n 'edx_video_id':\ - \ '1234'\n 'profile': 'hls',\n 'encode_data': {\n \ - \ 'url': 'foo.com/qwe.m3u8'\n 'file_size': 34\n 'bitrate':\ - \ 12\n }\n }\n ```" + description: |- + Example request data: + ``` + { + 'edx_video_id': '1234' + 'profile': 'hls', + 'encode_data': { + 'url': 'foo.com/qwe.m3u8' + 'file_size': 34 + 'bitrate': 12 + } + } + ``` parameters: [] responses: '200': @@ -5134,9 +7077,9 @@ paths: get: operationId: xblock_v2_xblocks_read summary: Get metadata about the specified block. - description: "Accepts an \"include\" query parameter which must be a comma separated\ - \ list of keys to include. Valid keys are\n\"index_dictionary\" and \"student_view_data\"\ - ." + description: |- + Accepts an "include" query parameter which must be a comma separated list of keys to include. Valid keys are + "index_dictionary" and "student_view_data". parameters: [] responses: '200': @@ -5151,8 +7094,9 @@ paths: /xblock/v2/xblocks/{usage_key_str}/handler_url/{handler_name}/: get: operationId: xblock_v2_xblocks_handler_url_read - summary: "Get an absolute URL which can be used (without any authentication)\ - \ to call\nthe given XBlock handler." + summary: |- + Get an absolute URL which can be used (without any authentication) to call + the given XBlock handler. description: The URL will expire but is guaranteed to be valid for a minimum of 2 days. parameters: [] @@ -5189,7 +7133,116 @@ paths: in: path required: true type: string -definitions: +definitions: + BadgeClass: + required: + - slug + - display_name + - description + - criteria + type: object + properties: + slug: + title: Slug + type: string + format: slug + pattern: ^[-a-zA-Z0-9_]+$ + maxLength: 255 + minLength: 1 + issuing_component: + title: Issuing component + type: string + format: slug + pattern: ^[-a-zA-Z0-9_]+$ + default: '' + maxLength: 50 + display_name: + title: Display name + type: string + maxLength: 255 + minLength: 1 + course_id: + title: Course id + type: string + maxLength: 255 + description: + title: Description + type: string + minLength: 1 + criteria: + title: Criteria + type: string + minLength: 1 + image_url: + title: Image url + type: string + readOnly: true + format: uri + BadgeAssertion: + required: + - image_url + - assertion_url + type: object + properties: + badge_class: + $ref: '#/definitions/BadgeClass' + image_url: + title: Image url + type: string + format: uri + maxLength: 200 + minLength: 1 + assertion_url: + title: Assertion url + type: string + format: uri + maxLength: 200 + minLength: 1 + created: + title: Created + type: string + format: date-time + readOnly: true + CCXCourse: + required: + - master_course_id + - display_name + - coach_email + - start + - due + - max_students_allowed + type: object + properties: + ccx_course_id: + title: Ccx course id + type: string + readOnly: true + master_course_id: + title: Master course id + type: string + minLength: 1 + display_name: + title: Display name + type: string + minLength: 1 + coach_email: + title: Coach email + type: string + format: email + minLength: 1 + start: + title: Start + type: string + due: + title: Due + type: string + max_students_allowed: + title: Max students allowed + type: integer + course_modules: + title: Course modules + type: string + readOnly: true CohortUsersAPI: required: - username @@ -5328,6 +7381,7 @@ definitions: CourseHomeMetadata: required: - course_id + - username - is_enrolled - is_self_paced - is_staff @@ -5336,12 +7390,18 @@ definitions: - original_user_is_staff - tabs - title + - can_load_courseware + - celebrations type: object properties: course_id: title: Course id type: string minLength: 1 + username: + title: Username + type: string + minLength: 1 is_enrolled: title: Is enrolled type: boolean @@ -5370,6 +7430,15 @@ definitions: title: Title type: string minLength: 1 + can_load_courseware: + title: Can load courseware + type: boolean + celebrations: + title: Celebrations + type: object + additionalProperties: + type: string + x-nullable: true DateSummary: required: - complete @@ -5388,6 +7457,7 @@ definitions: complete: title: Complete type: boolean + x-nullable: true date: title: Date type: string @@ -5420,6 +7490,10 @@ definitions: title: Extra info type: string minLength: 1 + first_component_block_id: + title: First component block id + type: string + readOnly: true DatesTab: required: - course_date_blocks @@ -5447,7 +7521,6 @@ definitions: type: string minLength: 1 CourseBlock: - title: Course blocks type: object properties: blocks: @@ -5455,7 +7528,6 @@ definitions: type: string readOnly: true CourseGoals: - title: Course goals required: - goal_options - selected_goal @@ -5465,11 +7537,13 @@ definitions: type: array items: type: string + x-nullable: true selected_goal: title: Selected goal type: object additionalProperties: type: string + x-nullable: true CourseTool: required: - analytics_id @@ -5489,7 +7563,6 @@ definitions: type: string readOnly: true DatesWidget: - title: Dates widget required: - course_date_blocks - dates_tab_link @@ -5509,7 +7582,6 @@ definitions: type: string minLength: 1 EnrollAlert: - title: Enroll alert required: - can_enroll - extra_text @@ -5523,7 +7595,6 @@ definitions: type: string minLength: 1 ResumeCourse: - title: Resume course required: - has_visited_course - url @@ -5539,15 +7610,15 @@ definitions: minLength: 1 OutlineTab: required: + - access_expiration - course_blocks - - course_expired_html - course_goals - course_tools - dates_widget - enroll_alert - handouts_html - has_ended - - offer_html + - offer - resume_course - welcome_message_html type: object @@ -5556,12 +7627,22 @@ definitions: title: Dates banner info type: string readOnly: true + can_show_upgrade_sock: + title: Can show upgrade sock + type: string + readOnly: true + verified_mode: + title: Verified mode + type: string + readOnly: true + access_expiration: + title: Access expiration + type: object + additionalProperties: + type: string + x-nullable: true course_blocks: $ref: '#/definitions/CourseBlock' - course_expired_html: - title: Course expired html - type: string - minLength: 1 course_goals: $ref: '#/definitions/CourseGoals' course_tools: @@ -5579,10 +7660,12 @@ definitions: has_ended: title: Has ended type: boolean - offer_html: - title: Offer html - type: string - minLength: 1 + offer: + title: Offer + type: object + additionalProperties: + type: string + x-nullable: true resume_course: $ref: '#/definitions/ResumeCourse' welcome_message_html: @@ -5590,13 +7673,10 @@ definitions: type: string minLength: 1 CertificateData: - title: Certificate data required: - cert_status - cert_web_view_url - download_url - - msg - - title type: object properties: cert_status: @@ -5611,104 +7691,54 @@ definitions: title: Download url type: string minLength: 1 - msg: - title: Msg - type: string - minLength: 1 - title: - title: Title - type: string - minLength: 1 - CreditRequirement: - required: - - display_name - - status - - status_date - type: object - properties: - display_name: - title: Display name - type: string - minLength: 1 - min_grade: - title: Min grade - type: string - readOnly: true - status: - title: Status - type: string - minLength: 1 - status_date: - title: Status date - type: string - format: date-time - CreditCourseRequirements: - title: Credit course requirements + CourseGrade: required: - - eligibility_status - - requirements + - letter_grade + - percent + - is_passing type: object properties: - dashboard_url: - title: Dashboard url - type: string - readOnly: true - eligibility_status: - title: Eligibility status + letter_grade: + title: Letter grade type: string minLength: 1 - requirements: - type: array - items: - $ref: '#/definitions/CreditRequirement' - GradedTotal: - title: Graded total - required: - - earned - - possible - type: object - properties: - earned: - title: Earned - type: number - possible: - title: Possible + percent: + title: Percent type: number - Subsection: + is_passing: + title: Is passing + type: boolean + SubsectionScores: required: + - assignment_type - display_name - - due - - format - - graded - - graded_total + - has_graded_assignment + - num_points_earned + - num_points_possible - percent_graded - show_correctness type: object properties: - display_name: - title: Display name + assignment_type: + title: Assignment type type: string minLength: 1 - due: - title: Due - type: string - format: date-time - format: - title: Format + display_name: + title: Display name type: string minLength: 1 - graded: - title: Graded + has_graded_assignment: + title: Has graded assignment type: boolean - graded_total: - $ref: '#/definitions/GradedTotal' + num_points_earned: + title: Num points earned + type: integer + num_points_possible: + title: Num points possible + type: integer percent_graded: title: Percent graded type: number - problem_scores: - title: Problem scores - type: string - readOnly: true show_correctness: title: Show correctness type: string @@ -5721,7 +7751,7 @@ definitions: title: Url type: string readOnly: true - Chapter: + SectionScores: required: - display_name - subsections @@ -5734,9 +7764,23 @@ definitions: subsections: type: array items: - $ref: '#/definitions/Subsection' + $ref: '#/definitions/SubsectionScores' + GradingPolicy: + required: + - grade_range + type: object + properties: + assignment_policies: + title: Assignment policies + type: string + readOnly: true + grade_range: + title: Grade range + type: object + additionalProperties: + type: string + x-nullable: true VerificationData: - title: Verification data required: - link - status @@ -5759,40 +7803,52 @@ definitions: ProgressTab: required: - certificate_data - - credit_course_requirements - - credit_support_url - - courseware_summary + - completion_summary + - course_grade + - end + - user_has_passing_grade + - has_scheduled_content + - section_scores - enrollment_mode + - grading_policy - studio_url - - user_timezone - verification_data type: object properties: certificate_data: $ref: '#/definitions/CertificateData' - credit_course_requirements: - $ref: '#/definitions/CreditCourseRequirements' - credit_support_url: - title: Credit support url + completion_summary: + title: Completion summary + type: object + additionalProperties: + type: string + x-nullable: true + course_grade: + $ref: '#/definitions/CourseGrade' + end: + title: End type: string - format: uri - minLength: 1 - courseware_summary: + format: date-time + user_has_passing_grade: + title: User has passing grade + type: boolean + has_scheduled_content: + title: Has scheduled content + type: boolean + section_scores: type: array items: - $ref: '#/definitions/Chapter' + $ref: '#/definitions/SectionScores' enrollment_mode: title: Enrollment mode type: string minLength: 1 + grading_policy: + $ref: '#/definitions/GradingPolicy' studio_url: title: Studio url type: string minLength: 1 - user_timezone: - title: User timezone - type: string - minLength: 1 verification_data: $ref: '#/definitions/VerificationData' course_modes.CourseMode: @@ -5841,8 +7897,18 @@ definitions: title: Bulk sku type: string minLength: 1 + _AbsolutMedia: + type: object + properties: + uri: + title: Uri + type: string + readOnly: true + uri_absolute: + title: Uri absolute + type: string + readOnly: true _Media: - title: Course image type: object properties: uri: @@ -5850,7 +7916,6 @@ definitions: type: string readOnly: true Image: - title: Image required: - raw - small @@ -5873,13 +7938,15 @@ definitions: format: uri minLength: 1 _CourseApiMediaCollection: - title: Media required: + - banner_image - course_image - course_video - image type: object properties: + banner_image: + $ref: '#/definitions/_AbsolutMedia' course_image: $ref: '#/definitions/_Media' course_video: @@ -6361,6 +8428,247 @@ definitions: type: string format: date-time readOnly: true + ReportDownload: + description: Report Download + required: + - url + - name + - link + type: object + properties: + url: + title: Url + description: URL from which report can be downloaded. + type: string + format: uri + minLength: 1 + name: + title: Name + description: Name of report. + type: string + minLength: 1 + link: + title: Link + description: HTML anchor tag that contains the name and link. + type: string + minLength: 1 + ReportDownloadsList: + required: + - downloads + type: object + properties: + downloads: + description: List of report downloads + type: array + items: + $ref: '#/definitions/ReportDownload' + ProblemResponseReportPostParams: + required: + - problem_locations + type: object + properties: + problem_locations: + description: 'A list of usage keys for the blocks to include in the report. ' + type: array + items: + description: A usage key location for a section or a problem. If the location + is a block that contains other blocks, (such as the course, section, subsection, + or unit blocks) then all blocks under that block will be included in the + report. + type: string + minLength: 1 + problem_types_filter: + description: 'A list of problem/block types to generate the report for. This + field can be omitted if the report should include details of allblock types. ' + type: array + items: + type: string + minLength: 1 + ProblemResponsesReportStatus: + required: + - status + - task_id + type: object + properties: + status: + title: Status + description: User-friendly text describing current status of report generation. + type: string + minLength: 1 + task_id: + title: Task id + description: A unique id for the report generation task. It can be used to + query the latest report generation status. + type: string + format: uuid + InstructorTask: + required: + - status + - task_type + - task_id + - created + - task_input + - requester + - task_state + - duration_sec + - task_message + type: object + properties: + status: + title: Status + description: Current status of task. + type: string + minLength: 1 + task_type: + title: Task type + description: Identifies the kind of task being performed, e.g. rescoring. + type: string + minLength: 1 + task_id: + title: Task id + description: The celery ID for the task. + type: string + minLength: 1 + created: + title: Created + description: The date and time when the task was created. + type: string + format: date-time + task_input: + title: Task input + description: The input parameters for the task. The format and content of + this data will depend on the kind of task being performed. For instanceit + may contain the problem locations for a problem resources task. + type: object + additionalProperties: + type: string + x-nullable: true + requester: + title: Requester + description: The username of the user who initiated this task. + type: string + minLength: 1 + task_state: + title: Task state + description: The last knows state of the celery task. + type: string + minLength: 1 + duration_sec: + title: Duration sec + description: Task duration information, if known + type: string + minLength: 1 + task_message: + title: Task message + description: User-friendly task status information, if available. + type: string + minLength: 1 + InstructorTasksList: + required: + - tasks + type: object + properties: + tasks: + description: List of instructor tasks. + type: array + items: + $ref: '#/definitions/InstructorTask' + LtiAgsLineItem: + required: + - resourceId + - scoreMaximum + - label + type: object + properties: + id: + title: Id + type: string + readOnly: true + resourceId: + title: Resourceid + type: string + minLength: 1 + scoreMaximum: + title: Scoremaximum + type: integer + label: + title: Label + type: string + maxLength: 100 + minLength: 1 + tag: + title: Tag + type: string + maxLength: 50 + resourceLinkId: + title: Resourcelinkid + type: string + startDateTime: + title: Startdatetime + type: string + format: date-time + endDateTime: + title: Enddatetime + type: string + format: date-time + mobile_api.User: + required: + - username + type: object + properties: + id: + title: ID + type: integer + readOnly: true + username: + title: Username + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + type: string + pattern: ^[\w.@+-]+$ + maxLength: 150 + minLength: 1 + email: + title: Email address + type: string + format: email + maxLength: 254 + name: + title: Name + type: string + readOnly: true + course_enrollments: + title: Course enrollments + type: string + readOnly: true + CourseEnrollment: + type: object + properties: + audit_access_expires: + title: Audit access expires + type: string + readOnly: true + created: + title: Created + type: string + format: date-time + readOnly: true + mode: + title: Mode + type: string + maxLength: 100 + minLength: 1 + is_active: + title: Is active + type: boolean + course: + title: Course + type: string + readOnly: true + certificate: + title: Certificate + type: string + readOnly: true Organization: required: - name @@ -6388,8 +8696,9 @@ definitions: minLength: 1 short_name: title: Short Name - description: Please do not use spaces or special characters. Only allowed - special characters are period (.), hyphen (-) and underscore (_). + description: Unique, short string identifier for organization. Please do not + use spaces or special characters. Only allowed special characters are period + (.), hyphen (-) and underscore (_). type: string maxLength: 255 minLength: 1 @@ -6576,6 +8885,10 @@ definitions: title: Updated at type: string format: date-time + receipt_id: + title: Receipt id + type: string + readOnly: true user_api.User: type: object properties: diff --git a/lms/djangoapps/instructor/apps.py b/lms/djangoapps/instructor/apps.py index 6b7b05bd23f7..898416585f38 100644 --- a/lms/djangoapps/instructor/apps.py +++ b/lms/djangoapps/instructor/apps.py @@ -8,7 +8,6 @@ from edx_django_utils.plugins import PluginSettings, PluginURLs from edx_proctoring.runtime import set_runtime_service -from openedx.core.constants import COURSE_ID_PATTERN from openedx.core.djangoapps.plugins.constants import ProjectType, SettingsType @@ -22,8 +21,8 @@ class InstructorConfig(AppConfig): PluginURLs.CONFIG: { ProjectType.LMS: { PluginURLs.NAMESPACE: '', - PluginURLs.REGEX: f'^courses/{COURSE_ID_PATTERN}/instructor/api/', - PluginURLs.RELATIVE_PATH: 'views.api_urls', + PluginURLs.REGEX: '', + PluginURLs.RELATIVE_PATH: 'urls', } }, PluginSettings.CONFIG: { diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 8252aba89ca7..b638b36f73d3 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -19,6 +19,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.http import HttpRequest, HttpResponse from django.test import RequestFactory, TestCase +from django.test.client import MULTIPART_CONTENT from django.urls import reverse as django_reverse from django.utils.translation import ugettext as _ from edx_when.api import get_dates_for_course, get_overrides_for_user, set_date_for_block @@ -140,6 +141,8 @@ INSTRUCTOR_GET_ENDPOINTS = { 'get_anon_ids', 'get_issued_certificates', + 'instructor_api_v1:list_instructor_tasks', + 'instructor_api_v1:list_report_downloads', } INSTRUCTOR_POST_ENDPOINTS = { 'add_users_to_cohorts', @@ -177,6 +180,7 @@ 'students_update_enrollment', 'update_forum_role_membership', 'override_problem_score', + 'instructor_api_v1:generate_problem_responses' } @@ -412,13 +416,15 @@ def setUp(self): ('list_forum_members', {'rolename': FORUM_ROLE_COMMUNITY_TA}), ('send_email', {'send_to': '["staff"]', 'subject': 'test', 'message': 'asdf'}), ('list_instructor_tasks', {}), + ('instructor_api_v1:list_instructor_tasks', {}), ('list_background_email_tasks', {}), - ('list_report_downloads', {}), + ('instructor_api_v1:list_report_downloads', {}), ('calculate_grades_csv', {}), ('get_students_features', {}), ('get_students_who_may_enroll', {}), ('get_proctored_exam_results', {}), ('get_problem_responses', {}), + ('instructor_api_v1:generate_problem_responses', {"problem_locations": [str(self.problem.location)]}), ('export_ora2_data', {}), ('export_ora2_submission_files', {}), ('export_ora2_summary', {}), @@ -446,7 +452,7 @@ def setUp(self): ('reset_student_attempts', {'problem_to_reset': self.problem_urlname, 'all_students': True}), ] - def _access_endpoint(self, endpoint, args, status_code, msg): + def _access_endpoint(self, endpoint, args, status_code, msg, content_type=MULTIPART_CONTENT): """ Asserts that accessing the given `endpoint` gets a response of `status_code`. @@ -459,7 +465,7 @@ def _access_endpoint(self, endpoint, args, status_code, msg): if endpoint in INSTRUCTOR_GET_ENDPOINTS: response = self.client.get(url, args) else: - response = self.client.post(url, args) + response = self.client.post(url, args, content_type=content_type) assert response.status_code == status_code, msg def test_student_level(self): @@ -484,7 +490,7 @@ def test_student_level(self): "Student should not be allowed to access endpoint " + endpoint ) - def _access_problem_responses_endpoint(self, msg): + def _access_problem_responses_endpoint(self, endpoint, msg): """ Access endpoint for problem responses report, ensuring that UsageKey.from_string returns a problem key that the endpoint @@ -496,7 +502,7 @@ def _access_problem_responses_endpoint(self, msg): mock_problem_key.course_key = self.course.id with patch.object(UsageKey, 'from_string') as patched_method: patched_method.return_value = mock_problem_key - self._access_endpoint('get_problem_responses', {}, 200, msg) + self._access_endpoint(endpoint, {"problem_locations": ["test"]}, 200, msg, content_type="application/json") def test_staff_level(self): """ @@ -516,8 +522,9 @@ def test_staff_level(self): # TODO: make these work if endpoint in ['update_forum_role_membership', 'list_forum_members']: continue - elif endpoint == 'get_problem_responses': + elif endpoint in ('get_problem_responses', 'instructor_api_v1:generate_problem_responses'): self._access_problem_responses_endpoint( + endpoint, "Staff member should be allowed to access endpoint " + endpoint ) continue @@ -553,8 +560,9 @@ def test_instructor_level(self): # TODO: make these work if endpoint in ['update_forum_role_membership']: continue - elif endpoint == 'get_problem_responses': + elif endpoint in ('get_problem_responses', 'instructor_api_v1:generate_problem_responses'): self._access_problem_responses_endpoint( + endpoint, "Instructor should be allowed to access endpoint " + endpoint ) continue @@ -2485,18 +2493,22 @@ def setUp(self): email=student.email, course_id=self.course.id ) - def test_get_problem_responses_invalid_location(self): + @ddt.data( + ('get_problem_responses', {'problem_location': ""}), + ('instructor_api_v1:generate_problem_responses', {"problem_locations": ["abc"]}), + ) + @ddt.unpack + def test_get_problem_responses_invalid_location(self, endpoint, post_data): """ Test whether get_problem_responses returns an appropriate status message when users submit an invalid problem location. """ url = reverse( - 'get_problem_responses', + endpoint, kwargs={'course_id': str(self.course.id)} ) - problem_location = '' - response = self.client.post(url, {'problem_location': problem_location}) + response = self.client.post(url, post_data, content_type="application/json") res_json = json.loads(response.content.decode('utf-8')) assert res_json == 'Could not find problem with this location.' @@ -2520,18 +2532,22 @@ def wrapper(self, *args, **kwargs): return wrapper @valid_problem_location - def test_get_problem_responses_successful(self): + @ddt.data( + ('get_problem_responses', {'problem_location': "test"}), + ('instructor_api_v1:generate_problem_responses', {'problem_locations': ["test"]}), + ) + @ddt.unpack + def test_get_problem_responses_successful(self, endpoint, post_data): """ Test whether get_problem_responses returns an appropriate status message if CSV generation was started successfully. """ url = reverse( - 'get_problem_responses', + endpoint, kwargs={'course_id': str(self.course.id)} ) - problem_location = '' - response = self.client.post(url, {'problem_location': problem_location}) + response = self.client.post(url, post_data, content_type="application/json") res_json = json.loads(response.content.decode('utf-8')) assert 'status' in res_json status = res_json['status'] @@ -2540,13 +2556,14 @@ def test_get_problem_responses_successful(self): assert 'task_id' in res_json @valid_problem_location - def test_get_problem_responses_already_running(self): + @ddt.data('get_problem_responses', 'instructor_api_v1:generate_problem_responses') + def test_get_problem_responses_already_running(self, endpoint): """ Test whether get_problem_responses returns an appropriate status message if CSV generation is already in progress. """ url = reverse( - 'get_problem_responses', + endpoint, kwargs={'course_id': str(self.course.id)} ) task_type = 'problem_responses_csv' @@ -2554,7 +2571,7 @@ def test_get_problem_responses_already_running(self): with patch('lms.djangoapps.instructor_task.api.submit_calculate_problem_responses_csv') as submit_task_function: error = AlreadyRunningError(already_running_status) submit_task_function.side_effect = error - response = self.client.post(url, {}) + response = self.client.post(url, {"problem_locations": ["test"]}, content_type="application/json") self.assertContains(response, already_running_status, status_code=400) @@ -2731,15 +2748,19 @@ def test_add_user_to_fiance_admin_role_with_valid_course(self): @patch('lms.djangoapps.instructor_task.models.logger.error') @patch.dict(settings.GRADES_DOWNLOAD, {'STORAGE_TYPE': 's3', 'ROOT_PATH': 'tmp/edx-s3/grades'}) - def test_list_report_downloads_error(self, mock_error): + @ddt.data('list_report_downloads', 'instructor_api_v1:list_report_downloads') + def test_list_report_downloads_error(self, endpoint, mock_error): """ Tests the Rate-Limit exceeded is handled and does not raise 500 error. """ ex_status = 503 ex_reason = 'Slow Down' - url = reverse('list_report_downloads', kwargs={'course_id': str(self.course.id)}) + url = reverse(endpoint, kwargs={'course_id': str(self.course.id)}) with patch('storages.backends.s3boto.S3BotoStorage.listdir', side_effect=BotoServerError(ex_status, ex_reason)): - response = self.client.post(url, {}) + if endpoint in INSTRUCTOR_GET_ENDPOINTS: + response = self.client.get(url) + else: + response = self.client.post(url, {}) mock_error.assert_called_with( 'Fetching files failed for course: %s, status: %s, reason: %s', self.course.id, @@ -2750,14 +2771,18 @@ def test_list_report_downloads_error(self, mock_error): res_json = json.loads(response.content.decode('utf-8')) assert res_json == {'downloads': []} - def test_list_report_downloads(self): - url = reverse('list_report_downloads', kwargs={'course_id': str(self.course.id)}) + @ddt.data('list_report_downloads', 'instructor_api_v1:list_report_downloads') + def test_list_report_downloads(self, endpoint): + url = reverse(endpoint, kwargs={'course_id': str(self.course.id)}) with patch('lms.djangoapps.instructor_task.models.DjangoStorageReportStore.links_for') as mock_links_for: mock_links_for.return_value = [ ('mock_file_name_1', 'https://1.mock.url'), ('mock_file_name_2', 'https://2.mock.url'), ] - response = self.client.post(url, {}) + if endpoint in INSTRUCTOR_GET_ENDPOINTS: + response = self.client.get(url) + else: + response = self.client.post(url, {}) expected_response = { "downloads": [ @@ -3455,6 +3480,7 @@ def mock_get_task_completion_info(self, *args): # pylint: disable=unused-argume return False, 'Task Errored In Some Way' +@ddt.ddt class TestInstructorAPITaskLists(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test instructor task list endpoint. @@ -3534,16 +3560,20 @@ def setUp(self): self.tasks[-1].make_invalid_output() @patch('lms.djangoapps.instructor_task.api.get_running_instructor_tasks') - def test_list_instructor_tasks_running(self, act): + @ddt.data('instructor_api_v1:list_instructor_tasks', 'list_instructor_tasks') + def test_list_instructor_tasks_running(self, endpoint, act): """ Test list of all running tasks. """ act.return_value = self.tasks - url = reverse('list_instructor_tasks', kwargs={'course_id': str(self.course.id)}) + url = reverse(endpoint, kwargs={'course_id': str(self.course.id)}) mock_factory = MockCompletionInfo() with patch( 'lms.djangoapps.instructor.views.instructor_task_helpers.get_task_completion_info' ) as mock_completion_info: mock_completion_info.side_effect = mock_factory.mock_get_task_completion_info - response = self.client.post(url, {}) + if endpoint in INSTRUCTOR_GET_ENDPOINTS: + response = self.client.get(url) + else: + response = self.client.post(url, {}) assert response.status_code == 200 # check response @@ -3576,18 +3606,24 @@ def test_list_background_email_tasks(self, act): assert actual_tasks == expected_tasks @patch('lms.djangoapps.instructor_task.api.get_instructor_task_history') - def test_list_instructor_tasks_problem(self, act): + @ddt.data('instructor_api_v1:list_instructor_tasks', 'list_instructor_tasks') + def test_list_instructor_tasks_problem(self, endpoint, act): """ Test list task history for problem. """ act.return_value = self.tasks - url = reverse('list_instructor_tasks', kwargs={'course_id': str(self.course.id)}) + url = reverse(endpoint, kwargs={'course_id': str(self.course.id)}) mock_factory = MockCompletionInfo() with patch( 'lms.djangoapps.instructor.views.instructor_task_helpers.get_task_completion_info' ) as mock_completion_info: mock_completion_info.side_effect = mock_factory.mock_get_task_completion_info - response = self.client.post(url, { - 'problem_location_str': self.problem_urlname, - }) + if endpoint in INSTRUCTOR_GET_ENDPOINTS: + response = self.client.get(url, { + 'problem_location_str': self.problem_urlname, + }) + else: + response = self.client.post(url, { + 'problem_location_str': self.problem_urlname, + }) assert response.status_code == 200 # check response @@ -3599,19 +3635,26 @@ def test_list_instructor_tasks_problem(self, act): assert actual_tasks == expected_tasks @patch('lms.djangoapps.instructor_task.api.get_instructor_task_history') - def test_list_instructor_tasks_problem_student(self, act): + @ddt.data('list_instructor_tasks', 'instructor_api_v1:list_instructor_tasks') + def test_list_instructor_tasks_problem_student(self, endpoint, act): """ Test list task history for problem AND student. """ act.return_value = self.tasks - url = reverse('list_instructor_tasks', kwargs={'course_id': str(self.course.id)}) + url = reverse(endpoint, kwargs={'course_id': str(self.course.id)}) mock_factory = MockCompletionInfo() with patch( 'lms.djangoapps.instructor.views.instructor_task_helpers.get_task_completion_info' ) as mock_completion_info: mock_completion_info.side_effect = mock_factory.mock_get_task_completion_info - response = self.client.post(url, { - 'problem_location_str': self.problem_urlname, - 'unique_student_identifier': self.student.email, - }) + if endpoint in INSTRUCTOR_GET_ENDPOINTS: + response = self.client.get(url, { + 'problem_location_str': self.problem_urlname, + 'unique_student_identifier': self.student.email, + }) + else: + response = self.client.post(url, { + 'problem_location_str': self.problem_urlname, + 'unique_student_identifier': self.student.email, + }) assert response.status_code == 200 # check response @@ -3662,7 +3705,7 @@ def get_matching_mock_email(self, **kwargs): return self.emails[email_id] def get_email_content_response(self, num_emails, task_history_request, with_failures=False): - """ Calls the list_email_content endpoint and returns the repsonse """ + """ Calls the list_email_content endpoint and returns the respsonse """ self.setup_fake_email_info(num_emails, with_failures) task_history_request.return_value = list(self.tasks.values()) url = reverse('list_email_content', kwargs={'course_id': str(self.course.id)}) diff --git a/lms/djangoapps/instructor/urls.py b/lms/djangoapps/instructor/urls.py new file mode 100644 index 000000000000..17db7f600eb6 --- /dev/null +++ b/lms/djangoapps/instructor/urls.py @@ -0,0 +1,17 @@ +""" +Instructor API endpoint urls. +""" + +from django.conf.urls import url, include + +from openedx.core.constants import COURSE_ID_PATTERN +from .views import api_urls + + +urlpatterns = [ + url(rf'^courses/{COURSE_ID_PATTERN}/instructor/api/', include(api_urls.urlpatterns)), + url( + r'^api/instructor/v1/', + include((api_urls.v1_api_urls, 'lms.djangoapps.instructor'), namespace='instructor_api_v1'), + ), +] diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 66d7b6ed3c0e..3adf2be59b6e 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -9,10 +9,11 @@ import csv import json import logging +import string import random import re -import string +import edx_api_doc_tools as apidocs from django.conf import settings from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist, PermissionDenied, ValidationError @@ -26,17 +27,18 @@ from django.utils.translation import ugettext as _ from django.views.decorators.cache import cache_control from django.views.decorators.csrf import ensure_csrf_cookie -from django.views.decorators.http import require_http_methods, require_POST +from django.views.decorators.http import require_POST, require_http_methods from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser from edx_when.api import get_date_for_block from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey, UsageKey -from rest_framework import status +from rest_framework import serializers, status from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from submissions import api as sub_api # installed from the edx-submissions repository +from xmodule.modulestore.django import modulestore from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.student import auth @@ -44,17 +46,17 @@ from common.djangoapps.student.models import ( ALLOWEDTOENROLL_TO_ENROLLED, ALLOWEDTOENROLL_TO_UNENROLLED, + CourseEnrollment, + CourseEnrollmentAllowed, DEFAULT_TRANSITION_STATE, ENROLLED_TO_ENROLLED, ENROLLED_TO_UNENROLLED, - UNENROLLED_TO_ALLOWEDTOENROLL, - UNENROLLED_TO_ENROLLED, - UNENROLLED_TO_UNENROLLED, - CourseEnrollment, - CourseEnrollmentAllowed, EntranceExamConfiguration, ManualEnrollmentAudit, Registration, + UNENROLLED_TO_ALLOWEDTOENROLL, + UNENROLLED_TO_ENROLLED, + UNENROLLED_TO_UNENROLLED, UserProfile, get_user_by_username_or_email, is_email_retired, @@ -63,7 +65,7 @@ from common.djangoapps.util.file import ( FileValidationException, course_and_time_based_filename_generator, - store_uploaded_file + store_uploaded_file, ) from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest from common.djangoapps.util.views import require_global_staff @@ -79,7 +81,7 @@ from lms.djangoapps.discussion.django_comment_client.utils import ( get_group_id_for_user, get_group_name, - has_forum_access + has_forum_access, ) from lms.djangoapps.instructor import enrollment from lms.djangoapps.instructor.access import ROLES, allow_access, list_with_level, revoke_access, update_forum_role @@ -89,13 +91,11 @@ get_user_email_language, send_beta_role_email, send_mail_to_student, - unenroll_email + unenroll_email, ) from lms.djangoapps.instructor.views import INVOICE_KEY from lms.djangoapps.instructor.views.instructor_task_helpers import extract_email_features, extract_task_features -from lms.djangoapps.instructor_analytics import basic as instructor_analytics_basic -from lms.djangoapps.instructor_analytics import csvs as instructor_analytics_csvs -from lms.djangoapps.instructor_analytics import distributions as instructor_analytics_distributions # lint-amnesty, pylint: disable=unused-import +from lms.djangoapps.instructor_analytics import basic as instructor_analytics_basic, csvs as instructor_analytics_csvs from lms.djangoapps.instructor_task import api as task_api from lms.djangoapps.instructor_task.api_helper import AlreadyRunningError, QueueConnectionError from lms.djangoapps.instructor_task.models import ReportStore @@ -107,17 +107,14 @@ FORUM_ROLE_COMMUNITY_TA, FORUM_ROLE_GROUP_MODERATOR, FORUM_ROLE_MODERATOR, - Role + Role, ) from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.user_api.preferences.api import get_user_preference from openedx.core.djangolib.markup import HTML, Text from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser -from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin +from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes from openedx.core.lib.courses import get_course_by_id -from xmodule.modulestore.django import modulestore - -from .. import permissions from .tools import ( dump_module_extensions, dump_student_extensions, @@ -127,8 +124,9 @@ parse_datetime, require_student_from_identifier, set_due_date_extension, - strip_if_string + strip_if_string, ) +from .. import permissions log = logging.getLogger(__name__) @@ -971,12 +969,144 @@ def extract_user_info(user): return JsonResponse(response_payload) +class ProblemResponseReportPostParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer that describes that POST parameters for the report generation API. + """ + problem_locations = serializers.ListSerializer( + child=serializers.CharField( + help_text=_( + "A usage key location for a section or a problem. " + "If the location is a block that contains other blocks, (such as the course, " + "section, subsection, or unit blocks) then all blocks under that block will be " + "included in the report." + ), + ), + required=True, + allow_empty=False, + help_text=_( + "A list of usage keys for the blocks to include in the report. " + ) + ) + problem_types_filter = serializers.ListSerializer( + child=serializers.CharField(), + required=False, + allow_empty=True, + help_text=_( + "A list of problem/block types to generate the report for. " + "This field can be omitted if the report should include details of all" + "block types. " + ), + ) + + +class ProblemResponsesReportStatusSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer that describes the response of the problem response report generation API. + """ + status = serializers.CharField(help_text=_("User-friendly text describing current status of report generation.")) + task_id = serializers.UUIDField( + help_text=_( + "A unique id for the report generation task. " + "It can be used to query the latest report generation status." + ) + ) + + +@view_auth_classes() +@method_decorator(transaction.non_atomic_requests, name='dispatch') +class ProblemResponseReportInitiate(DeveloperErrorViewMixin, APIView): + """ + Initiate generation of a CSV file containing all student answers + to a given problem. + """ + + @apidocs.schema( + parameters=[ + apidocs.path_parameter( + 'course_id', + str, + description="ID of the course for which report is to be generate.", + ), + ], + body=ProblemResponseReportPostParamsSerializer, + responses={ + 200: ProblemResponsesReportStatusSerializer, + 400: _( + "The provided parameters were invalid. Make sure you've provided at least " + "one valid usage key for `problem_locations`." + ), + 401: _("The requesting user is not authenticated."), + 403: _("The requesting user lacks access to the course."), + } + ) + @transaction.non_atomic_requests + @method_decorator(require_course_permission(permissions.CAN_RESEARCH)) + def post(self, request, course_id): + """ + Initiate generation of a CSV file containing all student answers + to a given problem. + + **Example requests** + + POST /api/instructor/v1/reports/{course_id}/generate/problem_responses { + "problem_locations": [ + "{usage_key1}", + "{usage_key2}", + "{usage_key3}" + ] + } + POST /api/instructor/v1/reports/{course_id}/generate/problem_responses { + "problem_locations": ["{usage_key}"], + "problem_types_filter": ["problem"] + } + + **POST Parameters** + + A POST request can include the following parameters: + + * problem_location: A list of usage keys for the blocks to include in + the report. If the location is a block that contains other blocks, + (such as the course, section, subsection, or unit blocks) then all + blocks under that block will be included in the report. + * problem_types_filter: Optional. A comma-separated list of block types + to include in the report. If set, only blocks of the specified types + will be included in the report. + + To get data on all the poll and survey blocks in a course, you could + POST the usage key of the course for `problem_location`, and + "poll, survey" as the value for `problem_types_filter`. + + + **Example Response:** + If initiation is successful (or generation task is already running): + ```json + { + "status": "The problem responses report is being created. ...", + "task_id": "4e49522f-31d9-431a-9cff-dd2a2bf4c85a" + } + ``` + + Responds with BadRequest if any of the provided problem locations are faulty. + """ + params = ProblemResponseReportPostParamsSerializer(data=request.data) + params.is_valid(raise_exception=True) + problem_locations = params.validated_data.get('problem_locations') + problem_types_filter = params.validated_data.get('problem_types_filter') + if problem_types_filter: + problem_types_filter = ','.join(problem_types_filter) + return _get_problem_responses( + request, + course_id=course_id, + problem_locations=problem_locations, + problem_types_filter=problem_types_filter, + ) + + @transaction.non_atomic_requests @require_POST @ensure_csrf_cookie -@cache_control(no_cache=True, no_store=True, must_revalidate=True) @require_course_permission(permissions.CAN_RESEARCH) -@common_exceptions_400 def get_problem_responses(request, course_id): """ Initiate generation of a CSV file containing all student answers @@ -1020,24 +1150,38 @@ def get_problem_responses(request, course_id): Responds with BadRequest if any of the provided problem locations are faulty. """ - course_key = CourseKey.from_string(course_id) # A comma-separated list of problem locations # The name of the POST parameter is `problem_location` (not pluralised) in # order to preserve backwards compatibility with existing third-party # scripts. - problem_locations = request.POST.get('problem_location', '') + problem_locations = request.POST.get('problem_location', '').split(',') # A comma-separated list of block types - problem_types_filter = request.POST.get('problem_types_filter', '') + problem_types_filter = request.POST.get('problem_types_filter') + return _get_problem_responses( + request, + course_id=course_id, + problem_locations=problem_locations, + problem_types_filter=problem_types_filter, + ) + + +@cache_control(no_cache=True, no_store=True, must_revalidate=True) +@common_exceptions_400 +def _get_problem_responses(request, *, course_id, problem_locations, problem_types_filter): + """ + Shared code for new DRF and old APIS for problem response report generation. + """ + course_key = CourseKey.from_string(course_id) report_type = _('problem responses') try: - for problem_location in problem_locations.split(','): - problem_key = UsageKey.from_string(problem_location).map_into_course(course_key) # lint-amnesty, pylint: disable=unused-variable + for problem_location in problem_locations: + UsageKey.from_string(problem_location).map_into_course(course_key) except InvalidKeyError: return JsonResponseBadRequest(_("Could not find problem with this location.")) task = task_api.submit_calculate_problem_responses_csv( - request, course_key, problem_locations, problem_types_filter, + request, course_key, ','.join(problem_locations), problem_types_filter, ) success_status = SUCCESS_MESSAGE_TEMPLATE.format(report_type=report_type) @@ -1852,23 +1996,164 @@ def list_email_content(request, course_id): return JsonResponse(response_payload) +class InstructorTaskSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer that describes the format of a single instructor task. + """ + status = serializers.CharField(help_text=_("Current status of task.")) + task_type = serializers.CharField(help_text=_("Identifies the kind of task being performed, e.g. rescoring.")) + task_id = serializers.CharField(help_text=_("The celery ID for the task.")) + created = serializers.DateTimeField(help_text=_("The date and time when the task was created.")) + task_input = serializers.DictField( + help_text=_( + "The input parameters for the task. The format and content of this " + "data will depend on the kind of task being performed. For instance" + "it may contain the problem locations for a problem resources task.") + ) + requester = serializers.CharField(help_text=_("The username of the user who initiated this task.")) + task_state = serializers.CharField(help_text=_("The last knows state of the celery task.")) + duration_sec = serializers.CharField(help_text=_("Task duration information, if known")) + task_message = serializers.CharField(help_text=_("User-friendly task status information, if available.")) + + +class InstructorTasksListSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer to describe the response of the instructor tasks list API. + """ + tasks = serializers.ListSerializer( + child=InstructorTaskSerializer(), + help_text=_("List of instructor tasks.") + ) + + +@view_auth_classes() +class InstructorTasks(DeveloperErrorViewMixin, APIView): + """ + **Use Cases** + + Lists currently running instructor tasks + + **Parameters** + - With no arguments, lists running tasks. + - `problem_location_str` lists task history for problem + - `problem_location_str` and `unique_student_identifier` lists task + history for problem AND student (intersection) + + **Example Requests**: + + GET /courses/{course_id}/instructor/api/v0/tasks + + **Response Values** + { + "tasks": [ + { + "status": "Incomplete", + "task_type": "grade_problems", + "task_id": "2519ff31-22d9-4a62-91e2-55495895b355", + "created": "2019-01-15T18:00:15.902470+00:00", + "task_input": "{}", + "duration_sec": "unknown", + "task_message": "No status information available", + "requester": "staff", + "task_state": "PROGRESS" + } + ] + } + """ + + @apidocs.schema( + parameters=[ + apidocs.string_parameter( + 'course_id', + apidocs.ParameterLocation.PATH, + description="ID for the course whose tasks need to be listed.", + ), + apidocs.string_parameter( + 'problem_location_str', + apidocs.ParameterLocation.QUERY, + description="Filter instructor tasks to this problem location.", + ), + apidocs.string_parameter( + 'unique_student_identifier', + apidocs.ParameterLocation.QUERY, + description="Filter tasks to a singe problem and a single student. " + "Must be used in combination with `problem_location_str`.", + ), + ], + responses={ + 200: InstructorTasksListSerializer, + 401: _("The requesting user is not authenticated."), + 403: _("The requesting user lacks access to the course."), + 404: _("The requested course does not exist."), + } + ) + def get(self, request, course_id): + """ + List instructor tasks filtered by `course_id`. + + **Use Cases** + + Lists currently running instructor tasks + + **Parameters** + - With no arguments, lists running tasks. + - `problem_location_str` lists task history for problem + - `problem_location_str` and `unique_student_identifier` lists task + history for problem AND student (intersection) + + **Example Requests**: + + GET /courses/{course_id}/instructor/api/v0/tasks + + **Response Values** + ```json + { + "tasks": [ + { + "status": "Incomplete", + "task_type": "grade_problems", + "task_id": "2519ff31-22d9-4a62-91e2-55495895b355", + "created": "2019-01-15T18:00:15.902470+00:00", + "task_input": "{}", + "duration_sec": "unknown", + "task_message": "No status information available", + "requester": "staff", + "task_state": "PROGRESS" + } + ] + } + ``` + """ + return _list_instructor_tasks(request=request, course_id=course_id) + + @require_POST @ensure_csrf_cookie -@cache_control(no_cache=True, no_store=True, must_revalidate=True) -@require_course_permission(permissions.SHOW_TASKS) def list_instructor_tasks(request, course_id): """ List instructor tasks. - Takes optional query paremeters. + Takes optional query parameters. - With no arguments, lists running tasks. - `problem_location_str` lists task history for problem - `problem_location_str` and `unique_student_identifier` lists task history for problem AND student (intersection) """ + return _list_instructor_tasks(request=request, course_id=course_id) + + +@cache_control(no_cache=True, no_store=True, must_revalidate=True) +@require_course_permission(permissions.SHOW_TASKS) +def _list_instructor_tasks(request, course_id): + """ + List instructor tasks. + + Internal function with common code for both DRF and and tradition views. + """ course_id = CourseKey.from_string(course_id) - problem_location_str = strip_if_string(request.POST.get('problem_location_str', False)) - student = request.POST.get('unique_student_identifier', None) + params = getattr(request, 'query_params', request.POST) + problem_location_str = strip_if_string(params.get('problem_location_str', False)) + student = params.get('unique_student_identifier', None) if student is not None: student = get_student_from_identifier(student) @@ -1940,10 +2225,85 @@ def list_entrance_exam_instructor_tasks(request, course_id): return JsonResponse(response_payload) +class ReportDownloadSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer that describes a single report download. + """ + url = serializers.URLField(help_text=_("URL from which report can be downloaded.")) + name = serializers.CharField(help_text=_("Name of report.")) + link = serializers.CharField(help_text=_("HTML anchor tag that contains the name and link.")) + + +class ReportDownloadsListSerializer(serializers.Serializer): # pylint: disable=abstract-method + """ + Serializer that describes the response of the report downloads list API. + """ + downloads = serializers.ListSerializer( + child=ReportDownloadSerializer(help_text="Report Download"), + help_text=_("List of report downloads"), + ) + + +@view_auth_classes() +class ReportDownloads(DeveloperErrorViewMixin, APIView): + """ + API view to list report downloads for a course. + """ + + @apidocs.schema(parameters=[ + apidocs.string_parameter( + 'course_id', + apidocs.ParameterLocation.PATH, + description=_("ID for the course whose reports need to be listed."), + ), + apidocs.string_parameter( + 'report_name', + apidocs.ParameterLocation.QUERY, + description=_( + "Filter results to only return details of for the report with the specified name." + ), + ), + ], responses={ + 200: ReportDownloadsListSerializer, + 401: _("The requesting user is not authenticated."), + 403: _("The requesting user lacks access to the course."), + 404: _("The requested course does not exist."), + }) + def get(self, request, course_id): + """ + List report CSV files that are available for download for this course. + + **Use Cases** + + Lists reports available for download + + **Example Requests**: + + GET /api/instructor/v1/reports/{course_id} + + **Response Values** + ```json + { + "downloads": [ + { + "url": "https://1.mock.url", + "link": "mock_file_name_1", + "name": "mock_file_name_1" + } + ] + } + ``` + + The report name will depend on the type of report generated. For example a + problem responses report for an entire course might be called: + + edX_DemoX_Demo_Course_student_state_from_block-v1_edX+DemoX+Demo_Course+type@course+block@course_2021-04-30-0918.csv + """ # pylint: disable=line-too-long + return _list_report_downloads(request=request, course_id=course_id) + + @require_POST @ensure_csrf_cookie -@cache_control(no_cache=True, no_store=True, must_revalidate=True) -@require_course_permission(permissions.CAN_RESEARCH) def list_report_downloads(request, course_id): """ List grade CSV files that are available for download for this course. @@ -1951,9 +2311,20 @@ def list_report_downloads(request, course_id): Takes the following query parameters: - (optional) report_name - name of the report """ + return _list_report_downloads(request=request, course_id=course_id) + + +@cache_control(no_cache=True, no_store=True, must_revalidate=True) +@require_course_permission(permissions.CAN_RESEARCH) +def _list_report_downloads(request, course_id): + """ + List grade CSV files that are available for download for this course. + + Internal function with common code shared between DRF and functional views. + """ course_id = CourseKey.from_string(course_id) report_store = ReportStore.from_config(config_name='GRADES_DOWNLOAD') - report_name = request.POST.get("report_name", None) + report_name = getattr(request, 'query_params', request.POST).get("report_name", None) response_payload = { 'downloads': [ diff --git a/lms/djangoapps/instructor/views/api_urls.py b/lms/djangoapps/instructor/views/api_urls.py index 8fc74f80dfb3..6a0b7d1e8e69 100644 --- a/lms/djangoapps/instructor/views/api_urls.py +++ b/lms/djangoapps/instructor/views/api_urls.py @@ -2,10 +2,22 @@ Instructor API endpoint urls. """ - from django.conf.urls import url from lms.djangoapps.instructor.views import api, gradebook_api +from openedx.core.constants import COURSE_ID_PATTERN + +# These endpoints are exposing existing views in a way that can be used by MFEs +# or other API clients. They are currently versioned at `v1` since they have +# been around without major changes for a while and will probably not be changed +# in incompatible ways. If they do need incompatible changes for use via MFEs +# then new v2 endpoints can be introduced. +v1_api_urls = [ + url(rf'^tasks/{COURSE_ID_PATTERN}$', api.InstructorTasks.as_view(), name='list_instructor_tasks', ), + url(rf'^reports/{COURSE_ID_PATTERN}$', api.ReportDownloads.as_view(), name='list_report_downloads', ), + url(rf'^reports/{COURSE_ID_PATTERN}/generate/problem_responses$', api.ProblemResponseReportInitiate.as_view(), + name='generate_problem_responses', ), +] urlpatterns = [ url(r'^students_update_enrollment$', api.students_update_enrollment, name='students_update_enrollment'), diff --git a/openedx/core/lib/api/serializers.py b/openedx/core/lib/api/serializers.py index c620599d50bb..01be90778067 100644 --- a/openedx/core/lib/api/serializers.py +++ b/openedx/core/lib/api/serializers.py @@ -53,8 +53,8 @@ def to_internal_value(self, data): """Convert unicode to a course key. """ try: return CourseKey.from_string(data) - except InvalidKeyError as ex: - raise serializers.ValidationError(f"Invalid course key: {ex.msg}") # lint-amnesty, pylint: disable=no-member + except InvalidKeyError as err: + raise serializers.ValidationError("Invalid course key") from err class UsageKeyField(serializers.Field): @@ -68,5 +68,5 @@ def to_internal_value(self, data): """Convert unicode to a usage key. """ try: return UsageKey.from_string(data) - except InvalidKeyError as ex: - raise serializers.ValidationError(f"Invalid usage key: {ex.msg}") # lint-amnesty, pylint: disable=no-member + except InvalidKeyError as err: + raise serializers.ValidationError("Invalid course key") from err