feat: learner home contract updates (#30930)
* refactor: update enterprise dashboard data shape * refactor: remove hasFinished * refactor: allow enterprise dashboard to be null * docs: update mock data * feat: get if an enrollment has unmet prerequisites * feat: get is staff for course * feat: get is too early for course Co-authored-by: nsprenkle <nsprenkle@2u.com>
This commit is contained in:
@@ -16,8 +16,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -103,8 +107,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -158,8 +166,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -205,8 +217,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -278,8 +294,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -340,8 +360,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -387,8 +411,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -464,8 +492,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": true,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": true,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -530,8 +562,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": true,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -582,8 +618,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": true,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -664,8 +704,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/2000",
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": true,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": true,
|
||||
"isAuditAccessExpired": true,
|
||||
"isEmailEnabled": false,
|
||||
@@ -716,8 +760,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": true,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -777,8 +825,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -850,8 +902,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -912,8 +968,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -945,8 +1005,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1018,8 +1082,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1081,8 +1149,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1128,8 +1200,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1202,8 +1278,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1265,8 +1345,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": true,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1348,8 +1432,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1456,8 +1544,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1553,8 +1645,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1635,8 +1731,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": true,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1717,8 +1817,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1788,8 +1892,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1845,8 +1953,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1927,8 +2039,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": "11/11/3030",
|
||||
"canUpgrade": null,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": null,
|
||||
"isEmailEnabled": false,
|
||||
@@ -1986,8 +2102,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": null,
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -2074,8 +2194,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": null,
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -2151,8 +2275,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": null,
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -2213,8 +2341,12 @@
|
||||
"enrollment": {
|
||||
"accessExpirationDate": null,
|
||||
"canUpgrade": false,
|
||||
"hasFinished": false,
|
||||
"hasStarted": false,
|
||||
"hasAccess": {
|
||||
"hasUnmetPrerequisites": false,
|
||||
"isTooEarly": false,
|
||||
"isStaff": false
|
||||
},
|
||||
"isAudit": false,
|
||||
"isAuditAccessExpired": false,
|
||||
"isEmailEnabled": false,
|
||||
@@ -2275,21 +2407,9 @@
|
||||
"isNeeded": true,
|
||||
"sendEmailUrl": "sendConfirmation@edx.org"
|
||||
},
|
||||
"enterpriseDashboards": {
|
||||
"availableDashboards": [
|
||||
{
|
||||
"label": "edX, Inc.",
|
||||
"url": "/edx-dashboard"
|
||||
},
|
||||
{
|
||||
"label": "Harvard",
|
||||
"url": "/harvard-dashboard"
|
||||
}
|
||||
],
|
||||
"mostRecentDashboard": {
|
||||
"label": "edX, Inc.",
|
||||
"url": "/edx-dashboard"
|
||||
}
|
||||
"enterpriseDashboard": {
|
||||
"label": "edX, Inc.",
|
||||
"url": "/edx-dashboard"
|
||||
},
|
||||
"platformSettings": {
|
||||
"supportEmail": "support@example.com",
|
||||
|
||||
@@ -94,6 +94,41 @@ class CourseRunSerializer(serializers.Serializer):
|
||||
return self.context.get("resume_course_urls", {}).get(instance.course_id)
|
||||
|
||||
|
||||
class HasAccessSerializer(serializers.Serializer):
|
||||
"""
|
||||
Info determining whether a user should be able to view course material.
|
||||
Mirrors logic in "show_courseware_links_for" from old dashboard.py
|
||||
"""
|
||||
|
||||
hasUnmetPrerequisites = serializers.SerializerMethodField()
|
||||
isTooEarly = serializers.SerializerMethodField()
|
||||
isStaff = serializers.SerializerMethodField()
|
||||
|
||||
def _get_course_access_checks(self, enrollment):
|
||||
"""Internal helper to unpack access object for this particular enrollment"""
|
||||
return self.context.get("course_access_checks", {}).get(
|
||||
enrollment.course_id, {}
|
||||
)
|
||||
|
||||
def get_hasUnmetPrerequisites(self, enrollment):
|
||||
"""Whether or not a course has unmet prerequisites"""
|
||||
return self._get_course_access_checks(enrollment).get(
|
||||
"has_unmet_prerequisites", False
|
||||
)
|
||||
|
||||
def get_isTooEarly(self, enrollment):
|
||||
"""Determine if the course is open to a learner (course has started or user has early beta access)"""
|
||||
return self._get_course_access_checks(enrollment).get(
|
||||
"is_too_early_to_view", False
|
||||
)
|
||||
|
||||
def get_isStaff(self, enrollment):
|
||||
"""Determine whether a user has staff access to this course"""
|
||||
return self._get_course_access_checks(enrollment).get(
|
||||
"user_has_staff_access", False
|
||||
)
|
||||
|
||||
|
||||
class EnrollmentSerializer(serializers.Serializer):
|
||||
"""
|
||||
Info about this particular enrollment.
|
||||
@@ -112,7 +147,7 @@ class EnrollmentSerializer(serializers.Serializer):
|
||||
accessExpirationDate = serializers.SerializerMethodField()
|
||||
isAudit = serializers.SerializerMethodField()
|
||||
hasStarted = serializers.SerializerMethodField()
|
||||
hasFinished = serializers.SerializerMethodField()
|
||||
hasAccess = HasAccessSerializer(source="*")
|
||||
isVerified = serializers.SerializerMethodField()
|
||||
canUpgrade = serializers.SerializerMethodField()
|
||||
isAuditAccessExpired = serializers.SerializerMethodField()
|
||||
@@ -138,10 +173,6 @@ class EnrollmentSerializer(serializers.Serializer):
|
||||
)
|
||||
return resume_button_url is not None
|
||||
|
||||
def get_hasFinished(self, enrollment):
|
||||
# TODO - AU-796
|
||||
return False
|
||||
|
||||
def get_isVerified(self, enrollment):
|
||||
return enrollment.is_verified_enrollment()
|
||||
|
||||
@@ -329,22 +360,13 @@ class EnterpriseDashboardSerializer(serializers.Serializer):
|
||||
url = serializers.URLField()
|
||||
|
||||
|
||||
class EnterpriseDashboardsSerializer(serializers.Serializer):
|
||||
"""Listing of available enterprise dashboards"""
|
||||
|
||||
availableDashboards = serializers.ListField(
|
||||
child=EnterpriseDashboardSerializer(), allow_empty=True
|
||||
)
|
||||
mostRecentDashboard = EnterpriseDashboardSerializer()
|
||||
|
||||
|
||||
class LearnerDashboardSerializer(serializers.Serializer):
|
||||
"""Serializer for all info required to render the Learner Dashboard"""
|
||||
|
||||
requires_context = True
|
||||
|
||||
emailConfirmation = EmailConfirmationSerializer()
|
||||
enterpriseDashboards = EnterpriseDashboardsSerializer()
|
||||
enterpriseDashboard = EnterpriseDashboardSerializer(allow_null=True)
|
||||
platformSettings = PlatformSettingsSerializer()
|
||||
courses = serializers.SerializerMethodField()
|
||||
suggestedCourses = serializers.ListField(
|
||||
|
||||
@@ -22,9 +22,10 @@ from lms.djangoapps.learner_home.serializers import (
|
||||
CourseSerializer,
|
||||
EmailConfirmationSerializer,
|
||||
EnrollmentSerializer,
|
||||
EnterpriseDashboardsSerializer,
|
||||
EnterpriseDashboardSerializer,
|
||||
EntitlementSerializer,
|
||||
GradeDataSerializer,
|
||||
HasAccessSerializer,
|
||||
LearnerEnrollmentSerializer,
|
||||
PlatformSettingsSerializer,
|
||||
ProgramsSerializer,
|
||||
@@ -68,18 +69,6 @@ class LearnerDashboardBaseTest(SharedModuleStoreTestCase):
|
||||
|
||||
return test_enrollment
|
||||
|
||||
@classmethod
|
||||
def generate_base_test_context(cls):
|
||||
"""Base context object that can be used across tests"""
|
||||
return {
|
||||
"ecommerce_payment_page": random_url(),
|
||||
"cert_statuses": {},
|
||||
"course_mode_info": {},
|
||||
"course_optouts": {},
|
||||
"resume_course_urls": {},
|
||||
"show_email_settings_for": {},
|
||||
}
|
||||
|
||||
|
||||
class TestPlatformSettingsSerializer(TestCase):
|
||||
"""Tests for the PlatformSettingsSerializer"""
|
||||
@@ -165,6 +154,94 @@ class TestCourseRunSerializer(LearnerDashboardBaseTest):
|
||||
assert output[key] is not None
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestHasAccessSerializer(LearnerDashboardBaseTest):
|
||||
"""Tests for the HasAccessSerializer"""
|
||||
|
||||
def create_test_context(self, course):
|
||||
return {
|
||||
"course_access_checks": {
|
||||
course.id: {
|
||||
"has_unmet_prerequisites": False,
|
||||
"is_too_early_to_view": False,
|
||||
"user_has_staff_access": False,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_unmet_prerequisites(self, has_unmet_prerequisites):
|
||||
# Given an enrollment
|
||||
input_data = self.create_test_enrollment()
|
||||
input_context = self.create_test_context(input_data.course)
|
||||
|
||||
# ... without unmet prerequisites
|
||||
if has_unmet_prerequisites:
|
||||
# ... or with unmet prerequisites
|
||||
prerequisite_course = CourseFactory()
|
||||
input_context.update(
|
||||
{
|
||||
"course_access_checks": {
|
||||
input_data.course.id: {
|
||||
"has_unmet_prerequisites": has_unmet_prerequisites,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# When I serialize
|
||||
output_data = HasAccessSerializer(input_data, context=input_context).data
|
||||
|
||||
# Then "hasUnmetPrerequisites" is outputs correctly
|
||||
self.assertEqual(output_data["hasUnmetPrerequisites"], has_unmet_prerequisites)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_is_staff(self, is_staff):
|
||||
# Given an enrollment
|
||||
input_data = self.create_test_enrollment()
|
||||
input_context = self.create_test_context(input_data.course)
|
||||
|
||||
# Where user has/hasn't staff access
|
||||
input_context.update(
|
||||
{
|
||||
"course_access_checks": {
|
||||
input_data.course.id: {
|
||||
"user_has_staff_access": is_staff,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# When I serialize
|
||||
output_data = HasAccessSerializer(input_data, context=input_context).data
|
||||
|
||||
# Then "isStaff" serializes properly
|
||||
self.assertEqual(output_data["isStaff"], is_staff)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_is_too_early(self, is_too_early):
|
||||
# Given an enrollment
|
||||
input_data = self.create_test_enrollment()
|
||||
input_context = self.create_test_context(input_data.course)
|
||||
|
||||
# Where the course is/n't yet open for a learner
|
||||
input_context.update(
|
||||
{
|
||||
"course_access_checks": {
|
||||
input_data.course.id: {
|
||||
"is_too_early_to_view": is_too_early,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# When I serialize
|
||||
output_data = HasAccessSerializer(input_data, context=input_context).data
|
||||
|
||||
# Then "isTooEarly" serializes properly
|
||||
self.assertEqual(output_data["isTooEarly"], is_too_early)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestEnrollmentSerializer(LearnerDashboardBaseTest):
|
||||
"""Tests for the EnrollmentSerializer"""
|
||||
@@ -364,9 +441,7 @@ class TestCertificateSerializer(LearnerDashboardBaseTest):
|
||||
output_data = CertificateSerializer(input_data, context=input_context).data
|
||||
|
||||
# Then the available date is the course end date
|
||||
expected_available_date = datetime_to_django_format(
|
||||
input_data.course.end
|
||||
)
|
||||
expected_available_date = datetime_to_django_format(input_data.course.end)
|
||||
self.assertEqual(output_data["availableDate"], expected_available_date)
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, ENABLE_V2_CERT_DISPLAY_SETTINGS=True)
|
||||
@@ -759,36 +834,25 @@ class TestEmailConfirmationSerializer(TestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestEnterpriseDashboardsSerializer(TestCase):
|
||||
"""High-level tests for EnterpriseDashboardsSerializer"""
|
||||
|
||||
@classmethod
|
||||
def generate_test_dashboard(cls):
|
||||
return {
|
||||
"label": f"{uuid4()}",
|
||||
"url": random_url(),
|
||||
}
|
||||
class TestEnterpriseDashboardSerializer(TestCase):
|
||||
"""High-level tests for EnterpriseDashboardSerializer"""
|
||||
|
||||
@classmethod
|
||||
def generate_test_data(cls):
|
||||
return {
|
||||
"availableDashboards": [
|
||||
cls.generate_test_dashboard() for _ in range(randint(0, 3))
|
||||
],
|
||||
"mostRecentDashboard": cls.generate_test_dashboard()
|
||||
if random_bool()
|
||||
else None,
|
||||
"label": f"{uuid4()}",
|
||||
"url": random_url(),
|
||||
}
|
||||
|
||||
def test_structure(self):
|
||||
"""Test that nothing breaks and the output fields look correct"""
|
||||
input_data = self.generate_test_data()
|
||||
|
||||
output_data = EnterpriseDashboardsSerializer(input_data).data
|
||||
output_data = EnterpriseDashboardSerializer(input_data).data
|
||||
|
||||
expected_keys = [
|
||||
"availableDashboards",
|
||||
"mostRecentDashboard",
|
||||
"label",
|
||||
"url",
|
||||
]
|
||||
assert output_data.keys() == set(expected_keys)
|
||||
|
||||
@@ -797,13 +861,13 @@ class TestEnterpriseDashboardsSerializer(TestCase):
|
||||
|
||||
input_data = self.generate_test_data()
|
||||
|
||||
output_data = EnterpriseDashboardsSerializer(input_data).data
|
||||
output_data = EnterpriseDashboardSerializer(input_data).data
|
||||
|
||||
self.assertDictEqual(
|
||||
output_data,
|
||||
{
|
||||
"availableDashboards": input_data["availableDashboards"],
|
||||
"mostRecentDashboard": input_data["mostRecentDashboard"],
|
||||
"label": input_data["label"],
|
||||
"url": input_data["url"],
|
||||
},
|
||||
)
|
||||
|
||||
@@ -819,7 +883,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
|
||||
input_data = {
|
||||
"emailConfirmation": None,
|
||||
"enterpriseDashboards": None,
|
||||
"enterpriseDashboard": None,
|
||||
"platformSettings": None,
|
||||
"enrollments": [],
|
||||
"unfulfilledEntitlements": [],
|
||||
@@ -831,7 +895,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
output_data,
|
||||
{
|
||||
"emailConfirmation": None,
|
||||
"enterpriseDashboards": None,
|
||||
"enterpriseDashboard": None,
|
||||
"platformSettings": None,
|
||||
"courses": [],
|
||||
"suggestedCourses": [],
|
||||
@@ -857,7 +921,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
|
||||
input_data = {
|
||||
"emailConfirmation": None,
|
||||
"enterpriseDashboards": None,
|
||||
"enterpriseDashboard": None,
|
||||
"platformSettings": None,
|
||||
"enrollments": enrollments,
|
||||
"unfulfilledEntitlements": [],
|
||||
@@ -889,7 +953,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
"lms.djangoapps.learner_home.serializers.PlatformSettingsSerializer.to_representation"
|
||||
)
|
||||
@mock.patch(
|
||||
"lms.djangoapps.learner_home.serializers.EnterpriseDashboardsSerializer.to_representation"
|
||||
"lms.djangoapps.learner_home.serializers.EnterpriseDashboardSerializer.to_representation"
|
||||
)
|
||||
@mock.patch(
|
||||
"lms.djangoapps.learner_home.serializers.EmailConfirmationSerializer.to_representation"
|
||||
@@ -897,7 +961,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
def test_linkage(
|
||||
self,
|
||||
mock_email_confirmation_serializer,
|
||||
mock_enterprise_dashboards_serializer,
|
||||
mock_enterprise_dashboard_serializer,
|
||||
mock_platform_settings_serializer,
|
||||
mock_learner_enrollment_serializer,
|
||||
mock_entitlements_serializer,
|
||||
@@ -906,8 +970,8 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
mock_email_confirmation_serializer.return_value = (
|
||||
mock_email_confirmation_serializer
|
||||
)
|
||||
mock_enterprise_dashboards_serializer.return_value = (
|
||||
mock_enterprise_dashboards_serializer
|
||||
mock_enterprise_dashboard_serializer.return_value = (
|
||||
mock_enterprise_dashboard_serializer
|
||||
)
|
||||
mock_platform_settings_serializer.return_value = (
|
||||
mock_platform_settings_serializer
|
||||
@@ -920,7 +984,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
|
||||
input_data = {
|
||||
"emailConfirmation": {},
|
||||
"enterpriseDashboards": [{}],
|
||||
"enterpriseDashboard": {},
|
||||
"platformSettings": {},
|
||||
"enrollments": [{}],
|
||||
"unfulfilledEntitlements": [{}],
|
||||
@@ -932,7 +996,7 @@ class TestLearnerDashboardSerializer(LearnerDashboardBaseTest):
|
||||
output_data,
|
||||
{
|
||||
"emailConfirmation": mock_email_confirmation_serializer,
|
||||
"enterpriseDashboards": mock_enterprise_dashboards_serializer,
|
||||
"enterpriseDashboard": mock_enterprise_dashboard_serializer,
|
||||
"platformSettings": mock_platform_settings_serializer,
|
||||
"courses": [
|
||||
mock_learner_enrollment_serializer,
|
||||
|
||||
@@ -232,7 +232,7 @@ class TestDashboardView(SharedModuleStoreTestCase, APITestCase):
|
||||
expected_keys = set(
|
||||
[
|
||||
"emailConfirmation",
|
||||
"enterpriseDashboards",
|
||||
"enterpriseDashboard",
|
||||
"platformSettings",
|
||||
"courses",
|
||||
"suggestedCourses",
|
||||
|
||||
@@ -14,9 +14,16 @@ from common.djangoapps.student.views.dashboard import (
|
||||
get_course_enrollments,
|
||||
get_org_black_and_whitelist_for_site,
|
||||
)
|
||||
from common.djangoapps.util.milestones_helpers import (
|
||||
get_pre_requisite_courses_not_completed,
|
||||
)
|
||||
from lms.djangoapps.bulk_email.models import Optout
|
||||
from lms.djangoapps.bulk_email.models_api import is_bulk_email_feature_enabled
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.courseware.access import administrative_accesses_to_course_for_user
|
||||
from lms.djangoapps.courseware.access_utils import (
|
||||
check_course_open_for_learner,
|
||||
)
|
||||
from lms.djangoapps.learner_home.serializers import LearnerDashboardSerializer
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
@@ -125,6 +132,62 @@ def get_cert_statuses(user, course_enrollments):
|
||||
}
|
||||
|
||||
|
||||
def _get_courses_with_unmet_prerequisites(user, course_enrollments):
|
||||
"""
|
||||
Determine which courses have unmet prerequisites.
|
||||
NOTE: that courses w/out prerequisites, or with met prerequisites are not returned
|
||||
in the output dict. That way we can do a simple "course_id in dict" check.
|
||||
|
||||
Returns: {
|
||||
<course_id>: { "courses": [listing of unmet prerequisites] }
|
||||
}
|
||||
"""
|
||||
|
||||
courses_having_prerequisites = frozenset(
|
||||
enrollment.course_id
|
||||
for enrollment in course_enrollments
|
||||
if enrollment.course_overview.pre_requisite_courses
|
||||
)
|
||||
|
||||
return get_pre_requisite_courses_not_completed(user, courses_having_prerequisites)
|
||||
|
||||
|
||||
def check_course_access(user, course_enrollments):
|
||||
"""
|
||||
Wrapper for checks surrounding user ability to view courseware
|
||||
|
||||
Returns: {
|
||||
<course_enrollment.id>: {
|
||||
"has_unmet_prerequisites": True/False,
|
||||
"is_too_early_to_view": True/False,
|
||||
"user_has_staff_access": True/False
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
course_access_dict = {}
|
||||
|
||||
courses_with_unmet_prerequisites = _get_courses_with_unmet_prerequisites(
|
||||
user, course_enrollments
|
||||
)
|
||||
|
||||
for course_enrollment in course_enrollments:
|
||||
course_access_dict[course_enrollment.course_id] = {
|
||||
"has_unmet_prerequisites": course_enrollment.course_id
|
||||
in courses_with_unmet_prerequisites,
|
||||
"is_too_early_to_view": not check_course_open_for_learner(
|
||||
user, course_enrollment.course
|
||||
),
|
||||
"user_has_staff_access": any(
|
||||
administrative_accesses_to_course_for_user(
|
||||
user, course_enrollment.course_id
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
return course_access_dict
|
||||
|
||||
|
||||
class InitializeView(RetrieveAPIView): # pylint: disable=unused-argument
|
||||
"""List of courses a user is enrolled in or entitled to"""
|
||||
|
||||
@@ -152,12 +215,11 @@ class InitializeView(RetrieveAPIView): # pylint: disable=unused-argument
|
||||
# Get cert status by course
|
||||
cert_statuses = get_cert_statuses(user, course_enrollments)
|
||||
|
||||
# TODO - Determine view access for courses (for showing courseware link or not)
|
||||
# Determine view access for course, (for showing courseware link) involves:
|
||||
course_access_checks = check_course_access(user, course_enrollments)
|
||||
|
||||
# TODO - Get related programs
|
||||
|
||||
# TODO - Get user verification status
|
||||
|
||||
# e-commerce info
|
||||
ecommerce_payment_page = get_ecommerce_payment_page(user)
|
||||
|
||||
@@ -178,6 +240,7 @@ class InitializeView(RetrieveAPIView): # pylint: disable=unused-argument
|
||||
"cert_statuses": cert_statuses,
|
||||
"course_mode_info": course_mode_info,
|
||||
"course_optouts": course_optouts,
|
||||
"course_access_checks": course_access_checks,
|
||||
"resume_course_urls": resume_button_urls,
|
||||
"show_email_settings_for": show_email_settings_for,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user