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:
Michael Terry
2022-04-19 16:11:29 -04:00
committed by GitHub
2 changed files with 47 additions and 5 deletions

View File

@@ -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)

View File

@@ -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