chore: improving programs rest API docs, type hints (#36438)
* chore: improving programs rest API docs, type hints reformatting the docstrings so they appear correctly in the openAPI docs. * moving them into the `GET` * some cleanup and simplification of language * removing real data that refers to specific hosts regenerated the open API documentation. also adding type hints to the API and telling `mypy` to check this file. This was primarily because these models are confusing enough in order to verify that the documentation was correct I had to do a lot of jumping through the code. FIXES: APER-3950
This commit is contained in:
@@ -3469,8 +3469,58 @@ paths:
|
||||
/dashboard/v0/programs/{enterprise_uuid}/:
|
||||
get:
|
||||
operationId: dashboard_v0_programs_read
|
||||
description: Return a list of a enterprise learner's all enrolled programs with
|
||||
their progress.
|
||||
summary: For an enterprise learner, get list of enrolled programs with progress.
|
||||
description: |-
|
||||
**Example Request**
|
||||
|
||||
GET /api/dashboard/v1/programs/{enterprise_uuid}/
|
||||
|
||||
**Parameters**
|
||||
|
||||
* `enterprise_uuid`: UUID of an enterprise customer.
|
||||
|
||||
**Example Response**
|
||||
|
||||
[
|
||||
{
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"title": "Demonstration Program",
|
||||
"type": "MicroMasters",
|
||||
"banner_image": {
|
||||
"large": {
|
||||
"url": "http://example.com/images/foo.large.jpg",
|
||||
"width": 1440,
|
||||
"height": 480
|
||||
},
|
||||
"medium": {
|
||||
"url": "http://example.com/images/foo.medium.jpg",
|
||||
"width": 726,
|
||||
"height": 242
|
||||
},
|
||||
"small": {
|
||||
"url": "http://example.com/images/foo.small.jpg",
|
||||
"width": 435,
|
||||
"height": 145
|
||||
},
|
||||
"x-small": {
|
||||
"url": "http://example.com/images/foo.x-small.jpg",
|
||||
"width": 348,
|
||||
"height": 116
|
||||
}
|
||||
},
|
||||
"authoring_organizations": [
|
||||
{
|
||||
"key": "example"
|
||||
}
|
||||
],
|
||||
"progress": {
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"completed": 0,
|
||||
"in_progress": 0,
|
||||
"not_started": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
@@ -3485,7 +3535,118 @@ paths:
|
||||
/dashboard/v0/programs/{program_uuid}/progress_details/:
|
||||
get:
|
||||
operationId: dashboard_v0_programs_progress_details_list
|
||||
description: Retrieves progress details of a user in a specified program.
|
||||
summary: Retrieves progress details of a learner in a specified program.
|
||||
description: |-
|
||||
**Example Request**
|
||||
|
||||
GET api/dashboard/v1/programs/{program_uuid}/progress_details/
|
||||
|
||||
**Parameters**
|
||||
|
||||
* `program_uuid`: A string representation of the uuid of the program.
|
||||
|
||||
**Response Values**
|
||||
|
||||
If the request for information about the program is successful, an HTTP 200 "OK" response
|
||||
is returned.
|
||||
|
||||
The HTTP 200 response has the following values.
|
||||
|
||||
* `urls`: Urls to enroll/purchase a course or view program record.
|
||||
|
||||
* `program_data`: Holds meta information about the program.
|
||||
|
||||
* `course_data`: Learner's progress details for all courses in the program (in-progress/remaining/completed).
|
||||
|
||||
* `certificate_data`: Details about learner's certificates status for all courses in the program and the
|
||||
program itself.
|
||||
|
||||
* `industry_pathways`: Industry pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
* `credit_pathways`: Credit pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
**Example Response**
|
||||
|
||||
{
|
||||
"urls": {
|
||||
"program_listing_url": "/dashboard/programs/",
|
||||
"track_selection_url": "/course_modes/choose/",
|
||||
"commerce_api_url": "/api/commerce/v1/baskets/",
|
||||
"buy_button_url": "http://example.com/basket/add/?",
|
||||
"program_record_url": "https://example.com/records/programs/8675309"
|
||||
},
|
||||
"program_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"title": "Demonstration Program",
|
||||
"subtitle": "",
|
||||
"type": "MicroMasters",
|
||||
"status": "active",
|
||||
"marketing_slug": "demo-program",
|
||||
"marketing_url": "micromasters/demo-program",
|
||||
"authoring_organizations": [],
|
||||
"card_image_url": "http://example.com/asset-v1:DemoX+Demo_Course.jpg",
|
||||
"is_program_eligible_for_one_click_purchase": false,
|
||||
"pathway_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"is_learner_eligible_for_one_click_purchase": false,
|
||||
"skus": ["AUD90210"],
|
||||
},
|
||||
"course_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"completed": [],
|
||||
"in_progress": [],
|
||||
"not_started": [
|
||||
{
|
||||
"key": "example+DemoX",
|
||||
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
|
||||
"title": "Demonstration Course",
|
||||
"course_runs": [],
|
||||
"entitlements": [],
|
||||
"owners": [],
|
||||
"image": "",
|
||||
"short_description": "",
|
||||
"type": "457f07ec-a78f-45b4-ba09-5fb176520d8a",
|
||||
}
|
||||
],
|
||||
},
|
||||
"certificate_data": [{
|
||||
"type": "course",
|
||||
"title": "Demo Course",
|
||||
'url': "/certificates/8675309",
|
||||
}],
|
||||
"industry_pathways": [
|
||||
{
|
||||
"id": 2,
|
||||
"uuid": "1b8fadf1-f6aa-4282-94e3-325b922a027f",
|
||||
"name": "Demo Industry Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo industry pathway",
|
||||
"destination_url": "http://example.edu/online/pathways/example-methods",
|
||||
"pathway_type": "industry",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"credit_pathways": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "86b9701a-61e6-48a2-92eb-70a824521c1f",
|
||||
"name": "Demo Credit Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo credit pathway!",
|
||||
"destination_url": "http://example.edu/online/pathways/example-thinking",
|
||||
"pathway_type": "credit",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
@@ -5145,26 +5306,6 @@ paths:
|
||||
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
|
||||
description: uuid
|
||||
required: false
|
||||
type: string
|
||||
- name: user
|
||||
in: query
|
||||
description: user
|
||||
required: false
|
||||
type: string
|
||||
- name: course_uuid
|
||||
in: query
|
||||
description: course_uuid
|
||||
required: false
|
||||
type: string
|
||||
- name: expired_at__isnull
|
||||
in: query
|
||||
description: expired_at__isnull
|
||||
required: false
|
||||
type: string
|
||||
- name: page
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
@@ -5351,16 +5492,6 @@ paths:
|
||||
operationId: experiments_v0_data_list
|
||||
description: ''
|
||||
parameters:
|
||||
- name: experiment_id
|
||||
in: query
|
||||
description: experiment_id
|
||||
required: false
|
||||
type: string
|
||||
- name: key
|
||||
in: query
|
||||
description: key
|
||||
required: false
|
||||
type: string
|
||||
- name: page
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
@@ -5493,16 +5624,6 @@ paths:
|
||||
operationId: experiments_v0_key-value_list
|
||||
description: ''
|
||||
parameters:
|
||||
- name: experiment_id
|
||||
in: query
|
||||
description: experiment_id
|
||||
required: false
|
||||
type: string
|
||||
- name: key
|
||||
in: query
|
||||
description: key
|
||||
required: false
|
||||
type: string
|
||||
- name: page
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
@@ -6245,6 +6366,198 @@ paths:
|
||||
tags:
|
||||
- learner_home
|
||||
parameters: []
|
||||
/learner_home/v1/programs/{enterprise_uuid}/:
|
||||
get:
|
||||
operationId: learner_home_v1_programs_read
|
||||
summary: For an enterprise learner, get list of enrolled programs with progress.
|
||||
description: |-
|
||||
**Example Request**
|
||||
|
||||
GET /api/dashboard/v1/programs/{enterprise_uuid}/
|
||||
|
||||
**Parameters**
|
||||
|
||||
* `enterprise_uuid`: UUID of an enterprise customer.
|
||||
|
||||
**Example Response**
|
||||
|
||||
[
|
||||
{
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"title": "Demonstration Program",
|
||||
"type": "MicroMasters",
|
||||
"banner_image": {
|
||||
"large": {
|
||||
"url": "http://example.com/images/foo.large.jpg",
|
||||
"width": 1440,
|
||||
"height": 480
|
||||
},
|
||||
"medium": {
|
||||
"url": "http://example.com/images/foo.medium.jpg",
|
||||
"width": 726,
|
||||
"height": 242
|
||||
},
|
||||
"small": {
|
||||
"url": "http://example.com/images/foo.small.jpg",
|
||||
"width": 435,
|
||||
"height": 145
|
||||
},
|
||||
"x-small": {
|
||||
"url": "http://example.com/images/foo.x-small.jpg",
|
||||
"width": 348,
|
||||
"height": 116
|
||||
}
|
||||
},
|
||||
"authoring_organizations": [
|
||||
{
|
||||
"key": "example"
|
||||
}
|
||||
],
|
||||
"progress": {
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"completed": 0,
|
||||
"in_progress": 0,
|
||||
"not_started": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
tags:
|
||||
- learner_home
|
||||
parameters:
|
||||
- name: enterprise_uuid
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
/learner_home/v1/programs/{program_uuid}/progress_details/:
|
||||
get:
|
||||
operationId: learner_home_v1_programs_progress_details_list
|
||||
summary: Retrieves progress details of a learner in a specified program.
|
||||
description: |-
|
||||
**Example Request**
|
||||
|
||||
GET api/dashboard/v1/programs/{program_uuid}/progress_details/
|
||||
|
||||
**Parameters**
|
||||
|
||||
* `program_uuid`: A string representation of the uuid of the program.
|
||||
|
||||
**Response Values**
|
||||
|
||||
If the request for information about the program is successful, an HTTP 200 "OK" response
|
||||
is returned.
|
||||
|
||||
The HTTP 200 response has the following values.
|
||||
|
||||
* `urls`: Urls to enroll/purchase a course or view program record.
|
||||
|
||||
* `program_data`: Holds meta information about the program.
|
||||
|
||||
* `course_data`: Learner's progress details for all courses in the program (in-progress/remaining/completed).
|
||||
|
||||
* `certificate_data`: Details about learner's certificates status for all courses in the program and the
|
||||
program itself.
|
||||
|
||||
* `industry_pathways`: Industry pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
* `credit_pathways`: Credit pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
**Example Response**
|
||||
|
||||
{
|
||||
"urls": {
|
||||
"program_listing_url": "/dashboard/programs/",
|
||||
"track_selection_url": "/course_modes/choose/",
|
||||
"commerce_api_url": "/api/commerce/v1/baskets/",
|
||||
"buy_button_url": "http://example.com/basket/add/?",
|
||||
"program_record_url": "https://example.com/records/programs/8675309"
|
||||
},
|
||||
"program_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"title": "Demonstration Program",
|
||||
"subtitle": "",
|
||||
"type": "MicroMasters",
|
||||
"status": "active",
|
||||
"marketing_slug": "demo-program",
|
||||
"marketing_url": "micromasters/demo-program",
|
||||
"authoring_organizations": [],
|
||||
"card_image_url": "http://example.com/asset-v1:DemoX+Demo_Course.jpg",
|
||||
"is_program_eligible_for_one_click_purchase": false,
|
||||
"pathway_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"is_learner_eligible_for_one_click_purchase": false,
|
||||
"skus": ["AUD90210"],
|
||||
},
|
||||
"course_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"completed": [],
|
||||
"in_progress": [],
|
||||
"not_started": [
|
||||
{
|
||||
"key": "example+DemoX",
|
||||
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
|
||||
"title": "Demonstration Course",
|
||||
"course_runs": [],
|
||||
"entitlements": [],
|
||||
"owners": [],
|
||||
"image": "",
|
||||
"short_description": "",
|
||||
"type": "457f07ec-a78f-45b4-ba09-5fb176520d8a",
|
||||
}
|
||||
],
|
||||
},
|
||||
"certificate_data": [{
|
||||
"type": "course",
|
||||
"title": "Demo Course",
|
||||
'url': "/certificates/8675309",
|
||||
}],
|
||||
"industry_pathways": [
|
||||
{
|
||||
"id": 2,
|
||||
"uuid": "1b8fadf1-f6aa-4282-94e3-325b922a027f",
|
||||
"name": "Demo Industry Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo industry pathway",
|
||||
"destination_url": "http://example.edu/online/pathways/example-methods",
|
||||
"pathway_type": "industry",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"credit_pathways": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "86b9701a-61e6-48a2-92eb-70a824521c1f",
|
||||
"name": "Demo Credit Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo credit pathway!",
|
||||
"destination_url": "http://example.edu/online/pathways/example-thinking",
|
||||
"pathway_type": "credit",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
tags:
|
||||
- learner_home
|
||||
parameters:
|
||||
- name: program_uuid
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
/learning_sequences/v1/course_outline/{course_key_str}:
|
||||
get:
|
||||
operationId: learning_sequences_v1_course_outline_read
|
||||
@@ -9338,16 +9651,6 @@ paths:
|
||||
operationId: user_v1_user_prefs_list
|
||||
description: DRF class for interacting with the UserPreference ORM
|
||||
parameters:
|
||||
- name: key
|
||||
in: query
|
||||
description: key
|
||||
required: false
|
||||
type: string
|
||||
- name: user
|
||||
in: query
|
||||
description: user
|
||||
required: false
|
||||
type: string
|
||||
- name: page
|
||||
in: query
|
||||
description: A page number within the paginated result set.
|
||||
@@ -9850,6 +10153,16 @@ paths:
|
||||
description: ''
|
||||
tags:
|
||||
- val
|
||||
patch:
|
||||
operationId: val_v0_videos_video-transcripts_partial_update
|
||||
description: Partially update a video transcript, only supporting updating the
|
||||
`provider` field.
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
tags:
|
||||
- val
|
||||
delete:
|
||||
operationId: val_v0_videos_video-transcripts_delete
|
||||
description: Delete a video transcript instance with the given information.
|
||||
@@ -9870,6 +10183,16 @@ paths:
|
||||
description: ''
|
||||
tags:
|
||||
- val
|
||||
patch:
|
||||
operationId: val_v0_videos_video-transcripts_create_partial_update
|
||||
description: Partially update a video transcript, only supporting updating the
|
||||
`provider` field.
|
||||
parameters: []
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
tags:
|
||||
- val
|
||||
delete:
|
||||
operationId: val_v0_videos_video-transcripts_create_delete
|
||||
description: Delete a video transcript instance with the given information.
|
||||
|
||||
1
mypy.ini
1
mypy.ini
@@ -11,6 +11,7 @@ files =
|
||||
openedx/core/djangoapps/content/learning_sequences,
|
||||
openedx/core/djangoapps/content_staging,
|
||||
openedx/core/djangoapps/content_libraries,
|
||||
openedx/core/djangoapps/programs/rest_api,
|
||||
openedx/core/djangoapps/xblock,
|
||||
openedx/core/lib/derived.py,
|
||||
openedx/core/types,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Views for the Programs REST API v1."""
|
||||
|
||||
from typing import Any, TYPE_CHECKING
|
||||
import logging
|
||||
|
||||
from enterprise.models import EnterpriseCourseEnrollment
|
||||
@@ -16,80 +17,74 @@ from openedx.core.djangoapps.programs.utils import (
|
||||
get_program_urls,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.contrib.auth.models import AnonymousUser, User # pylint: disable=imported-auth-user
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Programs(APIView):
|
||||
"""
|
||||
**Use Case**
|
||||
|
||||
* Get a list of all programs in which request user has enrolled.
|
||||
|
||||
**Example Request**
|
||||
|
||||
GET /api/dashboard/v1/programs/{enterprise_uuid}/
|
||||
|
||||
**GET Parameters**
|
||||
|
||||
A GET request must include the following parameters.
|
||||
|
||||
* enterprise_uuid: UUID of an enterprise customer.
|
||||
|
||||
**Example GET Response**
|
||||
|
||||
[
|
||||
{
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"title": "edX Demonstration Program",
|
||||
"type": "MicroMasters",
|
||||
"banner_image": {
|
||||
"large": {
|
||||
"url": "http://localhost:18381/media/programs/banner_images/ff41a5eb-2a73-4933-8e80.large.jpg",
|
||||
"width": 1440,
|
||||
"height": 480
|
||||
},
|
||||
"medium": {
|
||||
"url": "http://localhost:18381/media/programs/banner_images/ff41a5eb-2a73-4933-8e80.medium.jpg",
|
||||
"width": 726,
|
||||
"height": 242
|
||||
},
|
||||
"small": {
|
||||
"url": "http://localhost:18381/media/programs/banner_images/ff41a5eb-2a73-4933-8e80.small.jpg",
|
||||
"width": 435,
|
||||
"height": 145
|
||||
},
|
||||
"x-small": {
|
||||
"url": "http://localhost:18381/media/programs/banner_images/ff41a5eb-2a73-4933-8e8.x-small.jpg",
|
||||
"width": 348,
|
||||
"height": 116
|
||||
}
|
||||
},
|
||||
"authoring_organizations": [
|
||||
{
|
||||
"key": "edX"
|
||||
}
|
||||
],
|
||||
"progress": {
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"completed": 0,
|
||||
"in_progress": 0,
|
||||
"not_started": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
"""
|
||||
"""Program endpoints"""
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, enterprise_uuid):
|
||||
"""
|
||||
Return a list of a enterprise learner's all enrolled programs with their progress.
|
||||
def get(self, request: "HttpRequest", enterprise_uuid: str) -> "HttpResponse":
|
||||
"""For an enterprise learner, get list of enrolled programs with progress.
|
||||
|
||||
Args:
|
||||
request (Request): DRF request object.
|
||||
enterprise_uuid (string): UUID of an enterprise customer.
|
||||
**Example Request**
|
||||
|
||||
GET /api/dashboard/v1/programs/{enterprise_uuid}/
|
||||
|
||||
**Parameters**
|
||||
|
||||
* `enterprise_uuid`: UUID of an enterprise customer.
|
||||
|
||||
**Example Response**
|
||||
|
||||
[
|
||||
{
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"title": "Demonstration Program",
|
||||
"type": "MicroMasters",
|
||||
"banner_image": {
|
||||
"large": {
|
||||
"url": "http://example.com/images/foo.large.jpg",
|
||||
"width": 1440,
|
||||
"height": 480
|
||||
},
|
||||
"medium": {
|
||||
"url": "http://example.com/images/foo.medium.jpg",
|
||||
"width": 726,
|
||||
"height": 242
|
||||
},
|
||||
"small": {
|
||||
"url": "http://example.com/images/foo.small.jpg",
|
||||
"width": 435,
|
||||
"height": 145
|
||||
},
|
||||
"x-small": {
|
||||
"url": "http://example.com/images/foo.x-small.jpg",
|
||||
"width": 348,
|
||||
"height": 116
|
||||
}
|
||||
},
|
||||
"authoring_organizations": [
|
||||
{
|
||||
"key": "example"
|
||||
}
|
||||
],
|
||||
"progress": {
|
||||
"uuid": "ff41a5eb-2a73-4933-8e80-a1c66068ed2c",
|
||||
"completed": 0,
|
||||
"in_progress": 0,
|
||||
"not_started": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
"""
|
||||
user = request.user
|
||||
user: "AnonymousUser | User" = request.user
|
||||
|
||||
enrollments = self._get_enterprise_course_enrollments(enterprise_uuid, user)
|
||||
# return empty reponse if no enterprise enrollments exists for a user
|
||||
@@ -110,39 +105,37 @@ class Programs(APIView):
|
||||
|
||||
return Response(programs)
|
||||
|
||||
def _combine_programs_data_and_progress(self, programs_data, programs_progress):
|
||||
def _combine_programs_data_and_progress(
|
||||
self,
|
||||
programs_data: list[dict | None],
|
||||
programs_progress: list[dict | None],
|
||||
) -> list[dict | None]:
|
||||
"""
|
||||
Return the combined program and progress data so that api clinet can easily process the data.
|
||||
"""
|
||||
for program_data in programs_data:
|
||||
program_progress = next(
|
||||
(
|
||||
item
|
||||
for item in programs_progress
|
||||
if item["uuid"] == program_data["uuid"]
|
||||
),
|
||||
(item for item in programs_progress if item["uuid"] == program_data["uuid"]), # type: ignore[index]
|
||||
None,
|
||||
)
|
||||
program_data["progress"] = program_progress
|
||||
program_data["progress"] = program_progress # type: ignore[index]
|
||||
|
||||
return programs_data
|
||||
|
||||
def _extract_minimal_required_programs_data(self, programs_data):
|
||||
def _extract_minimal_required_programs_data(self, programs_data: list[dict | None]) -> list[dict[str, Any] | None]:
|
||||
"""
|
||||
Return only the minimal required program data need for program listing page.
|
||||
"""
|
||||
|
||||
def transform(key, value):
|
||||
transformers = {
|
||||
"authoring_organizations": transform_authoring_organizations
|
||||
}
|
||||
transformers = {"authoring_organizations": transform_authoring_organizations}
|
||||
|
||||
if key in transformers:
|
||||
return transformers[key](value)
|
||||
|
||||
return value
|
||||
|
||||
def transform_authoring_organizations(authoring_organizations):
|
||||
def transform_authoring_organizations(authoring_organizations) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Extract only the required data for `authoring_organizations` for a program
|
||||
"""
|
||||
@@ -164,19 +157,22 @@ class Programs(APIView):
|
||||
"banner_image",
|
||||
"authoring_organizations",
|
||||
]
|
||||
programs = []
|
||||
programs: list[dict[str, Any] | None] = []
|
||||
for program_data in programs_data:
|
||||
program = {}
|
||||
for program_data_key in program_data_keys:
|
||||
program[program_data_key] = transform(
|
||||
program_data_key, program_data[program_data_key]
|
||||
program_data_key,
|
||||
program_data[program_data_key], # type: ignore[index]
|
||||
)
|
||||
|
||||
programs.append(program)
|
||||
|
||||
return programs
|
||||
|
||||
def _get_enterprise_course_enrollments(self, enterprise_uuid, user):
|
||||
def _get_enterprise_course_enrollments(
|
||||
self, enterprise_uuid: str, user: "AnonymousUser | User"
|
||||
) -> list[CourseEnrollment]:
|
||||
"""
|
||||
Return only enterprise enrollments for a user.
|
||||
"""
|
||||
@@ -197,146 +193,129 @@ class Programs(APIView):
|
||||
|
||||
|
||||
class ProgramProgressDetailView(APIView):
|
||||
"""
|
||||
**Use Case**
|
||||
"""Endpoints For Program Progress Meter"""
|
||||
|
||||
* Get progress details of a learner enrolled in a program.
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
**Example Request**
|
||||
def get(self, request: "HttpRequest", program_uuid: str) -> "HttpResponse":
|
||||
"""Retrieves progress details of a learner in a specified program.
|
||||
|
||||
GET api/dashboard/v1/programs/{program_uuid}/progress_details/
|
||||
**Example Request**
|
||||
|
||||
**GET Parameters**
|
||||
GET api/dashboard/v1/programs/{program_uuid}/progress_details/
|
||||
|
||||
A GET request must include the following parameters.
|
||||
**Parameters**
|
||||
|
||||
* program_uuid: A string representation of uuid of the program.
|
||||
* `program_uuid`: A string representation of the uuid of the program.
|
||||
|
||||
**GET Response Values**
|
||||
**Response Values**
|
||||
|
||||
If the request for information about the program is successful, an HTTP 200 "OK" response
|
||||
is returned.
|
||||
|
||||
The HTTP 200 response has the following values.
|
||||
|
||||
* urls: Urls to enroll/purchase a course or view program record.
|
||||
* `urls`: Urls to enroll/purchase a course or view program record.
|
||||
|
||||
* program_data: Holds meta information about the program.
|
||||
* `program_data`: Holds meta information about the program.
|
||||
|
||||
* course_data: Learner's progress details for all courses in the program (in-progress/remaining/completed).
|
||||
* `course_data`: Learner's progress details for all courses in the program (in-progress/remaining/completed).
|
||||
|
||||
* certificate_data: Details about learner's certificates status for all courses in the program and the
|
||||
* `certificate_data`: Details about learner's certificates status for all courses in the program and the
|
||||
program itself.
|
||||
|
||||
* industry_pathways: Industry pathways for the program, comes under additional credit opportunities.
|
||||
* `industry_pathways`: Industry pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
* credit_pathways: Credit pathways for the program, comes under additional credit opportunities.
|
||||
* `credit_pathways`: Credit pathways for the program, comes under additional credit opportunities.
|
||||
|
||||
**Example GET Response**
|
||||
**Example Response**
|
||||
|
||||
{
|
||||
"urls": {
|
||||
"program_listing_url": "/dashboard/programs/",
|
||||
"track_selection_url": "/course_modes/choose/",
|
||||
"commerce_api_url": "/api/commerce/v1/baskets/",
|
||||
"buy_button_url": "http://ecommerce.com/basket/add/?",
|
||||
"program_record_url": "https://credentials.example.com/records/programs/121234235525242344"
|
||||
},
|
||||
"program_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"title": "edX Demonstration Program",
|
||||
"subtitle": "",
|
||||
"type": "MicroMasters",
|
||||
"status": "active",
|
||||
"marketing_slug": "demo-program",
|
||||
"marketing_url": "micromasters/demo-program",
|
||||
"authoring_organizations": [],
|
||||
"card_image_url": "http://edx.devstack.lms:18000/asset-v1:edX+DemoX+Demo_Course.jpg",
|
||||
"is_program_eligible_for_one_click_purchase": false,
|
||||
"pathway_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"is_learner_eligible_for_one_click_purchase": false,
|
||||
"skus": ["AUD122342"],
|
||||
},
|
||||
"course_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"completed": [],
|
||||
"in_progress": [],
|
||||
"not_started": [
|
||||
{
|
||||
"urls": {
|
||||
"program_listing_url": "/dashboard/programs/",
|
||||
"track_selection_url": "/course_modes/choose/",
|
||||
"commerce_api_url": "/api/commerce/v1/baskets/",
|
||||
"buy_button_url": "http://example.com/basket/add/?",
|
||||
"program_record_url": "https://example.com/records/programs/8675309"
|
||||
},
|
||||
"program_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"title": "Demonstration Program",
|
||||
"subtitle": "",
|
||||
"type": "MicroMasters",
|
||||
"status": "active",
|
||||
"marketing_slug": "demo-program",
|
||||
"marketing_url": "micromasters/demo-program",
|
||||
"authoring_organizations": [],
|
||||
"card_image_url": "http://example.com/asset-v1:DemoX+Demo_Course.jpg",
|
||||
"is_program_eligible_for_one_click_purchase": false,
|
||||
"pathway_ids": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"is_learner_eligible_for_one_click_purchase": false,
|
||||
"skus": ["AUD90210"],
|
||||
},
|
||||
"course_data": {
|
||||
"uuid": "a156a6e2-de91-4ce7-947a-888943e6b12a",
|
||||
"completed": [],
|
||||
"in_progress": [],
|
||||
"not_started": [
|
||||
{
|
||||
"key": "example+DemoX",
|
||||
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
|
||||
"title": "Demonstration Course",
|
||||
"course_runs": [],
|
||||
"entitlements": [],
|
||||
"owners": [],
|
||||
"image": "",
|
||||
"short_description": "",
|
||||
"type": "457f07ec-a78f-45b4-ba09-5fb176520d8a",
|
||||
}
|
||||
],
|
||||
},
|
||||
"certificate_data": [{
|
||||
"type": "course",
|
||||
"title": "Demo Course",
|
||||
'url': "/certificates/8675309",
|
||||
}],
|
||||
"industry_pathways": [
|
||||
{
|
||||
"key": "edX+DemoX",
|
||||
"uuid": "fe1a9ad4-a452-45cd-80e5-9babd3d43f96",
|
||||
"title": "Demonstration Course",
|
||||
"course_runs": [],
|
||||
"entitlements": [],
|
||||
"owners": [],
|
||||
"image": "",
|
||||
"short_description": "",
|
||||
"type": "457f07ec-a78f-45b4-ba09-5fb176520d8a",
|
||||
"id": 2,
|
||||
"uuid": "1b8fadf1-f6aa-4282-94e3-325b922a027f",
|
||||
"name": "Demo Industry Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo industry pathway",
|
||||
"destination_url": "http://example.edu/online/pathways/example-methods",
|
||||
"pathway_type": "industry",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
"certificate_data": [{
|
||||
"type": "course",
|
||||
"title": "edX Demo Course",
|
||||
'url': "/certificates/6e57d3cce8e34cfcb60bd8e8b04r07e0",
|
||||
}],
|
||||
"industry_pathways": [
|
||||
{
|
||||
"id": 2,
|
||||
"uuid": "1b8fadf1-f6aa-4282-94e3-325b922a027f",
|
||||
"name": "Demo Industry Pathway",
|
||||
"org_name": "edX",
|
||||
"email": "edx@edx.com",
|
||||
"description": "Sample demo industry pathway",
|
||||
"destination_url": "http://rit.edu/online/pathways/gtx-analytics-essential-tools-methods",
|
||||
"pathway_type": "industry",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
],
|
||||
"credit_pathways": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "86b9701a-61e6-48a2-92eb-70a824521c1f",
|
||||
"name": "Demo Credit Pathway",
|
||||
"org_name": "edX",
|
||||
"email": "edx@edx.com",
|
||||
"description": "Sample demo credit pathway!",
|
||||
"destination_url": "http://rit.edu/online/pathways/ritx-design-thinking",
|
||||
"pathway_type": "credit",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, program_uuid):
|
||||
"credit_pathways": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "86b9701a-61e6-48a2-92eb-70a824521c1f",
|
||||
"name": "Demo Credit Pathway",
|
||||
"org_name": "example",
|
||||
"email": "example@example.com",
|
||||
"description": "Sample demo credit pathway!",
|
||||
"destination_url": "http://example.edu/online/pathways/example-thinking",
|
||||
"pathway_type": "credit",
|
||||
"program_uuids": [
|
||||
"a156a6e2-de91-4ce7-947a-888943e6b12a"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
Retrieves progress details of a user in a specified program.
|
||||
|
||||
Args:
|
||||
request (Request): Django request object.
|
||||
program_uuid (string): URI element specifying uuid of the program.
|
||||
|
||||
Return:
|
||||
"""
|
||||
user = request.user
|
||||
site = request.site
|
||||
program_data, course_data = get_program_and_course_data(
|
||||
site, user, program_uuid
|
||||
)
|
||||
user: "AnonymousUser | User" = request.user
|
||||
site: "Site" = request.site
|
||||
program_data, course_data = get_program_and_course_data(site, user, program_uuid)
|
||||
if not program_data:
|
||||
return Response(
|
||||
status=404, data={"error_code": "No program data available."}
|
||||
)
|
||||
return Response(status=404, data={"error_code": "No program data available."})
|
||||
|
||||
certificate_data = get_certificates(user, program_data)
|
||||
program_data.pop("courses")
|
||||
@@ -345,9 +324,7 @@ class ProgramProgressDetailView(APIView):
|
||||
if not certificate_data:
|
||||
urls["program_record_url"] = None
|
||||
|
||||
industry_pathways, credit_pathways = get_industry_and_credit_pathways(
|
||||
program_data, site
|
||||
)
|
||||
industry_pathways, credit_pathways = get_industry_and_credit_pathways(program_data, site)
|
||||
|
||||
return Response(
|
||||
{
|
||||
|
||||
@@ -211,7 +211,7 @@ class ProgramProgressMeter:
|
||||
return inverted_programs
|
||||
|
||||
@cached_property
|
||||
def engaged_programs(self):
|
||||
def engaged_programs(self) -> list[dict | None]:
|
||||
"""Derive a list of programs in which the given user is engaged.
|
||||
|
||||
Returns:
|
||||
@@ -271,7 +271,7 @@ class ProgramProgressMeter:
|
||||
# An upgrade deadline of None means the course is always upgradeable.
|
||||
return any(not deadline or deadline and parse(deadline) > now for deadline in upgrade_deadlines)
|
||||
|
||||
def progress(self, programs=None, count_only=True):
|
||||
def progress(self, programs: list[dict | None] | None = None, count_only: bool = True) -> list[dict | None]:
|
||||
"""Gauge a user's progress towards program completion.
|
||||
|
||||
Keyword Arguments:
|
||||
|
||||
Reference in New Issue
Block a user