Merge pull request #30280 from openedx/mikix/more-enrollment-conditions
fix: add more can-enroll checks to course home outline API
This commit is contained in:
@@ -3,7 +3,7 @@ Tests for Outline Tab API in the Course Home API
|
||||
"""
|
||||
|
||||
import itertools
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
|
||||
from unittest.mock import Mock, patch # lint-amnesty, pylint: disable=wrong-import-order
|
||||
|
||||
@@ -15,10 +15,12 @@ from edx_toggles.toggles.testutils import override_waffle_flag # lint-amnesty,
|
||||
|
||||
from cms.djangoapps.contentstore.outlines import update_outline_from_modulestore
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.roles import CourseInstructorRole
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.content.learning_sequences.api import replace_course_outline
|
||||
from openedx.core.djangoapps.content.learning_sequences.data import CourseOutlineData, CourseVisibility
|
||||
from openedx.core.djangoapps.course_date_signals.utils import MIN_DURATION
|
||||
@@ -45,6 +47,10 @@ class OutlineTabTestViews(BaseCourseHomeTests):
|
||||
super().setUp()
|
||||
self.url = reverse('course-home:outline-tab', args=[self.course.id])
|
||||
|
||||
def update_course_and_overview(self):
|
||||
self.update_course(self.course, self.user.id)
|
||||
CourseOverview.load_from_module_store(self.course.id)
|
||||
|
||||
@override_waffle_flag(ENABLE_COURSE_GOALS, active=True)
|
||||
@ddt.data(CourseMode.AUDIT, CourseMode.VERIFIED)
|
||||
def test_get_authenticated_enrolled_user(self, enrollment_mode):
|
||||
@@ -311,7 +317,7 @@ class OutlineTabTestViews(BaseCourseHomeTests):
|
||||
self.user.save()
|
||||
if course_visibility:
|
||||
self.course.course_visibility = course_visibility
|
||||
self.course = self.update_course(self.course, self.user.id)
|
||||
self.update_course_and_overview()
|
||||
|
||||
self.store.create_item(
|
||||
self.user.id, self.course.id, 'course_info', 'handouts', fields={'data': '<p>Handouts</p>'}
|
||||
@@ -392,8 +398,42 @@ class OutlineTabTestViews(BaseCourseHomeTests):
|
||||
def test_user_has_passing_grade(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.course._grading_policy['GRADE_CUTOFFS']['Pass'] = 0 # pylint: disable=protected-access
|
||||
self.update_course(self.course, self.user.id)
|
||||
self.update_course_and_overview()
|
||||
CourseGradeFactory().update(self.user, self.course)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert response.data['user_has_passing_grade'] is True
|
||||
|
||||
def assert_can_enroll(self, can_enroll):
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert response.data['enroll_alert']['can_enroll'] == can_enroll
|
||||
|
||||
def test_can_enroll_basic(self):
|
||||
self.assert_can_enroll(True)
|
||||
|
||||
def test_cannot_enroll_invitation_only(self):
|
||||
self.course.invitation_only = True
|
||||
self.update_course_and_overview()
|
||||
self.assert_can_enroll(False)
|
||||
|
||||
def test_cannot_enroll_masters_only(self):
|
||||
CourseMode.objects.all().delete()
|
||||
CourseModeFactory(course_id=self.course.id, mode_slug=CourseMode.MASTERS)
|
||||
self.assert_can_enroll(False)
|
||||
|
||||
def test_cannot_enroll_before_enrollment(self):
|
||||
self.course.enrollment_start = datetime.now(timezone.utc) + timedelta(days=1)
|
||||
self.update_course_and_overview()
|
||||
self.assert_can_enroll(False)
|
||||
|
||||
def test_cannot_enroll_after_enrollment(self):
|
||||
self.course.enrollment_end = datetime.now(timezone.utc) - timedelta(days=1)
|
||||
self.update_course_and_overview()
|
||||
self.assert_can_enroll(False)
|
||||
|
||||
def test_cannot_enroll_if_full(self):
|
||||
self.course.max_student_enrollments_allowed = 1
|
||||
self.update_course_and_overview()
|
||||
CourseEnrollment.enroll(UserFactory(), self.course.id) # grr, some rando took our spot!
|
||||
self.assert_can_enroll(False)
|
||||
|
||||
@@ -33,7 +33,6 @@ from lms.djangoapps.courseware.context_processor import user_timezone_locale_pre
|
||||
from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_info_section, get_course_with_access
|
||||
from lms.djangoapps.courseware.date_summary import TodaysDate
|
||||
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade
|
||||
from lms.djangoapps.courseware.toggles import course_is_invitation_only
|
||||
from lms.djangoapps.courseware.views.views import get_cert_data
|
||||
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
|
||||
from openedx.core.djangoapps.content.learning_sequences.api import get_user_course_outline
|
||||
@@ -268,8 +267,11 @@ class OutlineTabView(RetrieveAPIView):
|
||||
'Please contact your degree administrator or '
|
||||
'{platform_name} Support if you have questions.'
|
||||
).format(platform_name=settings.PLATFORM_NAME)
|
||||
elif course_is_invitation_only(course):
|
||||
elif CourseEnrollment.is_enrollment_closed(request.user, course_overview):
|
||||
enroll_alert['can_enroll'] = False
|
||||
elif CourseEnrollment.objects.is_course_full(course_overview):
|
||||
enroll_alert['can_enroll'] = False
|
||||
enroll_alert['extra_text'] = _('Course is full')
|
||||
|
||||
# Sometimes there are sequences returned by Course Blocks that we
|
||||
# don't actually want to show to the user, such as when a sequence is
|
||||
|
||||
Reference in New Issue
Block a user