Files
edx-platform/lms/djangoapps/learner_dashboard/api/v0/views.py
salmannawaz 57b480b04f Update all edx-platform REST endpoints to support JWT Auth (#34152)
* chore: update API endpoints to support default JWT auth

The default DRF Auth classes were recently updated to allow for both JWT and Session auth by default. Any endpoint that overrides the AUTHENTICATION_CLASSES but has just session, just JWT or just both of those should be updated to remove the override.

Details in https://github.com/openedx/edx-platform/issues/33662
2024-02-13 10:46:58 -05:00

337 lines
12 KiB
Python

""" API v0 views. """
import logging
from enterprise.models import EnterpriseCourseEnrollment
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from common.djangoapps.student.models import CourseEnrollment
from openedx.core.djangoapps.programs.utils import (
ProgramProgressMeter,
get_certificates,
get_industry_and_credit_pathways,
get_program_and_course_data,
get_program_urls,
)
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/v0/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
}
}
]
"""
permission_classes = (IsAuthenticated,)
def get(self, request, enterprise_uuid):
"""
Return a list of a enterprise learner's all enrolled programs with their progress.
Args:
request (Request): DRF request object.
enterprise_uuid (string): UUID of an enterprise customer.
"""
user = request.user
enrollments = self._get_enterprise_course_enrollments(enterprise_uuid, user)
# return empty reponse if no enterprise enrollments exists for a user
if not enrollments:
return Response([])
meter = ProgramProgressMeter(
request.site,
user,
enrollments=enrollments,
mobile_only=False,
include_course_entitlements=False
)
engaged_programs = meter.engaged_programs
progress = meter.progress(programs=engaged_programs)
programs = self._extract_minimal_required_programs_data(engaged_programs)
programs = self._combine_programs_data_and_progress(programs, progress)
return Response(programs)
def _combine_programs_data_and_progress(self, programs_data, programs_progress):
"""
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']), None)
program_data['progress'] = program_progress
return programs_data
def _extract_minimal_required_programs_data(self, programs_data):
"""
Return only the minimal required program data need for program listing page.
"""
def transform(key, value):
transformers = {'authoring_organizations': transform_authoring_organizations}
if key in transformers:
return transformers[key](value)
return value
def transform_authoring_organizations(authoring_organizations):
"""
Extract only the required data for `authoring_organizations` for a program
"""
transformed_authoring_organizations = []
for authoring_organization in authoring_organizations:
transformed_authoring_organizations.append(
{
'key': authoring_organization['key'],
'logo_image_url': authoring_organization['logo_image_url']
}
)
return transformed_authoring_organizations
program_data_keys = ['uuid', 'title', 'type', 'banner_image', 'authoring_organizations']
programs = []
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])
programs.append(program)
return programs
def _get_enterprise_course_enrollments(self, enterprise_uuid, user):
"""
Return only enterprise enrollments for a user.
"""
enterprise_enrollment_course_ids = list(EnterpriseCourseEnrollment.objects.filter(
enterprise_customer_user__user_id=user.id,
enterprise_customer_user__enterprise_customer__uuid=enterprise_uuid,
).values_list('course_id', flat=True))
course_enrollments = CourseEnrollment.enrollments_for_user(user).filter(
course_id__in=enterprise_enrollment_course_ids
).select_related('course')
return list(course_enrollments)
class ProgramProgressDetailView(APIView):
"""
**Use Case**
* Get progress details of a learner enrolled in a program.
**Example Request**
GET api/dashboard/v0/programs/{program_uuid}/progress_details/
**GET Parameters**
A GET request must include the following parameters.
* program_uuid: A string representation of uuid of the program.
**GET 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 GET Response**
{
"urls": {
"program_listing_url": "/dashboard/programs/",
"track_selection_url": "/course_modes/choose/",
"commerce_api_url": "/api/commerce/v0/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": [
{
"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",
}
],
},
"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):
"""
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)
if not program_data:
return Response(
status=404,
data={'error_code': 'No program data available.'}
)
certificate_data = get_certificates(user, program_data)
program_data.pop('courses')
urls = get_program_urls(program_data)
if not certificate_data:
urls['program_record_url'] = None
industry_pathways, credit_pathways = get_industry_and_credit_pathways(program_data, site)
return Response(
{
'urls': urls,
'program_data': program_data,
'course_data': course_data,
'certificate_data': certificate_data,
'industry_pathways': industry_pathways,
'credit_pathways': credit_pathways,
}
)